C#中的[Intrinsic]属性有什么作用?

Aar*_*nke 8 .net c# intrinsics .net-core

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

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

该属性用于.NET核心的内部中的几个地方,例如,在将System.Numerics.Vectors文件夹,如Vector2_Intrinsics.cs。程式码片段:

[Intrinsic]
public Vector2(float x, float y)
{
    X = x;
    Y = y;
}
Run Code Online (Sandbox Code Playgroud)

def*_*ale 9

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

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

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

目的

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

  • 它通知开发人员可以将标记的字段,方法或属性的代码替换为VM。因此,如果代码发生更改,则应该在两个地方都进行更改。
  • 它用作JIT优化器的标志,以快速识别可以进行优化的方法。

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

用法

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

从评论中:我计划为.NET Core提出一个Color结构,该结构必须与其他内置类型具有相似的行为以保持一致性。

您可能不应该[Intrinsic]在初始建议中使用。通过之后,您可以考虑优化,如果您有一个Color可以从低级优化中受益的有效方案,则可以建议使用[Intrinsic]其某些方法或属性。

怎么运行的

以下是如何[Intrinsic]在核心是目前使用:

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

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

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

    if (pMD->IsJitIntrinsic())
        result |= CORINFO_FLG_JIT_INTRINSIC;
    
    Run Code Online (Sandbox Code Playgroud)
  • 此标志稍后用于过滤掉显然不是内在(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);
    
    Run Code Online (Sandbox Code Playgroud)
  • impIntrinsic然后调用lookupNamedIntrinsic以标识(主要是通过名称)真正(不仅可能)进行优化的方法;

  • 毕竟,这些importer都可以基于方法进行优化。例如,针对Enum.HasFlagimporter.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;
        }
    
    Run Code Online (Sandbox Code Playgroud)

免责声明:据我所知,该属性的行为在任何地方均未得到正确记录,因此可能会发生更改。上面的描述仅与当前掌握在母带中的代码有关,核心的这一部分正在积极开发中,将来可以更改整个过程。

历史

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

@jkotas:我们不需要JitIntrinsicAttribute。据我所知,该属性是面向未来的证明,从未用于任何实际用途。我们应该删除它,而改用CoreLib的IntrinsicAttribute。

  • 哇,这是我之前见过的最令人印象深刻的问题答案之一。您是否已经了解这方面的历史和背景信息,或者您是否已经追踪并研究过它?不管怎样,我向您致敬,先生! (4认同)