Enable nullable reference types in BizInvoke

This commit is contained in:
YoshiRulz 2021-03-26 11:38:38 +10:00
parent 23d8417ca8
commit b6f1afcce8
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
7 changed files with 67 additions and 57 deletions

View File

@ -71,10 +71,10 @@ namespace BizHawk.BizInvoke
foreach (var a in methods) foreach (var a in methods)
{ {
MethodBuilder unused; MethodBuilder unused;
var delegateType = BizInvokeUtilities.CreateDelegateType(a.Info, a.Attr.CallingConvention, typeBuilder, out unused).CreateType(); var delegateType = BizInvokeUtilities.CreateDelegateType(a.Info, a.Attr!.CallingConvention, typeBuilder, out unused).CreateType()!;
DelegateTypes.Add(new StoredDelegateInfo(a.Info, delegateType, a.Attr.EntryPoint ?? a.Info.Name)); DelegateTypes.Add(new StoredDelegateInfo(a.Info, delegateType, a.Attr.EntryPoint ?? a.Info.Name));
} }
StorageType = typeBuilder.CreateType(); StorageType = typeBuilder.CreateType()!;
OriginalType = type; OriginalType = type;
} }
} }
@ -105,18 +105,18 @@ namespace BizHawk.BizInvoke
public static IImportResolver GetExvoker(object o, ICallingConventionAdapter a) public static IImportResolver GetExvoker(object o, ICallingConventionAdapter a)
{ {
DelegateStorage ds; DelegateStorage? ds;
lock (Impls) lock (Impls)
{ {
var type = o.GetType(); var type = o.GetType();
if (!Impls.TryGetValue(type, out ds)) if (!Impls.TryGetValue(type, out ds))
{ {
ds = new DelegateStorage(type); ds = new DelegateStorage(type);
Impls.Add(type, ds); Impls.Add(type, ds!);
} }
} }
return new ExvokerImpl(o, ds, a); return new ExvokerImpl(o, ds!, a);
} }
} }
@ -127,7 +127,7 @@ namespace BizHawk.BizInvoke
public CallingConvention CallingConvention { get; } public CallingConvention CallingConvention { get; }
/// <remarks>The annotated method's name is used iff <see langword="null"/>.</remarks> /// <remarks>The annotated method's name is used iff <see langword="null"/>.</remarks>
public string EntryPoint { get; set; } public string? EntryPoint { get; set; } = null;
public BizExportAttribute(CallingConvention c) public BizExportAttribute(CallingConvention c)
{ {

View File

@ -5,7 +5,6 @@
<Import Project="../MainSlnCommon.props" /> <Import Project="../MainSlnCommon.props" />
<PropertyGroup> <PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>disable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="$(ProjectDir)../BizHawk.Common/BizHawk.Common.csproj" /> <ProjectReference Include="$(ProjectDir)../BizHawk.Common/BizHawk.Common.csproj" />

View File

@ -54,7 +54,7 @@ namespace BizHawk.BizInvoke
} }
{ {
var p = delegateInvoke.DefineParameter(0, ParameterAttributes.Retval, method.ReturnParameter.Name); var p = delegateInvoke.DefineParameter(0, ParameterAttributes.Retval, method.ReturnParameter!.Name);
foreach (var a in method.ReturnParameter.GetCustomAttributes(false)) foreach (var a in method.ReturnParameter.GetCustomAttributes(false))
{ {
p.SetCustomAttribute(GetAttributeBuilder(a)); p.SetCustomAttribute(GetAttributeBuilder(a));
@ -64,7 +64,9 @@ namespace BizHawk.BizInvoke
delegateInvoke.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); delegateInvoke.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
// add the [UnmanagedFunctionPointer] to the delegate so interop will know how to call it // add the [UnmanagedFunctionPointer] to the delegate so interop will know how to call it
var attr = new CustomAttributeBuilder(typeof(UnmanagedFunctionPointerAttribute).GetConstructor(new[] { typeof(CallingConvention) }), new object[] { nativeCall }); var attr = new CustomAttributeBuilder(
typeof(UnmanagedFunctionPointerAttribute).GetConstructor(new[] { typeof(CallingConvention) })!,
new object[] { nativeCall });
delegateType.SetCustomAttribute(attr); delegateType.SetCustomAttribute(attr);
invokeMethod = delegateInvoke; invokeMethod = delegateInvoke;
@ -80,7 +82,7 @@ namespace BizHawk.BizInvoke
var t = o.GetType(); var t = o.GetType();
if (t == typeof(OutAttribute) || t == typeof(InAttribute)) if (t == typeof(OutAttribute) || t == typeof(InAttribute))
{ {
return new CustomAttributeBuilder(t.GetConstructor(Type.EmptyTypes), new object[0]); return new CustomAttributeBuilder(t.GetConstructor(Type.EmptyTypes)!, new object[0]);
} }
throw new InvalidOperationException($"Unknown parameter attribute {t.Name}"); throw new InvalidOperationException($"Unknown parameter attribute {t.Name}");

View File

@ -18,7 +18,7 @@ namespace BizHawk.BizInvoke
{ {
private readonly Action<object, ICallingConventionAdapter> _connectCallingConventionAdapter; private readonly Action<object, ICallingConventionAdapter> _connectCallingConventionAdapter;
private readonly Action<object, IMonitor> _connectMonitor; private readonly Action<object, IMonitor>? _connectMonitor;
private readonly List<Action<object, IImportResolver, ICallingConventionAdapter>> _hooks; private readonly List<Action<object, IImportResolver, ICallingConventionAdapter>> _hooks;
@ -29,7 +29,7 @@ namespace BizHawk.BizInvoke
public InvokerImpl( public InvokerImpl(
List<Action<object, IImportResolver, ICallingConventionAdapter>> hooks, List<Action<object, IImportResolver, ICallingConventionAdapter>> hooks,
Type implType, Type implType,
Action<object, IMonitor> connectMonitor, Action<object, IMonitor>? connectMonitor,
Action<object, ICallingConventionAdapter> connectCallingConventionAdapter) Action<object, ICallingConventionAdapter> connectCallingConventionAdapter)
{ {
_connectCallingConventionAdapter = connectCallingConventionAdapter; _connectCallingConventionAdapter = connectCallingConventionAdapter;
@ -39,15 +39,15 @@ namespace BizHawk.BizInvoke
IsMonitored = connectMonitor != null; IsMonitored = connectMonitor != null;
} }
public object Create(IImportResolver dll, IMonitor monitor, ICallingConventionAdapter adapter) public object Create(IImportResolver dll, IMonitor? monitor, ICallingConventionAdapter adapter)
{ {
var ret = Activator.CreateInstance(_implType); var ret = Activator.CreateInstance(_implType)!;
_connectCallingConventionAdapter(ret, adapter); _connectCallingConventionAdapter(ret, adapter);
foreach (var f in _hooks) foreach (var f in _hooks)
{ {
f(ret, dll, adapter); f(ret, dll, adapter);
} }
_connectMonitor?.Invoke(ret, monitor); _connectMonitor?.Invoke(ret, monitor!);
return ret; return ret;
} }
} }
@ -94,18 +94,18 @@ namespace BizHawk.BizInvoke
where T : class where T : class
{ {
var nonTrivialAdapter = adapter.GetType() != CallingConventionAdapters.Native.GetType(); var nonTrivialAdapter = adapter.GetType() != CallingConventionAdapters.Native.GetType();
InvokerImpl impl; InvokerImpl? impl;
lock (Impls) lock (Impls)
{ {
var baseType = typeof(T); var baseType = typeof(T);
if (!Impls.TryGetValue(baseType, out impl)) if (!Impls.TryGetValue(baseType, out impl))
{ {
impl = CreateProxy(baseType, false, nonTrivialAdapter); impl = CreateProxy(baseType, false, nonTrivialAdapter);
Impls.Add(baseType, impl); Impls.Add(baseType, impl!);
} }
} }
if (impl.IsMonitored) if (impl!.IsMonitored)
{ {
throw new InvalidOperationException("Class was previously proxied with a monitor!"); throw new InvalidOperationException("Class was previously proxied with a monitor!");
} }
@ -118,18 +118,18 @@ namespace BizHawk.BizInvoke
where T : class where T : class
{ {
var nonTrivialAdapter = adapter.GetType() != CallingConventionAdapters.Native.GetType(); var nonTrivialAdapter = adapter.GetType() != CallingConventionAdapters.Native.GetType();
InvokerImpl impl; InvokerImpl? impl;
lock (Impls) lock (Impls)
{ {
var baseType = typeof(T); var baseType = typeof(T);
if (!Impls.TryGetValue(baseType, out impl)) if (!Impls.TryGetValue(baseType, out impl))
{ {
impl = CreateProxy(baseType, true, nonTrivialAdapter); impl = CreateProxy(baseType, true, nonTrivialAdapter);
Impls.Add(baseType, impl); Impls.Add(baseType, impl!);
} }
} }
if (!impl.IsMonitored) if (!(impl!.IsMonitored))
{ {
throw new InvalidOperationException("Class was previously proxied without a monitor!"); throw new InvalidOperationException("Class was previously proxied without a monitor!");
} }
@ -197,7 +197,7 @@ namespace BizHawk.BizInvoke
foreach (var mi in baseMethods) foreach (var mi in baseMethods)
{ {
var entryPointName = mi.Attr.EntryPoint ?? mi.Info.Name; var entryPointName = mi.Attr!.EntryPoint ?? mi.Info.Name;
var hook = mi.Attr.Compatibility var hook = mi.Attr.Compatibility
? ImplementMethodDelegate(type, mi.Info, mi.Attr.CallingConvention, entryPointName, monitorField, nonTrivialAdapter) ? ImplementMethodDelegate(type, mi.Info, mi.Attr.CallingConvention, entryPointName, monitorField, nonTrivialAdapter)
@ -208,9 +208,9 @@ namespace BizHawk.BizInvoke
return new( return new(
postCreateHooks, postCreateHooks,
type.CreateType(), type.CreateType()!,
connectMonitor: monitor connectMonitor: monitor
? (o, m) => o.GetType().GetField(monitorField.Name).SetValue(o, m) ? (o, m) => o.GetType().GetField(monitorField!.Name).SetValue(o, m)
: null, : null,
connectCallingConventionAdapter: (o, a) => o.GetType().GetField(adapterField.Name).SetValue(o, a)); connectCallingConventionAdapter: (o, a) => o.GetType().GetField(adapterField.Name).SetValue(o, a));
} }
@ -219,7 +219,11 @@ namespace BizHawk.BizInvoke
/// create a method implementation that uses GetDelegateForFunctionPointer internally /// create a method implementation that uses GetDelegateForFunctionPointer internally
/// </summary> /// </summary>
private static Action<object, IImportResolver, ICallingConventionAdapter> ImplementMethodDelegate( private static Action<object, IImportResolver, ICallingConventionAdapter> ImplementMethodDelegate(
TypeBuilder type, MethodInfo baseMethod, CallingConvention nativeCall, string entryPointName, FieldInfo monitorField, TypeBuilder type,
MethodInfo baseMethod,
CallingConvention nativeCall,
string entryPointName,
FieldInfo? monitorField,
bool nonTrivialAdapter) bool nonTrivialAdapter)
{ {
// create the delegate type // create the delegate type
@ -260,7 +264,7 @@ namespace BizHawk.BizInvoke
{ {
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, monitorField); il.Emit(OpCodes.Ldfld, monitorField);
il.Emit(OpCodes.Callvirt, typeof(IMonitor).GetMethod("Enter")); il.Emit(OpCodes.Callvirt, typeof(IMonitor).GetMethod("Enter")!);
exc = il.BeginExceptionBlock(); exc = il.BeginExceptionBlock();
} }
@ -275,7 +279,7 @@ namespace BizHawk.BizInvoke
if (monitorField != null) // monitor: finally exit if (monitorField != null) // monitor: finally exit
{ {
LocalBuilder loc = null; LocalBuilder? loc = null;
if (returnType != typeof(void)) if (returnType != typeof(void))
{ {
loc = il.DeclareLocal(returnType); loc = il.DeclareLocal(returnType);
@ -286,12 +290,12 @@ namespace BizHawk.BizInvoke
il.BeginFinallyBlock(); il.BeginFinallyBlock();
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, monitorField); il.Emit(OpCodes.Ldfld, monitorField);
il.Emit(OpCodes.Callvirt, typeof(IMonitor).GetMethod("Exit")); il.Emit(OpCodes.Callvirt, typeof(IMonitor).GetMethod("Exit")!);
il.EndExceptionBlock(); il.EndExceptionBlock();
if (returnType != typeof(void)) if (returnType != typeof(void))
{ {
il.Emit(OpCodes.Ldloc, loc); il.Emit(OpCodes.Ldloc, loc!);
} }
} }
@ -331,8 +335,12 @@ namespace BizHawk.BizInvoke
/// create a method implementation that uses calli internally /// create a method implementation that uses calli internally
/// </summary> /// </summary>
private static Action<object, IImportResolver, ICallingConventionAdapter> ImplementMethodCalli( private static Action<object, IImportResolver, ICallingConventionAdapter> ImplementMethodCalli(
TypeBuilder type, MethodInfo baseMethod, TypeBuilder type,
CallingConvention nativeCall, string entryPointName, FieldInfo monitorField, FieldInfo adapterField) MethodInfo baseMethod,
CallingConvention nativeCall,
string entryPointName,
FieldInfo? monitorField,
FieldInfo adapterField)
{ {
var paramInfos = baseMethod.GetParameters(); var paramInfos = baseMethod.GetParameters();
var paramTypes = paramInfos.Select(p => p.ParameterType).ToArray(); var paramTypes = paramInfos.Select(p => p.ParameterType).ToArray();
@ -363,7 +371,7 @@ namespace BizHawk.BizInvoke
{ {
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, monitorField); il.Emit(OpCodes.Ldfld, monitorField);
il.Emit(OpCodes.Callvirt, typeof(IMonitor).GetMethod("Enter")); il.Emit(OpCodes.Callvirt, typeof(IMonitor).GetMethod("Enter")!);
exc = il.BeginExceptionBlock(); exc = il.BeginExceptionBlock();
} }
@ -388,7 +396,7 @@ namespace BizHawk.BizInvoke
if (monitorField != null) // monitor: finally exit if (monitorField != null) // monitor: finally exit
{ {
LocalBuilder loc = null; LocalBuilder? loc = null;
if (returnType != typeof(void)) if (returnType != typeof(void))
{ {
loc = il.DeclareLocal(returnType); loc = il.DeclareLocal(returnType);
@ -399,12 +407,12 @@ namespace BizHawk.BizInvoke
il.BeginFinallyBlock(); il.BeginFinallyBlock();
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, monitorField); il.Emit(OpCodes.Ldfld, monitorField);
il.Emit(OpCodes.Callvirt, typeof(IMonitor).GetMethod("Exit")); il.Emit(OpCodes.Callvirt, typeof(IMonitor).GetMethod("Exit")!);
il.EndExceptionBlock(); il.EndExceptionBlock();
if (returnType != typeof(void)) if (returnType != typeof(void))
{ {
il.Emit(OpCodes.Ldloc, loc); il.Emit(OpCodes.Ldloc, loc!);
} }
} }
@ -477,7 +485,7 @@ namespace BizHawk.BizInvoke
if (type.IsByRef) if (type.IsByRef)
{ {
var et = type.GetElementType(); var et = type.GetElementType()!;
if (!et.IsPrimitive && !et.IsEnum) if (!et.IsPrimitive && !et.IsEnum)
{ {
throw new NotImplementedException("Only refs of primitive or enum types are supported!"); throw new NotImplementedException("Only refs of primitive or enum types are supported!");
@ -496,7 +504,7 @@ namespace BizHawk.BizInvoke
if (type.IsArray) if (type.IsArray)
{ {
var et = type.GetElementType(); var et = type.GetElementType()!;
if (!et.IsValueType) if (!et.IsValueType)
{ {
throw new NotImplementedException("Only arrays of value types are supported!"); throw new NotImplementedException("Only arrays of value types are supported!");
@ -545,7 +553,7 @@ namespace BizHawk.BizInvoke
typeof(IntPtr), typeof(IntPtr),
() => () =>
{ {
var mi = typeof(ICallingConventionAdapter).GetMethod("GetFunctionPointerForDelegate"); var mi = typeof(ICallingConventionAdapter).GetMethod("GetFunctionPointerForDelegate")!;
var end = il.DefineLabel(); var end = il.DefineLabel();
var isNull = il.DefineLabel(); var isNull = il.DefineLabel();
@ -573,13 +581,13 @@ namespace BizHawk.BizInvoke
il.Emit(OpCodes.Brfalse, isNull); il.Emit(OpCodes.Brfalse, isNull);
var encoding = il.DeclareLocal(typeof(Encoding), false); var encoding = il.DeclareLocal(typeof(Encoding), false);
il.EmitCall(OpCodes.Call, typeof(Encoding).GetProperty("UTF8").GetGetMethod(), Type.EmptyTypes); il.EmitCall(OpCodes.Call, typeof(Encoding).GetProperty("UTF8")!.GetGetMethod(), Type.EmptyTypes);
il.Emit(OpCodes.Stloc, encoding); il.Emit(OpCodes.Stloc, encoding);
var strlenbytes = il.DeclareLocal(typeof(int), false); var strlenbytes = il.DeclareLocal(typeof(int), false);
il.Emit(OpCodes.Ldloc, encoding); il.Emit(OpCodes.Ldloc, encoding);
il.Emit(OpCodes.Ldarg, (short)idx); il.Emit(OpCodes.Ldarg, (short)idx);
il.EmitCall(OpCodes.Callvirt, typeof(Encoding).GetMethod("GetByteCount", new[] { typeof(string) }), Type.EmptyTypes); il.EmitCall(OpCodes.Callvirt, typeof(Encoding).GetMethod("GetByteCount", new[] { typeof(string) })!, Type.EmptyTypes);
il.Emit(OpCodes.Stloc, strlenbytes); il.Emit(OpCodes.Stloc, strlenbytes);
var strval = il.DeclareLocal(typeof(string), true); // pin! var strval = il.DeclareLocal(typeof(string), true); // pin!
@ -605,13 +613,13 @@ namespace BizHawk.BizInvoke
il.Emit(OpCodes.Add); il.Emit(OpCodes.Add);
// charcount // charcount
il.Emit(OpCodes.Ldloc, strval); il.Emit(OpCodes.Ldloc, strval);
il.Emit(OpCodes.Call, typeof(string).GetProperty("Length").GetGetMethod()); il.Emit(OpCodes.Call, typeof(string).GetProperty("Length")!.GetGetMethod());
// bytes // bytes
il.Emit(OpCodes.Ldloc, bytes); il.Emit(OpCodes.Ldloc, bytes);
// bytelength // bytelength
il.Emit(OpCodes.Ldloc, strlenbytes); il.Emit(OpCodes.Ldloc, strlenbytes);
// call // call
il.EmitCall(OpCodes.Callvirt, typeof(Encoding).GetMethod("GetBytes", new[] { typeof(char*), typeof(int), typeof(byte*), typeof(int) }), Type.EmptyTypes); il.EmitCall(OpCodes.Callvirt, typeof(Encoding).GetMethod("GetBytes", new[] { typeof(char*), typeof(int), typeof(byte*), typeof(int) })!, Type.EmptyTypes);
// unused ret // unused ret
il.Emit(OpCodes.Pop); il.Emit(OpCodes.Pop);
@ -681,7 +689,7 @@ namespace BizHawk.BizInvoke
public CallingConvention CallingConvention { get; } public CallingConvention CallingConvention { get; }
/// <remarks>The annotated method's name is used iff <see langword="null"/>.</remarks> /// <remarks>The annotated method's name is used iff <see langword="null"/>.</remarks>
public string EntryPoint { get; set; } public string? EntryPoint { get; set; } = null;
/// <summary><see langword="true"/> iff a compatibility interop should be used, which is slower but supports more argument types.</summary> /// <summary><see langword="true"/> iff a compatibility interop should be used, which is slower but supports more argument types.</summary>
public bool Compatibility { get; set; } public bool Compatibility { get; set; }

View File

@ -5,6 +5,7 @@ namespace BizHawk.BizInvoke
{ {
public static unsafe class BizInvokerUtilities public static unsafe class BizInvokerUtilities
{ {
#nullable disable //TODO If U1 and U2 were structs, this wouldn't be a problem. Would changing them to structs break this helper's functionality? --yoshi
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
private class U private class U
{ {
@ -13,6 +14,7 @@ namespace BizHawk.BizInvoke
[FieldOffset(0)] [FieldOffset(0)]
public U2 Second; public U2 Second;
} }
#nullable restore
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
private class U1 private class U1
{ {
@ -24,6 +26,8 @@ namespace BizHawk.BizInvoke
{ {
[FieldOffset(0)] [FieldOffset(0)]
public object Target; public object Target;
public U2(object target) => Target = target;
} }
private class CF private class CF
{ {
@ -39,7 +43,7 @@ namespace BizHawk.BizInvoke
int ret; int ret;
fixed(int* fx = &c.FirstField) fixed(int* fx = &c.FirstField)
{ {
var u = new U { Second = new U2 { Target = c }}; var u = new U { Second = new U2(c) };
ret = (int)((ulong)(UIntPtr)fx - (ulong)u.First.P); ret = (int)((ulong)(UIntPtr)fx - (ulong)u.First.P);
} }
return ret; return ret;
@ -50,7 +54,7 @@ namespace BizHawk.BizInvoke
int ret; int ret;
fixed(char* fx = s) fixed(char* fx = s)
{ {
var u = new U { Second = new U2 { Target = s }}; var u = new U { Second = new U2(s) };
ret = (int)((ulong)(UIntPtr)fx - (ulong)u.First.P); ret = (int)((ulong)(UIntPtr)fx - (ulong)u.First.P);
} }
return ret; return ret;

View File

@ -68,7 +68,7 @@ namespace BizHawk.BizInvoke
{ {
if (!typeof(Delegate).IsAssignableFrom(delegateType)) if (!typeof(Delegate).IsAssignableFrom(delegateType))
throw new InvalidOperationException("Must be a delegate type!"); throw new InvalidOperationException("Must be a delegate type!");
var invoke = delegateType.GetMethod("Invoke"); var invoke = delegateType.GetMethod("Invoke")!;
ReturnType = invoke.ReturnType; ReturnType = invoke.ReturnType;
ParameterTypes = invoke.GetParameters().Select(p => p.ParameterType).ToList().AsReadOnly(); ParameterTypes = invoke.GetParameters().Select(p => p.ParameterType).ToList().AsReadOnly();
} }
@ -170,10 +170,10 @@ namespace BizHawk.BizInvoke
: (ICallingConventionAdapter)new MsHostSysVGuest(); : (ICallingConventionAdapter)new MsHostSysVGuest();
} }
private readonly Dictionary<Delegate, int> _slots; private readonly Dictionary<Delegate, int>? _slots;
private readonly ICallbackAdjuster _waterboxHost; private readonly ICallbackAdjuster _waterboxHost;
public WaterboxAdapter(IEnumerable<Delegate> slots, ICallbackAdjuster waterboxHost) public WaterboxAdapter(IEnumerable<Delegate>? slots, ICallbackAdjuster waterboxHost)
{ {
if (slots != null) if (slots != null)
{ {
@ -246,7 +246,7 @@ namespace BizHawk.BizInvoke
private readonly MemoryBlock _memory; private readonly MemoryBlock _memory;
private readonly object _sync = new object(); private readonly object _sync = new object();
private readonly WeakReference[] _refs; private readonly WeakReference?[] _refs;
public MsHostSysVGuest() public MsHostSysVGuest()
{ {
@ -259,8 +259,7 @@ namespace BizHawk.BizInvoke
{ {
for (int i = 0; i < _refs.Length; i++) for (int i = 0; i < _refs.Length; i++)
{ {
if (_refs[i] == null || !_refs[i].IsAlive) if (_refs[i] is not { IsAlive: true }) return i; // return index of first null or dead
return i;
} }
throw new InvalidOperationException("Out of Thunk memory"); throw new InvalidOperationException("Out of Thunk memory");
} }
@ -331,10 +330,8 @@ namespace BizHawk.BizInvoke
private void SetLifetime(int index, object lifetime) private void SetLifetime(int index, object lifetime)
{ {
if (_refs[index] == null) _refs[index] ??= new(null);
_refs[index] = new WeakReference(lifetime); _refs[index]!.Target = lifetime;
else
_refs[index].Target = lifetime;
} }
public IntPtr GetFunctionPointerForDelegate(Delegate d) public IntPtr GetFunctionPointerForDelegate(Delegate d)

View File

@ -21,11 +21,11 @@ namespace BizHawk.BizInvoke
_pal = OSTailoredCode.IsUnixHost _pal = OSTailoredCode.IsUnixHost
? (IMemoryBlockPal)new MemoryBlockLinuxPal(Size) ? (IMemoryBlockPal)new MemoryBlockLinuxPal(Size)
: new MemoryBlockWindowsPal(Size); : new MemoryBlockWindowsPal(Size);
Start = _pal.Start; Start = _pal!.Start;
EndExclusive = Start + Size; EndExclusive = Start + Size;
} }
private IMemoryBlockPal _pal; private IMemoryBlockPal? _pal;
/// <summary> /// <summary>
/// end address of the memory block (not part of the block; class invariant: equal to <see cref="Start"/> + <see cref="Size"/>) /// end address of the memory block (not part of the block; class invariant: equal to <see cref="Start"/> + <see cref="Size"/>)