wasm32 and the shared scope-exit sweep
- Type: refactor — Track A
- Found: 2026-09-07, closing the six-backend sweep-thunk sequence
Why this is a ticket rather than a seventh commit
The other six targets all had the same shape of answer: place the sweep once
after the body, jump over it, CALL it from every return past the first, and
spell three per-target things (a stack adjust, a call, a return). Every one of
them writes into a flat Code[] and can name an address inside the body being
emitted.
wasm32 cannot do any of that.
EmitManagedLocalCleanupForTargetbegins withif TargetArch = TARGET_WASM32 then Exit— the sweep this sequence shares is not the code wasm32 runs.WasmEmitManagedLocalswrites into the epilogue instead, andEmitProcEpilogis never called for this target at all.- Structured control flow means there is no raw code address to jump over or call.
So the equivalent change is: emit a real wasm function that performs the sweep, and call it. That function needs the frame — and there is no frame. The locals are wasm locals, not slots at an offset from a base pointer, so the argument the shared sweep would need does not exist in a form that can be passed.
What is already established
- Every landing in the sequence carried a byte-identity A/B against the previous
compiler across the seven targets.
--target=wasm32reportedidentical=30 differs=0on all six. wasm32's output has not changed by one byte, which is the intended outcome and is the evidence that the six arms are correctly scoped. TargetHasSweepThunkdoes not admit it, and the fall-through arms ofEmitSweepThunkStackAdjust/EmitSweepThunkCall/EmitSweepThunkReturneachError(...)with a named reason rather than silently emitting some other target's bytes — so admitting wasm32 by accident is a compile error, not a wrong binary.
Before doing any of it, measure the value
The payoff on the flat-code targets is code size: compiler.pas for riscv32
went 23,179,116 -> 16,133,996 bytes (30.4%), and for xtensa Call0 under
--xtensa-long-calls 26,308,460 -> 14,163,820 (46.2%, inflated by that flag
making every call site large). Neither number transfers. A wasm module's size is
dominated by different things, and a function call in wasm is not the same
trade as a call rel32. Measure the duplicated-sweep bytes in a real module
first; if the answer is small, the right resolution of this ticket is
rejected/ with the measurement attached.