Skip to content

Fix wasm dev list mutation and short string concat#9666

Draft
lukewilliamboswell wants to merge 5 commits into
mainfrom
wasm4-patches
Draft

Fix wasm dev list mutation and short string concat#9666
lukewilliamboswell wants to merge 5 commits into
mainfrom
wasm4-patches

Conversation

@lukewilliamboswell

@lukewilliamboswell lukewilliamboswell commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • merge the trusted wasm dev backend: roc-wasm4 examples hit runtime OOM and DebugAllocator leak abort #9667 wasm dev backend fix for list mutation OOMs and join-point bookkeeping leaks
  • keep the wasm32 list element incref callback ABI pointer-sized, so builtin callback calls pass an i32 count on wasm32
  • lower short wasm dev Str.concat results as inline small RocStr values instead of heap strings
  • add wasm static-lib coverage for list mutation paths and a zero-allocation short concat regression

Validation

  • zig fmt build.zig test/wasm/main.zig src/backend/wasm/WasmCodeGen.zig
  • git diff --check
  • zig build run-test-wasm-static-lib
  • zig build roc
  • zig build run-test-zig-module-backend
  • zig build minici

roc-wasm4 validation

  • /home/lbw/Documents/Github/roc/zig-out/bin/roc build examples/sound.roc --opt=dev --output=/tmp/sound-dev-9667-fixed.wasm
  • /home/lbw/Documents/Github/roc/zig-out/bin/roc build examples/basic.roc --opt=dev --output=/tmp/basic-dev-9667-fixed.wasm
  • timeout 8s w4 run-native /tmp/basic-dev-9667-fixed.wasm

basic.roc reached the timeout with no trap output, which matches the expected non-OOM behavior for the previous immediate WASM-4 reproduction.

lukewilliamboswell and others added 5 commits June 16, 2026 15:45
The wasm dev backend hand-rolled `list_set` to always allocate a fresh
element buffer, copy every element, and return a new list without ever
freeing the input allocation, checking uniqueness, or running element
refcount callbacks. In a loop (e.g. a WASM-4 frame callback) this leaks
one buffer per call until the platform allocator is exhausted, which is
why `basic.roc --opt=dev` booted and then trapped with `roc_alloc: out
of memory`. `list_replace_unsafe` and `list_swap` were `unreachable`
traps. Route all three through the shared `roc_builtins_list_replace`/
`roc_builtins_list_swap` builtins, threading the statically-proven
uniqueness mask so they mutate in place when the list is unique and
copy-on-write otherwise, matching the dev x86, LLVM, and interpreter
backends. `host_imports` mode (used only by the wasm eval-test runner)
gains matching compact host functions.

Separately, the join-point bookkeeping maps were module-lifetime and
never scoped to a proc. Join ids from lowering are globally unique, but
TRMC mints a fresh id from a per-proc `max_join_id + 1`, which collides
with another proc's id; the colliding proc's `put` then overwrote and
leaked the earlier proc's `param_locals` array (the DebugAllocator leak
in `generateCFStmtNode` while building `sound.roc`). Retire each join's
entries at its `.join_close`, mirroring the lexical push/pop discipline
the loop-target stacks already use, so entries live exactly as long as
their join is in scope and a jump to an out-of-scope join surfaces the
existing invariant violation instead of silently miscompiling.
@lukewilliamboswell lukewilliamboswell changed the title Fix wasm List.set refcounted element callbacks Fix wasm dev list mutation and short string concat Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants