I made a mistake in this IL that I do not see?

I am working on a compiler using System.Reflection.Emit , and I am getting JIT constraint errors that I cannot understand. The problem arises in my implementation of function descriptors. That is, generating code for

 function foo() { } f = foo; f(); 

Due to parameters independent of me, the language is dynamically entered, so I cannot know how many arguments f will be expected at compile time. To counter this, instead of emitting a Ldftn for foo , I generate a new λfoo method that takes an array of arguments given in the call expression and λfoo the eval stack for foo . Is this allowed in the CLR?

Now I get the error message "JIT encountered an internal constraint" (or "CLR found an invalid program" if I save the assembly and run it instead of recalling it from memory) with a stack showing it happening in λfoo . This is the IL that I generate.

 .method private instance class [MylibInterop]MylibInterop.MylibValuefoo'(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' 
+8
source share
1 answer

@leppie got this in the comments: the stack must be deterministic; it is not in the code that I generated (even if I know that it presses the correct number of arguments). I managed to get around this because the compiler had enough information to expand the loop (hence the constants in the generated IL) and thus create a deterministic stack.

+7
source share

All Articles