Skip to content

Conversation

@MichalStrehovsky
Copy link
Member

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

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

Copilot AI left a 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

@MichalStrehovsky
Copy link
Member Author

/azp run runtime-nativeaot-outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@VSadov
Copy link
Member

VSadov commented Dec 19, 2025

I was going through the JIT/VM runtime async PRs to see if anything was missed and noticed changes to hijacking. Do we need hijacking changes for native AOT?

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.
For asynchronous GC interrupts (i.e. signals) it is trivial since OS stores/restores the entire register set. We could, in theory do the same (capture the entire set) for hijacking, but the register sets have gotten fairly big recently and keep growing. So hijacking saves/restores just a subset that can possibly have live GC pointers. That is nonvolatile registers that survive the call + anything that a call can produce & can contain a pointer. Async adds the continuation register to the "call can produce and contain a pointer" set.

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.

@VSadov
Copy link
Member

VSadov commented Dec 20, 2025

LGTM. Are you going to do the same for other platforms too?

@am11
Copy link
Member

am11 commented Dec 20, 2025

Are you going to do the same for other platforms too?

Others are blocked on #121871. Would be nice to prioritize that so we can start testing async everywhere earlier in .NET 11 development cycle.

Co-authored-by: Vladimir Sadov <[email protected]>
Co-authored-by: Copilot <[email protected]>
@MichalStrehovsky
Copy link
Member Author

LGTM. Are you going to do the same for other platforms too?

Andy was suggesting I don't do all the runtime async work, so not going to work on this for now. I needed x64 in #122526 because all the crashing was causing too much noise and I didn't know if we have any other bugs.

Others are blocked on #121871. Would be nice to prioritize that so we can start testing async everywhere earlier in .NET 11 development cycle.

Reporting the register doesn't need to wait for that one. We report the extra register no matter if the called method is async or not (or has a return value at all). The other platforms will probably look the same - report extra register no matter what. If the assembly is not right, it's going to crash without runtime async too.

@am11
Copy link
Member

am11 commented Dec 22, 2025

Reporting the register doesn't need to wait for that one.

Yup, no problem implementing them in code but I meant testing won't be possible as non-x64 64-bit platforms seem to be having problem during native link step (with runtime-async:on).

@MichalStrehovsky MichalStrehovsky merged commit c591f97 into dotnet:main Dec 22, 2025
98 checks passed
@MichalStrehovsky MichalStrehovsky deleted the hijackx64 branch December 22, 2025 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants