WASM JIT: inline P/Invoke transition frame emits PHYSREG(REG_NA) for caller SP/FP, asserting in codegen
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
## Summary
The experimental WASM JIT (`clrjit_universal_wasm`) hits an assert on every method that requires an inline P/Invoke transition frame. The inline-frame lowering captures the caller''s hardware SP/FP into the `InlinedCallFrame`, but WASM has no such registers, so the emitted `GT_PHYSREG` nodes carry `REG_NA` and codegen asserts.
```
Assert failure: genIsValidReg(tree->gtSrcReg)
genCodeForPhysReg (codegenwasm.cpp)
```
Representative failing shape (JitDump, `System.ConsolePal:get_OutputEncoding`):
```
CALL CORINFO_HELP_INIT_PINVOKE_FRAME
LCL_ADDR V03 PInvokeFrame
t14 = PHYSREG int NA
```
## Root cause
The target-independent inline P/Invoke transition frame writes the caller SP/FP into the `InlinedCallFrame` for the VM stackwalk/unwind contract:
- `Lowering::InsertPInvokeMethodProlog` — `PhysReg(REG_SPBASE)` → `m_pCallSiteSP` (`lower.cpp:6848`); `PhysReg(REG_FPBASE)` → `m_pCalleeSavedEBP` (`lower.cpp:6863`)
- `Lowering::InsertPInvokeCallProlog` — `PhysReg(REG_SPBASE)` → `m_pCallSiteSP` (`lower.cpp:7069`)
On WASM `REG_SPBASE == REG_FPBASE == REG_NA` (`targetwasm.h`), so the resulting `GT_PHYSREG` nodes are invalid and `genCodeForPhysReg` asserts. These sites are guarded for x86/arm32 but not WASM, and `compMethodRequiresPInvokeFrame()` returns `true`, so WASM takes the full inline-frame path (`Lowering::DoPhase`, `lower.cpp:8926`).
## Why this needs a design decision (not a mechanical fix)
These slots feed the VM `InlinedCallFrame` stackwalk/unwind contract. WASM has no hardware SP/FP; the shadow-stack pointer (`lvaWasmSpArg`) is the nearest analogue, but whether the inline-frame transition mechanism applies to WASM at all — and what the runtime expects in `m_pCallSiteSP` / `m_pCalleeSavedEBP` for unwinding — is a WASM interop design decision. A blind codegen fix (e.g. substituting `lvaWasmSpArg` for SP and stubbing FP) would be guessing at the VM contract.
## Impact
In an SPMI replay of the WASM altjit over `libraries_tests_no_tiered_compilation` + `coreclr_tests`, this bucket accounts for ~4,912 asserting contexts, making it one of the larger remaining WASM codegen gaps. Tracking for the WASM interop owners.
> [!NOTE]
> This issue was authored with the assistance of GitHub Copilot.
Contributor guide
Assessment
This issue has not been assessed yet.