为什么我的方法调用Assembly.GetCallingAssembly()而不是JIT内联?

sha*_*oth 5 c# jit inline visual-studio vshost.exe

我正在尝试制作一个简短的C#片段,它将说明Assembly.GetCallingAssembly()由于MSDN中概述的JIT内联而改变行为.到目前为止,这是我的代码:

class Program
{
   static void Main(string[] args)
   {
       Console.WriteLine( GetAssembly().FullName );
       Console.ReadLine();
   }

   static Assembly GetAssembly()
   {
       return System.Reflection.Assembly.GetCallingAssembly();
   }
}
Run Code Online (Sandbox Code Playgroud)

我在"Release"中构建并开始使用"Start Without Debugging" - 这个设置使得这个答案的代码产生内联.我看到的结果是

ConsoleApplication2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Run Code Online (Sandbox Code Playgroud)

所以显然GetAssembly()没有内联Main(),否则我会mscorlib看作是召集大会.

我已经审查了所有内联标准,我不明白为什么GetAssembly()不会内联.

是否有可能知道为什么JIT编译器决定不内联调用?

Han*_*ant 8

这是.NET 3.5中Assembly.GetCallingAssembly()的声明:

[MethodImpl(MethodImplOptions.NoInlining)]
public static Assembly GetCallingAssembly()
{
    StackCrawlMark lookForMyCallersCaller = StackCrawlMark.LookForMyCallersCaller;
    return nGetExecutingAssembly(ref lookForMyCallersCaller);
}
Run Code Online (Sandbox Code Playgroud)

StackCrawlMark枚举很有意思,"查找我的调用者调用者"在调用者内联时无法正常工作.在CSSCL的SSCLI20源代码中有一条注释,其中枚举被声明:

声明此枚举类型的局部变量并将其通过ref传递给需要执行堆栈爬行的函数将同时阻止内联调用[sic]并将ESP点传递给堆栈爬行

这与GetCallingAssembly()中发生的事情非常匹配,它是一个局部变量,确实通过ref传递.不知道机制是什么,抖动可以产生名为CORINFO_FLG_BAD_INLINEE的方法属性.这反过来又强制调用MethodDesc :: SetNotInline().这是猜测,这是非常模糊的.