Skip to content

JIT: Restore arm64, LA64 and RISCV64 OSR callee saves from tier0 frame#126880

Open
jakobbotsch wants to merge 31 commits intodotnet:mainfrom
jakobbotsch:osr-arm64-restore-from-tier0
Open

JIT: Restore arm64, LA64 and RISCV64 OSR callee saves from tier0 frame#126880
jakobbotsch wants to merge 31 commits intodotnet:mainfrom
jakobbotsch:osr-arm64-restore-from-tier0

Conversation

@jakobbotsch
Copy link
Copy Markdown
Member

@jakobbotsch jakobbotsch commented Apr 14, 2026

Change OSR functions for arm64, loongarch64 and riscv64 to start their prolog out by restoring the values of all callee saves that were saved by the tier0 function. This should make it possible to transition from tier0 to OSR without requiring any unwinding – instead it can be done with a simple jump. The end goal is to fix #120865 which is showing up in ASP.NET benchmarks.

Also support saving patchpoint info produced by an altjit in the VM.

Copilot AI review requested due to automatic review settings April 14, 2026 14:37
@github-actions github-actions bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 14, 2026
Copy link
Copy Markdown
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 updates CoreCLR JIT OSR support on ARM64 so OSR methods can correctly “inherit” callee-saved registers from the Tier0 frame and restore them on exit, instead of saving/restoring the already-mutated register state from Tier0.

Changes:

  • Record and consume Tier0 callee-save information for ARM64 OSR, and update ARM64 prolog/epilog code to avoid re-saving inherited callee-saves and to restore them from the Tier0 frame at return.
  • Extend patchpoint/callee-save bookkeeping (including SuperPMI replay handling for older collections).
  • Update genPushCalleeSavedRegisters signature across targets and wire OSR prolog handling for AMD64/ARM64.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/coreclr/vm/jitinterface.cpp Adds debug-only AltJit patchpoint info tracking so AltJit OSR compilations can retrieve the right patchpoint info.
src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp Adjusts replayed OSR patchpoint info on ARM64 to include FP/LR in older collections.
src/coreclr/jit/lclvars.cpp Ensures ARM64 Tier0 patchpoint methods save FP/LR with all callee-saves (needed for OSR interactions).
src/coreclr/jit/compiler.cpp Updates patchpoint info generation for callee-save recording (incl. ARM64 LR) and updates debug dumping.
src/coreclr/jit/codegenxarch.cpp Updates genPushCalleeSavedRegisters signature to match common prolog flow.
src/coreclr/jit/codegenwasm.cpp Updates genPushCalleeSavedRegisters signature (no-op target).
src/coreclr/jit/codegencommon.cpp Adds ARM64 OSR handling to the “inherit tier0” prolog path and avoids double-saving inherited callee-saves.
src/coreclr/jit/codegenarmarch.cpp ARM64 prolog logic now skips saving FP/LR (and other inherited callee-saves) when OSR inherits them from Tier0.
src/coreclr/jit/codegenarm64.cpp ARM64 epilog now restores inherited callee-saves from the Tier0 frame and then pops the Tier0 frame.
src/coreclr/jit/codegen.h Updates CodeGen APIs to support unwind-only prolog save helpers and unified genPushCalleeSavedRegisters signature.

Comment thread src/coreclr/jit/codegenarm64.cpp Outdated
Comment thread src/coreclr/jit/compiler.cpp Outdated
Comment thread src/coreclr/vm/jitinterface.cpp
Comment thread src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp Outdated
Copilot AI review requested due to automatic review settings April 14, 2026 16:53
Copy link
Copy Markdown
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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/jit/codegenarm64.cpp Outdated
Comment thread src/coreclr/jit/codegenarm64.cpp Outdated
Copilot AI review requested due to automatic review settings April 14, 2026 17:55
Copy link
Copy Markdown
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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/vm/jitinterface.cpp
@jakobbotsch
Copy link
Copy Markdown
Member Author

/azp run runtime-jit-experimental

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Copilot AI review requested due to automatic review settings April 15, 2026 11:13
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Copilot AI review requested due to automatic review settings April 16, 2026 15:26
Copy link
Copy Markdown
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

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/jit/codegenxarch.cpp
Comment thread src/coreclr/jit/codegenwasm.cpp
Copilot AI review requested due to automatic review settings April 17, 2026 08:08
Copy link
Copy Markdown
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

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Comment thread src/coreclr/jit/codegenarm64.cpp Outdated
Comment thread src/coreclr/jit/codegenwasm.cpp
Comment thread src/coreclr/jit/codegenarm.cpp
Copilot AI review requested due to automatic review settings April 17, 2026 08:21
Copy link
Copy Markdown
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

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/codegenxarch.cpp
@jakobbotsch
Copy link
Copy Markdown
Member Author

/azp run runtime-jit-experimental

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch jakobbotsch marked this pull request as ready for review April 17, 2026 18:01
Copilot AI review requested due to automatic review settings April 17, 2026 18:01
Comment thread src/coreclr/jit/codegenarm64.cpp
newInfo->Next = s_altJitPatchpointInfoList;
newInfo->Method = m_pMethodBeingCompiled;
newInfo->Info = newPpi;
s_altJitPatchpointInfoList = newInfo;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkotas do we have something similar to the method table auxiliary data for MethodDesc where I could store this in debug builds? Or perhaps I should just use a hash table with a mutex.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have MethodDescCodeData that should work for what you trying to do here.

Copy link
Copy Markdown
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

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Comment on lines +11458 to +11464
for (AltJitPatchpointInfo* altJitPpi = s_altJitPatchpointInfoList; altJitPpi != NULL; altJitPpi = altJitPpi->Next)
{
if (altJitPpi->Method == m_pMethodBeingCompiled)
{
result = altJitPpi->Info;
break;
}
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ALT_JIT debug-only cache grows monotonically and is never cleaned up. Beyond the memory leak, keeping MethodDesc* keys for collectible methods past unload can lead to false matches if addresses get reused, returning the wrong PatchpointInfo. Consider scoping the cache to a reclaimable lifetime (e.g., tied to a LoaderAllocator cleanup) or using a non-colliding key.

Suggested change
for (AltJitPatchpointInfo* altJitPpi = s_altJitPatchpointInfoList; altJitPpi != NULL; altJitPpi = altJitPpi->Next)
{
if (altJitPpi->Method == m_pMethodBeingCompiled)
{
result = altJitPpi->Info;
break;
}
AltJitPatchpointInfo* previousAltJitPpi = NULL;
for (AltJitPatchpointInfo* altJitPpi = s_altJitPatchpointInfoList; altJitPpi != NULL; altJitPpi = altJitPpi->Next)
{
if (altJitPpi->Method == m_pMethodBeingCompiled)
{
uint32_t ppiSize = altJitPpi->Info->PatchpointInfoSize();
PatchpointInfo* copiedPpi = new (new uint8_t[ppiSize]) PatchpointInfo;
copiedPpi->Initialize(altJitPpi->Info->NumberOfLocals(), altJitPpi->Info->TotalFrameSize());
copiedPpi->Copy(altJitPpi->Info);
if (previousAltJitPpi == NULL)
{
s_altJitPatchpointInfoList = altJitPpi->Next;
}
else
{
previousAltJitPpi->Next = altJitPpi->Next;
}
delete[] reinterpret_cast<uint8_t*>(altJitPpi->Info);
delete altJitPpi;
result = copiedPpi;
break;
}
previousAltJitPpi = altJitPpi;

Copilot uses AI. Check for mistakes.
@jakobbotsch
Copy link
Copy Markdown
Member Author

jakobbotsch commented Apr 17, 2026

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Left a few comments above that I should address, but I think this is ready for review.

Diffs. Larger OSR method prologs. It will be understated a little bit since the collections do not have any callee saves in the patchpoint information, but using callee saves in tier0 functions is rare, so probably it isn't understated by that much.

After some thinking I was able to remove the tier0 frame type regression – we now put FP/LR into the callee save registers in the patchpoint info only if it was saved with the rest of the callee saves, and then we use that in OSR to determine the kind of frame. In the end we don't need to care about all 5 types of frames, only where fp/lr ends up being saved which turns out not to be too bad.

@jakobbotsch jakobbotsch requested a review from AndyAyersMS April 17, 2026 18:18
Copy link
Copy Markdown
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we're done with this cycle of OSR changes we should reconcile the various bits of documentation like OSR Details and Debuggging: OSR Prolog and OSR x64 Epilog Redesign.

And make a pass through #33658

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optimize runtime async OSR resumption performance

4 participants