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

时间:2019-05-31 04:27:25

标签: c# .net .net-core intrinsics

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

但是,C#中还有一个本身称为[Intrinsic]的属性,我试图弄清楚它的确切含义和工作方式。在.NET文档的common attributes页上,或者据我所知,它在文档的其他任何地方都不存在。

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

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

2 个答案:

答案 0 :(得分:3)

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

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

  

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

目的

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

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

举个简单的例子:在某些情况下,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对其进行解析,并将方法(methodtablebuilder.cpp)的IsJitIntrinsic标志设置为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.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;
        }
    

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

历史

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

  

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

答案 1 :(得分:0)

说明:

  

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

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

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

通常,我建议不要在意它,也不要在自己的课程中使用它。