Skip to content

Extract loops from toplevel function into helper functions#2212

Closed
vouillon wants to merge 11 commits into
masterfrom
loops
Closed

Extract loops from toplevel function into helper functions#2212
vouillon wants to merge 11 commits into
masterfrom
loops

Conversation

@vouillon
Copy link
Copy Markdown
Member

Wasm engines tier up (compile to optimised native code) functions that contain loops. For the toplevel/init function, which is large and called only once, this is wasteful. Extract contained loops into small helper functions so only the helpers get tiered up.

@hhugo
Copy link
Copy Markdown
Member

hhugo commented Apr 11, 2026

Couldn't it benefit js as well ? Allowing to optimize the loop ..

@vouillon
Copy link
Copy Markdown
Member Author

Couldn't it benefit js as well ? Allowing to optimize the loop ..

That could benefit JS as well, indeed. This seems harder to implement, though.
Also, we have actually observed performance issues with the Wasm code (Turbofan, V8's optimizing compiler, has performance issues with large Wasm functions), but not with JS code.

vouillon added 3 commits May 13, 2026 16:42
Wasm engines tier up (compile to optimised native code) functions that
contain loops. For the toplevel/init function, which is large and called
only once, this is wasteful. Extract contained loops into small helper
functions so only the helpers get tiered up.

The pass runs on the toplevel function after code generation. It extracts
loops whose branches all stay within the loop body (no escaping Br,
Return, or Rethrow). Variables are split into parameters (whose pre-loop
values are needed) and locals (written before first read). Non-nullable
ref locals are made nullable with RefCast on reads. Modified variables
are returned.
Array bounds checks and division-by-zero checks use Br to jump to
handler blocks set up by wrap_with_handlers. When those handler
blocks are outside the loop, the Br escapes the loop and
is_contained returns false. Wrapping the loop body with its own
handlers keeps those Br targets inside the loop.

Only done for the toplevel function (where loop hoisting applies).
…alues.

Have the helper functions return a struct rather than multiple values,
since this is better optimized by Binaryen.
vouillon added 8 commits May 20, 2026 16:23
needed_handlers used CFG-reachability from the start pc, which spills
past the wrap's structural region: starting at a try body entry, the
traversal followed Poptrap edges into post-try blocks; starting at a
loop header, it could reach blocks not dominated by the loop header.
Those checks live outside the wrap, so counting them caused dead
handler blocks to be emitted inside the wrap.

Walk the dominator subtree of the start pc instead, still skipping the
try body when a Pushtrap is encountered (it has its own wrap). The
function-level wrap is unaffected since the function entry dominates
every block in the function.
@vouillon
Copy link
Copy Markdown
Member Author

Closed in favor of #2245 which works both for JavaScript and Wasm.

@vouillon vouillon closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants