471,108 Members | 1,560 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,108 software developers and data experts.

Invalid IL generated by Emit method?

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?
Nov 17 '05 #1
4 2676
Hello

The problem is that in case of the branch is executed, there will be nothing
in the stack at the return statement, if the branch is not executed there
will be arg1 will be in the stack. The JIT compiler makes sure at that all
paths that lead to any instruction will have the same state of the stack.

Best regards,
Sherif El-Metainy

"Gianluca" <gi******@nospam.com> wrote in message
news:Purhe.1481$5m1.1439@trnddc06...
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?

Nov 17 '05 #2
Thanks! I was going nuts over this. I was trying to load each element of an
object[] array on the stack and redirect the call to a "wrapped" function
and could not explain why seemingly correct IL code kept failing.
Rearranging the labels worked, at times...

I thought of some kind of restriction for branching but couldn't find any
documentation over this. Well, thanks again.
"Sherif El-Metainy" <elmeteny REMOVETHIS at thewayout NOSPAM dot net> wrote
in message news:OJ**************@TK2MSFTNGP10.phx.gbl...
Hello

The problem is that in case of the branch is executed, there will be nothing in the stack at the return statement, if the branch is not executed there
will be arg1 will be in the stack. The JIT compiler makes sure at that all
paths that lead to any instruction will have the same state of the stack.

Best regards,
Sherif El-Metainy

"Gianluca" <gi******@nospam.com> wrote in message
news:Purhe.1481$5m1.1439@trnddc06...
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?


Nov 17 '05 #3
ops, but this makes it impossible to write a dynamic binder class. I'm
writing a dynamic IL generator for speeding up reflection. It works very
well for accessing fields and it extremely faster than reflection. But I
have a problem now when generating IL for calling methods. I have a
generating method called "Invoke" on an interface which takes the arguments
as object[] args. Just like MethodInfo.Invoke(). The IL code should "unpack"
the arguments and place them on the evaluation stack and then call the
reflected method. The end result would be prefectly valid stack state but
the JIT doesn't a loop that loads the stack dynamically because at the first
junction it detects an invalid stack state. Is there a way to turn this
thing off?

arg_2 is object[] args

il.DeclareLocal(typeof(int));
// i = args.Length
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Stloc_0);
// :loop
il.MarkLabel(loop);
// i = i - 1
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Sub);
il.Emit(OpCodes.Stloc_0);
// if i < 0 then exit
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Blt_S, exit);
// push args[i]
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldelem_Ref);
// loop
il.Emit(OpCodes.Br_S, loop);
// :exit
il.MarkLabel(exit);
// call
ils.EmitCall(OpCodes.Call, method, null);

At the call the stack could be empty or could contain the unpacked
arguments. Any idea on how to turn off the stack state restriction?
"Gianluca" <gi******@nospam.com> wrote in message
news:9bKhe.2192$5m1.37@trnddc06...
Thanks! I was going nuts over this. I was trying to load each element of an object[] array on the stack and redirect the call to a "wrapped" function
and could not explain why seemingly correct IL code kept failing.
Rearranging the labels worked, at times...

I thought of some kind of restriction for branching but couldn't find any
documentation over this. Well, thanks again.
"Sherif El-Metainy" <elmeteny REMOVETHIS at thewayout NOSPAM dot net> wrote in message news:OJ**************@TK2MSFTNGP10.phx.gbl...
Hello

The problem is that in case of the branch is executed, there will be

nothing
in the stack at the return statement, if the branch is not executed there
will be arg1 will be in the stack. The JIT compiler makes sure at that all paths that lead to any instruction will have the same state of the stack.
Best regards,
Sherif El-Metainy

"Gianluca" <gi******@nospam.com> wrote in message
news:Purhe.1481$5m1.1439@trnddc06...
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?



Nov 17 '05 #4
ok, the solution is to generate the correct number of load operations for
the actual method being wrapped.

"Gianluca" <gi******@nospam.com> wrote in message
news:3AKhe.7828$Y12.4069@trnddc09...
ops, but this makes it impossible to write a dynamic binder class. I'm
writing a dynamic IL generator for speeding up reflection. It works very
well for accessing fields and it extremely faster than reflection. But I
have a problem now when generating IL for calling methods. I have a
generating method called "Invoke" on an interface which takes the arguments as object[] args. Just like MethodInfo.Invoke(). The IL code should "unpack" the arguments and place them on the evaluation stack and then call the
reflected method. The end result would be prefectly valid stack state but
the JIT doesn't a loop that loads the stack dynamically because at the first junction it detects an invalid stack state. Is there a way to turn this
thing off?

arg_2 is object[] args

il.DeclareLocal(typeof(int));
// i = args.Length
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Stloc_0);
// :loop
il.MarkLabel(loop);
// i = i - 1
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Sub);
il.Emit(OpCodes.Stloc_0);
// if i < 0 then exit
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Blt_S, exit);
// push args[i]
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldelem_Ref);
// loop
il.Emit(OpCodes.Br_S, loop);
// :exit
il.MarkLabel(exit);
// call
ils.EmitCall(OpCodes.Call, method, null);

At the call the stack could be empty or could contain the unpacked
arguments. Any idea on how to turn off the stack state restriction?
"Gianluca" <gi******@nospam.com> wrote in message
news:9bKhe.2192$5m1.37@trnddc06...
Thanks! I was going nuts over this. I was trying to load each element of

an
object[] array on the stack and redirect the call to a "wrapped" function
and could not explain why seemingly correct IL code kept failing.
Rearranging the labels worked, at times...

I thought of some kind of restriction for branching but couldn't find any documentation over this. Well, thanks again.
"Sherif El-Metainy" <elmeteny REMOVETHIS at thewayout NOSPAM dot net>

wrote
in message news:OJ**************@TK2MSFTNGP10.phx.gbl...
Hello

The problem is that in case of the branch is executed, there will be

nothing
in the stack at the return statement, if the branch is not executed there will be arg1 will be in the stack. The JIT compiler makes sure at that all paths that lead to any instruction will have the same state of the stack.
Best regards,
Sherif El-Metainy

"Gianluca" <gi******@nospam.com> wrote in message
news:Purhe.1481$5m1.1439@trnddc06...
> 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?
>
>



Nov 17 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by DEK | last post: by
3 posts views Thread by ayende | last post: by
3 posts views Thread by magounc | last post: by
1 post views Thread by John | last post: by
reply views Thread by =?Utf-8?B?QXJ0dXJvIE1hcnRpbmV6?= | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.