gpt4 book ai didi

.net - ILGenerator 方法内联

转载 作者:行者123 更新时间:2023-12-02 17:34:10 25 4
gpt4 key购买 nike

给出以下代码:

using System;
using System.Reflection.Emit;
using System.Diagnostics;
using System.Reflection;

namespace ConsoleApplication1
{
class A
{
public int Do(int n)
{
return n;
}
}

public delegate int DoDelegate();

class Program
{
public static void Main(string[] args)
{
A a = new A();

Stopwatch stopwatch = Stopwatch.StartNew();
int s = 0;
for (int i = 0; i < 100000000; i++)
{
s += a.Do(i);
}

Console.WriteLine(stopwatch.ElapsedMilliseconds);
Console.WriteLine(s);


DynamicMethod dm = new DynamicMethod("Echo", typeof(int), new Type[] { typeof(int) }, true);
ILGenerator il = dm.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ret);

DynamicMethod dm2 = new DynamicMethod("Test", typeof(int), new Type[0]);
il = dm2.GetILGenerator();


Label loopStart = il.DefineLabel();
Label loopCond = il.DefineLabel();

il.DeclareLocal(typeof(int)); // i
il.DeclareLocal(typeof(int)); // s

// s = 0;
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_1);

// i = 0;
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_0);

il.Emit(OpCodes.Br_S, loopCond);

il.MarkLabel(loopStart);

// s += Echo(i);
il.Emit(OpCodes.Ldloc_1); // Load s
il.Emit(OpCodes.Ldloc_0); // Load i
il.Emit(OpCodes.Call, dm); // Call echo method
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc_1);

// i++
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc_0);

il.MarkLabel(loopCond);

// Check for loop condition
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4, 100000000);
il.Emit(OpCodes.Blt_S, loopStart);

il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ret);


DoDelegate doDel = (DoDelegate)dm2.CreateDelegate(typeof(DoDelegate));
s = doDel.Invoke(); // Dummy run to force JIT


stopwatch = Stopwatch.StartNew();
s = doDel.Invoke();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
Console.WriteLine(s);
}
}
}

对 Do 方法的调用被内联。循环在大约 40 毫秒内完成。例如,如果我将 Do 设为虚函数,则它不会内联,并且循环会在 240 毫秒内完成。到目前为止,一切都很好。当我使用 ILGenerator 生成 Do 方法 (Echo),然后使用与给定 main 方法相同的循环生成 DynamicMethod 时,对 Echo 方法的调用永远不会内联,并且循环完成大约需要 240 毫秒。 MSIL 代码是正确的,因为它返回与 C# 代码相同的结果。我确信方法内联是由 JIT 完成的,所以我认为没有理由不内联 Echo 方法。

有人知道为什么这个简单的方法不会被 JIT 内联吗?

最佳答案

经过进一步调查,我得出以下结论:

  1. ILGenerator 生成的方法永远不会被内联。无论您是使用委托(delegate)、从另一个 DynamicMethod 还是从使用 MethodBuilder 创建的方法调用它们,都没有关系。
  2. 现有方法(用 C# 编码并由 VS 编译的方法)仅当从使用 MethodBuilder 创建的方法调用时才能内联。如果从 DynamicMethod 调用,它们将永远不会被内联。

我在彻底测试了许多示例并研究了最终的汇编代码后得出了这一结论。

关于.net - ILGenerator 方法内联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8685263/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com