13

在 Google 上快速搜索“intrinsic attribute c#”只会返回有关其他属性的文章,例如[Serializable]. 显然,这些被称为“内在属性”。

但是,C# 中还有一个属性本身被称为[Intrinsic],我试图弄清楚它到底是什么以及它是如何工作的。据我所知,它不存在于.NET 文档的公共属性页面或文档中的其他任何地方。

此属性在 .NET Core 内部的多个位置使用,例如,在System.Numerics.Vectors文件夹中,例如Vector2_Intrinsics.cs. 代码片段:

[Intrinsic]
public Vector2(float x, float y)
{
    X = x;
    Y = y;
}
4

2 回答 2

33

这是我在通过github 上的dotnet/corefx存储库进行非常有限的搜索后设法找到的内容。

[Intrinsic]标记可能被 JIT 替换/优化的方法、属性和字段。源代码注释说类似(IntrinsicAttribute.cs):

对标有该属性的方法的调用或对字段的引用可能在某些调用站点被替换为 jit 内部扩展。使用此属性标记的类型可能会被运行时/编译器特殊处理。

目的

对于核心开发人员,[Intrinsic]至少有两个目的:

  • 它通知开发者标记的字段、方法或属性的代码可以被VM替换。因此,如果代码发生更改,则可能应该在两个地方都引入更改;
  • 它用作 JIT-optimizer 的标志,以快速识别可以优化的方法。

举个粗略的例子:在某些情况下,JIT 优化器可以Enum.HasFlag用简单的按位比较代替,而在其他情况下则不行。为此,它需要将方法标识为Enum.HasFlag,检查一些条件并将其替换为更优化的实现。优化器可以通过名称识别方法,但出于性能原因,最好在执行字符串比较之前通过简单的标志过滤掉方法。

用法

该属性仅与核心开发人员相关。您应该只在内部类中使用它,并且仅在您想要为其提出非常具体的 JIT 级优化的情况下使用它。[Intrinsic]几乎仅限于一小部分广泛使用的 .Net 类,由于某种原因,无法通过其他方式进行优化。

来自评论:我计划为 .NET Core 提出一个 Color 结构,该结构需要与其他内置类型类似以保持一致性。

您可能不应该[Intrinsic]在最初的提案中使用。它通过后,你可以考虑优化,如果你有一个有效的场景,什么时候Color会从低级优化中受益,你可以建议[Intrinsic]在它的一些方法或属性上使用。

这个怎么运作

以下[Intrinsic]是当前在核心中使用的方式:

  • 它被定义为一个众所周知的属性 ( wellknownattributes.h):

    case WellKnownAttribute::Intrinsic:
        return "System.Runtime.CompilerServices.IntrinsicAttribute";  
    
  • VM 对其进行解析并将IsJitIntrinsic方法 ( methodtablebuilder.cpp) 的标志设置为 true:

    if (bmtProp->fIsHardwareIntrinsic || (S_OK == GetCustomAttribute(pMethod->GetMethodSignature().GetToken(),
                                                WellKnownAttribute::Intrinsic,
                                                NULL,
                                                NULL)))
    {
        pNewMD->SetIsJitIntrinsic();
    }          
    
  • 此标志用于在方法属性 ( jitinterface.cpp) 中设置另一个标志:

    if (pMD->IsJitIntrinsic())
        result |= CORINFO_FLG_JIT_INTRINSIC;
    
  • 该标志稍后用于过滤掉显然不是内在的方法(importer.cpp):

    if ((mflags & (CORINFO_FLG_INTRINSIC | CORINFO_FLG_JIT_INTRINSIC)) != 0)
    {
        const bool isTail = canTailCall && (tailCall != 0);
    
        call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, mflags, pResolvedToken->token, readonlyCall, isTail,
                            pConstrainedResolvedToken, callInfo->thisTransform, &intrinsicID, &isSpecialIntrinsic);
    
  • impIntrinsic然后调用lookupNamedIntrinsic以识别(主要是通过名称)真正(不仅仅是潜在地)应该优化的方法;

  • 毕竟importer可以根据方法进行优化。例如,Enum.HasFlag( importer.cpp) 的优化:

     case NI_System_Enum_HasFlag:
        {
            GenTree* thisOp  = impStackTop(1).val;
            GenTree* flagOp  = impStackTop(0).val;
            GenTree* optTree = gtOptimizeEnumHasFlag(thisOp, flagOp);
    
            if (optTree != nullptr)
            {
                // Optimization successful. Pop the stack for real.
                impPopStack();
                impPopStack();
                retNode = optTree;
            }
            else
            {
                // Retry optimizing this during morph.
                isSpecial = true;
            }
    
            break;
        }
    

免责声明:据我所知,该属性的行为在任何地方都没有正确记录,因此可能会发生变化。以上描述仅与master中的代码相关,这部分核心正在积极开发中,未来可以更改整个过程。

历史

[Intrinsic]以下是基于 github 存储库历史的简短时间表:

@jkotas:我们不应该需要 JitIntrinsicAttribute。据我所知,这个属性是面向未来的,从未用于任何真实的东西。我们应该删除它,并改用 CoreLib 中的 IntrinsicAttribute。

于 2019-05-31T09:59:12.183 回答
0

解释:

使用 IntrinsicAttribute 自定义属性向编译器指示特殊类型。如果使用 IntrinsicAttribute 属性注释类型,则编译器不知道给定类型的实现将在运行时出现。标记为 Intrinsic 的类型的方法可以将方法声明为 extern,在这种情况下,假定实现在运行时可用。

来源:MSIL 到 JavaScript 编译器,第 4.4.1.1 节

链接:http ://tenpow.com/Academics/MSIL2JS/MSIL2JS.pdf

一般来说,我建议不要关心它,也不要将它用于你自己的课程。

于 2019-05-31T04:43:46.497 回答