Skip to content

JIT/wasm: Pri-1 R2R codegen fixes (BBJ_CALLFINALLY back-edge, null-check loads)#129807

Open
AndyAyersMS wants to merge 2 commits into
dotnet:mainfrom
AndyAyersMS:fix-wasm-codegen-pri1
Open

JIT/wasm: Pri-1 R2R codegen fixes (BBJ_CALLFINALLY back-edge, null-check loads)#129807
AndyAyersMS wants to merge 2 commits into
dotnet:mainfrom
AndyAyersMS:fix-wasm-codegen-pri1

Conversation

@AndyAyersMS

Copy link
Copy Markdown
Member

Two wasm JIT codegen correctness fixes surfaced by the Pri-1 R2R test pass.

BBJ_CALLFINALLY non-fallthrough back-edge
genCodeForBlock early-returns for BBJ_CALLFINALLYRET assuming fall-through to
the next linear block. On wasm the finally is invoked via call_indirect, so when
the paired continuation is reached via a back-edge (e.g. a catch leave targeting a
loop header outside the enclosing try/finally) no branch was emitted and control
fell out of the wasm loop, running a cloned finally a second time. Emit a br to
the continuation when it is not the next linear block. Fixes the double-finally in
strswitch_catchrettoinnertry and similar.

Null-check faulting GT_IND loads
On wasm a load from a null address does not fault, so a decoupled array bounds
check read the length from [null+lenOffset] as 0 and threw
IndexOutOfRangeException instead of NullReferenceException. genCodeForStoreInd
already emits an explicit null check for faulting stores; do the same for faulting
GT_IND loads (lower marks the address multiply-used, regalloc reserves the temp,
codegen emits the check using the same GTF_EXCEPT && OperMayThrow predicate the
throw-helper reservation phase uses). Fixes b42929, b41063, b31903,
b091942, and the JitTest_catchfinally_* array-null tests.

AndyAyersMS and others added 2 commits June 24, 2026 09:42
…llyret

BBJ_CALLFINALLYRET emits no code via genCodeForBlock's early return,
relying on fall-through to the continuation. On wasm the layout may
place the continuation elsewhere (e.g., a loop header reached via
back-edge from a catch handler that leaves to a label outside its
enclosing try-finally), in which case fall-through skips past the
target. Emit an explicit branch in genCallFinally when the
CALLFINALLYRET's continuation is not the linear next block.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
On wasm a load from a null address does not fault, so the array-length
read in a decoupled bounds check returned 0 and threw IndexOutOfRange
instead of NullReference. Emit an explicit null check for faulting loads,
matching GT_STOREIND (lower marks the address multiply-used, regalloc
reserves the temp, codegen emits the check using the same predicate as
the throw-helper reservation phase).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 24, 2026 16:47
@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 24, 2026
@AndyAyersMS AndyAyersMS requested a review from adamperlin June 24, 2026 16:47
@AndyAyersMS

Copy link
Copy Markdown
Member Author

@adamperlin PTAL
fyi @dotnet/wasm-contrib

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 the CoreCLR WASM JIT backend to address two correctness issues that arise from WASM’s different control-flow and faulting semantics compared to native targets (notably: call_indirect finally invocation and non-faulting loads from address 0).

Changes:

  • Ensure BBJ_CALLFINALLY codegen emits an explicit branch to the BBJ_CALLFINALLYRET continuation when that continuation is not the next block in the linear (preorder) block order.
  • Add explicit null-check emission for faulting GT_IND loads in WASM codegen, mirroring existing explicit null-check handling for faulting stores.
  • Plumb the required “multiply-used address” temp consumption through lowering and WASM regalloc so the address is available both for the null check and the subsequent load.

Reviewed changes

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

File Description
src/coreclr/jit/regallocwasm.cpp Consumes the temporary register for multiply-used GT_IND addresses so the null-check+load sequence can share the address value.
src/coreclr/jit/lowerwasm.cpp Marks faulting GT_IND load addresses as multiply-used so codegen can both null-check and load using the same computed address.
src/coreclr/jit/codegenwasm.cpp Emits explicit null checks for faulting loads and emits a corrective branch after call_indirect finally calls when the continuation is non-fallthrough.

@pavelsavara pavelsavara added the arch-wasm WebAssembly architecture label Jun 24, 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.

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.

3 participants