c#ILGenerator nop?
我在这里使用ILGenerator生成一些IL是我的代码:
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);
这产生了这个IL:
IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: ldc.i4.s 100 IL_0004: nop IL_0005: nop IL_0006: nop
(我从名为ILStream的VS Virtulizer获取IL代码)
从哪里开始编码? 有没有办法摆脱它们? 我试图模仿一些c#代码,它没有3个nops。
你正朝着正确的方向摆脱“nop”:
当您为Emit调用提供附加参数时,请务必在MSDN上检查正确的参数类型。
对于OpCodes.Ldc_I4_S,MSDN声明:
ldc.i4.s是一种更有效的编码,用于将整数从-128推送到127到>评估堆栈。
以下Emit方法重载可以使用ldc.i4.s操作码:
ILGenerator.Emit(OpCode,byte)
所以代码的第二部分在运行时会产生不可预测的结果(除了那些讨厌的nop),因为你试图在堆栈上加载“int8”,但是提供“int32”或“short”值:
else if (IsBetween(value, short.MinValue, short.MaxValue)) { gen.Emit(OpCodes.Ldc_I4_S, (short)value); } else { gen.Emit(OpCodes.Ldc_I4_S, value); }
如果要将int32 / short(或任何大于一个字节的值)正确加载到堆栈中,则应使用Ldc_I4而不是Ldc_I4_S。 因此,您的代码应该看起来像这样,而不是上面的示例:
else { gen.Emit(OpCodes.Ldc_I4, value); }
这是一个疯狂的猜测,但生成的三个nop可能与int32中的额外字节有关
希望有帮助……
我通过将int转换为值来解决了这个问题:
码:
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); } }