Support marshalling arrays of length 0 through BizInvoker

Such arrays will be marshalled with valid and unique pointers that can be compared but not read from or written to.
This commit is contained in:
nattthebear 2022-12-20 16:56:50 -05:00
parent 5b0fe947df
commit 66c19cfcb2
2 changed files with 50 additions and 2 deletions

View File

@ -86,6 +86,10 @@ namespace BizHawk.BizInvoke
/// How far into a string pointer the first chair is.
/// </summary>
private static readonly int StringOffset;
/// <summary>
/// How far into a value array type element 0 is.
/// </summary>
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();
}
/// <summary>
@ -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);

View File

@ -71,6 +71,48 @@ namespace BizHawk.BizInvoke
return ret;
}
/// <summary>
/// Compute the offset to the 0th element of an array of value types
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// Compute the offset to the 0th element of an array of object types
/// Slow, so cache it if you need it.
/// </summary>
/// <returns></returns>
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<object[], int>)method.CreateDelegate(typeof(Func<object[], int>));
return del(obj);
}
/// <summary>
/// Compute the byte offset of a field relative to a pointer to the class instance.
/// Slow, so cache it if you need it.