【问题标题】:What does the [Intrinsic] attribute in C# do?C# 中的 [Intrinsic] 属性有什么作用?
【发布时间】:2019-10-16 17:23:14
【问题描述】:

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

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

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

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

【问题讨论】:

  • 此属性的源代码可在此处获得:github.com/dotnet/coreclr/blob/master/src/… 其中包括一些 cmets。
  • JitIntrinsicAttribute 似乎可能相关:stackoverflow.com/questions/26903933/…
  • 这里是github.com/dotnet/corefx/issues/22940 的提案,您可以详细了解它并关注集成的推动
  • 只是在代码中使用 MethodInfo 时可以使用的注解。龙住在那里,你不想 Invoke() 它。并不是说这是一个非常实际的问题,但是 Microsoft 支持可以通过指出您可以添加测试来轻松地让您挂断电话。 .NET 中还有许多其他内在函数,例如 Math.Sqrt()。处理器具有专用的机器代码指令,因此无需生成方法调用,非常有效。然而,用反射调用它是可以的,mscorlib.dll 仍然有它的方法。

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


【解决方案1】:

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

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

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

目的

对于核心开发者,[Intrinsic] 至少有两个用途:

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

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

用法

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

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

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

工作原理

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

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

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

    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;
        }
    

免责声明:据我所知,该属性的行为在任何地方都没有正确记录,因此可能会发生变化。以上描述只针对master当前的代码,这部分core正在积极开发中,未来可以改变整个流程。

历史

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

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

【讨论】:

  • 同意我们不应该使用或关心未记录的功能这一事实。如果不是文档,MS 不希望开发者使用它,可以随时更改。
【解决方案2】:

解释:

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

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

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

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

【讨论】:

  • 尽管 intristics 是正确的主题并抓住了问题的本质,但我发现将 MSIL 的文档链接到 JavaScript 编译器是可疑的,无论如何只是我的看法
  • @TheGeneral 该文档解释了 MSIL 和 CTS(通用类型系统)的几个内部结构。编程语言无关紧要。
  • "我建议不要关心它" 我想了解此属性在 System.Numerics.Vectors 中的工作原理以及它存在的原因,因为我计划为 .NET Core 提出一个 Color 结构需要与其他内置类型类似以保持一致性。
  • 我只能说这个属性在内部使用是为了实现 .net 运行时库。我还没有找到使用它的单个用户项目。 Color 类或结构与任何其他类或结构没有什么不同。
猜你喜欢
  • 2011-10-21
  • 1970-01-01
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
  • 2011-12-17
相关资源
最近更新 更多