Question

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.

Was it helpful?

Solution 2

I solved the problem by casting the int to a value:

Code:

private static bool IsBetween(int value, int min, int max)
{
    return (value >= min && value <= max);
}

private static void WriteInt(ILGenerator gen, int value)
{
    gen.Emit(OpCodes.Ldarg_1);
    if (IsBetween(value, sbyte.MinValue, sbyte.MaxValue))
    {
        gen.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
    }
    else if (IsBetween(value, byte.MinValue, byte.MaxValue))
    {
        gen.Emit(OpCodes.Ldc_I4_S, (byte)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);
    }
}

OTHER TIPS

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...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top