Ошибка в коде IL с использованием Reflection.Emit

Я пишу компилятор, который генерирует .NET IL. Я пишу это на Linux Mint, используя C#/Mono.

Есть проблема с некоторым кодом, который я генерирую с помощью Reflection.Emit. Пожалуйста, извините за ужасные имена в сгенерированном коде. Ниже приведена соответствующая часть вывода из monodis.

.method public static 
       default valuetype Argon.30 Argon.28313529 (valuetype Argon.35 A_0)  cil managed 
{
    // Method begins at RVA 0x215c
// Code size 73 (0x49)
.maxstack 10
.locals init (
    valuetype Argon.35  V_0,
    valuetype Argon.35  V_1)
IL_0000:  ldarg.0 
IL_0001:  stloc.0 
IL_0002:  ldloca.s 0
IL_0004:  ldc.i4.7 
IL_0005:  newobj instance void valuetype Argon.35::'.ctor'(int32)
IL_000a:  call instance valuetype Argon.35 valuetype Argon.35::'add'(valuetype Argon.35)
IL_000f:  stloc.0 
IL_0010:  ldloc.0 
IL_0011:  stloc.1 
IL_0012:  ldloca.s 1
IL_0014:  ldc.i4.2 
IL_0015:  newobj instance void valuetype Argon.35::'.ctor'(int32)
IL_001a:  call instance valuetype Argon.35 valuetype Argon.35::'sub'(valuetype Argon.35)
IL_001f:  stloc.0 
IL_0020:  ldsfld class Argon.747970655F30 Argon.747970655F30::'instance'
IL_0025:  call valuetype Argon.30 Argon.283129()
IL_002a:  pop 
IL_002b:  ldarg.0 
IL_002c:  call valuetype Argon.30 Argon.28313229(valuetype Argon.35)
IL_0031:  pop 
IL_0032:  ldstr " + 5 = "
IL_0037:  newobj instance void class Argon.32::'.ctor'(string)
IL_003c:  call valuetype Argon.30 Argon.28313129(class Argon.32)
IL_0041:  pop 
IL_0042:  ldloc.0 
IL_0043:  call valuetype Argon.30 Argon.28313229(valuetype Argon.35)
IL_0048:  ret 
} // end of global method Argon.28313529

Когда я запускаю это в моно, я получаю следующую ошибку.

System.InvalidProgramException: Недопустимый код IL в: Argon.28313529 (Argon.35): IL_0048: ret

Кажется, нет проблем с запуском этого под Microsoft .NET. Насколько я понимаю, это связано с тем, что моно выполняет проверки перед оптимизацией.

Кроме того, ниже приведена предыдущая версия кода без ошибки.

.method public static 
       default valuetype Argon.30 Argon.28313529 (valuetype Argon.35 A_0)  cil managed 
{
    // Method begins at RVA 0x215c
// Code size 46 (0x2e)
.maxstack 6
.locals init (
    valuetype Argon.35  V_0)
IL_0000:  ldarg.0 
IL_0001:  stloc.0 
IL_0002:  ldloca.s 0
IL_0004:  ldc.i4.7 
IL_0005:  newobj instance void valuetype Argon.35::'.ctor'(int32)
IL_000a:  call instance valuetype Argon.35 valuetype Argon.35::'add'(valuetype Argon.35)
IL_000f:  stloc.0 
IL_0010:  ldarg.0 
IL_0011:  call valuetype Argon.30 Argon.28313229(valuetype Argon.35)
IL_0016:  pop 
IL_0017:  ldstr " + 5 = "
IL_001c:  newobj instance void class Argon.32::'.ctor'(string)
IL_0021:  call valuetype Argon.30 Argon.28313129(class Argon.32)
IL_0026:  pop 
IL_0027:  ldloc.0 
IL_0028:  call valuetype Argon.30 Argon.28313229(valuetype Argon.35)
IL_002d:  ret 
} // end of global method Argon.28313529

person MI3Guy    schedule 22.08.2014    source источник
comment
Попробуйте проверить свой код с помощью PEVerify.exe из пакета SDK для .NET. Это может дать вам лучшее сообщение об ошибке, чем верификатор Mono.   -  person cynic    schedule 22.08.2014


Ответы (2)


Разве вы не оставляете экземпляр Argon.747970655F30, помещенный в стек в IL_0020, в дополнение к экземпляру Argon.30, возвращенному инструкцией в IL_0043? Это оставило бы 2 элемента в стеке, когда вы ret, а не один.

person Iridium    schedule 22.08.2014
comment
В этом была проблема. Функция не создавалась как метод экземпляра. - person MI3Guy; 22.08.2014

Инструкция на IL_0020 разбалансирует стек, она не должна была быть испущена. Это похоже на ошибку в парсере вашего языка. Эквивалентно тому, чтобы не сообщать об ошибках кодирования такого рода:

class Example {
    Example instance;
    static void Method() { }
    void Bug() {
        instance.Method();    // CS0176
    }
}
person Hans Passant    schedule 22.08.2014