@@ -544,6 +544,32 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitor<Substi
544544 }
545545#endif // FEATURE_MULTIREG_RET
546546
547+ CORINFO_METHOD_HANDLE GetMethodHandle (GenTreeCall* call)
548+ {
549+ assert (call->IsDevirtualizationCandidate (m_compiler));
550+ if (call->IsVirtual ())
551+ {
552+ return call->gtCallMethHnd ;
553+ }
554+ else
555+ {
556+ GenTree* runtimeMethHndNode =
557+ call->gtCallAddr ->AsCall ()->gtArgs .FindWellKnownArg (WellKnownArg::RuntimeMethodHandle)->GetNode ();
558+ assert (runtimeMethHndNode != nullptr );
559+ switch (runtimeMethHndNode->OperGet ())
560+ {
561+ case GT_RUNTIMELOOKUP:
562+ return runtimeMethHndNode->AsRuntimeLookup ()->GetMethodHandle ();
563+ case GT_CNS_INT:
564+ return CORINFO_METHOD_HANDLE (runtimeMethHndNode->AsIntCon ()->IconValue ());
565+ default :
566+ assert (!" Unexpected type in RuntimeMethodHandle arg." );
567+ return nullptr ;
568+ }
569+ return nullptr ;
570+ }
571+ }
572+
547573 // ------------------------------------------------------------------------
548574 // LateDevirtualization: re-examine calls after inlining to see if we
549575 // can do more devirtualization
@@ -586,8 +612,9 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitor<Substi
586612
587613 if (tree->OperGet () == GT_CALL)
588614 {
589- GenTreeCall* call = tree->AsCall ();
590- bool tryLateDevirt = call->IsVirtual () && (call->gtCallType == CT_USER_FUNC);
615+ GenTreeCall* call = tree->AsCall ();
616+ // TODO-CQ: Drop `call->gtCallType == CT_USER_FUNC` once we have GVM devirtualization
617+ bool tryLateDevirt = call->IsDevirtualizationCandidate (m_compiler) && (call->gtCallType == CT_USER_FUNC);
591618
592619#ifdef DEBUG
593620 tryLateDevirt = tryLateDevirt && (JitConfig.JitEnableLateDevirtualization () == 1 );
@@ -605,7 +632,7 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitor<Substi
605632
606633 CORINFO_CONTEXT_HANDLE context = call->gtLateDevirtualizationInfo ->exactContextHnd ;
607634 InlineContext* inlinersContext = call->gtLateDevirtualizationInfo ->inlinersContext ;
608- CORINFO_METHOD_HANDLE method = call-> gtCallMethHnd ;
635+ CORINFO_METHOD_HANDLE method = GetMethodHandle ( call) ;
609636 unsigned methodFlags = 0 ;
610637 const bool isLateDevirtualization = true ;
611638 const bool explicitTailCall = call->IsTailPrefixedCall ();
@@ -615,7 +642,7 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitor<Substi
615642 m_compiler->impDevirtualizeCall (call, nullptr , &method, &methodFlags, &contextInput, &context,
616643 isLateDevirtualization, explicitTailCall);
617644
618- if (!call->IsVirtual ( ))
645+ if (!call->IsDevirtualizationCandidate (m_compiler ))
619646 {
620647 assert (context != nullptr );
621648 assert (inlinersContext != nullptr );
0 commit comments