【问题标题】:CLR 4.0 inlining policy? (maybe bug with MethodImplOptions.NoInlining)CLR 4.0 内联策略? (可能是 MethodImplOptions.NoInlining 的错误)
【发布时间】: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 那样内联 FooBar 调用?它们小于 32 字节的 IL,非常适合内联。
  • 为什么 Bob 的 JIT 内联调用和标有 [MethodImpl(MethodImplOptions.NoInlining)] 属性的 SomeSecurityCriticalMethod 的内部调用?
  • 当被内联的BazSomeSecurityCriticalMethod 方法调用时,为什么GetExecutingAssembly 返回一个有效的程序集?我希望它执行堆栈遍历以检测正在执行的程序集,但堆栈将仅包含 Program.Main() 调用,并且不应返回 ClassLib assenbly 到 ConsoleApp 的任何方法。

【问题讨论】:

    标签: assemblies clr .net-4.0 inline jit


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-22
      • 2019-09-14
      • 2014-07-07
      • 2015-01-24
      • 1970-01-01
      • 2022-08-14
      • 2021-10-07
      相关资源
      最近更新 更多