我在方法内联(交叉汇编内联)中测试了一些新的 CLR 4.0 行为并发现了一些结果:
程序集类库.dll:
using System.Diagnostics;
using System;
using System.Reflection;
using System.Security;
using System.Runtime.CompilerServices;
namespace ClassLib
{
public static class A
{
static readonly MethodInfo GetExecuting =
typeof(Assembly).GetMethod("GetExecutingAssembly");
public static Assembly Foo(out StackTrace stack) // 13 bytes
{
// explicit call to GetExecutingAssembly()
stack = new StackTrace();
return Assembly.GetExecutingAssembly();
}
public static Assembly Bar(out StackTrace stack) // 25 bytes
{
// reflection call to GetExecutingAssembly()
stack = new StackTrace();
return (Assembly) GetExecuting.Invoke(null, null);
}
public static Assembly Baz(out StackTrace stack) // 9 bytes
{
stack = new StackTrace();
return null;
}
public static Assembly Bob(out StackTrace stack) // 13 bytes
{
// call of non-inlinable method!
return SomeSecurityCriticalMethod(out stack);
}
[SecurityCritical, MethodImpl(MethodImplOptions.NoInlining)]
static Assembly SomeSecurityCriticalMethod(out StackTrace stack)
{
stack = new StackTrace();
return Assembly.GetExecutingAssembly();
}
}
}
程序集 ConsoleApp.exe
using System;
using ClassLib;
using System.Diagnostics;
class Program
{
static void Main()
{
Console.WriteLine("runtime: {0}", Environment.Version);
StackTrace stack;
Console.WriteLine("Foo: {0}\n{1}", A.Foo(out stack), stack);
Console.WriteLine("Bar: {0}\n{1}", A.Bar(out stack), stack);
Console.WriteLine("Baz: {0}\n{1}", A.Baz(out stack), stack);
Console.WriteLine("Bob: {0}\n{1}", A.Bob(out stack), stack);
}
}
结果:
runtime: 4.0.30128.1
Foo: ClassLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
at ClassLib.A.Foo(StackTrace& stack)
at Program.Main()
Bar: ClassLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
at ClassLib.A.Bar(StackTrace& stack)
at Program.Main()
Baz:
at Program.Main()
Bob: ClassLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
at Program.Main()
所以问题是:
- 为什么 JIT 不内联
Foo
和Bar
调用为Baz
做?它们小于 32 字节的 IL,非常适合内联。 - 为什么 JIT 内联调用
Bob
和SomeSecurityCriticalMethod
的内部调用标有[MethodImpl(MethodImplOptions.NoInlining)]
属性? - 为什么
GetExecutingAssembly
当被内联调用时返回有效程序集Baz
和SomeSecurityCriticalMethod
方法?我期望它执行堆栈遍历以检测正在执行的程序集,但堆栈将仅包含Program.Main()
没有调用ClassLib
的方法组装,到ConsoleApp
应该归还。
最佳答案
关于assemblies - CLR 4.0 内联策略? (可能是 MethodImplOptions.NoInlining 的错误),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2533806/