Uh oh!
There was an error while loading. Please reload this page.
[wasm] Delete hand-written R2R-to-interpreter thunks; use crossgen2's - #132965
[wasm] Delete hand-written R2R-to-interpreter thunks; use crossgen2's#132965pavelsavara wants to merge 6 commits into
Conversation
build-runtime.cmd and build-native.cmd only treated android and browser as cross-targets, so a wasi build on a Windows host ran copy_version_files.cmd (which copies only *.h/*.rc) instead of copy_version_files.ps1, which also generates _version.c, and CMake configure then failed with missing source files.
The R2R-to-interpreter transition thunks were a hand-written table in vm/wasm/helpers.cpp (g_wasmPortableEntryPointThunks plus the CallInterpreter_* functions). crossgen2 already emits these thunks into each R2R image (WasmR2RToInterpreterThunkNode, keyed 'I'+signature) and the runtime discovers them by string via LookupPregeneratedThunkByString, so the static table is a buggy, incomplete duplicate that shadows the correct crossgen2 thunks - it had no float/double-return shape, among others. Remove the table and route LookupPortableEntryPointThunk solely through the R2R string hash. Pure interpreter keeps working via the existing deferral path (EnsurePortableEntryPointIsCallableFromR2R -> AddPendingPortableEntryPointThunk). Add src/tests/readytorun/wasm/WasmInterpreterTransitions, which exercises both transition directions across struct, scalar, void, and float/double returns.
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Tagging subscribers to this area: @JulieLeeMSFT, @BrzVlad, @janvorli |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
…e/small-struct tests
Why the pregenerated portable-entry-point thunk table cannot be deleted The R2R→interpreter thunk is needed whenever a caller reaches an interpreted method through a materialized native entry point — i.e. any call_indirect: ldftn/delegate/virtual dispatch, plus every R2R→interpreter call. On wasm that entry point is an index into crossgen2 emits these thunks ( Pure interpreter loads zero R2R images. With But the interpreter still needs a portable entry point the instant managed code takes a delegate/function-pointer to an interpreted method. This leaves us with
Both options are incomplete because we don't pre-create thunks for signatures in the app assemblies. None of this is on critical path for me, to unblock Blazor on R2R. I'm closing this and we will re-consider later. I'm back to #132926 |
Right. It means that you should not need any R2R->interpreter thunks (there is no R2R code), managed->managed calls should be going through interpreter without any intermediate thunks, and managed<->native calls should be covered by thunks generated by the pre-generated C thunks. Can you share a few examples of situations that are causing problems once the hardcoded list of thunks is deleted?
The change in #132926 is dead-end. |
Correct no R2R code.
That's what #132926 is generating.
On wasm a native function pointer is a typed index into the function table. Even a pure interpreter must (A) convert a managed method (delegate / ldftn) into such a native pointer, and (B) have that pointer be callable — from the interpreter and from native/host code — which requires a real, per-signature wasm function (the thunk) that marshals the typed args and re-enters the interpreter.
|
jkotas
commented
Sep 1, 2026
That's not correct. Pure interpreter is expected to use portable-entry-point for managed method delegate. This portable-entry-point does not have to have runtime/src/coreclr/vm/interpexec.cpp Lines 3355 to 3356 in 04a9b1a _pActualCode. |
jkotas
commented
Sep 1, 2026
Do you see the condition that I have linked to be false in the problematic cases? There are multiple clones of this condition in interpexec.cpp handling different types of calls. |
Addresses @jkotas's feedback on #132926: rather than grow another static table of hand-written R2R-to-interpreter thunks, delete them and rely on the ones crossgen2 already emits.
What
The R2R-to-interpreter transition thunks were a hand-written table in
vm/wasm/helpers.cpp(g_wasmPortableEntryPointThunks+ theCallInterpreter_*functions). crossgen2 already emits these thunks into each R2R image (WasmR2RToInterpreterThunkNode, keyed"I"+signature, from #127483), and the runtime discovers them by string viaLookupPregeneratedThunkByString. The static table was therefore a buggy, incomplete duplicate that shadowed the correct crossgen2 thunks — it was checked first, yet had no float/double-return shape, among others.This removes the table and routes
LookupPortableEntryPointThunksolely through the R2R string hash. Pure interpreter keeps working via the existing deferral path (EnsurePortableEntryPointIsCallableFromR2R→AddPendingPortableEntryPointThunk, resolved when an R2R module loads).helpers.cpp: −368 / +5.Test
Adds
src/tests/readytorun/wasm/WasmInterpreterTransitions, exercising both transition directions across struct (S8/S12/S16), scalar, void, and float/double returns.[BypassReadyToRun]+ composite R2R ensures every cross-call actually hits a thunk (a wrong parameter order still type-checks undercall_indirect, so the cases assert pinned values).Validation (local, Windows host)
WasmInterpreterTransitionspasses (Expected 100 / Actual 100).WasmR2RStructAlignment,Runtime_131640.WasmArgumentLayoutTests(crossgen2 lowering, unchanged here): 52 / 52.console-nodeCoreCLR sample runs clean.helpers.cppcompiles for both browser and wasi (the wasi target runtime builds).Commits
configureplatform.cmakecross-components fix is not included, so a full wasi build is not green from this PR alone. Can be split into its own PR if preferred.Draft while gathering CI signal.
Note
This PR description was generated with AI assistance.