Browser wasm: feature-detected module variants (relaxed-SIMD) + variant-aware runtime.js #25

Merged
catbot merged 1 commit from claude/issue-24 into master 2026-06-15 17:15:08 +02:00
Member

Summary

Adds a general, feature-parameterized mechanism so a wasm32 browser target can ship multiple codegen variants and have the runtime serve each browser the most capable one it supports — without dropping engines that lack a feature. The motivating case is relaxed SIMD (Chrome 114+/Firefox 120+ enable it by default; Safari still flag-gates it as of mid-2026), but the plumbing is generic.

Both halves are owned in Crafter.Build, as the issue notes:

  • -msimd128 was hardcoded for every wasm32 target (no way to produce a relaxed-SIMD variant or fallback).
  • A single wasm URL was templated into the HTML.

What changed

  • Configuration::wasmVariants declares N codegen variants — each a {label, flags, probes} WasmVariant. Build() produces the baseline outputName.wasm plus one outputName.<label>.wasm per variant, recompiling the whole build graph (incl. dep libs and the std PCM) with the variant's -m flags. Relaxed-SIMD is per-translation-unit codegen, not a link switch, so a full rebuild is the only correct way to produce it. wasmVariantFlags folds into VariantId, so each variant's objects/PCMs land in their own build+bin dir and never clobber the baseline.
  • EnableWasiBrowserRuntime now emits a variants.json manifest (label → url + probes), preferred-first with the baseline (empty probes) as the universal fallback.
  • wasi-runtime/runtime.js runs inlined wasm-feature-detect probes (relaxed-simd, simd, tail-call, bulk-memory, exception-handling, threads — no external dependency), picks the first variant whose probes all pass, and falls back to the single baked CRAFTER_WASM_URL when no manifest is present (backward compatible with existing builds).
  • EnableWasiRelaxedSimdVariant(cfg) registers the relaxed-SIMD variant in one call. Call it before EnableWasiBrowserRuntime so the manifest includes it.

Tests

  • crafter-build test — full suite green (13 passed).

  • New WasmVariants test: variant registration/idempotency, VariantId perturbation, and variants.json contents/ordering.

  • WasiBrowserRuntime test updated for the extra manifest file.

  • End-to-end: built the examples/wasi project with EnableWasiRelaxedSimdVariant for wasm32-wasip1. It emits both wasi-hello.wasm and wasi-hello.relaxed-simd.wasm + variants.json. Loaded in Firefox, the runtime logged:

    [wasi] selected wasm variant 'relaxed-simd' (relaxed-simd)
    Hello, WASI!
    

    confirming the probe-driven selection picks and actually executes the relaxed-SIMD variant.

Resolves #24

🤖 Generated with Claude Code

## Summary Adds a general, feature-parameterized mechanism so a wasm32 browser target can ship multiple codegen variants and have the runtime serve each browser the most capable one it supports — without dropping engines that lack a feature. The motivating case is relaxed SIMD (Chrome 114+/Firefox 120+ enable it by default; Safari still flag-gates it as of mid-2026), but the plumbing is generic. Both halves are owned in Crafter.Build, as the issue notes: - `-msimd128` was hardcoded for every wasm32 target (no way to produce a relaxed-SIMD variant or fallback). - A single wasm URL was templated into the HTML. ## What changed - **`Configuration::wasmVariants`** declares N codegen variants — each a `{label, flags, probes}` `WasmVariant`. `Build()` produces the baseline `outputName.wasm` plus one `outputName.<label>.wasm` per variant, recompiling the whole build graph (incl. dep libs and the std PCM) with the variant's `-m` flags. Relaxed-SIMD is per-translation-unit codegen, not a link switch, so a full rebuild is the only correct way to produce it. `wasmVariantFlags` folds into `VariantId`, so each variant's objects/PCMs land in their own build+bin dir and never clobber the baseline. - **`EnableWasiBrowserRuntime`** now emits a `variants.json` manifest (`label → url + probes`), preferred-first with the baseline (empty probes) as the universal fallback. - **`wasi-runtime/runtime.js`** runs inlined wasm-feature-detect probes (`relaxed-simd`, `simd`, `tail-call`, `bulk-memory`, `exception-handling`, `threads` — no external dependency), picks the first variant whose probes all pass, and falls back to the single baked `CRAFTER_WASM_URL` when no manifest is present (backward compatible with existing builds). - **`EnableWasiRelaxedSimdVariant(cfg)`** registers the relaxed-SIMD variant in one call. Call it before `EnableWasiBrowserRuntime` so the manifest includes it. ## Tests - `crafter-build test` — full suite green (13 passed). - New `WasmVariants` test: variant registration/idempotency, `VariantId` perturbation, and `variants.json` contents/ordering. - `WasiBrowserRuntime` test updated for the extra manifest file. - **End-to-end**: built the `examples/wasi` project with `EnableWasiRelaxedSimdVariant` for `wasm32-wasip1`. It emits both `wasi-hello.wasm` and `wasi-hello.relaxed-simd.wasm` + `variants.json`. Loaded in Firefox, the runtime logged: ``` [wasi] selected wasm variant 'relaxed-simd' (relaxed-simd) Hello, WASI! ``` confirming the probe-driven selection picks and actually executes the relaxed-SIMD variant. Resolves #24 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: feature-detected browser-wasm variants (relaxed-SIMD) + variant-aware runtime
Some checks failed
CI / build-test-release (pull_request) Failing after 7m19s
022ada70a6
The browser wasm pipeline hardcoded -msimd128 for every wasm32 target and
baked a single wasm URL into index.html, so newer codegen features that
aren't yet baseline across engines (relaxed SIMD today; threads, future SIMD
revisions later) couldn't be adopted without dropping the browsers that lack
them.

Add a general, feature-parameterized mechanism owned entirely by
Crafter.Build:

- Configuration::wasmVariants declares N codegen variants (label, extra -m
  flags, runtime probes). Build() compiles the baseline plus one
  outputName.<label>.wasm per variant, recompiling the whole graph (incl.
  dep libs + std PCM) with the variant's flags — relaxed-SIMD is per-TU
  codegen, not a link switch. wasmVariantFlags folds into VariantId so each
  variant's objects/PCMs land in their own build+bin dir.
- EnableWasiBrowserRuntime emits a variants.json manifest (label -> url +
  probes), preferred-first with the baseline as the universal fallback.
- The shipped runtime.js runs inlined wasm-feature-detect probes
  (relaxed-simd, simd, tail-call, bulk-memory, exception-handling, threads),
  picks the first variant whose probes all pass, and falls back to the single
  baked CRAFTER_WASM_URL when no manifest is present (backward compatible).
- EnableWasiRelaxedSimdVariant registers the relaxed-SIMD variant — the
  motivating case (Chrome 114+/Firefox 120+ enable it by default; Safari
  still flag-gates it as of mid-2026).

Verified end to end: a wasm32-wasip1 build emits both wasi-hello.wasm and
wasi-hello.relaxed-simd.wasm + variants.json; Firefox selects the
relaxed-simd variant and runs it.

Resolves #24

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
catbot merged commit 183f053af0 into master 2026-06-15 17:15:08 +02:00
catbot deleted branch claude/issue-24 2026-06-15 17:15:08 +02:00
Sign in to join this conversation.
No description provided.