assemblies - CLR 4.0 内联策略? (可能是 MethodImplOptions.NoInlining 的错误)

标签 assemblies clr .net-4.0 inline jit

我在方法内联(交叉汇编内联)中测试了一些新的 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 不内联 FooBar调用为 Baz做?它们小于 32 字节的 IL,非常适合内联。
  • 为什么 JIT 内联调用 BobSomeSecurityCriticalMethod 的内部调用标有 [MethodImpl(MethodImplOptions.NoInlining)]属性?
  • 为什么 GetExecutingAssembly当被内联调用时返回有效程序集 BazSomeSecurityCriticalMethod方法?我期望它执行堆栈遍历以检测正在执行的程序集,但堆栈将仅包含 Program.Main()没有调用 ClassLib 的方法组装,到ConsoleApp应该归还。

最佳答案

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

关于assemblies - CLR 4.0 内联策略? (可能是 MethodImplOptions.NoInlining 的错误),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2533806/

相关文章:

c# - 是还是不是?我可以在不同的程序集中划分接口(interface)和实现类吗?

c# - 锁定属性

sql-server - CLR 程序集表示找不到数据库中已存在的引用程序集

.net - 程序集锁定规则以及影子副本何时有用?

c# - 如果序列为空,如何使 LINQ 的 Max 函数返回默认值?

asp.net - 从程序集中复制 DLL 以进行部署

c# - 使用ImageList对象时出现"Could not load file or assembly..."错误

c# - 每个进程是否只有一个静态变量实例?

c# - BlockingCollection.GetConsumingEnumerable() 是否删除项目

c# - 哪些 .NET 4.5(或更早版本)更高级别的构造使线程更容易?