Directly call same-image managed R2R helpers - #134555
davidwrighton wants to merge 8 commits into
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Tagging subscribers to this area: @dotnet/crossgen-contrib |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
R2R version compatibility and non-local helper fallback issues remain unresolved, along with requested documentation and regression coverage.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (2)
What changed in this PR
This PR enables ReadyToRun code to directly call same-image managed JIT helpers, with eager activation fixups and WebAssembly support.
Changes:
- Adds
METHOD_ENTRY_READYTORUNand R2R format version 29.3. - Resolves and roots local managed helpers, including throw-only helpers.
- Updates activation sequencing and Wasm direct-call lowering.
Outstanding issues include R2R version compatibility, a helper fallback bug, missing format documentation, and requested regression coverage.
| File | Summary |
|---|---|
src/coreclr/vm/nativeimage.h |
Tracks activation fixups. |
src/coreclr/vm/nativeimage.cpp |
Initializes activation state. |
src/coreclr/vm/jitinterface.cpp |
Handles method-entry fixups; regression coverage is requested. |
src/coreclr/vm/ceeload.h |
Declares activation fixup APIs. |
src/coreclr/vm/ceeload.cpp |
Processes eager and activation fixups. |
src/coreclr/vm/assembly.hpp |
Declares activation-phase handling. |
src/coreclr/vm/assembly.cpp |
Runs activation fixups before activation. |
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs |
Caches helper methods. |
src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs |
Adds R2R flags and fixup kind. |
src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs |
Updates the R2R version. |
src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs |
Updates the helper lookup contract. |
src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs |
Decodes the new fixup. |
src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs |
Resolves local helpers; fallback output handling requires correction. |
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunJitHelperRootProvider.cs |
Roots helper methods. |
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs |
Tracks helper compilation. |
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/IRootingServiceProvider.cs |
Extends root-provider metadata. |
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs |
Creates activation imports. |
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs |
Emits activation sections. |
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs |
Marks JIT helpers. |
src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h |
Updates the NativeAOT R2R version. |
src/coreclr/jit/lowerwasm.cpp |
Supports direct Wasm calls and PEP handling. |
src/coreclr/jit/lower.h |
Declares Wasm lowering helpers. |
src/coreclr/jit/lower.cpp |
Implements direct Wasm call lowering. |
src/coreclr/inc/readytorun.h |
Defines R2R 29.3 additions; compatibility and format documentation issues remain. |
Preserve upstream's R2R 29.3 BulkWriteBarrierSmall update and use a major version bump for the incompatible EagerActivation import-section flag. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Two critical runtime issues and missing R2R format documentation remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 2
Open (2)
Resolved since last review (2)
The relocation only arises with #134555, where a same-image managed helper is returned as IAT_VALUE but genEmitHelperCall still loads the PEP through an indirection cell. Encoding it as a function index would load from imageBase + funcIndex, so the fix belongs in the JIT. On main no code path emits it for composite images. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Run all eager imports immediately before module activation and order managed helper method-entry fixups after ordinary eager imports. Keep direct managed helper selection restricted to Wasm so non-Wasm crossgen builds do not reference methods that require runtime JIT. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Compile managed JIT helpers optimistically without publishing output, exclude helpers that fail or require processor feature fixups, and then compile the stable helper set before ordinary methods. This enables direct same-image helper calls across targets while retaining helper-cell fallback for unsupported methods. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The helper-entry cache can retain stale direct-call eligibility; format documentation and end-to-end coverage are also requested.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Resolved since last review (2)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| LowerPEPCall(call); | ||
| if (call->gtDirectCallAddress != nullptr) | ||
| { | ||
| AddWasmPortableEntryPointArg(call, m_compiler->gtNewIconNode(0, TYP_I_IMPL)); |
There was a problem hiding this comment.
This arg is just to fulfill the signature demand?
| // R2R Version 31 adds READYTORUN_FIXUP_MethodEntry_ReadyToRun for initializing a | ||
| // method's ReadyToRun entry point and fixups. | ||
| // R2R 31 is not backward compatible with 30.x or earlier. |
There was a problem hiding this comment.
| // R2R Version 31 adds READYTORUN_FIXUP_MethodEntry_ReadyToRun for initializing a | |
| // method's ReadyToRun entry point and fixups. | |
| // R2R 31 is not backward compatible with 30.x or earlier. | |
| // R2R Version 31 adds READYTORUN_FIXUP_MethodEntry_ReadyToRun |
R2R 31 is not backward compatible with 30.x or earlier.
I am not sure what this is trying to say.
Also, the description can be shorter.
| Eager = 0x0001, // Section at module load time. | ||
| PCode = 0x0004, // Section contains pointers to code | ||
| None = 0x0000, | ||
| Eager = 0x0001, // Section before module activation. |
There was a problem hiding this comment.
| Eager = 0x0001, // Section before module activation. | |
| Eager = 0x0001, // Fixups must be resolved at module load time before any code in the module runs. |
Section before module activation.
Does not make sense
| break; | ||
|
|
||
| case FILE_ACTIVE: | ||
| EagerFixups(); |
There was a problem hiding this comment.
I do not think it can be together with Activate (ie running module constructors). It would break if there are cycles between module constructors.
We should move the whole FILE_LOAD_EAGER_FIXUPS phase.
| ReadyToRunFixupKind.MethodEntry_ReadyToRun, | ||
| method, | ||
| isInstantiatingStub: false), | ||
| sortLast: true); |
There was a problem hiding this comment.
Why is sortLast: true needed here?


Summary
Allow ReadyToRun code to call managed JIT-helper bodies directly when the helper can be compiled portably into the same binary.
Crossgen2 probe-compiles managed JIT helpers before compiling ordinary methods. Helpers that compile successfully without processor-feature fixups can call one another directly and are exposed to ordinary methods as local compiled bodies. Helpers that require runtime JIT or processor-specific dispatch continue to use the existing helper-cell path. The JIT treats an
IAT_VALUElookup as a direct call; on Wasm it passes zero for the portable-entrypoint argument rather than loading and calling through the PEP cell.Direct calls bypass normal method-entrypoint resolution, so the compiler emits a
METHOD_ENTRY_READYTORUNfixup in the ordinaryEagerimport section. CoreCLR processes eager imports atFILE_ACTIVE, immediately beforeActivate(), with method-entry fixups ordered after all other eager work. JIT-helper roots are also identified explicitly so throw-only managed helpers are emitted instead of being removed byFunctionJustThrows.The new fixup updates the R2R format to version 31.0. This is a major version bump because runtimes implementing 30.x and earlier do not understand the new fixup.
Performance
Measured
ArrayDeAbstraction.foreach_member_array_via_interface_property_in_loopon CoreCLR Wasm using a retail runtime and libraries built from this branch. Values are medians in ns/op; lower is better.Individual R2R benefits from direct helper calls within the CoreLib image. Composite R2R additionally permits the benchmark and CoreLib helpers to share one Wasm module, eliminating the helper-cell load and
call_indirectforGetGCStaticBaseandVirtualFunctionPointer.A fresh five-second sampled profile was generated from an unmodified final composite image. It collected 18,491 attributed samples:
VirtualFunctionPointerget_CurrentGetGCStaticBaseMoveNextAn earlier description incorrectly said
GetGCStaticBasefell from 10.49% to 3.10%. The 3.10% result came from a separate manual WAT experiment and is not attributable to the checked-in changes, so that comparison has been removed.The interpreted path is not changed by this optimization. Five repeated interpreted runs had a median of medians of 88,718 ns/op and a 17.2% run-to-run spread; the previously observed +2.5% difference is therefore not evidence of a regression.
Wasm image size
Measured with a controlled same-worktree A/B against merged
upstream/main(5b82fc4ae86): preserve the upstream image, apply only this PR's source diff, and rerun the same browser-Wasm Release build.System.Private.CoreLib.wasmcomposite.wasmThe complete composite layout includes
composite.wasmand theSystem.Private.CoreLib.wasm,System.Linq.wasm, and benchmark forwarding headers.wasm-objdump -hattributes nearly all of the reduction to the Wasm Code section.Validation
./build.sh -os browser -c Release -subset clr+libs./build.sh clr+libs+host -rc release -lc releaseMETHOD_ENTRY_READYTORUNhelper entries ordered last in the ordinary eager sectionSpanHelpers.FillNote
This pull request description was generated with GitHub Copilot.