Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# ILGenerator nop?

Tags:

c#

cil

Im generating some IL with the ILGenerator here is my code:

DynamicMethod method = new DynamicMethod("test", null, Type.EmptyTypes);
ILGenerator gen = method.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Ldc_I4_S, 100);

This generated this IL:

IL_0000:  ldarg.0    
IL_0001:  ldarg.1    
IL_0002:  ldc.i4.s   100
IL_0004:  nop        
IL_0005:  nop        
IL_0006:  nop        

(I get the IL Code from a VS Virtulizer named ILStream)

From where do the nops code? is there any way to get rid of them? Im trying to imitate some c# code and it doesn't have 3 nops.

like image 256
Peter Avatar asked Sep 30 '09 13:09

Peter


1 Answers

You are in the right direction to get rid of the "nop"s :

When you provide an additional argument to an Emit call, always be sure to check on MSDN for the proper argument type.

For OpCodes.Ldc_I4_S, MSDN states :

ldc.i4.s is a more efficient encoding for pushing the integers from -128 to 127 onto the >evaluation stack.

The following Emit method overload can use the ldc.i4.s opcode:

ILGenerator.Emit(OpCode, byte)

So the second part of your code will have unpredictable results (besides those pesky nop's) at run-time, since you're trying to load an "int8" on the stack, but providing an "int32" or "short" value :

else if (IsBetween(value, short.MinValue, short.MaxValue))
{
    gen.Emit(OpCodes.Ldc_I4_S, (short)value);
}
else
{
    gen.Emit(OpCodes.Ldc_I4_S, value);
}

You should use Ldc_I4 instead of Ldc_I4_S if you want to properly load an int32/short (or anything of greater magnitude than a byte) onto the stack. So your code should look like this instead of the above sample :

else
{
    gen.Emit(OpCodes.Ldc_I4, value);
}

This is a wild guess, but the three nop's that were generated probably have something to do with the extra bytes from your int32

Hope that helps...

like image 148
T. Fabre Avatar answered Oct 15 '22 09:10

T. Fabre