diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index c228810d4ee18d..e104b2a941ce58 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7164,12 +7164,13 @@ class Compiler bool isCompatibleMethodGDV(GenTreeCall* call, CORINFO_METHOD_HANDLE gdvTarget); - void addGuardedDevirtualizationCandidate(GenTreeCall* call, - CORINFO_METHOD_HANDLE methodHandle, - CORINFO_CLASS_HANDLE classHandle, - unsigned methodAttr, - unsigned classAttr, - unsigned likelihood); + void addGuardedDevirtualizationCandidate(GenTreeCall* call, + CORINFO_METHOD_HANDLE methodHandle, + CORINFO_CLASS_HANDLE classHandle, + CORINFO_CONTEXT_HANDLE contextHandle, + unsigned methodAttr, + unsigned classAttr, + unsigned likelihood); int getGDVMaxTypeChecks() { diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index fb55a115d8ca21..fab7f06d634445 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -475,7 +475,8 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitorimpDevirtualizeCall(call, nullptr, &method, &methodFlags, &context, nullptr, + CORINFO_CONTEXT_HANDLE contextInput = context; + m_compiler->impDevirtualizeCall(call, nullptr, &method, &methodFlags, &contextInput, &context, isLateDevirtualization, explicitTailCall); m_madeChanges = true; } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index e2aa53c10a61ac..0c1e31c43ffb7c 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -5999,8 +5999,8 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, likelyHood += 100 - likelyHood * numExactClasses; } - addGuardedDevirtualizationCandidate(call, exactMethod, exactCls, exactMethodAttrs, clsAttrs, - likelyHood); + addGuardedDevirtualizationCandidate(call, exactMethod, exactCls, dvInfo.exactContext, exactMethodAttrs, + clsAttrs, likelyHood); } if (call->GetInlineCandidatesCount() == numExactClasses) @@ -6027,6 +6027,8 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, CORINFO_METHOD_HANDLE likelyMethod = likelyMethodes[candidateId]; unsigned likelihood = likelihoods[candidateId]; + CORINFO_CONTEXT_HANDLE likelyContext = NULL; + uint32_t likelyClassAttribs = 0; if (likelyClass != NO_CLASS_HANDLE) { @@ -6062,7 +6064,8 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, break; } - likelyMethod = dvInfo.devirtualizedMethod; + likelyContext = dvInfo.exactContext; + likelyMethod = dvInfo.devirtualizedMethod; } uint32_t likelyMethodAttribs = info.compCompHnd->getMethodAttribs(likelyMethod); @@ -6130,8 +6133,8 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, // Add this as a potential candidate. // - addGuardedDevirtualizationCandidate(call, likelyMethod, likelyClass, likelyMethodAttribs, likelyClassAttribs, - likelihood); + addGuardedDevirtualizationCandidate(call, likelyMethod, likelyClass, likelyContext, likelyMethodAttribs, + likelyClassAttribs, likelihood); } } @@ -6156,12 +6159,13 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, // classAttr - attributes of the class // likelihood - odds that this class is the class seen at runtime // -void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, - CORINFO_METHOD_HANDLE methodHandle, - CORINFO_CLASS_HANDLE classHandle, - unsigned methodAttr, - unsigned classAttr, - unsigned likelihood) +void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, + CORINFO_METHOD_HANDLE methodHandle, + CORINFO_CLASS_HANDLE classHandle, + CORINFO_CONTEXT_HANDLE contextHandle, + unsigned methodAttr, + unsigned classAttr, + unsigned likelihood) { // This transformation only makes sense for delegate and virtual calls assert(call->IsDelegateInvoke() || call->IsVirtual()); @@ -6234,6 +6238,7 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, pInfo->guardedClassHandle = classHandle; pInfo->likelihood = likelihood; pInfo->requiresInstMethodTableArg = false; + pInfo->exactContextHnd = contextHandle; // If the guarded class is a value class, look for an unboxed entry point. // @@ -6295,8 +6300,14 @@ void Compiler::impMarkInlineCandidate(GenTree* callNode, { InlineResult inlineResult(this, call, nullptr, "impMarkInlineCandidate for GDV"); + CORINFO_CONTEXT_HANDLE moreExactContext = call->GetGDVCandidateInfo(candidateId)->exactContextHnd; + if (moreExactContext == NULL) + { + moreExactContext = exactContextHnd; + } + // Do the actual evaluation - impMarkInlineCandidateHelper(call, candidateId, exactContextHnd, exactContextNeedsRuntimeLookup, callInfo, + impMarkInlineCandidateHelper(call, candidateId, moreExactContext, exactContextNeedsRuntimeLookup, callInfo, ilOffset, &inlineResult); // Ignore non-inlineable candidates // TODO: Consider keeping them to just devirtualize without inlining, at least for interface diff --git a/src/coreclr/jit/indirectcalltransformer.cpp b/src/coreclr/jit/indirectcalltransformer.cpp index 8b0318b935c82b..37f0d626cbbc30 100644 --- a/src/coreclr/jit/indirectcalltransformer.cpp +++ b/src/coreclr/jit/indirectcalltransformer.cpp @@ -862,7 +862,7 @@ class IndirectCallTransformer JITDUMP("Direct call [%06u] in block " FMT_BB "\n", compiler->dspTreeID(call), block->bbNum); - CORINFO_METHOD_HANDLE methodHnd = call->gtCallMethHnd; + CORINFO_METHOD_HANDLE methodHnd = inlineInfo->guardedMethodHandle; CORINFO_CONTEXT_HANDLE context = inlineInfo->exactContextHnd; if (clsHnd != NO_CLASS_HANDLE) { @@ -872,7 +872,8 @@ class IndirectCallTransformer unsigned methodFlags = compiler->info.compCompHnd->getMethodAttribs(methodHnd); const bool isLateDevirtualization = true; const bool explicitTailCall = (call->AsCall()->gtCallMoreFlags & GTF_CALL_M_EXPLICIT_TAILCALL) != 0; - compiler->impDevirtualizeCall(call, nullptr, &methodHnd, &methodFlags, &context, nullptr, + CORINFO_CONTEXT_HANDLE contextInput = context; + compiler->impDevirtualizeCall(call, nullptr, &methodHnd, &methodFlags, &contextInput, &context, isLateDevirtualization, explicitTailCall); } else diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 453e80c381e5c0..4a65778676feb4 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1277,6 +1277,10 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) } MethodDesc decl = HandleToObject(info->virtualMethod); + + // Transform from the unboxing thunk to the normal method + decl = decl.IsUnboxingThunk() ? decl.GetUnboxedMethod() : decl; + Debug.Assert(!decl.HasInstantiation); if ((info->context != null) && decl.OwningType.IsInterface) @@ -1369,7 +1373,6 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) #endif ); } - info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN); } else { @@ -1382,17 +1385,17 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) , methodWithTokenImpl #endif ); + } - if (unboxingStub) - { - info->resolvedTokenDevirtualizedUnboxedMethod = info->resolvedTokenDevirtualizedMethod; - info->resolvedTokenDevirtualizedUnboxedMethod.tokenContext = contextFromMethod(nonUnboxingImpl); - info->resolvedTokenDevirtualizedUnboxedMethod.hMethod = ObjectToHandle(nonUnboxingImpl); - } - else - { - info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN); - } + if (unboxingStub) + { + info->resolvedTokenDevirtualizedUnboxedMethod = info->resolvedTokenDevirtualizedMethod; + info->resolvedTokenDevirtualizedUnboxedMethod.tokenContext = contextFromMethod(nonUnboxingImpl); + info->resolvedTokenDevirtualizedUnboxedMethod.hMethod = ObjectToHandle(nonUnboxingImpl); + } + else + { + info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN); } #if READYTORUN @@ -1400,8 +1403,11 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) // Only generate verification for builds with the stress mode enabled if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout) { - ISymbolNode virtualResolutionNode = _compilation.SymbolNodeFactory.CheckVirtualFunctionOverride(methodWithTokenDecl, objType, methodWithTokenImpl); - AddPrecodeFixup(virtualResolutionNode); + if (!methodWithTokenDecl.Method.OwningType.IsValueType || !methodWithTokenImpl.Method.OwningType.IsValueType) + { + ISymbolNode virtualResolutionNode = _compilation.SymbolNodeFactory.CheckVirtualFunctionOverride(methodWithTokenDecl, objType, methodWithTokenImpl); + AddPrecodeFixup(virtualResolutionNode); + } } #endif info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index ad0f2c7dd6dae3..3d418e5fe1d3b0 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -1015,12 +1015,6 @@ CorInfoInitClassResult MethodContext::repInitClass(CORINFO_FIELD_HANDLE field, key.method = CastHandle(method); key.context = CastHandle(context); - if ((InitClass == nullptr) || (InitClass->GetIndex(key) == -1)) - { - // We could try additional inlines with stress modes, just reject them. - return CORINFO_INITCLASS_DONT_INLINE; - } - DWORD value = InitClass->Get(key); DEBUG_REP(dmpInitClass(key, value)); CorInfoInitClassResult result = (CorInfoInitClassResult)value;