Вот что мне удалось найти после очень ограниченного поиска в репозитории dotnet / corefx на github.
[Intrinsic]
отмечает методы, свойства и поля, которые могут быть потенциально заменены / оптимизированы JIT. Комментарии исходного кода говорят что-то похожее (IntrinsicAttribute.cs
):
Вызовы методов или ссылки на поля, отмеченные этим атрибутом, могут быть заменены на некоторых сайтах вызовов внутренними расширениями jit. Типы, отмеченные этим атрибутом, могут специально обрабатываться средой выполнения / компилятором.
Цель
Для разработчиков ядра [Intrinsic]
служит как минимум двум целям:
- уведомляет разработчика о том, что код помеченного поля, метода или свойства может быть заменен виртуальной машиной. Таким образом, если код изменяется, изменение, вероятно, должно быть введено в обоих местах;
- он используется в качестве флага для JIT-оптимизатора для быстрой идентификации методов, которые потенциально могут быть оптимизированы.
В качестве грубого примера: JIT-оптимизатор может заменить Enum.HasFlag
простым побитовым сравнением в некоторых случаях, а не в других. Для этого необходимо определить метод как Enum.HasFlag
, проверить некоторые условия и заменить его более оптимальной реализацией. Оптимизатор может идентифицировать метод по имени, но по соображениям производительности лучше отфильтровать методы по простому флагу перед выполнением сравнения строк.
Использование
Атрибут актуален только для разработчиков ядра. Вы должны использовать его только во внутреннем классе и только в том случае, если вы хотите предложить для него очень специфические оптимизации уровня JIT. [Intrinsic]
в значительной степени ограничен небольшим набором широко используемых классов .Net, которые по некоторым причинам не могут быть оптимизированы другими средствами.
из комментариев : Я планирую предложить структуру Color для .NET Core, которая должна вести себя аналогично другим встроенным типам для согласованности.
Возможно, вам не следует использовать [Intrinsic]
в вашем первоначальном предложении. После того, как он пройдет, вы можете подумать об оптимизации, и если у вас есть действительный сценарий, когда Color
выиграет от низкоуровневых оптимизаций, вы можете предложить использовать [Intrinsic]
в некоторых из его методов или свойств.
Как это работает
Вот как [Intrinsic]
в настоящее время используется в ядре:
определяется как общеизвестный атрибут (wellknownattributes.h
):
case WellKnownAttribute::Intrinsic:
return "System.Runtime.CompilerServices.IntrinsicAttribute";
ВМ анализирует ее и устанавливает для флага 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;
}
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: насколько я могу судить, поведение атрибута нигде не документировано должным образом и, следовательно, может быть изменено. Вышеприведенное описание относится только к коду, находящемуся в настоящее время в master, эта часть ядра активно разрабатывается, и весь процесс может быть изменен в будущем.
История
Вот краткий график времени [Intrinsic]
, основанный на истории хранилища github:
@ jkotas : нам не нужен атрибут JitIntrinsic. Насколько я знаю, этот атрибут был проверкой на будущее, никогда не использовался для чего-то реального. Мы должны удалить его и использовать вместо него IntrinsicAttribute из CoreLib.