发现以下内容时,我正在阅读.NET源代码:

// Constructs a Decimal from an integer value.
//
public Decimal(int value) {
    //  JIT today can't inline methods that contains "starg" opcode.
    //  For more details, see DevDiv Bugs 81184: x86 JIT CQ:
    //  Removing the inline striction of "starg".
    int value_copy = value;
    if (value_copy >= 0) {
        flags = 0;
    }
    else {
        flags = SignMask;
        value_copy = -value_copy;
    }
    lo = value_copy;
    mid = 0;
    hi = 0;
}

如您所见,Decimal结构的构造函数将方法参数复制到局部变量,而不是直接使用它。我想知道评论的含义以及它与性能和优化之间的关系?

我的猜测是,一旦您想修改现有参数,就可以不再内联方法了?

http://referencesource.microsoft.com/#mscorlib/system/decimal.cs#f9a4da9d6e110054#references

最佳答案



简短答案:您的猜测是正确的(如果该源代码注释今天仍然是正确的)。



“JIT” 是.NET运行时的一部分,它将intermediate language (IL) (i.e. .NET "bytecode")转换为计算机的汇编语言。只有这样,您的计算机才能执行代码。 JIT仅在实际需要时才按方法执行此转换方法:每当首次调用方法时,它都会首先编译为实际的汇编语言,即“即时”(JIT)。

C#编译器不会立即为您的计算机体系结构生成汇编语言。相反,它生成intermediate language,这是抽象堆栈机的某种汇编语言(已在ECMA 334 international standard中定义)。

例如,对参数的分配(在您的示例中为value)将由C#编译器转换为一条称为的IL指令starg (“存储到参数”)。

注释基本上说,如果该方法包含这样的分配(value = …),则JIT当前将无法对其进行“内联”。 "Inlining a method" 意味着JIT不会生成方法的调用指令(即,将命令转移到不同的代码位置),而是将方法的整个主体插入到被调用的位置。通常这样做是为了优化执行速度,因为不需要分支/跳转,此外,我还假定也不必设置新的堆栈框架。

通过分配给局部变量(value_copy = …),可以避免JIT的这种限制,因为对局部变量的赋值会生成另一条IL指令:stloc(“存储到局部变量”)。

另请参阅:

  • Andrey Akinshin: "A story about JIT-x86 inlining and starg"(博客文章)
  • 关于c# - .NET局部变量优化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26369163/

    10-12 22:36