@@ -3411,6 +3411,8 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
34113411 // This one is just `return true/false`
34123412 case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant:
34133413
3414+ case NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier:
3415+
34143416 // Not expanding this can lead to noticeable allocations in T0
34153417 case NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan:
34163418
@@ -3640,6 +3642,14 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
36403642 break ;
36413643 }
36423644
3645+ case NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier:
3646+ {
3647+ GenTree* val = impPopStack ().val ;
3648+ GenTree* dst = impPopStack ().val ;
3649+ retNode = gtNewStoreIndNode (TYP_REF, dst, val, GTF_IND_TGT_HEAP);
3650+ break ;
3651+ }
3652+
36433653 case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant:
36443654 {
36453655 GenTree* op1 = impPopStack ().val ;
@@ -7978,6 +7988,53 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call,
79787988 call->AddGDVCandidateInfo (this , pInfo);
79797989}
79807990
7991+ // ------------------------------------------------------------------------
7992+ // impConvertToUserCallAndMarkForInlining: convert a helper call to a user call
7993+ // and mark it for inlining. This is used for helper calls that are
7994+ // known to be backed by a user method that can be inlined.
7995+ //
7996+ // Arguments:
7997+ // call - the helper call to convert
7998+ //
7999+ void Compiler::impConvertToUserCallAndMarkForInlining (GenTreeCall* call)
8000+ {
8001+ assert (call->IsHelperCall ());
8002+
8003+ if (!opts.OptEnabled (CLFLG_INLINING))
8004+ {
8005+ return ;
8006+ }
8007+
8008+ CORINFO_METHOD_HANDLE helperCallHnd = call->gtCallMethHnd ;
8009+ CORINFO_METHOD_HANDLE managedCallHnd = NO_METHOD_HANDLE;
8010+ CORINFO_CONST_LOOKUP pNativeEntrypoint = {};
8011+ info.compCompHnd ->getHelperFtn (eeGetHelperNum (helperCallHnd), &pNativeEntrypoint, &managedCallHnd);
8012+
8013+ if (managedCallHnd != NO_METHOD_HANDLE)
8014+ {
8015+ call->gtCallMethHnd = managedCallHnd;
8016+ call->gtCallType = CT_USER_FUNC;
8017+
8018+ CORINFO_CALL_INFO hCallInfo = {};
8019+ hCallInfo.hMethod = managedCallHnd;
8020+ hCallInfo.methodFlags = info.compCompHnd ->getMethodAttribs (hCallInfo.hMethod );
8021+ impMarkInlineCandidate (call, nullptr , false , &hCallInfo, compInlineContext);
8022+
8023+ #if DEBUG
8024+ CORINFO_METHOD_HANDLE existingValue = NO_METHOD_HANDLE;
8025+ if (impInlineRoot ()->HelperToManagedMapLookup (helperCallHnd, &existingValue))
8026+ {
8027+ // Let's make sure HelperToManagedMap::Overwrite behavior always overwrites the same value.
8028+ assert (existingValue == managedCallHnd);
8029+ }
8030+ #endif
8031+
8032+ impInlineRoot ()->GetHelperToManagedMap ()->Set (helperCallHnd, managedCallHnd, HelperToManagedMap::Overwrite);
8033+ JITDUMP (" Converting helperCall [%06u] to user call [%s] and marking for inlining\n " , dspTreeID (call),
8034+ eeGetMethodFullName (managedCallHnd));
8035+ }
8036+ }
8037+
79818038// ------------------------------------------------------------------------
79828039// impMarkInlineCandidate: determine if this call can be subsequently inlined
79838040//
@@ -10931,6 +10988,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
1093110988 {
1093210989 result = NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant;
1093310990 }
10991+ else if (strcmp (methodName, " WriteBarrier" ) == 0 )
10992+ {
10993+ result = NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier;
10994+ }
1093410995 else if (strcmp (methodName, " IsReferenceOrContainsReferences" ) == 0 )
1093510996 {
1093610997 result =
0 commit comments