diff --git a/src/coreclr/vm/gcinfodecoder.cpp b/src/coreclr/vm/gcinfodecoder.cpp index 50c09cdd0bb41e..c2aff6210e58fd 100644 --- a/src/coreclr/vm/gcinfodecoder.cpp +++ b/src/coreclr/vm/gcinfodecoder.cpp @@ -6,6 +6,9 @@ #endif #include "gcinfodecoder.h" +#ifdef FEATURE_INTERPRETER +#include "interpexec.h" +#endif // FEATURE_INTERPRETER #ifdef USE_GC_INFO_DECODER @@ -2114,6 +2117,7 @@ template OBJECTREF* TGcInfoDecoder::Ge #endif // Unknown platform #ifdef FEATURE_INTERPRETER + template <> OBJECTREF* TGcInfoDecoder::GetStackSlot( INT32 spOffset, GcStackSlotBase spBase, @@ -2139,7 +2143,26 @@ template <> OBJECTREF* TGcInfoDecoder::GetStackSlot( _ASSERTE(fp); pObjRef = (OBJECTREF*)(fp + spOffset); } + InterpMethodContextFrame* pFrame = (InterpMethodContextFrame*)GetSP(pRD->pCurrentContext); + _ASSERTE(pFrame->pStack == (int8_t *)GetFP(pRD->pCurrentContext)); + InterpMethodContextFrame* pFrameCallee = pFrame->pNext; + // If the stack slot is in a callee's frame, then we do not actually need to report it. This should ONLY happen if the + // stack slot is in the argument area of the caller. As a double check, we validate in the caller of this function that + // the stack slot in question is a interior pinned slot (which when FEATURE_INTERPRETER is defined indicates a conservatively reported stack slot). + if (pFrameCallee != NULL) + { + if (pFrameCallee->ip != 0) + { + _ASSERTE(pFrameCallee->pStack > pFrame->pStack); // Since only the last funclet is GC reported, we shouldn't have any cases where the stack doesn't grow + if (pFrameCallee->pStack <= (int8_t*)pObjRef) + { + // The stack slot is in the callee's frame, not the caller's frame. + // Return as a sentinel to indicate nothing is reported here. + pObjRef = NULL; + } + } + } return pObjRef; } #endif @@ -2221,7 +2244,16 @@ template void TGcInfoDecoder::ReportSt OBJECTREF* pObjRef = GetStackSlot(spOffset, spBase, pRD); _ASSERTE(IS_ALIGNED(pObjRef, sizeof(OBJECTREF*))); - +#ifdef FEATURE_INTERPRETER + // This value is returned when the interpreter stack slot is not actually meaningful. + // This should only happen for stack slots which are conservatively reported, and for better perf + // we completely skip reporting them. + if (pObjRef == (OBJECTREF*)NULL) + { + _ASSERTE((gcFlags & (GC_CALL_PINNED | GC_CALL_INTERIOR)) == (GC_CALL_PINNED | GC_CALL_INTERIOR)); + return; + } +#endif // FEATURE_INTERPRETER #ifdef _DEBUG LOG((LF_GCROOTS, LL_INFO1000, /* Part One */ "Reporting %s" FMT_STK, diff --git a/src/tests/GC/API/GC/Collect0.cs b/src/tests/GC/API/GC/Collect0.cs index 55840378fd5d08..0a8514afca5e12 100644 --- a/src/tests/GC/API/GC/Collect0.cs +++ b/src/tests/GC/API/GC/Collect0.cs @@ -7,6 +7,7 @@ public class Test_Collect0 { [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/118965", typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsCoreClrInterpreter))] public static int TestEntryPoint() { int[] array = new int[25]; diff --git a/src/tests/GC/API/GC/Collect0.csproj b/src/tests/GC/API/GC/Collect0.csproj index 7a51346cd22079..120de12576c7e7 100644 --- a/src/tests/GC/API/GC/Collect0.csproj +++ b/src/tests/GC/API/GC/Collect0.csproj @@ -9,5 +9,6 @@ +