ReviewOS

zig-utils/zig-js

Roadmap: make WebAssembly native and faster than JSC

#486
Open chris opened this 8 days ago ·
8 days ago

Parent: #459 Depends on: #460, #461, #483

Goal

Make WebAssembly a native, optimizing execution engine that wins every directly comparable accepted JSC row while preserving the complete ten-profile conformance matrix.

Measured boundary

The July 18 SIMD matrix records zig-js at only 0.10–0.14x JSC throughput at eight independent contexts. The current implementation executes fixed-width SIMD through portable architecture-independent code. Threads are correct but contended CAS drops to 0.54x one-worker scaling at eight workers, and wait/notify scaling is irregular.

Child workstreams

  • #487 — native baseline compiler
  • #488 — architecture-native fixed-width/relaxed SIMD
  • #489 — optimizing compiler and memory/call/loop specialization
  • #490 — native shared-memory atomics and wait/notify scaling

Non-negotiable contract

  • Keep the 151,802/151,802 applicable-command ten-profile matrix, zero hidden skips, bit-exact NaN/trap behavior, JS API semantics, streaming compilation, GC/reference types, exceptions, tail calls, multi-memory, memory64, threads, and no-GIL safety.
  • Use only owned Zig code and the #483 backend. WABT/wasm-tools/upstream corpora remain pinned test-data producers/oracles, never runtime/build dependencies.
  • No module/export/source recognition, precomputed benchmark result, skipped bounds/trap/atomic semantics, or JSC-derived implementation.

Completion gate

  • Every child completes its semantic, sanitizer, backend, profile, and evidence gates.
  • Integer, float, shuffle, and memory SIMD rows meet or exceed JSC at one and eight contexts on declared reference hardware.
  • Scalar, call-heavy, allocation/GC, exceptions, memory growth, memory64, multi-memory, and JS↔Wasm boundary rows in #460 also meet their declared gates.
  • Threads/atomics scale according to #490 without weakening the Wasm memory model.
  • Compile/instantiate latency, code bytes, RSS, and cold/warm behavior are published with throughput.
  • All claims come from clean raw artifacts and exact runner/module commits.

Foundation

#141/#142/#264/#283/#284–#288/#305/#366; SIMD publication commits 880e4535 and be438ae0.

8 days ago

#854 / 44c72b15 hardens native Wasm exception externref-root publication with deterministic worst-case O(n log n) exact-bit deduplication. Exec/API exception, moving-GC, concurrent publication, OOM, and no-GIL TSan gates pass. The packed exact-parent suite is byte-identical at 73 files / 18,778 pass / 13 existing fail / 479 skip / 0 crash; no unavailable live exception-corpus claim is made.

8 days ago

Completed the Wasm GC exception-graph identity hardening tracked by #864 in fix(wasm): seed exception collection identity (#864).

Nested and cyclic exnref payload traversal now has securely seeded exact identity, retryable entropy/allocation failure, and mark-before-sweep atomicity without graph caps or a cross-instance mutable epoch. The issue records exact-parent Wasm inventory parity and the complete unit/TSan/ABI evidence.

8 days ago

Completed the Wasm streaming compiler capability boundary tracked by #865 in fix(wasm): harden streaming compiler handles (#865).

Opaque streaming handles are now nonzero secure-entropy capabilities and the exact registry has an independent secure seed. The pinned feed ABI, same-VM ownership, concurrency, finalization, release, and teardown remain exact; packed wg-1.0 output is byte-identical to the parent inventory.

8 days ago

Interpreter-tier throughput, recorded here because it moves the measured boundary above rather than closing any child workstream.

Two commits reserve each activation's operand/local/label capacity once from bounds the validator publishes, instead of re-deriving capacity on every push:

  • 2e46ff2a — validate records per-body operand/control-frame high-water marks; reserveActivation reserves them at call entry. 1.093x geometric mean.
  • 9ce52ff8 — completes that bound (catch-delivery heights, tail-call result arity) so the push loses its capacity check entirely. 1.220x incremental.

Composed, roughly 1.33x over the tree before either. Interleaved exact-parent A/B, 11 alternating samples per workload, 88 rows per side, all checksums identical to the parent; comparing minima gives the same figure.

workloadspeedup (9ce52ff alone)
wasm_integer_simd1.18x
wasm_float_simd1.24x
wasm_memory_simd1.17x
wasm_shuffle_simd1.12x
wasm_integer_scalar1.26x
wasm_float_scalar1.25x
wasm_memory_scalar1.25x
wasm_shuffle_scalar1.29x

This does not substitute for #487–#489: it makes the portable interpreter cheaper, it does not make execution native, and it is measured against zig-js's own parent rather than JSC. The SIMD deficit in the boundary above is a codegen problem, not an interpreter-overhead problem.

One correctness note relevant to this issue's "zero hidden skips" contract: the first version of this work passed 18,778 corpus assertions in ReleaseFast while corrupting the heap on four separate push paths. Debug caught it — the same build aborted 48 times under Debug, because appendAssumeCapacity's capacity assert only exists there. Any future work that pre-reserves execution stacks needs a Debug corpus run to mean anything; a green ReleaseFast sweep does not.

Sign in to comment on this issue.