MethodImpl(AggressiveInlining) - 它有多激进?

kmp*_*kmp 19 .net c#

所以我稍微看了一下MethodImplAttribute,我遇到了MethodImplOptions.AggressiveInlining,它被描述为:

如果可能,应该内联该方法.

Oooooh,我心里想,这听起来很有趣 - 我可以假装我比编译器更聪明,强制代码只使用我的邪恶意志的力量和几个方括号,ha,ha,ha ...

因此,我启动了Visual Studio 2013,创建了一个控制台应用程序,将.NET版本设置为4.5.1并编写程序以结束所有程序(Release当然,在模式下编译它):

using System;
using System.Runtime.CompilerServices;

namespace ConsoleApplication1
{   
    public static class SoHelpful
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int GetSomeValueProbablyTwelve()
        {
            return 12;
        }
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static int GetSomeValueLikelyThirteen()
        {
            return 13;
        }
        public static int GetSomeValueMaybeItIsTwentyEight()
        {
            return 29;
        }
    }

    class Program
    {       
        static void Main()
        {
            int twelve = SoHelpful.GetSomeValueProbablyTwelve();
            int thirteen = SoHelpful.GetSomeValueLikelyThirteen();
            int twentyNine = SoHelpful.GetSomeValueMaybeItIsTwentyEight();
            Console.WriteLine((twelve + thirteen + twentyNine));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我做了一个快速的ildasm,我看到了这个:

.class public abstract auto ansi sealed beforefieldinit ConsoleApplication1.SoHelpful
       extends [mscorlib]System.Object
{
  .method public hidebysig static int32  GetSomeValueProbablyTwelve() cil managed
  {
    // Code size       3 (0x3)
    .maxstack  8
    IL_0000:  ldc.i4.s   12
    IL_0002:  ret
  } // end of method SoHelpful::GetSomeValueProbablyTwelve

  .method public hidebysig static int32  GetSomeValueLikelyThirteen() cil managed noinlining
  {
    // Code size       3 (0x3)
    .maxstack  8
    IL_0000:  ldc.i4.s   13
    IL_0002:  ret
  } // end of method SoHelpful::GetSomeValueLikelyThirteen

  .method public hidebysig static int32  GetSomeValueMaybeItIsTwentyEight() cil managed
  {
    // Code size       3 (0x3)
    .maxstack  8
    IL_0000:  ldc.i4.s   29
    IL_0002:  ret
  } // end of method SoHelpful::GetSomeValueMaybeItIsTwentyEight

} // end of class ConsoleApplication1.SoHelpful

.class private auto ansi beforefieldinit ConsoleApplication1.Program
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       29 (0x1d)
    .maxstack  2
    .locals init ([0] int32 twelve,
             [1] int32 thirteen,
             [2] int32 twentyNine)
    IL_0000:  call       int32 ConsoleApplication1.SoHelpful::GetSomeValueProbablyTwelve()
    IL_0005:  stloc.0
    IL_0006:  call       int32 ConsoleApplication1.SoHelpful::GetSomeValueLikelyThirteen()
    IL_000b:  stloc.1
    IL_000c:  call       int32 ConsoleApplication1.SoHelpful::GetSomeValueMaybeItIsTwentyEight()
    IL_0011:  stloc.2
    IL_0012:  ldloc.0
    IL_0013:  ldloc.1
    IL_0014:  add
    IL_0015:  ldloc.2
    IL_0016:  add
    IL_0017:  call       void [mscorlib]System.Console::WriteLine(int32)
    IL_001c:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Program::.ctor

} // end of class ConsoleApplication1.Program
Run Code Online (Sandbox Code Playgroud)

有意思,所以定义了三种方法:

.method public hidebysig static int32  GetSomeValueLikelyThirteen() cil managed noinlining
.method public hidebysig static int32  GetSomeValueProbablyTwelve() cil managed
.method public hidebysig static int32  GetSomeValueMaybeItIsTwentyEight() cil managed
Run Code Online (Sandbox Code Playgroud)

因此,它看起来像我的侵略性内联属性丢失了.

我可以看到noinliningGetSomeValueLikelyThirteen,但GetSomeValueProbablyTwelveGetSomeValueMaybeItIsTwentyEight是相同的.

那发生了什么?我想有几种可能性:

  1. C#编译器已经意识到GetSomeValueProbablyTwelve只是不能内联所以不会用我愚蠢的属性白痴麻烦JIT.
  2. C#编译器已经意识到GetSomeValueMaybeItIsTwentyEight可以内联,这就是为什么它在IL中是相同的GetSomeValueProbablyTwelve(所以我的归属在很大程度上是毫无意义的,在这种情况下也是愚蠢的).
  3. 有一些编译设置或我必须调整以获得要识别的属性.
  4. 它根本没有实现C#.
  5. 我发现了一个错误
  6. 还有别的

那么,有谁知道它是什么?

Sam*_*ell 15

MethodImplAttributes.AggressiveInlining编译为MethodDef元数据表的ImplFlags列中的标志(ECMA-335 PartitionII§22.26).此属性的值在分区II§23.1.11中列出,但未记录(0x0100表中不存在值).AggressiveInlining

在编译过程中,编译器会从元数据中删除属性本身.如果在方法的ImplFlags中设置了0x0100位,则反汇编程序必须实现特殊逻辑以添加属性.

  • 我发现了[Visual Studio 的“内联分析器”扩展](https://marketplace.visualstudio.com/items?itemName=StephanZhetner.InlinedAnalyzer) 或 [GitHub](https://github.com/szehetner/InlinedAnalyzer)使内联分析更容易了解 JIT 将做什么。它还可以告诉您为什么某些内容没有内联。 (4认同)