diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index f6fa0e2d946b64..41624dc24867eb 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -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 { diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index d44fd1bd572eea..fbcfe117a01641 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -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); diff --git a/src/coreclr/jit/gcencode.cpp b/src/coreclr/jit/gcencode.cpp index f9a5e65b6015e7..e85066b64ed59f 100644 --- a/src/coreclr/jit/gcencode.cpp +++ b/src/coreclr/jit/gcencode.cpp @@ -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.