diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index dbc56f2344e513..6c0557bccf66f9 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -10403,7 +10403,7 @@ bool Compiler::lvaIsOSRLocal(unsigned varNum) // if ((varNum >= info.compLocalsCount) && (varNum != lvaMonAcquired) && (varNum != lvaAsyncThreadObjectVar) && (varNum != lvaResumedIndicator) && (varNum != lvaAsyncExecutionContextVar) && - (varNum != lvaAsyncSynchronizationContextVar)) + (varNum != lvaAsyncSynchronizationContextVar) && (varNum != lvaCachedGenericContextArg)) { assert(varDsc->lvIsStructField); assert(varDsc->lvParentLcl < info.compLocalsCount); @@ -10433,6 +10433,16 @@ int Compiler::lvaOSRLocalTier0FrameOffset(unsigned varNum) { assert(lvaIsOSRLocal(varNum)); + if (varNum == lvaCachedGenericContextArg) + { + if (info.compPatchpointInfo->HasGenericContextArgOffset()) + { + return info.compPatchpointInfo->GenericContextArgOffset(); + } + + assert(info.compPatchpointInfo->HasKeptAliveThis()); + return info.compPatchpointInfo->KeptAliveThisOffset(); + } if (varNum == lvaMonAcquired) { return info.compPatchpointInfo->MonitorAcquiredOffset(); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 03fa22ec8c5463..6cdc28e334641c 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4489,7 +4489,7 @@ class Compiler //------------------------------------------------------------------------- // All these frame offsets are inter-related and must be kept in sync - int lvaCachedGenericContextArgOffs; + unsigned lvaCachedGenericContextArg = BAD_VAR_NUM; int lvaCachedGenericContextArgOffset(); // For CORINFO_CALLCONV_PARAMTYPE and if generic context is passed as // THIS pointer diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index ff316205567597..7afd3e45101b6d 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -2723,8 +2723,9 @@ inline bool Compiler::lvaReportParamTypeArg() inline int Compiler::lvaCachedGenericContextArgOffset() { assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT); + assert(lvaCachedGenericContextArg != BAD_VAR_NUM); - return lvaCachedGenericContextArgOffs; + return lvaGetDesc(lvaCachedGenericContextArg)->GetStackOffset(); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index b8753896d6e09c..5860f9c8fcbdd2 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -316,6 +316,23 @@ void Compiler::lvaInitTypeRef() } } +#ifdef JIT32_GCENCODER + const unsigned genericContextOptions = + CORINFO_GENERICS_CTXT_FROM_METHODDESC | CORINFO_GENERICS_CTXT_FROM_METHODTABLE; +#else + const unsigned genericContextOptions = CORINFO_GENERICS_CTXT_FROM_METHODDESC | + CORINFO_GENERICS_CTXT_FROM_METHODTABLE | CORINFO_GENERICS_CTXT_FROM_THIS; +#endif + + if ((info.compMethodInfo->options & genericContextOptions) != 0) + { + lvaCachedGenericContextArg = lvaGrabTemp(true DEBUGARG("cached generic context")); + + LclVarDsc* cachedGenericContextArg = lvaGetDesc(lvaCachedGenericContextArg); + cachedGenericContextArg->lvType = TYP_I_IMPL; + cachedGenericContextArg->lvOnFrame = false; + } + if (getNeedsGSSecurityCookie()) { // Ensure that there will be at least one stack variable since @@ -3439,6 +3456,45 @@ PhaseStatus Compiler::lvaMarkLocalVars() const bool isRecompute = false; lvaComputeRefCounts(isRecompute, setSlotNumbers); + if (lvaCachedGenericContextArg != BAD_VAR_NUM) + { + LclVarDsc* cachedGenericContextArg = lvaGetDesc(lvaCachedGenericContextArg); + + bool reportGenericContextArg = lvaReportParamTypeArg(); +#ifndef JIT32_GCENCODER + reportGenericContextArg |= lvaKeepAliveAndReportThis(); +#endif + + if (reportGenericContextArg) + { + cachedGenericContextArg->lvImplicitlyReferenced = 1; + cachedGenericContextArg->lvOnFrame = true; + lvaSetVarDoNotEnregister(lvaCachedGenericContextArg DEBUGARG(DoNotEnregisterReason::VMNeedsStackAddr)); + lvaSetVarAddrExposed( + lvaCachedGenericContextArg DEBUGARG(AddressExposedReason::EXTERNALLY_VISIBLE_IMPLICITLY)); + + if (opts.IsOSR()) + { + PatchpointInfo* patchpointInfo = info.compPatchpointInfo; + if (lvaReportParamTypeArg()) + { + assert(patchpointInfo->HasGenericContextArgOffset()); + cachedGenericContextArg->lvIsOSRLocal = true; + } +#ifndef JIT32_GCENCODER + else if (patchpointInfo->HasKeptAliveThis()) + { + cachedGenericContextArg->lvIsOSRLocal = true; + } +#endif + } + } + else + { + cachedGenericContextArg->lvImplicitlyReferenced = 0; + } + } + // If we don't need precise reference counts, e.g. we're not optimizing, we're done. if (!PreciseRefCountsRequired()) { @@ -3507,10 +3563,11 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) // and not tracked. for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++) { - LclVarDsc* varDsc = lvaGetDesc(lclNum); - const bool isSpecialVarargsParam = varDsc->lvIsParam && lvaIsArgAccessedViaVarArgsCookie(lclNum); + LclVarDsc* varDsc = lvaGetDesc(lclNum); + const bool isSpecialVarargsParam = varDsc->lvIsParam && lvaIsArgAccessedViaVarArgsCookie(lclNum); + const bool isDormantGenericContextArg = (lclNum == lvaCachedGenericContextArg) && !varDsc->lvOnFrame; - if (isSpecialVarargsParam) + if (isSpecialVarargsParam || isDormantGenericContextArg) { assert(varDsc->lvRefCnt() == 0); } @@ -3541,9 +3598,10 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) // Special case for some varargs params ... these must // remain unreferenced. - const bool isSpecialVarargsParam = varDsc->lvIsParam && lvaIsArgAccessedViaVarArgsCookie(lclNum); + const bool isSpecialVarargsParam = varDsc->lvIsParam && lvaIsArgAccessedViaVarArgsCookie(lclNum); + const bool isDormantGenericContextArg = (lclNum == lvaCachedGenericContextArg) && !varDsc->lvOnFrame; - if (!isSpecialVarargsParam) + if (!isSpecialVarargsParam && !isDormantGenericContextArg) { varDsc->lvImplicitlyReferenced = 1; } @@ -4565,12 +4623,6 @@ void Compiler::lvaFixVirtualFrameOffsets() temp->tdAdjustTempOffs(delta + frameLocalsDelta); } - if (lvaCachedGenericContextArgOffs < frameBoundary) - { - lvaCachedGenericContextArgOffs += frameLocalsDelta; - } - lvaCachedGenericContextArgOffs += delta; - #if FEATURE_FIXED_OUT_ARGS if (lvaOutgoingArgSpaceVar != BAD_VAR_NUM) @@ -5059,42 +5111,18 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() #ifdef JIT32_GCENCODER noway_assert(codeGen->isFramePointerUsed()); #endif - if (opts.IsOSR()) - { - PatchpointInfo* ppInfo = info.compPatchpointInfo; - assert(ppInfo->HasGenericContextArgOffset()); - const int originalOffset = ppInfo->GenericContextArgOffset(); - lvaCachedGenericContextArgOffs = originalFrameStkOffs + originalOffset; - } - else + if (!lvaIsOSRLocal(lvaCachedGenericContextArg)) { - // For CORINFO_CALLCONV_PARAMTYPE (if needed) - lvaIncrementFrameSize(TARGET_POINTER_SIZE); - stkOffs -= TARGET_POINTER_SIZE; - lvaCachedGenericContextArgOffs = stkOffs; + stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaCachedGenericContextArg, TARGET_POINTER_SIZE, stkOffs); } } #ifndef JIT32_GCENCODER else if (lvaKeepAliveAndReportThis()) { - bool canUseExistingSlot = false; - if (opts.IsOSR()) - { - PatchpointInfo* ppInfo = info.compPatchpointInfo; - if (ppInfo->HasKeptAliveThis()) - { - const int originalOffset = ppInfo->KeptAliveThisOffset(); - lvaCachedGenericContextArgOffs = originalFrameStkOffs + originalOffset; - canUseExistingSlot = true; - } - } - - if (!canUseExistingSlot) + if (!lvaIsOSRLocal(lvaCachedGenericContextArg)) { // When "this" is also used as generic context arg. - lvaIncrementFrameSize(TARGET_POINTER_SIZE); - stkOffs -= TARGET_POINTER_SIZE; - lvaCachedGenericContextArgOffs = stkOffs; + stkOffs = lvaAllocLocalAndSetVirtualOffset(lvaCachedGenericContextArg, TARGET_POINTER_SIZE, stkOffs); } } #endif @@ -5328,7 +5356,9 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() continue; } - if ((lclNum == lvaMonAcquired) || (lclNum == lvaResumedIndicator) || (lclNum == lvaAsyncThreadObjectVar) || + if ((lclNum == lvaMonAcquired) || + ((lclNum == lvaCachedGenericContextArg) && !lvaIsOSRLocal(lvaCachedGenericContextArg)) || + (lclNum == lvaResumedIndicator) || (lclNum == lvaAsyncThreadObjectVar) || (lclNum == lvaAsyncExecutionContextVar) || (lclNum == lvaAsyncSynchronizationContextVar)) { continue;