diff --git a/src/BizHawk.BizInvoke/BizInvoker.cs b/src/BizHawk.BizInvoke/BizInvoker.cs index 56ddf19bec..2f1bef0495 100644 --- a/src/BizHawk.BizInvoke/BizInvoker.cs +++ b/src/BizHawk.BizInvoke/BizInvoker.cs @@ -86,6 +86,10 @@ namespace BizHawk.BizInvoke /// How far into a string pointer the first chair is. /// private static readonly int StringOffset; + /// + /// How far into a value array type element 0 is. + /// + private static readonly int ValueArrayElementOffset; static BizInvoker() { @@ -94,6 +98,7 @@ namespace BizHawk.BizInvoke ImplModuleBuilder = ImplAssemblyBuilder.DefineDynamicModule("BizInvokerModule"); ClassFieldOffset = BizInvokerUtilities.ComputeClassFirstFieldOffset(); StringOffset = BizInvokerUtilities.ComputeStringOffset(); + ValueArrayElementOffset = BizInvokerUtilities.ComputeValueArrayElementOffset(); } /// @@ -546,9 +551,10 @@ namespace BizHawk.BizInvoke il.Emit(OpCodes.Ldarg, (short)idx); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, loc); - il.Emit(OpCodes.Ldc_I4_0); - il.Emit(OpCodes.Ldelema, et); il.Emit(OpCodes.Conv_I); + il.Emit(OpCodes.Ldc_I4, ValueArrayElementOffset); + il.Emit(OpCodes.Conv_I); + il.Emit(OpCodes.Add); il.Emit(OpCodes.Br, end); il.MarkLabel(isNull); diff --git a/src/BizHawk.BizInvoke/BizInvokerUtilities.cs b/src/BizHawk.BizInvoke/BizInvokerUtilities.cs index e2bd0b02d2..502fab0991 100644 --- a/src/BizHawk.BizInvoke/BizInvokerUtilities.cs +++ b/src/BizHawk.BizInvoke/BizInvokerUtilities.cs @@ -71,6 +71,48 @@ namespace BizHawk.BizInvoke return ret; } + /// + /// Compute the offset to the 0th element of an array of value types + /// + /// + public static int ComputeValueArrayElementOffset() + { + var arr = new int[4]; + int ret; + fixed (int* p = arr) + { + U u = new(new U2(arr)); + ret = (int)((ulong)(UIntPtr) p - (ulong) u.First!.P); + } + return ret; + } + + /// + /// Compute the offset to the 0th element of an array of object types + /// Slow, so cache it if you need it. + /// + /// + public static int ComputeObjectArrayElementOffset() + { + var obj = new object[4]; + var method = new DynamicMethod("ComputeObjectArrayElementOffsetHelper", typeof(int), new[] { typeof(object[]) }, typeof(string).Module, true); + var il = method.GetILGenerator(); + var local = il.DeclareLocal(typeof(object[]), true); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Stloc, local); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Ldelema, typeof(object)); + il.Emit(OpCodes.Conv_I); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Conv_I); + il.Emit(OpCodes.Sub); + il.Emit(OpCodes.Conv_I4); + il.Emit(OpCodes.Ret); + var del = (Func)method.CreateDelegate(typeof(Func)); + return del(obj); + } + /// /// Compute the byte offset of a field relative to a pointer to the class instance. /// Slow, so cache it if you need it.