Googleで「組み込み属性c#」をすばやく検索すると、[Serializable]
などの他の属性に関する記事のみが返されます。どうやらこれらは「固有属性」と呼ばれています。
ただし、それ自体が[Intrinsic]
と呼ばれるC#の属性もあり、それが正確に何であり、どのように機能するかを理解しようとしています。 .NETドキュメントの common attributes ページ、またはドキュメント内の他のどこにも、私が見る限り存在しません。
この属性は、.NET Core内のいくつかの場所で使用されます。たとえば、 System.Numerics.Vectors
などの Vector2_Intrinsics.cs
フォルダ内です。コードスニペット:
[Intrinsic]
public Vector2(float x, float y)
{
X = x;
Y = y;
}
これが、githubの dotnet/corefx リポジトリを非常に限定的に検索した結果、私が見つけたものです。
[Intrinsic]
は、JITによって置換または最適化される可能性のあるメソッド、プロパティ、およびフィールドを示します。ソースコードのコメントは、似たようなことを言っています( IntrinsicAttribute.cs
):
メソッドへの呼び出しまたはこの属性でマークされたフィールドへの参照は、いくつかの呼び出しサイトでjit組み込み展開に置き換えられる場合があります。この属性でマークされた型は、ランタイム/コンパイラによって特別に処理される場合があります。
コア開発者にとって、[Intrinsic]
は少なくとも2つの目的を果たします。
大まかな例を示すと、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
フラグを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.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]
の短いタイムラインは次のとおりです。
2014年より前のある時点で、[JitIntrisic]
属性はSystem.Numerics
の一部として導入され、新しいプロセッサ命令をサポートすることを目的としています( JitIntrinsicAttributeがコード生成にどのように影響するか? )。
2016年6月6日、 Chris McKinsey が問題を公開しました #5626。 "enum1.HasFlag(enum2)を最適化して、タイプが同じである場合に、ボックス割り当てを行わずにインラインビットテストを行います" 当時、Enum.HasFlag
にはよく知られているパフォーマンスの問題がありました( Enum.HasFlagを非常に遅くするのは何ですか? を参照)。
この問題に取り組んでいる間、 Andy Ayers は、JIT組み込み関数を導入するための汎用的なメカニズムを導入することを提案しました( Issue#13813: jit instrinsicsの指定 )
これにより、2つのプルリクエストが発生しました。 新しいjit組み込みサポート は、[Intrinsic]
および JIT:列挙型の最適化の一般的な仕組みを導入しました。 HasFlag がEnum.HasFlag
用に実装しました。 [Intrinsic]
に伴う変更については非常にわかりやすいので、両方を確認することをお勧めします。
後で、 Vector
クラスをCoreLib に移動することについてのディスカッション中に、[JitIntrinsic]
はどこにも使用せず、置き換える必要があることが示唆されました/削除されました:
@ jkotas :JitIntrinsicAttributeは必要ありません。私の知る限り、この属性は将来を見据えたものであり、実際に使用されることはありません。それを削除し、代わりにCoreLibのIntrinsicAttributeを使用する必要があります。
[JitIntrinsic]
が削除され、[Intrinsic]
に置き換えられました( JitIntrinsicAttributeをIntrinsicAttribute で置き換えます)。これが、この属性がVector2
に含まれるようになった方法です。説明:
コンパイラーには、IntrinsicAttributeカスタム属性を使用して特別なタイプが示されます。型にIntrinsicAttribute属性で注釈が付けられている場合、コンパイラーは、指定された型の実装が実行時に存在することを認識していません。組み込みとしてマークされた型のメソッドは、メソッドがexternであることを宣言できます。その場合、実装は実行時に利用可能であると見なされます。
ソース:MSILからJavaScriptコンパイラ、セクション4.4.1.1
リンク: http://tenpow.com/Academics/MSIL2JS/MSIL2JS.pdf
一般に、私はそれを気にしないで、自分のクラスで使用しないことをお勧めします。