c# ILGenerator nop?

丶灬走出姿态 提交于 2019-12-21 13:08:13

问题


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.


回答1:


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




回答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);
    }
}


来源:https://stackoverflow.com/questions/1498162/c-sharp-ilgenerator-nop

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!