ILGenerator 在数组中存储元素时发出 Break 指令

发布于 2024-09-30 09:37:40 字数 2089 浏览 3 评论 0原文

我正在使用 ILGenerator.Emit 生成动态类型。我正在生成一个方法体,它将方法参数的类型存储在数组中。为了实际将元素存储在数组中,我循环遍历给定方法的参数并构建必要的 IL 来存储元素。在第二次迭代中,Break 指令出现在 Stelem.ref (下面的 L_003d) 指令之后。这总是发生在第二次迭代时,我不明白为什么。这是代码:

        ilGenerator.Emit(OpCodes.Ldc_I4, exampleMethod.GetParameters().Length);
        ilGenerator.Emit(OpCodes.Newarr, typeof(Type));
        ilGenerator.Emit(OpCodes.Stloc, typeArray);

        for (int idx = 0; idx < exampleMethod.GetParameters().Length; idx++)
        {
            ilGenerator.Emit(OpCodes.Ldloc, typeArray);
            ilGenerator.Emit(OpCodes.Ldc_I4, idx);
            ilGenerator.Emit(OpCodes.Ldarg, idx + 1);
            ilGenerator.Emit(OpCodes.Box, typeof(int));
            ilGenerator.EmitCall(OpCodes.Callvirt, typeof(object).GetMethod("GetType"), null);
            ilGenerator.Emit(OpCodes.Stelem_Ref, idx);//second iteration causes a break to be output in the IL
        }

        ilGenerator.Emit(OpCodes.Ret);

IL 输出在这里

.method public virtual instance int32 Add3(int32, int32, int32) cil managed
 {
.maxstack 3
.locals init (
    [0] class [mscorlib]System.Type[] typeArray)
L_0000: ldc.i4 3
L_0005: newarr [mscorlib]System.Type
L_000a: stloc.0 
L_000b: ldloc.0 
L_000c: ldc.i4 0
L_0011: ldarg A_0
L_0015: nop 
L_0016: nop 
L_0017: box int32
L_001c: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_0021: stelem.ref 
L_0022: nop 
L_0023: nop 
L_0024: nop 
L_0025: nop 
L_0026: ldloc.0 
L_0027: ldc.i4 1
L_002c: ldarg A_1
L_0030: nop 
L_0031: nop 
L_0032: box int32
L_0037: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_003c: stelem.ref 
**L_003d: break** 
L_003e: nop 
L_003f: nop 
L_0040: nop 
L_0041: ldloc.0 
L_0042: ldc.i4 2
L_0047: ldarg A_2
L_004b: nop 
L_004c: nop 
L_004d: box int32
L_0052: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_0057: stelem.ref 
L_0058: ldarg.0 
L_0059: nop 
L_005a: nop 
L_005b: nop 
L_005c: ret 
}

任何指示或建议将不胜感激。

非常感

谢德莫特

I'm generating dynamic types using ILGenerator.Emit. I am generating a method body that will store the types of the method arguments in an array. To actually store the elements in the array I am looping through parameters of a given method and building up the necessary IL to store the elements. On the second iteration a Break instruction appears after the Stelem.ref (L_003d below) instruction. This always happens on the second iteration and I cannot figure out why. Here is the code:

        ilGenerator.Emit(OpCodes.Ldc_I4, exampleMethod.GetParameters().Length);
        ilGenerator.Emit(OpCodes.Newarr, typeof(Type));
        ilGenerator.Emit(OpCodes.Stloc, typeArray);

        for (int idx = 0; idx < exampleMethod.GetParameters().Length; idx++)
        {
            ilGenerator.Emit(OpCodes.Ldloc, typeArray);
            ilGenerator.Emit(OpCodes.Ldc_I4, idx);
            ilGenerator.Emit(OpCodes.Ldarg, idx + 1);
            ilGenerator.Emit(OpCodes.Box, typeof(int));
            ilGenerator.EmitCall(OpCodes.Callvirt, typeof(object).GetMethod("GetType"), null);
            ilGenerator.Emit(OpCodes.Stelem_Ref, idx);//second iteration causes a break to be output in the IL
        }

        ilGenerator.Emit(OpCodes.Ret);

and the IL output is here

.method public virtual instance int32 Add3(int32, int32, int32) cil managed
 {
.maxstack 3
.locals init (
    [0] class [mscorlib]System.Type[] typeArray)
L_0000: ldc.i4 3
L_0005: newarr [mscorlib]System.Type
L_000a: stloc.0 
L_000b: ldloc.0 
L_000c: ldc.i4 0
L_0011: ldarg A_0
L_0015: nop 
L_0016: nop 
L_0017: box int32
L_001c: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_0021: stelem.ref 
L_0022: nop 
L_0023: nop 
L_0024: nop 
L_0025: nop 
L_0026: ldloc.0 
L_0027: ldc.i4 1
L_002c: ldarg A_1
L_0030: nop 
L_0031: nop 
L_0032: box int32
L_0037: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_003c: stelem.ref 
**L_003d: break** 
L_003e: nop 
L_003f: nop 
L_0040: nop 
L_0041: ldloc.0 
L_0042: ldc.i4 2
L_0047: ldarg A_2
L_004b: nop 
L_004c: nop 
L_004d: box int32
L_0052: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_0057: stelem.ref 
L_0058: ldarg.0 
L_0059: nop 
L_005a: nop 
L_005b: nop 
L_005c: ret 
}

Any pointers or suggestions would be greatly appreciated.

Many thanks

Dermot

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

狼亦尘 2024-10-07 09:37:41

break 的操作码是 0x01,顺便说一句,它也是您作为参数传递给 stelem.ref 发出的 idx 值。请注意,第三次迭代时有一个额外的 ldarg.0(其中 idx 为 2)。

您不应为 stelem 发出指定参数。

The opcode for break is 0x01, which incidentally is also the idx value you pass as a parameter to the stelem.ref emit. Note that there's an extra ldarg.0 on the third iteration (where idx is 2).

You should not specify a parameter to the stelem emit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文