Skip to content

Commit 71df7db

Browse files
authored
JIT: Eagerly invalidate GC state for registers trashed by linker relaxation sequences (#128073)
TLS accesses are optimized in NativeAOT with the help of the linker. The JIT emits a sequence of instructions that is specially recognized, and the linker then rewrites (relaxes) those instructions to a more efficient pattern. Normally, when the JIT emits instructions, it only lazily updates GC state. For example, if `rax` contains a GC reference, we delay any actual GC information update until we actually emit an instruction that clobbers `rax`. This is regardless of whether or not the value in `rax` died a long time ago. This is a problem for these linker relaxation sequences. The linker's instructions may end up clobbering registers earlier than we do in our emitted instructions, and in that case we are reporting a GC register as live while it had been trashed. Fix the case for linux-x64 and linux-arm64 by eagerly emitting GC state updates for these special patterns.
1 parent ab8649f commit 71df7db

4 files changed

Lines changed: 35 additions & 0 deletions

File tree

src/coreclr/jit/codegenarmarch.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3353,6 +3353,14 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
33533353
// mrs
33543354
emitter->emitIns_R(INS_mrs_tpid0, attr, REG_R1);
33553355

3356+
// We remove x0 here since the linker relaxation
3357+
// sequence will rewrite the instructions we are emitting here with
3358+
// instructions that may clobber these registers.
3359+
// (This is more important for the emitter, but we match it here
3360+
// for symmetry and to avoid confusion about the state of the
3361+
// registers.)
3362+
gcInfo.gcMarkRegSetNpt(RBM_R0);
3363+
33563364
// adrp
33573365
// ldr
33583366
// add

src/coreclr/jit/codegenxarch.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,15 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
484484
else if (con->IsIconHandle(GTF_ICON_TLSGD_OFFSET))
485485
{
486486
attr = EA_SET_FLG(attr, EA_CNS_TLSGD_RELOC);
487+
488+
// This marks the start of a TLS access linker relaxation
489+
// sequence for linux-x64. The linker may rewrite to
490+
// instructions that trash rax at this point, so we update
491+
// GC state eagerly here.
492+
// (This is more important for the emitter, but we match it here
493+
// for symmetry and to avoid confusion about the state of the
494+
// registers.)
495+
gcInfo.gcMarkRegSetNpt(RBM_RAX);
487496
}
488497
}
489498

src/coreclr/jit/emitarm64.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11749,6 +11749,17 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
1174911749
emitRecordRelocation(odst, id->idAddr()->iiaAddr,
1175011750
id->idIsTlsGD() ? CorInfoReloc::ARM64_LIN_TLSDESC_ADR_PAGE21
1175111751
: CorInfoReloc::ARM64_PAGEBASE_REL21);
11752+
11753+
if (id->idIsTlsGD())
11754+
{
11755+
// This is the beginning of the TLS access linker
11756+
// relaxation sequence for linux arm64. The linker may
11757+
// replace these with other instructions that may trash x0.
11758+
// We thus need to eagerly update GC for x0, in case the
11759+
// linker's instructions trashes it earlier than we would
11760+
// emit a mutating instruction that trashes it.
11761+
emitGCregDeadUpd(REG_R0, dst);
11762+
}
1175211763
}
1175311764
else
1175411765
{

src/coreclr/jit/emitxarch.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18451,6 +18451,13 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
1845118451
{
1845218452
dst = emitOutputData16(dst);
1845318453
sz = emitSizeOfInsDsc_NONE(id);
18454+
18455+
// This may mark the beginning of a TLS access linker
18456+
// relaxation sequence. The linker can replace these general
18457+
// sequences by other instructions that trash rax. We need to
18458+
// eagerly invalidate GC info in rax before the linker's
18459+
// instructions would trash it.
18460+
emitGCregDeadUpd(REG_RAX, dst);
1845418461
break;
1845518462
}
1845618463

0 commit comments

Comments
 (0)