Skip to content

[wasm] Model class-init helper as value-returning in the JIT#130813

Open
lewing wants to merge 5 commits into
dotnet:mainfrom
lewing:lewing-wasm-r2r-classinit
Open

[wasm] Model class-init helper as value-returning in the JIT#130813
lewing wants to merge 5 commits into
dotnet:mainfrom
lewing:lewing-wasm-r2r-classinit

Conversation

@lewing

@lewing lewing commented Jul 15, 2026

Copy link
Copy Markdown
Member

Summary

On wasm, the class-init JIT helpers (CORINFO_HELP_INITCLASS / CORINFO_HELP_INITINSTCLASS) are dispatched through portable entry points to the managed InitClass / InitInstantiatedClass helpers (InitHelpers.cs). Those helpers were changed to return void* (a discarded dummy value) so the compiled call_indirect signature matches the interpreter's value-returning portable-entry-point convention — but the JIT caller side was never updated and still typed these helpers as TYP_VOID.

As a result, R2R-compiled wasm code emits a (...)->() call_indirect for the first class-init of a type, while the runtime dispatches the cold class-init through the i32-returning thunk. The wasm engine traps with function signature mismatch.

This change models the class-init helpers as value-returning (TYP_I_IMPL) on wasm at the five sites that create them:

  • fgGetStaticsCCtorHelper (the shared-cctor path used by non-generic methods)
  • impInitClass (runtime-lookup path)
  • the three fgInitThisClass generic-lookup cases (THISOBJ, CLASSPARAM, METHODPARAM)

The helper result is pushed and then discarded via the existing unused-value drop in wasm codegen. The change is guarded by #ifdef TARGET_WASM; other targets are unaffected.

⚠️ Dependency

This is the JIT caller-side half of the class-init-helper return-arity change. It depends on the corelib half — InitClass / InitInstantiatedClass returning void* in InitHelpers.cs — which is not yet on main (it is part of the in-progress wasm R2R / SPC bring-up work, e.g. AndyAyersMS:next-blocker-spc). This PR is not correct in isolation without that corelib change: the JIT would model the helper as i32-returning while the helper still returned void. The two halves must land together (or this should be folded into the SPC bring-up set).

Opening as draft for human review of the JIT modeling change. There is currently no wasm-R2R CI leg, so validation below is from a local sweep.

Validation (local, browser wasm R2R)

Built the fixed cross-JIT, re-crossgen'd, and ran under corerun.js with DOTNET_ReadyToRun=1:

Test Before After
conv_ovf, 127931, indexMinusOne (interpreted corelib) trap (exit 1) exit 100
conv_ovf (R2R corelib) trap (exit 1) exit 100
b491215, GitHub_13561 (type-load) pass still pass

This resolves the residual overflow bucket of #129622 and removes the class-init signature-mismatch trap in #130634 (that repro now progresses into managed execution and surfaces a separate, unrelated NullReferenceException).

Contributes to #129622 / #130634.

Note

This PR was created with assistance from GitHub Copilot (AI).

Copilot AI review requested due to automatic review settings July 15, 2026 19:25
@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 Jul 15, 2026
@lewing
lewing requested a review from AndyAyersMS July 15, 2026 19:25
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
10 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@lewing
lewing requested a review from pavelsavara July 15, 2026 19:26
@pavelsavara pavelsavara added the arch-wasm WebAssembly architecture label Jul 15, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

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 updates CoreCLR JIT IR modeling on TARGET_WASM so the class-init helpers (CORINFO_HELP_INITCLASS / CORINFO_HELP_INITINSTCLASS) are treated as value-returning (TYP_I_IMPL) rather than TYP_VOID, to align wasm indirect-call signature expectations with the helper’s return arity.

Changes:

  • Model CORINFO_HELP_INITCLASS as TYP_I_IMPL on wasm in fgGetStaticsCCtorHelper.
  • Model CORINFO_HELP_INITCLASS / CORINFO_HELP_INITINSTCLASS as TYP_I_IMPL on wasm at helper creation sites in impInitClass and fgInitThisClass.
  • Add explanatory comments describing the wasm-specific return-arity rationale.

Reviewed changes

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

File Description
src/coreclr/jit/flowgraph.cpp Changes wasm helper return type modeling for CORINFO_HELP_INITCLASS in fgGetStaticsCCtorHelper, with added rationale comments.
src/coreclr/jit/importer.cpp Models the runtime-lookup InitClass helper call as value-returning on wasm in impInitClass.
src/coreclr/jit/morph.cpp Models the three generic-lookup fgInitThisClass helper call cases as value-returning on wasm.

Comment thread src/coreclr/jit/flowgraph.cpp Outdated
Comment thread src/coreclr/jit/flowgraph.cpp Outdated
…the JIT

Completes gate #2 (91d9e36). That change made corelib InitClass/
InitInstantiatedClass (InitHelpers.cs) return void* so the compiled
call_indirect signature matches the interpreter's value-returning portable
entry point convention, but the JIT caller side still typed
CORINFO_HELP_INITCLASS/INITINSTCLASS as TYP_VOID. On wasm the R2R caller
therefore emitted a (...)->() call_indirect while the runtime dispatches the
cold class-init through the i32-returning thunk, trapping with
"function signature mismatch" on the first R2R class-init.

Model the class-init helpers as value-returning (TYP_I_IMPL) on wasm at the
five sites that create them (fgGetStaticsCCtorHelper, impInitClass runtime
lookup, and the three fgInitThisClass generic-lookup cases). The helper
result is pushed and discarded via the existing unused-value drop in wasm
codegen.

Fixes the residual overflow bucket of dotnet#129622 (conv_ovf, 127931,
indexMinusOne now pass under R2R in both interpreted- and R2R-corelib
configs) and removes the class-init signature-mismatch trap in dotnet#130634.
No regression in the previously passing type-load tests.

Prototype-only; for the future WASI R2R PR.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2902374a-f352-4c46-bcec-8a35c97733ae
Copilot AI review requested due to automatic review settings July 15, 2026 19:34
@lewing
lewing force-pushed the lewing-wasm-r2r-classinit branch from 6acd714 to 80ed48b Compare July 15, 2026 19:34
@lewing

lewing commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

Thanks — both points addressed in the pushed update (also refactored the per-site #ifdefs into a single Compiler::HelperInitClassRetType constant):

  1. Comment referenced a nonexistent genCodeForCall. Fixed — the comment now points at the actual unused-value drop in CodeGen::WasmProduceReg (codegenwasm.cpp).

  2. Depends on the CoreLib InitHelpers signature. Correct, and intentional — this is the JIT caller-side half of the class-init helper return-arity change; it only works together with InitClass/InitInstantiatedClass returning void* (that CoreLib change is part of the in-progress wasm R2R / SPC bring-up and is not on main yet). This is called out in the PR description's ⚠️ Dependency section, and I've now reinforced it in the HelperInitClassRetType comment. That coupling is exactly why this is a draft — it must land with (or fold into) the CoreLib change, not on its own.

Locally validated with both halves present: the residual overflow bucket of #129622 (conv_ovf, 127931, indexMinusOne) passes under R2R in both interpreted- and R2R-corelib configs, with no regression in the type-load tests.

Note

This comment was generated by GitHub Copilot (AI).

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 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/compiler.h Outdated
@AndyAyersMS

Copy link
Copy Markdown
Member

My speculative "get SPC working" change set fixed this on the helper side, by retyping InitClass and InitInitialized class to return void *.

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs

Doing that seems a bit simpler to me?

@lewing

lewing commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

My speculative "get SPC working" change set fixed this on the helper side, by retyping InitClass and InitInitialized class to return void *.

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs

Doing that seems a bit simpler to me?

This pr is meant to stack on top of your branch. The diagnosis is that your callee side change requires this caller side change to avoid the call_indirect type mismatch. Will double check.

@lewing

lewing commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

Thanks Andy — your void* retype is the callee half and this PR is the caller half; they're the two matching sides of the same signature, not alternatives.

I ran a clean A/B on conv_ovf with your void* InitClass/InitInstantiatedClass compiled into the corelib in both runs, toggling only the JIT change:

caller call_indirect result
gate-#2 void* only (i32,i32,i32)->() function signature mismatch
gate-#2 void* + this PR (i32,i32,i32,i32)->i32 ✅ pass

The reason the helper-side change alone isn't enough: the JIT models helper return types explicitly — fgGetStaticsCCtorHelper hardcodes CORINFO_HELP_INITCLASS → TYP_VOID, and helper-call return types aren't derived from the managed method — so the compiled call_indirect keeps declaring ->void until the JIT side is updated to match the now-void* helper.

Note

This comment was generated by GitHub Copilot (AI).

@lewing

lewing commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

With this on top of your speculative branch I get past the call_indirect problems and land on some exception handling issues we're looking into.

@lewing

lewing commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

With this on top of your speculative branch I get past the call_indirect problems and land on some exception handling issues we're looking into.

the eh issue is looking like a non-composite cross module r2r eh bug or an incomplete reloc pass

Comment thread src/coreclr/jit/compiler.h Outdated
Per review feedback, condense the HelperInitClassRetType comment to the
essential point (on wasm these helpers return void*, so model them as
value-returning to match the callee) plus the CoreLib-dependency note.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2902374a-f352-4c46-bcec-8a35c97733ae
Copilot AI review requested due to automatic review settings July 16, 2026 00:51

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 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/compiler.h Outdated
@lewing

lewing commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

With this on top of your speculative branch I get past the call_indirect problems and land on some exception handling issues we're looking into.

the eh issue is looking like a non-composite cross module r2r eh bug or an incomplete reloc pass

figured out the eh issue, r2r functional on the branch. issue/pr incoming

@lewing

lewing commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

depends on #131119 landing first

@davidwrighton

Copy link
Copy Markdown
Member

@lewing #131119 has merged. Could you make this ready for merge?

@lewing
lewing marked this pull request as ready for review July 22, 2026 00:07
Copilot AI review requested due to automatic review settings July 22, 2026 00:07
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@lewing
lewing enabled auto-merge (squash) July 22, 2026 00:09
@lewing

lewing commented Jul 22, 2026

Copy link
Copy Markdown
Member Author

@lewing #131119 has merged. Could you make this ready for merge?

done

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 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/compiler.h Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 00:21

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 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/jit/compiler.h Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 01:15

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

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

Labels

arch-wasm WebAssembly architecture 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.

5 participants