Я пишу компилятор, который генерирует.NET IL. Я пишу его на Linux Mint, используя С#/Mono.
Существует проблема с некоторым кодом, который я генерирую с помощью Reflection.Emit. Извините за ужасные имена в сгенерированном коде. Ниже приведена соответствующая часть выхода из монодиса.
.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
Не оставляете ли вы экземпляр Argon.747970655F30
в стеке IL_0020
, в дополнение к экземпляру Argon.30
возвращаемому инструкцией на IL_0043
? Это оставит 2 элемента в стеке, когда вы ret
, а не один.
Инструкция на IL_0020 несбалансирует стек, его не должно было испускать. Это похоже на ошибку в вашем парсере. Эквивалентно не сообщать о такой ошибке кодирования:
class Example {
Example instance;
static void Method() { }
void Bug() {
instance.Method(); // CS0176
}
}