I'm working on a compiler using System.Reflection.Emit
, and I'm getting JIT limitation errors I can't figure out. The problem occurs in my implementation of function handles. I.e. generating the code for
function foo() { }
f = foo;
f();
Due to specifications beyond my control, the language is dynamically typed, so I can't know how many arguments f
will expect at compile time. To counter this, rather than emitting a Ldftn
for foo
, I generate a new method, λfoo
, that takes an array of the arguments given in the call expression and pushes them onto the eval stack for foo
. Is that allowed in the CLR?
What I get right now is a "JIT has encountered an internal limitation" exception (or "CLR has detected an invalid program" if I save the assembly and run it instead of calling it from memory) with a stack trace showing it happens in λfoo
. This is the IL I'm generating.
.method private instance class [MylibInterop]MylibInterop.MylibValue
'λfoo'(class [MylibInterop]MylibInterop.MylibValue[] A_1) cil managed
{
// Code size 90 (0x5a)
.maxstack 10
.locals init (int32 V_0,
int32 V_1)
IL_0000: ldarg.1
IL_0001: call instance int32 [mscorlib]System.Array::get_Length()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4 0x0
IL_000d: ble IL_001d
IL_0012: ldstr "Too many arguments to lambda call"
IL_0017: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_001c: throw
IL_001d: ldarg.0
IL_001e: ldc.i4.0
IL_001f: stloc.1
IL_0020: ldloc.0
IL_0021: newobj instance void [MylibInterop]MylibInterop.MylibValue::.ctor(int32)
IL_0026: ldloc.1
IL_0027: ldloc.0
IL_0028: bge IL_003d
IL_002d: ldarg.1
IL_002e: ldloc.1
IL_002f: ldelem [MylibInterop]MylibInterop.MylibValue
IL_0034: ldloc.1
IL_0035: ldc.i4.1
IL_0036: add
IL_0037: stloc.1
IL_0038: br IL_0026
IL_003d: ldloc.0
IL_003e: stloc.1
IL_003f: ldloc.1
IL_0040: ldc.i4 0x0
IL_0045: bge IL_0054
IL_004a: ldnull
IL_004b: ldloc.1
IL_004c: ldc.i4.1
IL_004d: add
IL_004e: stloc.1
IL_004f: br IL_003f
IL_0054: call instance class [MylibInterop]MylibInterop.MylibValue debug.Program::foo(class [MylibInterop]MylibInterop.MylibValue)
IL_0059: ret
} // end of method Program::'λfoo'
int32
is on the stack when calling atIL_0054
instead of your instance (this
) and theMylibValue
arg. – Pythagorasthis
and the arg are pushed atIL_001D
andIL_0021
respectively. I'll look harder at the loop but I didn't think I had left an int on the stack. Google has been no help in fixing the type load failed peverify error, but all code except this methods runs as expected regardless of it. – Coseismal/IL
switch, this should ignore the type errors unless they are marked as IL. – PythagorasIL_002d: ldarg.1 IL_002e: ldloc.1 IL_002f: ldelem [MylibInterop]MylibInterop.MylibValue IL_0034: ldloc.1 IL_0035: ldc.i4.1 IL_0036: add IL_0037: stloc.1
. It looks as though you are adding ldloc.1 and ldc.i4.1, but not doing anything with ldarg.1, ldloc.1 and ldelem. Am I reading that wrong? Perhaps you could give some psuedo-code to demonstrate what it is supposed to be doing. – SommelierIL_000d: ble IL_001d
should be "bge" because you want to skip the throw if Length is greater-than-or-equal than 0; not less-than-or-equal than 0. – Sommelier