JIT: Eagerly invalidate GC state for registers trashed by linker relaxation sequences#128073
Merged
Conversation
…xation sequences 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 clobber `rax`. This is regardless of whether or not the value in `rax` is dying. 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.
Contributor
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adjusts CoreCLR JIT GC register-state reporting around NativeAOT TLS-access linker relaxation marker sequences so the emitted GC info doesn’t incorrectly report a GC ref still live in registers that the linker-relaxed sequence may clobber (linux-x64: rax, linux-arm64: x0).
Changes:
- x64: when emitting the
INS_data16marker byte used in the TLS relaxation pattern, eagerly markRAXas GC-dead at that point. - arm64: when emitting the TLSGD
adrprelocation form, eagerly markR0/x0as GC-dead at that point. - For symmetry/clarity, mirror these updates in CodeGen’s
gcInfostate (gcMarkRegSetNpt) for the relevant sequences.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/coreclr/jit/emitxarch.cpp | Eagerly clears GC liveness for RAX when emitting INS_data16 TLS marker bytes. |
| src/coreclr/jit/emitarm64.cpp | Eagerly clears GC liveness for x0 for TLSGD-related adrp emission. |
| src/coreclr/jit/codegenxarch.cpp | Mirrors the RAX GC-state clear in CodeGen for TLSGD reloc sequences. |
| src/coreclr/jit/codegenarmarch.cpp | Mirrors the x0 GC-state clear in CodeGen for the arm64 TLS relaxation sequence. |
jakobbotsch
commented
May 12, 2026
Member
Author
|
cc @dotnet/jit-contrib PTAL @kg |
kg
approved these changes
May 12, 2026
Member
Author
|
/ba-g Failure to obtain CI agent |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
raxcontains a GC reference, we delay any actual GC information update until we actually emit an instruction that clobbersrax. This is regardless of whether or not the value inraxdied 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.
Fix #128060
x64 diff for
DispatchContinuationsNativeAOT codegen: