在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;
}
答案 0 :(得分:3)
这是我在github上的dotnet/corefx存储库中进行非常有限的搜索后设法找到的东西。
[Intrinsic]
标记了可以被JIT替换/优化的方法,属性和字段。源代码注释表示类似的内容(IntrinsicAttribute.cs
):
在带有jit内在扩展的某些调用站点上,可以替换对带有此属性标记的方法的调用或对字段的引用。标记有此属性的类型可以由运行时/编译器特殊处理。
对于核心开发人员,[Intrinsic]
至少有两个作用:
举个简单的例子:在某些情况下,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.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;
}
免责声明:据我所知,该属性的行为在任何地方均未得到适当记录,因此可能会发生变化。上面的描述仅与母版中当前使用的代码有关,内核的这一部分正在积极开发中,将来可以更改整个过程。
以下是基于GitHub存储库历史记录的[Intrinsic]
的简短时间表:
在[JitIntrisic]
中引入System.Numerics
属性是Enum.HasFlag
的一部分,目的是支持新的处理器指令(请参阅How does JitIntrinsicAttribute affect code generation?)。
2016年6月6日,Chris McKinsey开了一个问题#5626. "Optimize enum1.HasFlag(enum2) into inline bittest without boxing allocations when types are the same"。当时,[Intrinsic]
有一个众所周知的性能问题(请参阅What is it that makes Enum.HasFlag so slow?)。
在研究问题Andy Ayers时,建议引入一种通用机制来引入JIT内在函数(Issue #13813: Add more flexible method for specifying jit instrinsics)
这导致了两个请求:New jit intrinsic support介绍了Enum.HasFlag
的一般机制,JIT: optimize Enum.HasFlag为[Intrinsic]
实现了它。我建议对它们进行仔细的研究,因为它们对[JitIntrinsic]
所带来的变化具有很好的说明性。
稍后,在讨论移动Vector
classes to the CoreLib时,建议不要在任何地方使用[JitIntrinsic]
并应将其替换/删除:
@jkotas:我们不需要JitIntrinsicAttribute。据我所知,该属性是面向未来的证明,从未用于任何实际用途。我们应该删除它,而改用CoreLib的IntrinsicAttribute。
[Intrinsic]
,并替换为Vector2
(Replace JitIntrinsicAttribute with IntrinsicAttribute)。这就是该属性出现在{{1}}中的方式。答案 1 :(得分:0)
说明:
特殊类型使用 IntrinsicAttribute自定义属性。如果类型带有注释 IntrinsicAttribute属性,编译器不知道 给定类型的实现将在运行时出现。 标记为“本征”类型的方法可以将方法声明为 extern,在这种情况下,假定实现在 运行时。
来源:从MSIL到JavaScript编译器,第4.4.1.1节
链接:http://tenpow.com/Academics/MSIL2JS/MSIL2JS.pdf
通常,我建议不要在意它,也不要在自己的课程中使用它。