Skip to content

Commit 6b4ee34

Browse files
[clr-interp] Tweak GC reporting (#122620)
The interpreter calling convention can result in double reporting of arguments passed to callee's. This works today as all of the arguments will be conservatively reported, but it also adds the problem of excess conservative reporting. This change fixes that most of that problem by only dropping reporting of conservative pointers when they point into a callee's stack space. Note that this does not fix is the scenario where an object reference is held on the IL stack across a call. In those cases the value shall still be reported conservatively. This PR also tweaks the Collect0 test to disable it under the interpreter as the C# compiler generates that particular problematic pattern for this test case.
1 parent 27a5c7d commit 6b4ee34

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

src/coreclr/vm/gcinfodecoder.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
#endif
77

88
#include "gcinfodecoder.h"
9+
#ifdef FEATURE_INTERPRETER
10+
#include "interpexec.h"
11+
#endif // FEATURE_INTERPRETER
912

1013
#ifdef USE_GC_INFO_DECODER
1114

@@ -2113,6 +2116,7 @@ template <typename GcInfoEncoding> OBJECTREF* TGcInfoDecoder<GcInfoEncoding>::Ge
21132116
#endif // Unknown platform
21142117

21152118
#ifdef FEATURE_INTERPRETER
2119+
21162120
template <> OBJECTREF* TGcInfoDecoder<InterpreterGcInfoEncoding>::GetStackSlot(
21172121
INT32 spOffset,
21182122
GcStackSlotBase spBase,
@@ -2138,7 +2142,26 @@ template <> OBJECTREF* TGcInfoDecoder<InterpreterGcInfoEncoding>::GetStackSlot(
21382142
_ASSERTE(fp);
21392143
pObjRef = (OBJECTREF*)(fp + spOffset);
21402144
}
2145+
InterpMethodContextFrame* pFrame = (InterpMethodContextFrame*)GetSP(pRD->pCurrentContext);
2146+
_ASSERTE(pFrame->pStack == (int8_t *)GetFP(pRD->pCurrentContext));
2147+
InterpMethodContextFrame* pFrameCallee = pFrame->pNext;
21412148

2149+
// 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
2150+
// stack slot is in the argument area of the caller. As a double check, we validate in the caller of this function that
2151+
// the stack slot in question is a interior pinned slot (which when FEATURE_INTERPRETER is defined indicates a conservatively reported stack slot).
2152+
if (pFrameCallee != NULL)
2153+
{
2154+
if (pFrameCallee->ip != 0)
2155+
{
2156+
_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
2157+
if (pFrameCallee->pStack <= (int8_t*)pObjRef)
2158+
{
2159+
// The stack slot is in the callee's frame, not the caller's frame.
2160+
// Return as a sentinel to indicate nothing is reported here.
2161+
pObjRef = NULL;
2162+
}
2163+
}
2164+
}
21422165
return pObjRef;
21432166
}
21442167
#endif
@@ -2220,7 +2243,16 @@ template <typename GcInfoEncoding> void TGcInfoDecoder<GcInfoEncoding>::ReportSt
22202243

22212244
OBJECTREF* pObjRef = GetStackSlot(spOffset, spBase, pRD);
22222245
_ASSERTE(IS_ALIGNED(pObjRef, sizeof(OBJECTREF*)));
2223-
2246+
#ifdef FEATURE_INTERPRETER
2247+
// This value is returned when the interpreter stack slot is not actually meaningful.
2248+
// This should only happen for stack slots which are conservatively reported, and for better perf
2249+
// we completely skip reporting them.
2250+
if (pObjRef == (OBJECTREF*)NULL)
2251+
{
2252+
_ASSERTE((gcFlags & (GC_CALL_PINNED | GC_CALL_INTERIOR)) == (GC_CALL_PINNED | GC_CALL_INTERIOR));
2253+
return;
2254+
}
2255+
#endif // FEATURE_INTERPRETER
22242256
#ifdef _DEBUG
22252257
LOG((LF_GCROOTS, LL_INFO1000, /* Part One */
22262258
"Reporting %s" FMT_STK,

src/tests/GC/API/GC/Collect0.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
public class Test_Collect0 {
99
[Fact]
10+
[ActiveIssue("https://github.com/dotnet/runtime/issues/118965", typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsCoreClrInterpreter))]
1011
public static int TestEntryPoint() {
1112

1213
int[] array = new int[25];

src/tests/GC/API/GC/Collect0.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
</PropertyGroup>
1010
<ItemGroup>
1111
<Compile Include="Collect0.cs" />
12+
<ProjectReference Include="$(TestLibraryProjectPath)" />
1213
</ItemGroup>
1314
</Project>

0 commit comments

Comments
 (0)