G
Gianluca
This is the simplified code I'm trying to generate:
ilg.DeclareLocal(typeof(int)); // define local integer
Label exit = ilg.DefineLabel(); // define "exit" label
ilg.Emit(OpCodes.Ldc_I4_0); // put 0 on the stack
ilg.Emit(OpCodes.Stloc_0); // set the local integer to 0
ilg.Emit(OpCodes.Ldloc_0); // load the local integer (0) on the stack
ilg.Emit(OpCodes.Ldc_I4_1); // load integer 1 on the stack
ilg.Emit(OpCodes.Beq, exit); // if the two values on the stack ar equal,
jump to "exit"
ilg.Emit(OpCodes.Ldarg_1); // load the first argument on the stack
ilg.MarkLabel(exit); // : Exit
ilg.Emit(OpCodes.Ret); // return
This is stripped down version of something that makes more sense than this.
It's a simple "public object GetValue(object value)" function and according
to the IL above it will simply return the first argument since 0 and 1 are
not equal, the branch is not executed and the first argument is loaded on
the stack and returned to the caller.
When executing this function I get a "Common Language Runtime detected an
invalid program." system exception. Now, if you move the label to another
place it works fine:
ilg.DeclareLocal(typeof(int)); // define local integer
Label exit = ilg.DefineLabel(); // define "exit" label
ilg.Emit(OpCodes.Ldc_I4_0); // put 0 on the stack
ilg.Emit(OpCodes.Stloc_0); // set the local integer to 0
ilg.MarkLabel(exit); // : Exit
ilg.Emit(OpCodes.Ldloc_0); // load the local integer (0) on the stack
ilg.Emit(OpCodes.Ldc_I4_1); // load integer 1 on the stack
ilg.Emit(OpCodes.Beq, exit); // if the two values on the stack ar equal,
jump to "exit"
ilg.Emit(OpCodes.Ldarg_1); // load the first argument on the stack
ilg.Emit(OpCodes.Ret); // return
As you can see the lable has been move before the comparison and if the Beq
is executed it would end up in an infinite loop. BUt since 0 and 1 are not
equal the sample code above works perfectly fine.
Anyone has an explanation for this other than a bug somewhere in the JIT,
Emit method or something else?
ilg.DeclareLocal(typeof(int)); // define local integer
Label exit = ilg.DefineLabel(); // define "exit" label
ilg.Emit(OpCodes.Ldc_I4_0); // put 0 on the stack
ilg.Emit(OpCodes.Stloc_0); // set the local integer to 0
ilg.Emit(OpCodes.Ldloc_0); // load the local integer (0) on the stack
ilg.Emit(OpCodes.Ldc_I4_1); // load integer 1 on the stack
ilg.Emit(OpCodes.Beq, exit); // if the two values on the stack ar equal,
jump to "exit"
ilg.Emit(OpCodes.Ldarg_1); // load the first argument on the stack
ilg.MarkLabel(exit); // : Exit
ilg.Emit(OpCodes.Ret); // return
This is stripped down version of something that makes more sense than this.
It's a simple "public object GetValue(object value)" function and according
to the IL above it will simply return the first argument since 0 and 1 are
not equal, the branch is not executed and the first argument is loaded on
the stack and returned to the caller.
When executing this function I get a "Common Language Runtime detected an
invalid program." system exception. Now, if you move the label to another
place it works fine:
ilg.DeclareLocal(typeof(int)); // define local integer
Label exit = ilg.DefineLabel(); // define "exit" label
ilg.Emit(OpCodes.Ldc_I4_0); // put 0 on the stack
ilg.Emit(OpCodes.Stloc_0); // set the local integer to 0
ilg.MarkLabel(exit); // : Exit
ilg.Emit(OpCodes.Ldloc_0); // load the local integer (0) on the stack
ilg.Emit(OpCodes.Ldc_I4_1); // load integer 1 on the stack
ilg.Emit(OpCodes.Beq, exit); // if the two values on the stack ar equal,
jump to "exit"
ilg.Emit(OpCodes.Ldarg_1); // load the first argument on the stack
ilg.Emit(OpCodes.Ret); // return
As you can see the lable has been move before the comparison and if the Beq
is executed it would end up in an infinite loop. BUt since 0 and 1 are not
equal the sample code above works perfectly fine.
Anyone has an explanation for this other than a bug somewhere in the JIT,
Emit method or something else?