Skip to content

JIT: fix double reporting of some GC frame slots #71245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4005,24 +4005,17 @@ inline bool Compiler::lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* var
// This is because struct variables are never tracked as a whole for GC purposes.
// It is up to the caller to ensure that the fields of struct variables are
// correctly tracked.
// On Amd64, we never GC-track fields of dependently promoted structs, even
//
// We never GC-track fields of dependently promoted structs, even
// though they may be tracked for optimization purposes.
// It seems that on x86 and arm, we simply don't track these
// fields, though I have not verified that. I attempted to make these GC-tracked,
// but there was too much logic that depends on these being untracked, so changing
// this would require non-trivial effort.

//
inline bool Compiler::lvaIsGCTracked(const LclVarDsc* varDsc)
{
if (varDsc->lvTracked && (varDsc->lvType == TYP_REF || varDsc->lvType == TYP_BYREF))
{
// Stack parameters are always untracked w.r.t. GC reportings
const bool isStackParam = varDsc->lvIsParam && !varDsc->lvIsRegArg;
#ifdef TARGET_AMD64
return !isStackParam && !lvaIsFieldOfDependentlyPromotedStruct(varDsc);
#else // !TARGET_AMD64
return !isStackParam;
#endif // !TARGET_AMD64
}
else
{
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -2368,6 +2368,11 @@ class emitter
void emitSetFrameRangeLcls(int offsLo, int offsHi);
void emitSetFrameRangeArgs(int offsLo, int offsHi);

bool emitIsWithinFrameRangeGCRs(int offs)
{
return (offs >= emitGCrFrameOffsMin) && (offs < emitGCrFrameOffsMax);
}

static instruction emitJumpKindToIns(emitJumpKind jumpKind);
static emitJumpKind emitInsToJumpKind(instruction ins);
static emitJumpKind emitReverseJumpKind(emitJumpKind jumpKind);
Expand Down
26 changes: 25 additions & 1 deletion src/coreclr/jit/gcencode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4226,7 +4226,31 @@ void GCInfo::gcMakeRegPtrTable(
continue;
}

int offset = varDsc->GetStackOffset() + i * TARGET_POINTER_SIZE;
unsigned const fieldOffset = i * TARGET_POINTER_SIZE;
int const offset = varDsc->GetStackOffset() + fieldOffset;

#ifdef DEBUG
if (varDsc->lvPromoted)
{
assert(compiler->lvaGetPromotionType(varDsc) == Compiler::PROMOTION_TYPE_DEPENDENT);

// A dependently promoted tracked gc local can end up in the gc tracked
// frame range. If so it should be excluded from tracking via lvaIsGCTracked.
//
unsigned const fieldLclNum = compiler->lvaGetFieldLocal(varDsc, fieldOffset);
assert(fieldLclNum != BAD_VAR_NUM);
LclVarDsc* const fieldVarDsc = compiler->lvaGetDesc(fieldLclNum);

if (compiler->GetEmitter()->emitIsWithinFrameRangeGCRs(offset))
{
assert(!compiler->lvaIsGCTracked(fieldVarDsc));
JITDUMP("Untracked GC struct slot V%02u+%u (P-DEP promoted V%02u) is at frame offset %d within "
"tracked ref range; will report slot as untracked\n",
varNum, fieldOffset, fieldLclNum, offset);
}
}
#endif

#if DOUBLE_ALIGN
// For genDoubleAlign(), locals are addressed relative to ESP and
// arguments are addressed relative to EBP.
Expand Down