-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Fix up hijacking on x64 platforms in presence of runtime async #122631
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
base: main
Are you sure you want to change the base?
Conversation
|
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas |
| LEAF_ENTRY RhpGcStressHijack, _TEXT | ||
| FixupHijackedCallstack | ||
| or ecx, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX | ||
| mov r8d, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_RAX + PTFF_SAVE_RCX |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this to mov because the original or assumed FixupHijackedCallstack zeroed the register out which is subtle.
| xor ecx, ecx | ||
| mov [rdx + OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation], rcx | ||
| mov [rdx + OFFSETOF__Thread__m_pvHijackedReturnAddress], rcx | ||
| xor r8, r8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be r8d to match the ecx but I don't think there's advantage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for preserving the RCX register during GC hijacking on x64 platforms to handle async continuation return values. This is part of fixing runtime async support as mentioned in issue #122492.
Key Changes
- Adds PTFF_SAVE_RCX flag constant to indicate RCX should be preserved during hijacking
- Updates hijacking frame macros to save and restore RCX alongside RAX (and RDX on Unix)
- Changes register usage from RCX to R8 for passing the register bitmask to avoid conflicts with preserved RCX
- Adjusts stack calculations to account for the additional saved register
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc | Adds PTFF_SAVE_RCX constant definition for Unix x64 platforms |
| src/coreclr/nativeaot/Runtime/amd64/GcProbe.asm | Updates Windows x64 hijacking code to preserve RCX, changes bitmask register from RCX to R8, adjusts stack offsets |
| src/coreclr/nativeaot/Runtime/amd64/GcProbe.S | Updates Unix x64 hijacking code to preserve RCX, changes bitmask register from RCX to R8, adjusts stack offsets and alignment |
| src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc | Adds PTFF_SAVE_RCX constant definition for Windows x64 platforms |
| ;; | ||
| ;; Register state on entry: | ||
| ;; RDX: thread pointer | ||
| ;; RCX: register bitmask |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment stating "RCX: register bitmask" is outdated. The register bitmask is now passed in R8, not RCX, as seen in the code on line 150 where r8d is set to the flags and line 168 where r8 is passed to PUSH_PROBE_FRAME. This change was necessary to preserve RCX for async continuation return values. The comment should be updated to say "R8: register bitmask".
| ;; RCX: register bitmask | |
| ;; R8: register bitmask |
|
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Yes, I think so. What registers may need updating when GC happens is encoded by the JIT for every possible GC site. But in order to update, these registers must be saved/restored in a state that GC can modify. I did not look in details at the changes yet, but the LLM-like approach by analogy would totally make sense. On every platform we need to add one more register to the set that is stored/restored by the hijacking. The tracking and updating will happen by itself, but it needs a stored value to work with. |
Contributes to #122492.
(Please review as if LLM wrote this. LLM didn't write this, but there was a lot of pattern matching without understanding.)
Cc @dotnet/ilc-contrib