From 2c48a697aa5526c7ab8a39a94af579163a0b3b45 Mon Sep 17 00:00:00 2001 From: Steven He Date: Wed, 21 Jan 2026 23:36:02 +0900 Subject: [PATCH 1/3] Fix devirtualization regression --- src/coreclr/jit/fginline.cpp | 8 +++---- src/coreclr/jit/gentree.cpp | 40 ++----------------------------- src/coreclr/jit/gentree.h | 2 +- src/coreclr/jit/importercalls.cpp | 1 + src/coreclr/jit/inline.h | 1 + 5 files changed, 8 insertions(+), 44 deletions(-) diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index b07f5a1b0f4175..b46723cf17e075 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -586,9 +586,8 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorOperIs(GT_CALL)) { - GenTreeCall* call = tree->AsCall(); - CORINFO_METHOD_HANDLE method = NO_METHOD_HANDLE; - bool tryLateDevirt = call->IsDevirtualizationCandidate(m_compiler, &method); + GenTreeCall* call = tree->AsCall(); + bool tryLateDevirt = call->IsDevirtualizationCandidate(m_compiler); #ifdef DEBUG tryLateDevirt = tryLateDevirt && (JitConfig.JitEnableLateDevirtualization() == 1); @@ -604,14 +603,13 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorgtLateDevirtualizationInfo->methodHnd; CORINFO_CONTEXT_HANDLE context = call->gtLateDevirtualizationInfo->exactContextHnd; InlineContext* inlinersContext = call->gtLateDevirtualizationInfo->inlinersContext; unsigned methodFlags = 0; const bool isLateDevirtualization = true; const bool explicitTailCall = call->IsTailPrefixedCall(); - assert(method != NO_METHOD_HANDLE); - CORINFO_CONTEXT_HANDLE contextInput = context; context = nullptr; m_compiler->impDevirtualizeCall(call, nullptr, &method, &methodFlags, &contextInput, &context, diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index ab235263b96d80..d9f3f64f0e32c4 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2370,49 +2370,13 @@ int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const // // Arguments: // compiler - [In] the compiler instance so that we can call eeFindHelper -// pMethHandle - [Out] the method handle if the call is a devirtualization candidate // // Return Value: // Returns true if this GT_CALL node is a devirtualization candidate. // -bool GenTreeCall::IsDevirtualizationCandidate(Compiler* compiler, CORINFO_METHOD_HANDLE* pMethHandle) const +bool GenTreeCall::IsDevirtualizationCandidate(Compiler* compiler) const { - CORINFO_METHOD_HANDLE methHandleToDevirt = NO_METHOD_HANDLE; - bool isDevirtCandidate = false; - - if (IsVirtual() && gtCallType == CT_USER_FUNC) - { - methHandleToDevirt = gtCallMethHnd; - isDevirtCandidate = true; - } - else if (IsGenericVirtual(compiler) && (JitConfig.JitEnableGenericVirtualDevirtualization() != 0)) - { - GenTree* runtimeMethHndNode = - gtCallAddr->AsCall()->gtArgs.FindWellKnownArg(WellKnownArg::RuntimeMethodHandle)->GetNode(); - assert(runtimeMethHndNode != nullptr); - switch (runtimeMethHndNode->OperGet()) - { - case GT_RUNTIMELOOKUP: - methHandleToDevirt = runtimeMethHndNode->AsRuntimeLookup()->GetMethodHandle(); - isDevirtCandidate = true; - break; - case GT_CNS_INT: - methHandleToDevirt = CORINFO_METHOD_HANDLE(runtimeMethHndNode->AsIntCon()->gtCompileTimeHandle); - isDevirtCandidate = true; - break; - default: - // Unable to get method handle for devirtualization. - // This can happen if the method handle is not an RUNTIMELOOKUP or CNS_INT for generic virtuals, - break; - } - } - - if (pMethHandle) - { - *pMethHandle = methHandleToDevirt; - } - - return isDevirtCandidate; + return IsVirtual() || IsGenericVirtual(compiler); } //------------------------------------------------------------------------- diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 0aeae5512d44fb..4560fb0f2fe1a4 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -5273,7 +5273,7 @@ struct GenTreeCall final : public GenTree gtCallAddr->IsHelperCall(compiler, CORINFO_HELP_GVMLOOKUP_FOR_SLOT))); } - bool IsDevirtualizationCandidate(Compiler* compiler, CORINFO_METHOD_HANDLE* pMethHandle = nullptr) const; + bool IsDevirtualizationCandidate(Compiler* compiler) const; bool IsInlineCandidate() const { diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 869b947a318c80..c631b78dc6ddee 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -1292,6 +1292,7 @@ var_types Compiler::impImportCall(OPCODE opcode, JITDUMP("\nSaving generic context %p and inline context %p for call [%06u]\n", dspPtr(exactContextHnd), dspPtr(compInlineContext), dspTreeID(call->AsCall())); LateDevirtualizationInfo* const info = new (this, CMK_Inlining) LateDevirtualizationInfo; + info->methodHnd = callInfo->hMethod; info->exactContextHnd = exactContextHnd; info->inlinersContext = compInlineContext; call->AsCall()->gtLateDevirtualizationInfo = info; diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h index fdad38be37ec8b..4021e420a5ff23 100644 --- a/src/coreclr/jit/inline.h +++ b/src/coreclr/jit/inline.h @@ -634,6 +634,7 @@ struct InlineCandidateInfo : public HandleHistogramProfileCandidateInfo // struct LateDevirtualizationInfo { + CORINFO_METHOD_HANDLE methodHnd; CORINFO_CONTEXT_HANDLE exactContextHnd; InlineContext* inlinersContext; }; From 65d7516acfd1d0360f708cbe10fb4d3c494a6de1 Mon Sep 17 00:00:00 2001 From: Steven He Date: Wed, 21 Jan 2026 23:54:40 +0900 Subject: [PATCH 2/3] Oops --- src/coreclr/jit/gentree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index d9f3f64f0e32c4..38c71dfd4e280b 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2376,7 +2376,7 @@ int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const // bool GenTreeCall::IsDevirtualizationCandidate(Compiler* compiler) const { - return IsVirtual() || IsGenericVirtual(compiler); + return IsVirtual() || (IsGenericVirtual(compiler) && (JitConfig.JitEnableGenericVirtualDevirtualization() != 0)); } //------------------------------------------------------------------------- From b510b8ee9b2a5502d958458ea0d9286d3276e48c Mon Sep 17 00:00:00 2001 From: Steven He Date: Thu, 22 Jan 2026 00:00:15 +0900 Subject: [PATCH 3/3] JIT format --- src/coreclr/jit/fginline.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index b46723cf17e075..7cb39262367923 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -586,8 +586,8 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorOperIs(GT_CALL)) { - GenTreeCall* call = tree->AsCall(); - bool tryLateDevirt = call->IsDevirtualizationCandidate(m_compiler); + GenTreeCall* call = tree->AsCall(); + bool tryLateDevirt = call->IsDevirtualizationCandidate(m_compiler); #ifdef DEBUG tryLateDevirt = tryLateDevirt && (JitConfig.JitEnableLateDevirtualization() == 1);