WebAssembly wg-1.0 spec suite (packed runner)
On this page 5
This document describes the self-contained upstream spec runner
(zig build wasm-spec) and its checked-in artifacts. A second, complementary
harness — the live-WABT corpus evaluator (zig build wasm-spec-eval +
tools/wasm-spec.ts) — is documented in wasm.md. Both pin the same
upstream corpus; they differ in how NaN-boundary assertions are scored (see
below).
Pin
- Upstream:
WebAssembly/spectagwg-1.0(pure MVP surface), commit977f97014c962f7bd1291fcc6d28b41a924882bf. - Converter: checksum-pinned WABT 1.0.39
wat2wasmvia Home-executedtools/wasm-spec/gen.ts. The generator normalizes modernized elem/data text forms and packs every binary module intotests/wasm/spec/modules.binwith amanifest.jsondirective index.
The wasm-spec-wg1 submodule is intentionally this frozen MVP fixture, not a
checkout of upstream main. Core 2 and proposal corpora are separate,
exact-pin profiles in the WebAssembly matrix. Stable Core 3 has its
own wasm-spec-wg3 submodule at official tag wg-3.0; #366
tracks its terminal gate. Keeping the baselines separate makes published
command counts reproducible. Newer upstream main snapshots run through the
separate non-release shadow profile, with their own
exact inventories instead of moving either stable gitlink.
Running
zig build wasm-spec # full suite, prints per-file + total
zig build wasm-spec -Dwasm-spec-filter=linking # only matching files
zig build wasm-spec -Dwasm-spec-out=tests/wasm/spec/inventory.json
WASM_SPEC_DIR overrides the artifact directory. For CI compatibility the
step also accepts -Dwasm-spec-inventory=<path> (alias of -Dwasm-spec-out)
and -Dwast2json=<path> (unused — the packed artifacts already embed
converter output, so no converter is needed at run time). The runner
re-executes itself once per .wast file (WASM_SPEC_WORKER=<file>) for crash
isolation: a worker that dies or exceeds the 120 s watchdog is recorded as a
crash entry instead of aborting the inventory. Every directive executes
through the real JavaScript WebAssembly API — no test-only engine hooks.
Current inventory
Checked in at tests/wasm/spec/inventory.json:
| files | pass | fail | skip | crash |
|---|---|---|---|---|
| 73 | 18,791 | 0 | 479 | 0 |
All 479 skips are classified — there are no hidden exclusions:
| count | class | rationale |
|---|---|---|
| 430 | assert_malformed quote/text modules | The wat text format is outside the binary runtime; a binary-only engine cannot express these. |
| 40 | NaN payload/sign expectations | SetToNaN is implementation-defined at the JS Number boundary; the argument's NaN pattern cannot cross the JS API, so the expectation is unobservable. The eval harness in wasm.md scores these exactly through a test-only bit-exact path. |
| 4 | generator rejects | WABT itself cannot parse these generated fragments (data.wast:315, data.wast:323, elem.wast:281, elem.wast:289). |
| 5 | Core 2.0 policy | The engine deliberately implements Core 2.0 semantics (matching V8): transactional-instantiation visibility at linking.wast:236/248/342/354 and br_table polymorphic-bottom typing at unreached-invalid.wast:538. Each is locked by a dedicated exec/validate unit test. |
Error-text aliases
The WebAssembly JS API fixes only the class of each failure
(CompileError/LinkError/RuntimeError); diagnostic text is
implementation-defined. The runner therefore carries a small, explicit alias
table (6 compile-wording and 2 link-wording groups) mapping the reference
interpreter's expected strings onto this engine's deterministic diagnostics;
the error class always matches, and every alias was verified against the
specific directives it unlocks. Notably the 32 "segment does not fit"
directives surface as RuntimeError, matching V8.
Regenerating the artifacts
Only needed when the pin changes:
~/Code/Home/lang/zig-out/bin/home-tool run tools/wasm-spec/fetch.ts /tmp/spec-src /tmp/wabt
~/Code/Home/lang/zig-out/bin/home-tool run tools/wasm-spec/gen.ts \
/tmp/spec-src/test/core tests/wasm/spec /tmp/wabt/bin/wat2wasm
zig build wasm-spec -Dwasm-spec-out=tests/wasm/spec/inventory.json
The fetcher verifies the release SHA-256 before extraction and verifies the
converter reports version 1.0.39. The upstream macOS archive carries a
Homebrew OpenSSL install name; on Pantry-managed hosts the fetcher relocates
that install name to the installed Pantry libcrypto.3.dylib before the
version check.
Commit all three regenerated files (manifest.json, modules.bin,
inventory.json) together. The checked-in artifacts are the source of truth;
CI and local runs never touch the network.