问题
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