CLR 4.0内联政策? (也许是MethodImplOptions.NoInlining的错误)

时间:2010-03-28 17:30:19

标签: assemblies clr .net-4.0 inline jit

我在方法内联中测试了一些新的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();
    }
  }
}

装配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那样内联BarBaz来电?它们低于32字节的IL并且是内联的良好候选者。
  • 为什么JIT内联Bob的内容以及SomeSecurityCriticalMethod的{​​{1}}内部调用?
  • 当内联[MethodImpl(MethodImplOptions.NoInlining)]GetExecutingAssembly方法调用时,为什么Baz会返回有效的程序集?我希望它执行堆栈遍历以检测正在执行的程序集,但堆栈将只包含SomeSecurityCriticalMethod调用,并且Program.Main()的任何方法都不能组合,应该返回ClassLib

1 个答案:

答案 0 :(得分:3)

CLR 4.0对大多数事情都有ETW事件,这里是Jit的ETW跟踪,它应该给出MethodJitInliningFailed原因,here是你查看跟踪信息的方式