【发布时间】:2011-02-01 19:00:18
【问题描述】:
我在方法内联(跨程序集内联)中测试了一些新的 CLR 4.0 行为,并发现了一些意外结果:
组装 ClassLib.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();
}
}
}
Assembly 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 不像
Baz那样内联Foo和Bar调用?它们小于 32 字节的 IL,非常适合内联。 - 为什么
Bob的 JIT 内联调用和标有[MethodImpl(MethodImplOptions.NoInlining)]属性的SomeSecurityCriticalMethod的内部调用? - 当被内联的
Baz和SomeSecurityCriticalMethod方法调用时,为什么GetExecutingAssembly返回一个有效的程序集?我希望它执行堆栈遍历以检测正在执行的程序集,但堆栈将仅包含Program.Main()调用,并且不应返回ClassLibassenbly 到ConsoleApp的任何方法。
【问题讨论】:
标签: assemblies clr .net-4.0 inline jit