Corrected the handling of arrays

This includes arrays of primitives and arrays of generics. Our code is
similar to the code generated by the Mono C# compiler for the "fixed"
construct. The .Net compiler produces slightly different code (two local
variables instead of one) - more research is required.
This commit is contained in:
Stefanos A. 2013-11-30 02:00:07 +01:00
parent 0d9df5ad72
commit 31d14cebff

View file

@ -350,16 +350,57 @@ namespace OpenTK.Rewrite
var p = method.Parameters[i]; var p = method.Parameters[i];
il.Emit(OpCodes.Ldarg, i); il.Emit(OpCodes.Ldarg, i);
if (p.ParameterType.IsGenericInstance) if (p.ParameterType.IsByReference)
{ {
body.Variables.Add(new VariableDefinition(new PinnedType(p.ParameterType)));
}
else if (p.ParameterType.IsArray || p.ParameterType.IsByReference)
{
body.Variables.Add(new VariableDefinition(new PinnedType(nint)));
var index = body.Variables.Count - 1; var index = body.Variables.Count - 1;
il.Emit(OpCodes.Stloc, index); il.Emit(OpCodes.Stloc, index);
il.Emit(OpCodes.Ldloc, index); il.Emit(OpCodes.Ldloc, index);
il.Emit(OpCodes.Conv_I);
}
else if (p.ParameterType.IsArray)
{
if (p.ParameterType.Name != method.Module.Import(typeof(string[])).Name)
{
// Pin the array and pass the address
// of its first element.
var element_type = p.ParameterType.GetElementType();
body.Variables.Add(new VariableDefinition(new PinnedType(new ByReferenceType(element_type))));
int pinned_index = body.Variables.Count - 1;
var empty = il.Create(OpCodes.Ldc_I4, 0);
var pin = il.Create(OpCodes.Ldarg, i);
var end = il.Create(OpCodes.Stloc, pinned_index);
// if (array == null) goto empty
il.Emit(OpCodes.Brfalse, empty);
// else if (array.Length != 0) goto pin
il.Emit(OpCodes.Ldarg, i);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Brtrue, pin);
// empty: IntPtr ptr = IntPtr.Zero
il.Append(empty);
il.Emit(OpCodes.Conv_U);
il.Emit(OpCodes.Br, end);
// pin: &array[0]
il.Append(pin);
il.Emit(OpCodes.Ldc_I4, 0);
il.Emit(OpCodes.Ldelema, element_type);
// end: fixed (IntPtr ptr = &array[0])
il.Append(end);
il.Emit(OpCodes.Ldloc, pinned_index);
il.Emit(OpCodes.Conv_I);
}
else
{
// String[] requires special marshalling.
// Let the runtime handle this for now.
}
} }
} }
return i; return i;