From 3341b2402b5048ad8c3064c9bf7c82fb3ca8c5ea Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 26 Jun 2025 13:43:25 +0200 Subject: [PATCH] Enable support for InlinedCallFrame in the interpreter This change enables using InlinedCallFrame around pinvokes called from the interpreter. It ensures that the InlinedCallFrame caller can be set to the interpreted code and that stack walk from the InlinedCallFrame through the interpreted code and then through the InterpreterFrame works properly. As an example and to test it, I have added an InlinedCallFrame to the temporary implementation of the INTOP_GC_COLLECT and changed it to call a QCALL. --- src/coreclr/vm/frames.h | 15 +++++++++++++++ src/coreclr/vm/interpexec.cpp | 12 ++++++++++-- src/coreclr/vm/stackwalk.cpp | 7 +------ src/coreclr/vm/stackwalk.h | 1 - 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 892e55586d7abd..fbf222baf36f8e 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -2134,6 +2134,21 @@ typedef DPTR(class InlinedCallFrame) PTR_InlinedCallFrame; class InlinedCallFrame : public Frame { public: + +#ifndef DACCESS_COMPILE +#ifdef FEATURE_INTERPRETER + InlinedCallFrame() : Frame(FrameIdentifier::InlinedCallFrame) + { + WRAPPER_NO_CONTRACT; + m_Datum = NULL; + m_pCallSiteSP = NULL; + m_pCallerReturnAddress = 0; + m_pCalleeSavedFP = 0; + m_pThread = NULL; + } +#endif // FEATURE_INTERPRETER +#endif // DACCESS_COMPILE + MethodDesc *GetFunction_Impl() { WRAPPER_NO_CONTRACT; diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 372e8b2cfbafc6..9505ee4f5d40e5 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -1719,8 +1719,16 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr // Interpreter-TODO: Remove this { pInterpreterFrame->SetTopInterpMethodContextFrame(pFrame); - GCX_COOP(); - GCHeapUtilities::GetGCHeap()->GarbageCollect(-1, false, collection_blocking | collection_aggressive); + + InlinedCallFrame inlinedCallFrame; + inlinedCallFrame.m_pCallerReturnAddress = (TADDR)ip; + inlinedCallFrame.m_pCallSiteSP = pFrame; + inlinedCallFrame.m_pCalleeSavedFP = (TADDR)stack; + inlinedCallFrame.m_pThread = GetThread(); + inlinedCallFrame.m_Datum = NULL; + inlinedCallFrame.Push(); + GCInterface_Collect(-1, collection_blocking | collection_aggressive, false); + inlinedCallFrame.Pop(); } ip++; break; diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp index 103aa7fe0db6db..59972a9bae0b4c 100644 --- a/src/coreclr/vm/stackwalk.cpp +++ b/src/coreclr/vm/stackwalk.cpp @@ -1053,9 +1053,6 @@ void StackFrameIterator::CommonCtor(Thread * pThread, PTR_Frame pFrame, ULONG32 m_movedPastFirstExInfo = false; m_fFuncletNotSeen = false; m_fFoundFirstFunclet = false; -#ifdef FEATURE_INTERPRETER - m_walkingInterpreterFrames = false; -#endif #if defined(RECORD_RESUMABLE_FRAME_SP) m_pvResumableFrameTargetSP = NULL; #endif @@ -2848,7 +2845,7 @@ void StackFrameIterator::ProcessCurrentFrame(void) { PREGDISPLAY pRD = m_crawl.GetRegisterSet(); - if (!m_walkingInterpreterFrames) + if (GetIP(pRD->pCurrentContext) != (TADDR)InterpreterFrame::DummyCallerIP) { // We have hit the InterpreterFrame while we were not processing the interpreter frames. // Switch to walking the underlying interpreted frames. @@ -2864,12 +2861,10 @@ void StackFrameIterator::ProcessCurrentFrame(void) pRD->pCurrentContext->ContextFlags = CONTEXT_FULL; SyncRegDisplayToCurrentContext(pRD); ProcessIp(GetControlPC(pRD)); - m_walkingInterpreterFrames = m_crawl.isFrameless; } else { // We have finished walking the interpreted frames. Process the InterpreterFrame itself. - m_walkingInterpreterFrames = false; // Restore the registers to the values they had before we started walking the interpreter frames. SetIP(pRD->pCurrentContext, m_interpExecMethodIP); SetSP(pRD->pCurrentContext, m_interpExecMethodSP); diff --git a/src/coreclr/vm/stackwalk.h b/src/coreclr/vm/stackwalk.h index ca4afa3e2df93a..6b650a277137e3 100644 --- a/src/coreclr/vm/stackwalk.h +++ b/src/coreclr/vm/stackwalk.h @@ -769,7 +769,6 @@ class StackFrameIterator // Indicates that the stack walk has moved past a funclet bool m_fFoundFirstFunclet; #ifdef FEATURE_INTERPRETER - bool m_walkingInterpreterFrames; // Saved registers of the context of the InterpExecMethod. These registers are reused for interpreter frames, // but we need to restore the original values after we are done with all the interpreted frames belonging to // that InterpExecMethod.