diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index f2e47ae2ddac44..37af015ab3008d 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -4291,7 +4291,7 @@ PhaseStatus Compiler::lvaMarkLocalVars() #endif // !FEATURE_EH_FUNCLETS - // PSPSym and LocAllocSPvar are not used by the NativeAOT ABI + // PSPSym is not used by the NativeAOT ABI if (!IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { #if defined(FEATURE_EH_FUNCLETS) @@ -4303,29 +4303,29 @@ PhaseStatus Compiler::lvaMarkLocalVars() lvaSetVarDoNotEnregister(lvaPSPSym DEBUGARG(DoNotEnregisterReason::VMNeedsStackAddr)); } #endif // FEATURE_EH_FUNCLETS + } #ifdef JIT32_GCENCODER - // LocAllocSPvar is only required by the implicit frame layout expected by the VM on x86. Whether - // a function contains a Localloc is conveyed in the GC information, in the InfoHdrSmall.localloc - // field. The function must have an EBP frame. Then, the VM finds the LocAllocSP slot by assuming - // the following stack layout: - // - // -- higher addresses -- - // saved EBP <-- EBP points here - // other callee-saved registers // InfoHdrSmall.savedRegsCountExclFP specifies this size - // optional GS cookie // InfoHdrSmall.security is 1 if this exists - // LocAllocSP slot - // -- lower addresses -- - // - // See also eetwain.cpp::GetLocallocSPOffset() and its callers. - if (compLocallocUsed) - { - lvaLocAllocSPvar = lvaGrabTempWithImplicitUse(false DEBUGARG("LocAllocSPvar")); - LclVarDsc* locAllocSPvar = lvaGetDesc(lvaLocAllocSPvar); - locAllocSPvar->lvType = TYP_I_IMPL; - } -#endif // JIT32_GCENCODER + // LocAllocSPvar is only required by the implicit frame layout expected by the VM on x86. Whether + // a function contains a Localloc is conveyed in the GC information, in the InfoHdrSmall.localloc + // field. The function must have an EBP frame. Then, the VM finds the LocAllocSP slot by assuming + // the following stack layout: + // + // -- higher addresses -- + // saved EBP <-- EBP points here + // other callee-saved registers // InfoHdrSmall.savedRegsCountExclFP specifies this size + // optional GS cookie // InfoHdrSmall.security is 1 if this exists + // LocAllocSP slot + // -- lower addresses -- + // + // See also eetwain.cpp::GetLocallocSPOffset() and its callers. + if (compLocallocUsed) + { + lvaLocAllocSPvar = lvaGrabTempWithImplicitUse(false DEBUGARG("LocAllocSPvar")); + LclVarDsc* locAllocSPvar = lvaGetDesc(lvaLocAllocSPvar); + locAllocSPvar->lvType = TYP_I_IMPL; } +#endif // JIT32_GCENCODER // Ref counting is now enabled normally. lvaRefCountState = RCS_NORMAL; diff --git a/src/coreclr/nativeaot/Runtime/ICodeManager.h b/src/coreclr/nativeaot/Runtime/ICodeManager.h index 4c9957dd606217..dfc6e9efa915a8 100644 --- a/src/coreclr/nativeaot/Runtime/ICodeManager.h +++ b/src/coreclr/nativeaot/Runtime/ICodeManager.h @@ -229,6 +229,11 @@ class ICodeManager virtual PTR_VOID GetFramePointer(MethodInfo * pMethodInfo, REGDISPLAY * pRegisterSet) PURE_VIRTUAL +#ifdef TARGET_X86 + virtual uintptr_t GetResumeSp(MethodInfo * pMethodInfo, + REGDISPLAY * pRegisterSet) PURE_VIRTUAL +#endif + virtual void EnumGcRefs(MethodInfo * pMethodInfo, PTR_VOID safePointAddress, REGDISPLAY * pRegisterSet, diff --git a/src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp b/src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp index f6d560fa295111..ae073e57c7ecd0 100644 --- a/src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp +++ b/src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp @@ -1677,6 +1677,13 @@ void StackFrameIterator::CalculateCurrentMethodState() m_effectiveSafePointAddress = m_ControlPC; m_FramePointer = GetCodeManager()->GetFramePointer(&m_methodInfo, &m_RegDisplay); +#ifdef TARGET_X86 + if (m_dwFlags & UpdateResumeSp) + { + m_RegDisplay.ResumeSP = GetCodeManager()->GetResumeSp(&m_methodInfo, &m_RegDisplay); + } +#endif + m_dwFlags |= MethodStateCalculated; } diff --git a/src/coreclr/nativeaot/Runtime/StackFrameIterator.h b/src/coreclr/nativeaot/Runtime/StackFrameIterator.h index 10b4c2bd65bc51..cf7f524de8dbbe 100644 --- a/src/coreclr/nativeaot/Runtime/StackFrameIterator.h +++ b/src/coreclr/nativeaot/Runtime/StackFrameIterator.h @@ -148,8 +148,11 @@ class StackFrameIterator // When encountering a reverse P/Invoke, unwind directly to the P/Invoke frame using the saved transition frame. SkipNativeFrames = 0x80, + // Set SP to an address that is valid for funclet resumption (x86 only) + UpdateResumeSp = 0x100, + GcStackWalkFlags = (CollapseFunclets | RemapHardwareFaultsToSafePoint | SkipNativeFrames), - EHStackWalkFlags = ApplyReturnAddressAdjustment, + EHStackWalkFlags = (ApplyReturnAddressAdjustment | UpdateResumeSp), StackTraceStackWalkFlags = GcStackWalkFlags }; diff --git a/src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.h b/src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.h index ad428db1250cef..326a8aa6ddf37b 100644 --- a/src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.h +++ b/src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.h @@ -7,7 +7,7 @@ // // NOTE: the offsets MUST be in hex notation WITHOUT the 0x prefix -PLAT_ASM_SIZEOF(c0, ExInfo) +PLAT_ASM_SIZEOF(c4, ExInfo) PLAT_ASM_OFFSET(0, ExInfo, m_pPrevExInfo) PLAT_ASM_OFFSET(4, ExInfo, m_pExContext) PLAT_ASM_OFFSET(8, ExInfo, m_exception) @@ -15,7 +15,7 @@ PLAT_ASM_OFFSET(0c, ExInfo, m_kind) PLAT_ASM_OFFSET(0d, ExInfo, m_passNumber) PLAT_ASM_OFFSET(10, ExInfo, m_idxCurClause) PLAT_ASM_OFFSET(14, ExInfo, m_frameIter) -PLAT_ASM_OFFSET(bc, ExInfo, m_notifyDebuggerSP) +PLAT_ASM_OFFSET(c0, ExInfo, m_notifyDebuggerSP) PLAT_ASM_OFFSET(0, PInvokeTransitionFrame, m_RIP) PLAT_ASM_OFFSET(4, PInvokeTransitionFrame, m_FramePointer) @@ -23,16 +23,15 @@ PLAT_ASM_OFFSET(8, PInvokeTransitionFrame, m_pThread) PLAT_ASM_OFFSET(0c, PInvokeTransitionFrame, m_Flags) PLAT_ASM_OFFSET(10, PInvokeTransitionFrame, m_PreservedRegs) -PLAT_ASM_SIZEOF(a8, StackFrameIterator) +PLAT_ASM_SIZEOF(ac, StackFrameIterator) PLAT_ASM_OFFSET(08, StackFrameIterator, m_FramePointer) PLAT_ASM_OFFSET(0c, StackFrameIterator, m_ControlPC) PLAT_ASM_OFFSET(10, StackFrameIterator, m_RegDisplay) -PLAT_ASM_OFFSET(a0, StackFrameIterator, m_OriginalControlPC) -PLAT_ASM_OFFSET(a4, StackFrameIterator, m_pPreviousTransitionFrame) +PLAT_ASM_OFFSET(a4, StackFrameIterator, m_OriginalControlPC) +PLAT_ASM_OFFSET(a8, StackFrameIterator, m_pPreviousTransitionFrame) PLAT_ASM_SIZEOF(1c, PAL_LIMITED_CONTEXT) PLAT_ASM_OFFSET(0, PAL_LIMITED_CONTEXT, IP) - PLAT_ASM_OFFSET(4, PAL_LIMITED_CONTEXT, Rsp) PLAT_ASM_OFFSET(8, PAL_LIMITED_CONTEXT, Rbp) PLAT_ASM_OFFSET(0c, PAL_LIMITED_CONTEXT, Rdi) @@ -40,10 +39,10 @@ PLAT_ASM_OFFSET(10, PAL_LIMITED_CONTEXT, Rsi) PLAT_ASM_OFFSET(14, PAL_LIMITED_CONTEXT, Rax) PLAT_ASM_OFFSET(18, PAL_LIMITED_CONTEXT, Rbx) -PLAT_ASM_SIZEOF(28, REGDISPLAY) -PLAT_ASM_OFFSET(1c, REGDISPLAY, SP) - +PLAT_ASM_SIZEOF(2c, REGDISPLAY) PLAT_ASM_OFFSET(0c, REGDISPLAY, pRbx) PLAT_ASM_OFFSET(10, REGDISPLAY, pRbp) PLAT_ASM_OFFSET(14, REGDISPLAY, pRsi) PLAT_ASM_OFFSET(18, REGDISPLAY, pRdi) +PLAT_ASM_OFFSET(1c, REGDISPLAY, SP) +PLAT_ASM_OFFSET(28, REGDISPLAY, ResumeSP) diff --git a/src/coreclr/nativeaot/Runtime/i386/ExceptionHandling.asm b/src/coreclr/nativeaot/Runtime/i386/ExceptionHandling.asm index 2172d3982d1821..4e823bbbd6ad1c 100644 --- a/src/coreclr/nativeaot/Runtime/i386/ExceptionHandling.asm +++ b/src/coreclr/nativeaot/Runtime/i386/ExceptionHandling.asm @@ -334,7 +334,7 @@ FASTCALL_FUNC RhpCallCatchFunclet, 16 mov ecx, [esp + esp_offsetof_ExInfo] ;; ecx <- current ExInfo * mov eax, [esp + esp_offsetof_RegDisplay] ;; eax <- REGDISPLAY* - mov eax, [eax + OFFSETOF__REGDISPLAY__SP] ;; eax <- resume SP value + mov eax, [eax + OFFSETOF__REGDISPLAY__ResumeSP] ;; eax <- resume SP value @@: mov ecx, [ecx + OFFSETOF__ExInfo__m_pPrevExInfo] ;; ecx <- next ExInfo cmp ecx, 0 diff --git a/src/coreclr/nativeaot/Runtime/regdisplay.h b/src/coreclr/nativeaot/Runtime/regdisplay.h index d5082fb9efbe74..739a4eec230908 100644 --- a/src/coreclr/nativeaot/Runtime/regdisplay.h +++ b/src/coreclr/nativeaot/Runtime/regdisplay.h @@ -49,6 +49,8 @@ struct REGDISPLAY #ifdef TARGET_X86 TADDR PCTAddr; + // SP for use by catch funclet when resuming execution + uintptr_t ResumeSP; inline unsigned long *GetEaxLocation() { return (unsigned long *)pRax; } inline unsigned long *GetEcxLocation() { return (unsigned long *)pRcx; } diff --git a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp index b6dd6ee812d2bb..d3c2ef42241743 100644 --- a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp @@ -184,7 +184,6 @@ static PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntim #endif } - CoffNativeCodeManager::CoffNativeCodeManager(TADDR moduleBase, PTR_VOID pvManagedCodeStartRange, uint32_t cbManagedCodeRange, PTR_RUNTIME_FUNCTION pRuntimeFunctionTable, uint32_t nRuntimeFunctionTable, @@ -323,7 +322,7 @@ bool CoffNativeCodeManager::IsFilter(MethodInfo * pMethInfo) } PTR_VOID CoffNativeCodeManager::GetFramePointer(MethodInfo * pMethInfo, - REGDISPLAY * pRegisterSet) + REGDISPLAY * pRegisterSet) { CoffNativeMethodInfo * pMethodInfo = (CoffNativeMethodInfo *)pMethInfo; @@ -341,6 +340,39 @@ PTR_VOID CoffNativeCodeManager::GetFramePointer(MethodInfo * pMethInfo, return NULL; } +#ifdef TARGET_X86 +uintptr_t CoffNativeCodeManager::GetResumeSp(MethodInfo * pMethodInfo, + REGDISPLAY * pRegisterSet) +{ + PTR_uint8_t gcInfo; + uint32_t codeOffset = GetCodeOffset(pMethodInfo, (PTR_VOID)pRegisterSet->IP, &gcInfo); + + hdrInfo infoBuf; + size_t infoSize = DecodeGCHdrInfo(GCInfoToken(gcInfo), codeOffset, &infoBuf); + PTR_CBYTE table = gcInfo + infoSize; + + _ASSERTE(infoBuf.epilogOffs == hdrInfo::NOT_IN_EPILOG && infoBuf.prologOffs == hdrInfo::NOT_IN_PROLOG); + + bool isESPFrame = !infoBuf.ebpFrame && !infoBuf.doubleAlign; + + CoffNativeMethodInfo * pNativeMethodInfo = (CoffNativeMethodInfo *)pMethodInfo; + if (pNativeMethodInfo->mainRuntimeFunction != pNativeMethodInfo->runtimeFunction) + { + // Treat funclet's frame as ESP frame + isESPFrame = true; + } + + if (isESPFrame) + { + const uintptr_t curESP = pRegisterSet->SP; + return curESP + GetPushedArgSize(&infoBuf, table, codeOffset); + } + + const uintptr_t curEBP = pRegisterSet->GetFP(); + return GetOutermostBaseFP(curEBP, &infoBuf); +} +#endif // TARGET_X86 + uint32_t CoffNativeCodeManager::GetCodeOffset(MethodInfo* pMethodInfo, PTR_VOID address, /*out*/ PTR_uint8_t* gcInfo) { CoffNativeMethodInfo * pNativeMethodInfo = (CoffNativeMethodInfo *)pMethodInfo; diff --git a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.h b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.h index 6c56ee9c1ef95b..c1dacbfd8f9866 100644 --- a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.h +++ b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.h @@ -65,6 +65,11 @@ class CoffNativeCodeManager : public ICodeManager PTR_VOID GetFramePointer(MethodInfo * pMethodInfo, REGDISPLAY * pRegisterSet); +#ifdef TARGET_X86 + uintptr_t GetResumeSp(MethodInfo * pMethodInfo, + REGDISPLAY * pRegisterSet); +#endif + uint32_t GetCodeOffset(MethodInfo * pMethodInfo, PTR_VOID address, /*out*/ PTR_uint8_t* gcInfo); bool IsSafePoint(PTR_VOID pvAddress); diff --git a/src/coreclr/vm/gc_unwind_x86.inl b/src/coreclr/vm/gc_unwind_x86.inl index 8f981ed84cd609..c5ba9593446e2d 100644 --- a/src/coreclr/vm/gc_unwind_x86.inl +++ b/src/coreclr/vm/gc_unwind_x86.inl @@ -366,7 +366,6 @@ size_t GetLocallocSPOffset(hdrInfo * info) return position * sizeof(TADDR); } -#ifndef FEATURE_NATIVEAOT inline size_t GetParamTypeArgOffset(hdrInfo * info) { @@ -451,6 +450,7 @@ TADDR GetOutermostBaseFP(TADDR ebp, hdrInfo * info) } } +#ifndef FEATURE_NATIVEAOT /***************************************************************************** * * For functions with handlers, checks if it is currently in a handler. @@ -662,7 +662,7 @@ inline size_t GetSizeOfFrameHeaderForEnC(hdrInfo * info) return sizeof(TADDR) + GetEndShadowSPSlotsOffset(info, MAX_EnC_HANDLER_NESTING_LEVEL); } -#endif +#endif // FEATURE_NATIVEAOT /*****************************************************************************/ static