Skip to content

Remove NativeAOT debug handle tagging#129034

Merged
MichalStrehovsky merged 5 commits into
mainfrom
fix/jit-cross-target-handle-bits
Jun 15, 2026
Merged

Remove NativeAOT debug handle tagging#129034
MichalStrehovsky merged 5 commits into
mainfrom
fix/jit-cross-target-handle-bits

Conversation

@MichalStrehovsky

@MichalStrehovsky MichalStrehovsky commented Jun 5, 2026

Copy link
Copy Markdown
Member

Remove the debug-only high-bit tag from NativeAOT JIT interface handles. This avoids rejecting valid handles on targets where the tag bit is not preserved.

Also re-enables the affected regression coverage by removing the NativeAOT workaround/skip from the existing tests.

Cc @EgorBo

MichalStrehovsky and others added 2 commits June 5, 2026 14:27
Ensure RyuJIT keeps host-sized handle values when cross-targeting from 64-bit to 32-bit builds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 5, 2026 05:34
@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 Jun 5, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@github-actions

This comment has been minimized.

Copilot AI 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 adjusts RyuJIT’s constant/handle plumbing so that, in cross-target scenarios (e.g., 64-bit host compiling 32-bit target), handle values are treated as host-pointer-sized where required, avoiding truncation of the upper bits during constant import/propagation and preventing incorrect folding.

Changes:

  • Update static-readonly constant import to request sizeof(ssize_t) bytes for TYP_REF so gtNewGenericCon(TYP_REF, ...) reads a complete host-sized handle.
  • Tighten/extend handle constant preservation in JIT assertion propagation and constant bashing so handle VNs don’t lose upper bits on 32-bit targets.
  • Re-enable/strengthen coverage by removing test workarounds/skips that were masking the issue.

Reviewed changes

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

Show a summary per file
File Description
src/tests/Regressions/coreclr/15647/interfacestatics.ilproj Removes TrimMode workaround so the test exercises the problematic optimization again.
src/tests/JIT/Methodical/jitinterface/bug603649.cs Re-enables the test by removing the ActiveIssue skip.
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Adds a DEBUG invariant check to catch truncated/invalid handles early.
src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Adjusts getStaticFieldContent object-handle buffer handling for cross-target correctness.
src/coreclr/jit/importer.cpp Requests host-sized bytes for TYP_REF static-readonly constants to avoid truncation.
src/coreclr/jit/compiler.hpp Avoids incorrect debug-time “fits in int32” assertions for GC-typed constants.
src/coreclr/jit/assertionprop.cpp Preserves host-sized handle constants/printing when VNs represent handles.

Comment thread src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Outdated
Comment thread src/coreclr/jit/importer.cpp Outdated
@github-actions

This comment has been minimized.

@MichalStrehovsky

Copy link
Copy Markdown
Member Author

/azp run runtime-nativeaot-outerloop

@azure-pipelines

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

@EgorBo

EgorBo commented Jun 8, 2026

Copy link
Copy Markdown
Member

I assume CI failures are related? e.g.

2026-06-08T07:03:43.0458339Z     Assertion failed.
2026-06-08T07:03:43.0465478Z     (s_handleHighBitSet & (nint)handle) != 0
2026-06-08T07:03:43.0470117Z        at Internal.JitInterface.CorInfoImpl.HandleToObject(Void* handle) in /_/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs:line 773
2026-06-08T07:03:43.0474499Z        at Internal.JitInterface.CorInfoImpl.recordRelocation(Void* location, Void* locationRW, Void* target, CorInfoReloc fRelocType, Int32 addlD

@MichalStrehovsky

Copy link
Copy Markdown
Member Author

I assume CI failures are related? e.g.

I only checked x86, so arm32 still not working is not completely surprising. Before I spend time setting up environment so that copilot can have a go at it, does the change so far make sense? I see the issue is now assigned to me... but I'm not a JIT dev, just someone who prompted GPT to make things compile with the added assert in CorInfoImpl.cs and GPT did its thing.

@EgorBo

EgorBo commented Jun 8, 2026

Copy link
Copy Markdown
Member

I assume CI failures are related? e.g.

I only checked x86, so arm32 still not working is not completely surprising. Before I spend time setting up environment so that copilot can have a go at it, does the change so far make sense? I see the issue is now assigned to me... but I'm not a JIT dev, just someone who prompted GPT to make things compile with the added assert in CorInfoImpl.cs and GPT did its thing.

I can take a look tomorrow. I'm not sure I fully understand the problem so will have to look deeply. Meanwhole sent a PR to clean up one of the offender from your PR - #129144

@MichalStrehovsky

Copy link
Copy Markdown
Member Author

@copilot undo all the non-test changes. Instead of those, delete the s_handleHighBitSet constant.

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 10, 2026 22:30
@MichalStrehovsky MichalStrehovsky removed the request for review from Copilot June 10, 2026 22:30

Copilot AI commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@copilot undo all the non-test changes. Instead of those, delete the s_handleHighBitSet constant.

Done in 11abc8f: the prior non-test JIT/NativeAOT changes were reverted, and s_handleHighBitSet plus its tagging/masking uses were removed. The remaining net PR diff is the handle-tag removal plus the existing test updates.

Copilot AI changed the title Preserve JIT handle bits in cross-target builds Remove NativeAOT debug handle tagging Jun 10, 2026
@MichalStrehovsky

Copy link
Copy Markdown
Member Author

/azp run runtime-nativeaot-outerloop

@azure-pipelines

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

Copilot AI review requested due to automatic review settings June 12, 2026 02:18
@MichalStrehovsky

Copy link
Copy Markdown
Member Author

/azp run runtime-nativeaot-outerloop

@azure-pipelines

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

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

@github-actions

Copy link
Copy Markdown
Contributor

🤖 Copilot Code Review — PR #129034

Note

This review was generated by Copilot.

Holistic Assessment

Motivation: The problem is real and well-documented in #122013. The debug-only s_handleHighBitSet poison (0x4000000000000000 on 64-bit hosts) was applied to NativeAOT JIT interface handles but never validated on return. In cross-target builds (64-bit host → 32-bit target), the JIT truncates nint-sized handles to int-sized target pointers, losing the high bit. This causes handle equality mismatches that lead to incorrect constant folding and wrong codegen. Multiple maintainers (jkotas, EgorBo, SingleAccretion) explicitly agreed in #122013 that deleting the poison is the right fix.

Approach: Correct and minimal — remove the unused debug poison at the source (VM side) rather than attempting to patch every JIT truncation site. The test workarounds are properly cleaned up in the same PR.

Summary: ✅ LGTM. This is a clean, focused, maintainer-agreed bug fix. The handle scheme (handleBase = 0x420000, handleMultiplier = 8) already guarantees handles fit within 32-bit range, so removing the tag makes the (int)handle cast in HandleToObject correct for cross-target builds. No blocking issues found.


Detailed Findings

✅ Correctness — Handle tag removal is safe

The s_handleHighBitSet tag was added in PR #41126 as a debug aid for cross-bitness compilation but was never validated — no assertion ever checked that the bit survived round-tripping through the JIT. Meanwhile, the tag actively caused bugs: when the JIT truncated handles to target pointer size, the poisoned bit was lost, causing two handles for the same object to compare as unequal. Removing the tag eliminates this entire class of bug without losing any diagnostic value.

The remaining handle arithmetic in HandleToObject ((int)handle - handleBase) / handleMultiplier) and ObjectToHandleUnchecked (handleMultiplier * _handleToObject.Count + handleBase) is correct — handleBase is 0x420000 and handle values grow linearly from there, well within 32-bit range.

✅ Test changes — Workarounds correctly removed

  • bug603649.cs: The [ActiveIssue("...#122013", ...IsNativeAot, ...Is32)] skip is correctly removed since the root cause is fixed.
  • interfacestatics.ilproj: The <TrimMode>partial</TrimMode> workaround (which hid the bug by preventing the compiler from constant-folding the problematic handles) is correctly removed. The comment on RequiresProcessIsolation is updated to reflect its actual purpose (needed for CLRTestTargetUnsupported).

💡 Observation — Remaining issue #122013 reference in codebase

There are no remaining references to issue #122013 as an ActiveIssue or workaround in the codebase (the grep match in CgStress1.cs is coincidental test data). The issue can be closed once this PR merges.

✅ Scope and focus — PR is well-scoped

The PR was iterated from a larger multi-site JIT fix down to this minimal VM-side-only change based on reviewer feedback. The current diff is the cleanest possible fix: 3 files, +1/−15 lines, all directly related to the bug.

Generated by Code Review for issue #129034 · ● 3.3M ·

@MichalStrehovsky

Copy link
Copy Markdown
Member Author

/ba-g the crypto crash is #129339

@MichalStrehovsky MichalStrehovsky merged commit ca65f7d into main Jun 15, 2026
135 of 144 checks passed
@MichalStrehovsky MichalStrehovsky deleted the fix/jit-cross-target-handle-bits branch June 15, 2026 21:14
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.

6 participants