Fix async continuation hijacking for x86 NativeAOT - #128706

Merged
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624
Jun 3, 2026
Merged

Fix async continuation hijacking for x86 NativeAOT#128706
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented May 28, 2026

Copy link
Copy Markdown
Member

NativeAOT hijacking did not properly report the async continuation when hijacking an async function. While we did save and restore the register (implemented in #123084), the part that actually determined whether the register contained a GC ref was missing.

The GC reporting for return values is handled differently on x86 compared to other platforms. On other platforms the JIT reports GC information on the caller's return address instruction which means that the continuation gets reported naturally. This is not the case for x86 where this must be handled specially.

Fix#128624
Fix#127900

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 x86 GC/hijack metadata so async continuations can be reported as GC roots when NativeAOT hijacks async methods.

Changes:

  • Adds an async bit to x86 GC info encoding/decoding.
  • Plumbs async-return metadata through CoreCLR and NativeAOT hijack helpers.
  • Reports the hijacked async continuation from the saved ECX location on x86.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/threadsuspend.cppUses code-manager-provided async hijack info.
src/coreclr/vm/gc_unwind_x86.inlCopies decoded async flag into x86 unwind header info.
src/coreclr/vm/eetwain.cppReturns async metadata from decoded GC info.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.hExtends x86 return-value metadata API.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cppDecodes async flag with return kind.
src/coreclr/nativeaot/Runtime/thread.cppReports hijacked async continuation during root scanning.
src/coreclr/nativeaot/Runtime/StackFrameIterator.hTracks hijacked async continuation location.
src/coreclr/nativeaot/Runtime/StackFrameIterator.cppRestores async continuation location from transition frame flags.
src/coreclr/nativeaot/Runtime/inc/rhbinder.hAdds x86 ECX-is-GC-ref transition-frame flag.
src/coreclr/nativeaot/Runtime/ICodeManager.hEncodes/decodes async flag alongside return kind.
src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.hUpdates x86 structure offsets after iterator layout change.
src/coreclr/jit/gcencode.cppEmits async metadata in x86 GC info.
src/coreclr/inc/gcinfotypes.hExpands x86 GC header metadata for async state.
src/coreclr/inc/gcdecoder.cppDecodes async metadata from x86 GC info.
src/coreclr/inc/gc_unwind_x86.hAdds async flag to decoded x86 header info.
src/coreclr/inc/eetwain.hExtends CoreCLR hijack-info API signature.

Comment threadsrc/coreclr/inc/gcinfotypes.h
Comment threadsrc/coreclr/inc/gcinfotypes.h Outdated
@jkotas

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

@VSadov

VSadov commented May 28, 2026

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

I think the reasons for not switching x86 to the same GC encoding plan as in x64/arm64 were:

  • the original x86 format is very tightly specialized and likely to be more compact and faster to decode.
    Although I do not think it is a big deal right now as anyone still using x86 is not doing that for perf or for the size of binaries.
    (my guess - they target constrained environments and want smaller footprint at run time)
  • there is a chance that some quirks of x86 are not expressible in x64 format.
  • it may be too big investment for x86, so we kind of preferred to keep incrementally patching/fixing old format if possible.

CopilotAI review requested due to automatic review settings May 28, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/inc/gcdecoder.cpp:215

  • decodeHeader now treats second-opcode values 0x04-0x07 as returnKind/isAsync regardless of the version parameter. For GCInfo v3 ReadyToRun images those same opcodes are the existing SET_NOGCREGIONS_CNT encodings, so old x86 GC info will be decoded with the wrong header state. Please branch on the GC info version here (and keep the old opcode layout for v3) before interpreting bit 2 as the async flag.
 if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding & 3;
header->isAsync = (encoding & 4) != 0;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;

CopilotAI review requested due to automatic review settings May 29, 2026 08:54
Comment threadsrc/coreclr/inc/readytorun.h

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 24 out of 24 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/inc/readytorun.h
CopilotAI review requested due to automatic review settings June 2, 2026 10:40
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/GcInfo.cs Outdated
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No NativeAOT outerloop x86 failures.

@jakobbotsch
jakobbotsch marked this pull request as ready for review June 2, 2026 15:13
@jakobbotsch
jakobbotsch requested review from Copilot and jkotasJune 2, 2026 15:13
@jakobbotsch
jakobbotsch requested a review from VSadovJune 2, 2026 15:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/thread.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ICodeManager.h
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
CopilotAI review requested due to automatic review settings June 2, 2026 16:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated no new comments.

@jakobbotsch
jakobbotsch merged commit 483b9ea into dotnet:mainJun 3, 2026
145 of 149 checks passed
@jakobbotsch
jakobbotsch deleted the fix-128624 branch June 3, 2026 09:41
hoyosjs pushed a commit to dotnet/diagnostics that referenced this pull request Jun 9, 2026
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 17, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
NativeAOT hijacking did not properly report the async continuation when
hijacking an async function. While we did save and restore the register
(implemented in #123084), the part that actually determined whether the
register contained a GC ref was missing.
The GC reporting for return values is handled differently on x86
compared to other platforms. On other platforms the JIT reports GC
information on the caller's return address instruction which means that
the continuation gets reported naturally. This is not the case for x86
where this must be handled specially.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

4 participants

@jakobbotsch@jkotas@VSadov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Fix async continuation hijacking for x86 NativeAOT - #128706

Merged
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624
Jun 3, 2026
Merged

Fix async continuation hijacking for x86 NativeAOT#128706
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented May 28, 2026

Copy link
Copy Markdown
Member

NativeAOT hijacking did not properly report the async continuation when hijacking an async function. While we did save and restore the register (implemented in #123084), the part that actually determined whether the register contained a GC ref was missing.

The GC reporting for return values is handled differently on x86 compared to other platforms. On other platforms the JIT reports GC information on the caller's return address instruction which means that the continuation gets reported naturally. This is not the case for x86 where this must be handled specially.

Fix#128624
Fix#127900

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 x86 GC/hijack metadata so async continuations can be reported as GC roots when NativeAOT hijacks async methods.

Changes:

  • Adds an async bit to x86 GC info encoding/decoding.
  • Plumbs async-return metadata through CoreCLR and NativeAOT hijack helpers.
  • Reports the hijacked async continuation from the saved ECX location on x86.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/threadsuspend.cppUses code-manager-provided async hijack info.
src/coreclr/vm/gc_unwind_x86.inlCopies decoded async flag into x86 unwind header info.
src/coreclr/vm/eetwain.cppReturns async metadata from decoded GC info.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.hExtends x86 return-value metadata API.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cppDecodes async flag with return kind.
src/coreclr/nativeaot/Runtime/thread.cppReports hijacked async continuation during root scanning.
src/coreclr/nativeaot/Runtime/StackFrameIterator.hTracks hijacked async continuation location.
src/coreclr/nativeaot/Runtime/StackFrameIterator.cppRestores async continuation location from transition frame flags.
src/coreclr/nativeaot/Runtime/inc/rhbinder.hAdds x86 ECX-is-GC-ref transition-frame flag.
src/coreclr/nativeaot/Runtime/ICodeManager.hEncodes/decodes async flag alongside return kind.
src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.hUpdates x86 structure offsets after iterator layout change.
src/coreclr/jit/gcencode.cppEmits async metadata in x86 GC info.
src/coreclr/inc/gcinfotypes.hExpands x86 GC header metadata for async state.
src/coreclr/inc/gcdecoder.cppDecodes async metadata from x86 GC info.
src/coreclr/inc/gc_unwind_x86.hAdds async flag to decoded x86 header info.
src/coreclr/inc/eetwain.hExtends CoreCLR hijack-info API signature.

Comment threadsrc/coreclr/inc/gcinfotypes.h
Comment threadsrc/coreclr/inc/gcinfotypes.h Outdated
@jkotas

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

@VSadov

VSadov commented May 28, 2026

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

I think the reasons for not switching x86 to the same GC encoding plan as in x64/arm64 were:

  • the original x86 format is very tightly specialized and likely to be more compact and faster to decode.
    Although I do not think it is a big deal right now as anyone still using x86 is not doing that for perf or for the size of binaries.
    (my guess - they target constrained environments and want smaller footprint at run time)
  • there is a chance that some quirks of x86 are not expressible in x64 format.
  • it may be too big investment for x86, so we kind of preferred to keep incrementally patching/fixing old format if possible.

CopilotAI review requested due to automatic review settings May 28, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/inc/gcdecoder.cpp:215

  • decodeHeader now treats second-opcode values 0x04-0x07 as returnKind/isAsync regardless of the version parameter. For GCInfo v3 ReadyToRun images those same opcodes are the existing SET_NOGCREGIONS_CNT encodings, so old x86 GC info will be decoded with the wrong header state. Please branch on the GC info version here (and keep the old opcode layout for v3) before interpreting bit 2 as the async flag.
 if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding & 3;
header->isAsync = (encoding & 4) != 0;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;

CopilotAI review requested due to automatic review settings May 29, 2026 08:54
Comment threadsrc/coreclr/inc/readytorun.h

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 24 out of 24 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/inc/readytorun.h
CopilotAI review requested due to automatic review settings June 2, 2026 10:40
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/GcInfo.cs Outdated
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No NativeAOT outerloop x86 failures.

@jakobbotsch
jakobbotsch marked this pull request as ready for review June 2, 2026 15:13
@jakobbotsch
jakobbotsch requested review from Copilot and jkotasJune 2, 2026 15:13
@jakobbotsch
jakobbotsch requested a review from VSadovJune 2, 2026 15:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/thread.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ICodeManager.h
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
CopilotAI review requested due to automatic review settings June 2, 2026 16:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated no new comments.

@jakobbotsch
jakobbotsch merged commit 483b9ea into dotnet:mainJun 3, 2026
145 of 149 checks passed
@jakobbotsch
jakobbotsch deleted the fix-128624 branch June 3, 2026 09:41
hoyosjs pushed a commit to dotnet/diagnostics that referenced this pull request Jun 9, 2026
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 17, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
NativeAOT hijacking did not properly report the async continuation when
hijacking an async function. While we did save and restore the register
(implemented in #123084), the part that actually determined whether the
register contained a GC ref was missing.
The GC reporting for return values is handled differently on x86
compared to other platforms. On other platforms the JIT reports GC
information on the caller's return address instruction which means that
the continuation gets reported naturally. This is not the case for x86
where this must be handled specially.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

4 participants

@jakobbotsch@jkotas@VSadov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix async continuation hijacking for x86 NativeAOT - #128706

Merged
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624
Jun 3, 2026
Merged

Fix async continuation hijacking for x86 NativeAOT#128706
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented May 28, 2026

Copy link
Copy Markdown
Member

NativeAOT hijacking did not properly report the async continuation when hijacking an async function. While we did save and restore the register (implemented in #123084), the part that actually determined whether the register contained a GC ref was missing.

The GC reporting for return values is handled differently on x86 compared to other platforms. On other platforms the JIT reports GC information on the caller's return address instruction which means that the continuation gets reported naturally. This is not the case for x86 where this must be handled specially.

Fix#128624
Fix#127900

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 x86 GC/hijack metadata so async continuations can be reported as GC roots when NativeAOT hijacks async methods.

Changes:

  • Adds an async bit to x86 GC info encoding/decoding.
  • Plumbs async-return metadata through CoreCLR and NativeAOT hijack helpers.
  • Reports the hijacked async continuation from the saved ECX location on x86.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/threadsuspend.cppUses code-manager-provided async hijack info.
src/coreclr/vm/gc_unwind_x86.inlCopies decoded async flag into x86 unwind header info.
src/coreclr/vm/eetwain.cppReturns async metadata from decoded GC info.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.hExtends x86 return-value metadata API.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cppDecodes async flag with return kind.
src/coreclr/nativeaot/Runtime/thread.cppReports hijacked async continuation during root scanning.
src/coreclr/nativeaot/Runtime/StackFrameIterator.hTracks hijacked async continuation location.
src/coreclr/nativeaot/Runtime/StackFrameIterator.cppRestores async continuation location from transition frame flags.
src/coreclr/nativeaot/Runtime/inc/rhbinder.hAdds x86 ECX-is-GC-ref transition-frame flag.
src/coreclr/nativeaot/Runtime/ICodeManager.hEncodes/decodes async flag alongside return kind.
src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.hUpdates x86 structure offsets after iterator layout change.
src/coreclr/jit/gcencode.cppEmits async metadata in x86 GC info.
src/coreclr/inc/gcinfotypes.hExpands x86 GC header metadata for async state.
src/coreclr/inc/gcdecoder.cppDecodes async metadata from x86 GC info.
src/coreclr/inc/gc_unwind_x86.hAdds async flag to decoded x86 header info.
src/coreclr/inc/eetwain.hExtends CoreCLR hijack-info API signature.

Comment threadsrc/coreclr/inc/gcinfotypes.h
Comment threadsrc/coreclr/inc/gcinfotypes.h Outdated
@jkotas

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

@VSadov

VSadov commented May 28, 2026

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

I think the reasons for not switching x86 to the same GC encoding plan as in x64/arm64 were:

  • the original x86 format is very tightly specialized and likely to be more compact and faster to decode.
    Although I do not think it is a big deal right now as anyone still using x86 is not doing that for perf or for the size of binaries.
    (my guess - they target constrained environments and want smaller footprint at run time)
  • there is a chance that some quirks of x86 are not expressible in x64 format.
  • it may be too big investment for x86, so we kind of preferred to keep incrementally patching/fixing old format if possible.

CopilotAI review requested due to automatic review settings May 28, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/inc/gcdecoder.cpp:215

  • decodeHeader now treats second-opcode values 0x04-0x07 as returnKind/isAsync regardless of the version parameter. For GCInfo v3 ReadyToRun images those same opcodes are the existing SET_NOGCREGIONS_CNT encodings, so old x86 GC info will be decoded with the wrong header state. Please branch on the GC info version here (and keep the old opcode layout for v3) before interpreting bit 2 as the async flag.
 if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding & 3;
header->isAsync = (encoding & 4) != 0;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;

CopilotAI review requested due to automatic review settings May 29, 2026 08:54
Comment threadsrc/coreclr/inc/readytorun.h

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 24 out of 24 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/inc/readytorun.h
CopilotAI review requested due to automatic review settings June 2, 2026 10:40
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/GcInfo.cs Outdated
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No NativeAOT outerloop x86 failures.

@jakobbotsch
jakobbotsch marked this pull request as ready for review June 2, 2026 15:13
@jakobbotsch
jakobbotsch requested review from Copilot and jkotasJune 2, 2026 15:13
@jakobbotsch
jakobbotsch requested a review from VSadovJune 2, 2026 15:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/thread.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ICodeManager.h
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
CopilotAI review requested due to automatic review settings June 2, 2026 16:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated no new comments.

@jakobbotsch
jakobbotsch merged commit 483b9ea into dotnet:mainJun 3, 2026
145 of 149 checks passed
@jakobbotsch
jakobbotsch deleted the fix-128624 branch June 3, 2026 09:41
hoyosjs pushed a commit to dotnet/diagnostics that referenced this pull request Jun 9, 2026
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 17, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
NativeAOT hijacking did not properly report the async continuation when
hijacking an async function. While we did save and restore the register
(implemented in #123084), the part that actually determined whether the
register contained a GC ref was missing.
The GC reporting for return values is handled differently on x86
compared to other platforms. On other platforms the JIT reports GC
information on the caller's return address instruction which means that
the continuation gets reported naturally. This is not the case for x86
where this must be handled specially.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

4 participants

@jakobbotsch@jkotas@VSadov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix async continuation hijacking for x86 NativeAOT - #128706

Merged
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624
Jun 3, 2026
Merged

Fix async continuation hijacking for x86 NativeAOT#128706
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented May 28, 2026

Copy link
Copy Markdown
Member

NativeAOT hijacking did not properly report the async continuation when hijacking an async function. While we did save and restore the register (implemented in #123084), the part that actually determined whether the register contained a GC ref was missing.

The GC reporting for return values is handled differently on x86 compared to other platforms. On other platforms the JIT reports GC information on the caller's return address instruction which means that the continuation gets reported naturally. This is not the case for x86 where this must be handled specially.

Fix#128624
Fix#127900

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 x86 GC/hijack metadata so async continuations can be reported as GC roots when NativeAOT hijacks async methods.

Changes:

  • Adds an async bit to x86 GC info encoding/decoding.
  • Plumbs async-return metadata through CoreCLR and NativeAOT hijack helpers.
  • Reports the hijacked async continuation from the saved ECX location on x86.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/threadsuspend.cppUses code-manager-provided async hijack info.
src/coreclr/vm/gc_unwind_x86.inlCopies decoded async flag into x86 unwind header info.
src/coreclr/vm/eetwain.cppReturns async metadata from decoded GC info.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.hExtends x86 return-value metadata API.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cppDecodes async flag with return kind.
src/coreclr/nativeaot/Runtime/thread.cppReports hijacked async continuation during root scanning.
src/coreclr/nativeaot/Runtime/StackFrameIterator.hTracks hijacked async continuation location.
src/coreclr/nativeaot/Runtime/StackFrameIterator.cppRestores async continuation location from transition frame flags.
src/coreclr/nativeaot/Runtime/inc/rhbinder.hAdds x86 ECX-is-GC-ref transition-frame flag.
src/coreclr/nativeaot/Runtime/ICodeManager.hEncodes/decodes async flag alongside return kind.
src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.hUpdates x86 structure offsets after iterator layout change.
src/coreclr/jit/gcencode.cppEmits async metadata in x86 GC info.
src/coreclr/inc/gcinfotypes.hExpands x86 GC header metadata for async state.
src/coreclr/inc/gcdecoder.cppDecodes async metadata from x86 GC info.
src/coreclr/inc/gc_unwind_x86.hAdds async flag to decoded x86 header info.
src/coreclr/inc/eetwain.hExtends CoreCLR hijack-info API signature.

Comment threadsrc/coreclr/inc/gcinfotypes.h
Comment threadsrc/coreclr/inc/gcinfotypes.h Outdated
@jkotas

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

@VSadov

VSadov commented May 28, 2026

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

I think the reasons for not switching x86 to the same GC encoding plan as in x64/arm64 were:

  • the original x86 format is very tightly specialized and likely to be more compact and faster to decode.
    Although I do not think it is a big deal right now as anyone still using x86 is not doing that for perf or for the size of binaries.
    (my guess - they target constrained environments and want smaller footprint at run time)
  • there is a chance that some quirks of x86 are not expressible in x64 format.
  • it may be too big investment for x86, so we kind of preferred to keep incrementally patching/fixing old format if possible.

CopilotAI review requested due to automatic review settings May 28, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/inc/gcdecoder.cpp:215

  • decodeHeader now treats second-opcode values 0x04-0x07 as returnKind/isAsync regardless of the version parameter. For GCInfo v3 ReadyToRun images those same opcodes are the existing SET_NOGCREGIONS_CNT encodings, so old x86 GC info will be decoded with the wrong header state. Please branch on the GC info version here (and keep the old opcode layout for v3) before interpreting bit 2 as the async flag.
 if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding & 3;
header->isAsync = (encoding & 4) != 0;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;

CopilotAI review requested due to automatic review settings May 29, 2026 08:54
Comment threadsrc/coreclr/inc/readytorun.h

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 24 out of 24 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/inc/readytorun.h
CopilotAI review requested due to automatic review settings June 2, 2026 10:40
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/GcInfo.cs Outdated
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No NativeAOT outerloop x86 failures.

@jakobbotsch
jakobbotsch marked this pull request as ready for review June 2, 2026 15:13
@jakobbotsch
jakobbotsch requested review from Copilot and jkotasJune 2, 2026 15:13
@jakobbotsch
jakobbotsch requested a review from VSadovJune 2, 2026 15:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/thread.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ICodeManager.h
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
CopilotAI review requested due to automatic review settings June 2, 2026 16:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated no new comments.

@jakobbotsch
jakobbotsch merged commit 483b9ea into dotnet:mainJun 3, 2026
145 of 149 checks passed
@jakobbotsch
jakobbotsch deleted the fix-128624 branch June 3, 2026 09:41
hoyosjs pushed a commit to dotnet/diagnostics that referenced this pull request Jun 9, 2026
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 17, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
NativeAOT hijacking did not properly report the async continuation when
hijacking an async function. While we did save and restore the register
(implemented in #123084), the part that actually determined whether the
register contained a GC ref was missing.
The GC reporting for return values is handled differently on x86
compared to other platforms. On other platforms the JIT reports GC
information on the caller's return address instruction which means that
the continuation gets reported naturally. This is not the case for x86
where this must be handled specially.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

4 participants

@jakobbotsch@jkotas@VSadov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Fix async continuation hijacking for x86 NativeAOT - #128706

Merged
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624
Jun 3, 2026
Merged

Fix async continuation hijacking for x86 NativeAOT#128706
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented May 28, 2026

Copy link
Copy Markdown
Member

NativeAOT hijacking did not properly report the async continuation when hijacking an async function. While we did save and restore the register (implemented in #123084), the part that actually determined whether the register contained a GC ref was missing.

The GC reporting for return values is handled differently on x86 compared to other platforms. On other platforms the JIT reports GC information on the caller's return address instruction which means that the continuation gets reported naturally. This is not the case for x86 where this must be handled specially.

Fix#128624
Fix#127900

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 x86 GC/hijack metadata so async continuations can be reported as GC roots when NativeAOT hijacks async methods.

Changes:

  • Adds an async bit to x86 GC info encoding/decoding.
  • Plumbs async-return metadata through CoreCLR and NativeAOT hijack helpers.
  • Reports the hijacked async continuation from the saved ECX location on x86.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/threadsuspend.cppUses code-manager-provided async hijack info.
src/coreclr/vm/gc_unwind_x86.inlCopies decoded async flag into x86 unwind header info.
src/coreclr/vm/eetwain.cppReturns async metadata from decoded GC info.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.hExtends x86 return-value metadata API.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cppDecodes async flag with return kind.
src/coreclr/nativeaot/Runtime/thread.cppReports hijacked async continuation during root scanning.
src/coreclr/nativeaot/Runtime/StackFrameIterator.hTracks hijacked async continuation location.
src/coreclr/nativeaot/Runtime/StackFrameIterator.cppRestores async continuation location from transition frame flags.
src/coreclr/nativeaot/Runtime/inc/rhbinder.hAdds x86 ECX-is-GC-ref transition-frame flag.
src/coreclr/nativeaot/Runtime/ICodeManager.hEncodes/decodes async flag alongside return kind.
src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.hUpdates x86 structure offsets after iterator layout change.
src/coreclr/jit/gcencode.cppEmits async metadata in x86 GC info.
src/coreclr/inc/gcinfotypes.hExpands x86 GC header metadata for async state.
src/coreclr/inc/gcdecoder.cppDecodes async metadata from x86 GC info.
src/coreclr/inc/gc_unwind_x86.hAdds async flag to decoded x86 header info.
src/coreclr/inc/eetwain.hExtends CoreCLR hijack-info API signature.

Comment threadsrc/coreclr/inc/gcinfotypes.h
Comment threadsrc/coreclr/inc/gcinfotypes.h Outdated
@jkotas

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

@VSadov

VSadov commented May 28, 2026

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

I think the reasons for not switching x86 to the same GC encoding plan as in x64/arm64 were:

  • the original x86 format is very tightly specialized and likely to be more compact and faster to decode.
    Although I do not think it is a big deal right now as anyone still using x86 is not doing that for perf or for the size of binaries.
    (my guess - they target constrained environments and want smaller footprint at run time)
  • there is a chance that some quirks of x86 are not expressible in x64 format.
  • it may be too big investment for x86, so we kind of preferred to keep incrementally patching/fixing old format if possible.

CopilotAI review requested due to automatic review settings May 28, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/inc/gcdecoder.cpp:215

  • decodeHeader now treats second-opcode values 0x04-0x07 as returnKind/isAsync regardless of the version parameter. For GCInfo v3 ReadyToRun images those same opcodes are the existing SET_NOGCREGIONS_CNT encodings, so old x86 GC info will be decoded with the wrong header state. Please branch on the GC info version here (and keep the old opcode layout for v3) before interpreting bit 2 as the async flag.
 if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding & 3;
header->isAsync = (encoding & 4) != 0;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;

CopilotAI review requested due to automatic review settings May 29, 2026 08:54
Comment threadsrc/coreclr/inc/readytorun.h

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 24 out of 24 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/inc/readytorun.h
CopilotAI review requested due to automatic review settings June 2, 2026 10:40
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/GcInfo.cs Outdated
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No NativeAOT outerloop x86 failures.

@jakobbotsch
jakobbotsch marked this pull request as ready for review June 2, 2026 15:13
@jakobbotsch
jakobbotsch requested review from Copilot and jkotasJune 2, 2026 15:13
@jakobbotsch
jakobbotsch requested a review from VSadovJune 2, 2026 15:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/thread.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ICodeManager.h
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
CopilotAI review requested due to automatic review settings June 2, 2026 16:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated no new comments.

@jakobbotsch
jakobbotsch merged commit 483b9ea into dotnet:mainJun 3, 2026
145 of 149 checks passed
@jakobbotsch
jakobbotsch deleted the fix-128624 branch June 3, 2026 09:41
hoyosjs pushed a commit to dotnet/diagnostics that referenced this pull request Jun 9, 2026
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 17, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
NativeAOT hijacking did not properly report the async continuation when
hijacking an async function. While we did save and restore the register
(implemented in #123084), the part that actually determined whether the
register contained a GC ref was missing.
The GC reporting for return values is handled differently on x86
compared to other platforms. On other platforms the JIT reports GC
information on the caller's return address instruction which means that
the continuation gets reported naturally. This is not the case for x86
where this must be handled specially.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

4 participants

@jakobbotsch@jkotas@VSadov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix async continuation hijacking for x86 NativeAOT - #128706

Merged
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624
Jun 3, 2026
Merged

Fix async continuation hijacking for x86 NativeAOT#128706
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented May 28, 2026

Copy link
Copy Markdown
Member

NativeAOT hijacking did not properly report the async continuation when hijacking an async function. While we did save and restore the register (implemented in #123084), the part that actually determined whether the register contained a GC ref was missing.

The GC reporting for return values is handled differently on x86 compared to other platforms. On other platforms the JIT reports GC information on the caller's return address instruction which means that the continuation gets reported naturally. This is not the case for x86 where this must be handled specially.

Fix#128624
Fix#127900

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 x86 GC/hijack metadata so async continuations can be reported as GC roots when NativeAOT hijacks async methods.

Changes:

  • Adds an async bit to x86 GC info encoding/decoding.
  • Plumbs async-return metadata through CoreCLR and NativeAOT hijack helpers.
  • Reports the hijacked async continuation from the saved ECX location on x86.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/threadsuspend.cppUses code-manager-provided async hijack info.
src/coreclr/vm/gc_unwind_x86.inlCopies decoded async flag into x86 unwind header info.
src/coreclr/vm/eetwain.cppReturns async metadata from decoded GC info.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.hExtends x86 return-value metadata API.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cppDecodes async flag with return kind.
src/coreclr/nativeaot/Runtime/thread.cppReports hijacked async continuation during root scanning.
src/coreclr/nativeaot/Runtime/StackFrameIterator.hTracks hijacked async continuation location.
src/coreclr/nativeaot/Runtime/StackFrameIterator.cppRestores async continuation location from transition frame flags.
src/coreclr/nativeaot/Runtime/inc/rhbinder.hAdds x86 ECX-is-GC-ref transition-frame flag.
src/coreclr/nativeaot/Runtime/ICodeManager.hEncodes/decodes async flag alongside return kind.
src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.hUpdates x86 structure offsets after iterator layout change.
src/coreclr/jit/gcencode.cppEmits async metadata in x86 GC info.
src/coreclr/inc/gcinfotypes.hExpands x86 GC header metadata for async state.
src/coreclr/inc/gcdecoder.cppDecodes async metadata from x86 GC info.
src/coreclr/inc/gc_unwind_x86.hAdds async flag to decoded x86 header info.
src/coreclr/inc/eetwain.hExtends CoreCLR hijack-info API signature.

Comment threadsrc/coreclr/inc/gcinfotypes.h
Comment threadsrc/coreclr/inc/gcinfotypes.h Outdated
@jkotas

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

@VSadov

VSadov commented May 28, 2026

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

I think the reasons for not switching x86 to the same GC encoding plan as in x64/arm64 were:

  • the original x86 format is very tightly specialized and likely to be more compact and faster to decode.
    Although I do not think it is a big deal right now as anyone still using x86 is not doing that for perf or for the size of binaries.
    (my guess - they target constrained environments and want smaller footprint at run time)
  • there is a chance that some quirks of x86 are not expressible in x64 format.
  • it may be too big investment for x86, so we kind of preferred to keep incrementally patching/fixing old format if possible.

CopilotAI review requested due to automatic review settings May 28, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/inc/gcdecoder.cpp:215

  • decodeHeader now treats second-opcode values 0x04-0x07 as returnKind/isAsync regardless of the version parameter. For GCInfo v3 ReadyToRun images those same opcodes are the existing SET_NOGCREGIONS_CNT encodings, so old x86 GC info will be decoded with the wrong header state. Please branch on the GC info version here (and keep the old opcode layout for v3) before interpreting bit 2 as the async flag.
 if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding & 3;
header->isAsync = (encoding & 4) != 0;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;

CopilotAI review requested due to automatic review settings May 29, 2026 08:54
Comment threadsrc/coreclr/inc/readytorun.h

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 24 out of 24 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/inc/readytorun.h
CopilotAI review requested due to automatic review settings June 2, 2026 10:40
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/GcInfo.cs Outdated
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No NativeAOT outerloop x86 failures.

@jakobbotsch
jakobbotsch marked this pull request as ready for review June 2, 2026 15:13
@jakobbotsch
jakobbotsch requested review from Copilot and jkotasJune 2, 2026 15:13
@jakobbotsch
jakobbotsch requested a review from VSadovJune 2, 2026 15:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/thread.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ICodeManager.h
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
CopilotAI review requested due to automatic review settings June 2, 2026 16:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated no new comments.

@jakobbotsch
jakobbotsch merged commit 483b9ea into dotnet:mainJun 3, 2026
145 of 149 checks passed
@jakobbotsch
jakobbotsch deleted the fix-128624 branch June 3, 2026 09:41
hoyosjs pushed a commit to dotnet/diagnostics that referenced this pull request Jun 9, 2026
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 17, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
NativeAOT hijacking did not properly report the async continuation when
hijacking an async function. While we did save and restore the register
(implemented in #123084), the part that actually determined whether the
register contained a GC ref was missing.
The GC reporting for return values is handled differently on x86
compared to other platforms. On other platforms the JIT reports GC
information on the caller's return address instruction which means that
the continuation gets reported naturally. This is not the case for x86
where this must be handled specially.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

4 participants

@jakobbotsch@jkotas@VSadov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix async continuation hijacking for x86 NativeAOT - #128706

Merged
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624
Jun 3, 2026
Merged

Fix async continuation hijacking for x86 NativeAOT#128706
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented May 28, 2026

Copy link
Copy Markdown
Member

NativeAOT hijacking did not properly report the async continuation when hijacking an async function. While we did save and restore the register (implemented in #123084), the part that actually determined whether the register contained a GC ref was missing.

The GC reporting for return values is handled differently on x86 compared to other platforms. On other platforms the JIT reports GC information on the caller's return address instruction which means that the continuation gets reported naturally. This is not the case for x86 where this must be handled specially.

Fix#128624
Fix#127900

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 x86 GC/hijack metadata so async continuations can be reported as GC roots when NativeAOT hijacks async methods.

Changes:

  • Adds an async bit to x86 GC info encoding/decoding.
  • Plumbs async-return metadata through CoreCLR and NativeAOT hijack helpers.
  • Reports the hijacked async continuation from the saved ECX location on x86.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/threadsuspend.cppUses code-manager-provided async hijack info.
src/coreclr/vm/gc_unwind_x86.inlCopies decoded async flag into x86 unwind header info.
src/coreclr/vm/eetwain.cppReturns async metadata from decoded GC info.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.hExtends x86 return-value metadata API.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cppDecodes async flag with return kind.
src/coreclr/nativeaot/Runtime/thread.cppReports hijacked async continuation during root scanning.
src/coreclr/nativeaot/Runtime/StackFrameIterator.hTracks hijacked async continuation location.
src/coreclr/nativeaot/Runtime/StackFrameIterator.cppRestores async continuation location from transition frame flags.
src/coreclr/nativeaot/Runtime/inc/rhbinder.hAdds x86 ECX-is-GC-ref transition-frame flag.
src/coreclr/nativeaot/Runtime/ICodeManager.hEncodes/decodes async flag alongside return kind.
src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.hUpdates x86 structure offsets after iterator layout change.
src/coreclr/jit/gcencode.cppEmits async metadata in x86 GC info.
src/coreclr/inc/gcinfotypes.hExpands x86 GC header metadata for async state.
src/coreclr/inc/gcdecoder.cppDecodes async metadata from x86 GC info.
src/coreclr/inc/gc_unwind_x86.hAdds async flag to decoded x86 header info.
src/coreclr/inc/eetwain.hExtends CoreCLR hijack-info API signature.

Comment threadsrc/coreclr/inc/gcinfotypes.h
Comment threadsrc/coreclr/inc/gcinfotypes.h Outdated
@jkotas

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

@VSadov

VSadov commented May 28, 2026

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

I think the reasons for not switching x86 to the same GC encoding plan as in x64/arm64 were:

  • the original x86 format is very tightly specialized and likely to be more compact and faster to decode.
    Although I do not think it is a big deal right now as anyone still using x86 is not doing that for perf or for the size of binaries.
    (my guess - they target constrained environments and want smaller footprint at run time)
  • there is a chance that some quirks of x86 are not expressible in x64 format.
  • it may be too big investment for x86, so we kind of preferred to keep incrementally patching/fixing old format if possible.

CopilotAI review requested due to automatic review settings May 28, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/inc/gcdecoder.cpp:215

  • decodeHeader now treats second-opcode values 0x04-0x07 as returnKind/isAsync regardless of the version parameter. For GCInfo v3 ReadyToRun images those same opcodes are the existing SET_NOGCREGIONS_CNT encodings, so old x86 GC info will be decoded with the wrong header state. Please branch on the GC info version here (and keep the old opcode layout for v3) before interpreting bit 2 as the async flag.
 if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding & 3;
header->isAsync = (encoding & 4) != 0;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;

CopilotAI review requested due to automatic review settings May 29, 2026 08:54
Comment threadsrc/coreclr/inc/readytorun.h

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 24 out of 24 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/inc/readytorun.h
CopilotAI review requested due to automatic review settings June 2, 2026 10:40
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/GcInfo.cs Outdated
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No NativeAOT outerloop x86 failures.

@jakobbotsch
jakobbotsch marked this pull request as ready for review June 2, 2026 15:13
@jakobbotsch
jakobbotsch requested review from Copilot and jkotasJune 2, 2026 15:13
@jakobbotsch
jakobbotsch requested a review from VSadovJune 2, 2026 15:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/thread.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ICodeManager.h
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
CopilotAI review requested due to automatic review settings June 2, 2026 16:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated no new comments.

@jakobbotsch
jakobbotsch merged commit 483b9ea into dotnet:mainJun 3, 2026
145 of 149 checks passed
@jakobbotsch
jakobbotsch deleted the fix-128624 branch June 3, 2026 09:41
hoyosjs pushed a commit to dotnet/diagnostics that referenced this pull request Jun 9, 2026
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 17, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
NativeAOT hijacking did not properly report the async continuation when
hijacking an async function. While we did save and restore the register
(implemented in #123084), the part that actually determined whether the
register contained a GC ref was missing.
The GC reporting for return values is handled differently on x86
compared to other platforms. On other platforms the JIT reports GC
information on the caller's return address instruction which means that
the continuation gets reported naturally. This is not the case for x86
where this must be handled specially.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

4 participants

@jakobbotsch@jkotas@VSadov
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Fix async continuation hijacking for x86 NativeAOT - #128706

Merged
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624
Jun 3, 2026
Merged

Fix async continuation hijacking for x86 NativeAOT#128706
jakobbotsch merged 17 commits into
dotnet:mainfrom
jakobbotsch:fix-128624

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented May 28, 2026

Copy link
Copy Markdown
Member

NativeAOT hijacking did not properly report the async continuation when hijacking an async function. While we did save and restore the register (implemented in #123084), the part that actually determined whether the register contained a GC ref was missing.

The GC reporting for return values is handled differently on x86 compared to other platforms. On other platforms the JIT reports GC information on the caller's return address instruction which means that the continuation gets reported naturally. This is not the case for x86 where this must be handled specially.

Fix#128624
Fix#127900

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 x86 GC/hijack metadata so async continuations can be reported as GC roots when NativeAOT hijacks async methods.

Changes:

  • Adds an async bit to x86 GC info encoding/decoding.
  • Plumbs async-return metadata through CoreCLR and NativeAOT hijack helpers.
  • Reports the hijacked async continuation from the saved ECX location on x86.

Reviewed changes

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

Show a summary per file
FileDescription
src/coreclr/vm/threadsuspend.cppUses code-manager-provided async hijack info.
src/coreclr/vm/gc_unwind_x86.inlCopies decoded async flag into x86 unwind header info.
src/coreclr/vm/eetwain.cppReturns async metadata from decoded GC info.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.hExtends x86 return-value metadata API.
src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cppDecodes async flag with return kind.
src/coreclr/nativeaot/Runtime/thread.cppReports hijacked async continuation during root scanning.
src/coreclr/nativeaot/Runtime/StackFrameIterator.hTracks hijacked async continuation location.
src/coreclr/nativeaot/Runtime/StackFrameIterator.cppRestores async continuation location from transition frame flags.
src/coreclr/nativeaot/Runtime/inc/rhbinder.hAdds x86 ECX-is-GC-ref transition-frame flag.
src/coreclr/nativeaot/Runtime/ICodeManager.hEncodes/decodes async flag alongside return kind.
src/coreclr/nativeaot/Runtime/i386/AsmOffsetsCpu.hUpdates x86 structure offsets after iterator layout change.
src/coreclr/jit/gcencode.cppEmits async metadata in x86 GC info.
src/coreclr/inc/gcinfotypes.hExpands x86 GC header metadata for async state.
src/coreclr/inc/gcdecoder.cppDecodes async metadata from x86 GC info.
src/coreclr/inc/gc_unwind_x86.hAdds async flag to decoded x86 header info.
src/coreclr/inc/eetwain.hExtends CoreCLR hijack-info API signature.

Comment threadsrc/coreclr/inc/gcinfotypes.h
Comment threadsrc/coreclr/inc/gcinfotypes.h Outdated
@jkotas

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

@VSadov

VSadov commented May 28, 2026

Copy link
Copy Markdown
Member

@VSadov How hard would it be to switch windows x86 to the same plan for GC reporting around hijacked address instead of doing this? I know you intentionally left x86 on the old plan, but I do not remember the reasons.

I think the reasons for not switching x86 to the same GC encoding plan as in x64/arm64 were:

  • the original x86 format is very tightly specialized and likely to be more compact and faster to decode.
    Although I do not think it is a big deal right now as anyone still using x86 is not doing that for perf or for the size of binaries.
    (my guess - they target constrained environments and want smaller footprint at run time)
  • there is a chance that some quirks of x86 are not expressible in x64 format.
  • it may be too big investment for x86, so we kind of preferred to keep incrementally patching/fixing old format if possible.

CopilotAI review requested due to automatic review settings May 28, 2026 16:57

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/coreclr/inc/gcdecoder.cpp:215

  • decodeHeader now treats second-opcode values 0x04-0x07 as returnKind/isAsync regardless of the version parameter. For GCInfo v3 ReadyToRun images those same opcodes are the existing SET_NOGCREGIONS_CNT encodings, so old x86 GC info will be decoded with the wrong header state. Please branch on the GC info version here (and keep the old opcode layout for v3) before interpreting bit 2 as the async flag.
 if (encoding <= SET_RET_KIND_MAX)
{
header->returnKind = (ReturnKind)encoding & 3;
header->isAsync = (encoding & 4) != 0;
}
else if (encoding < FFFF_NOGCREGION_CNT)
{
header->noGCRegionCnt = encoding - SET_NOGCREGIONS_CNT;

CopilotAI review requested due to automatic review settings May 29, 2026 08:54
Comment threadsrc/coreclr/inc/readytorun.h

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 24 out of 24 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/inc/readytorun.h
CopilotAI review requested due to automatic review settings June 2, 2026 10:40
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 2 comments.

Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/GcInfo.cs Outdated
@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

No NativeAOT outerloop x86 failures.

@jakobbotsch
jakobbotsch marked this pull request as ready for review June 2, 2026 15:13
@jakobbotsch
jakobbotsch requested review from Copilot and jkotasJune 2, 2026 15:13
@jakobbotsch
jakobbotsch requested a review from VSadovJune 2, 2026 15:14

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated 3 comments.

Comment threadsrc/coreclr/nativeaot/Runtime/thread.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/ICodeManager.h
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs Outdated
CopilotAI review requested due to automatic review settings June 2, 2026 16:06

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 28 out of 28 changed files in this pull request and generated no new comments.

@jakobbotsch
jakobbotsch merged commit 483b9ea into dotnet:mainJun 3, 2026
145 of 149 checks passed
@jakobbotsch
jakobbotsch deleted the fix-128624 branch June 3, 2026 09:41
hoyosjs pushed a commit to dotnet/diagnostics that referenced this pull request Jun 9, 2026
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone Jun 17, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
NativeAOT hijacking did not properly report the async continuation when
hijacking an async function. While we did save and restore the register
(implemented in #123084), the part that actually determined whether the
register contained a GC ref was missing.
The GC reporting for return values is handled differently on x86
compared to other platforms. On other platforms the JIT reports GC
information on the caller's return address instruction which means that
the continuation gets reported naturally. This is not the case for x86
where this must be handled specially.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 18, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

4 participants

@jakobbotsch@jkotas@VSadov