Я сделал ошибку в этом IL, которого я не вижу?

Я работаю над компилятором, используя System.Reflection.Emit, и я получаю ошибки ограничения JIT, я не могу понять. Проблема возникает в моей реализации дескрипторов функций. Т.е. генерация кода для

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

Из-за не зависящих от меня спецификаций язык динамически типизирован, поэтому я не знаю, сколько аргументов f будет ожидать во время компиляции. Чтобы противостоять этому, а не испускать Ldftn за fooЯ генерирую новый метод, λfoo, который принимает массив аргументов, заданных в выражении вызова, и помещает их в стек eval для foo, Это разрешено в CLR?

Сейчас я получаю исключение "JIT обнаружил внутреннее ограничение" (или "CLR обнаружил недопустимую программу", если я сохраняю сборку и запускаю ее вместо вызова из памяти) с трассировкой стека, показывающей, что это происходит в λfoo, Это IL, который я генерирую.

.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'

1 ответ

@leppie получил это в комментариях: стек должен быть детерминированным; его нет в коде, который я генерировал (даже если я знаю, что он выдвигает правильное количество аргументов). Я смог обойти это, потому что у компилятора было достаточно информации, чтобы развернуть цикл (отсюда и константы в сгенерированном IL) и, таким образом, создать детерминированный стек.

Другие вопросы по тегам