Skip to content

The browser builds run on every engine: memory64 lowered at link, relaxed SIMD out, the Safari gates gone - #4051

Merged
borisbat merged 1 commit into
masterfrom
bbatkin/wasm-memory64-lowering
Sep 16, 2026
Merged

borisbat merged 1 commit into
masterfrom
bbatkin/wasm-memory64-lowering

Conversation

@borisbat

Copy link
Copy Markdown
Collaborator

behavior change: every compiled browser artifact now runs on Safari and iOS - after the merge the operator runs dasllama-deploy.sh caddy on the dasllama.io box (the vhost's COEP value changes) and roll_toolchain.sh --ref <merge sha> on zen4 (the playground's build host), or Safari visitors keep getting a module they cannot load.

Why. The compiled browser builds were memory64 modules, and WebKit implements neither memory64 nor relaxed SIMD, so on every Mac, iPhone and iPad the dasllama.io examples showed a note and daslang.io's example cards fell back to the interpreter.

What changes.

  • Every final wasm link passes -sMEMORY64=2: the objects and archives keep their 8-byte pointers, Binaryen lowers the memory to 32-bit, and the JS boundary keeps its BigInt pointers.
  • The wasm JIT feature string drops +relaxed-simd, and the codegen version moves so no cached object keeps the old string.
  • dasllama.io's /examples/* sends COEP require-corp, the one value WebKit implements, and the shells load the analytics script with crossorigin.
  • Every memory64 gate is gone: the three dasllama shells, the daslang.io examples page and its service worker, the playground's engine radio and its spec, the node 24 step in pages.yml.
  • dasllama-deploy.sh caddy now replaces the vhost's header /examples/* block when its text differs from the snippet's, where it used to splice only an absent one.
  • Tests: the shell test fails a shell that names memory64, Safari or iPhone, a cross-origin script tag without crossorigin, or a credentialless COEP in the snippet or the preview server; the wasm idot test reads the emitted object's target_features and fails on relaxed-simd. Both sites get a news post.

Observable behavior.

  • Safari on a Mac, any iOS browser: "needs a memory64 browser" -> the storyteller, storywish, parrot and the daslang.io cards run.
  • Chrome and Firefox: unchanged; Pocket TTS on the storywish page reads the same real-time factor without the fused multiply-add.
  • The playground's wasm radio no longer disables itself on WebKit.
  • A lowered module addresses at most 4 GB (2 GB under emscripten's default MAXIMUM_MEMORY).

Where to look. The link line in utils/daspkg/commands.das, link_wasm in src/builtin/module_jit.cpp, wasm_target_features in modules/dasLLVM/daslib/llvm_jit_common.das, and the COEP switch in utils/internal/dasllama-ladder/caddy.snippet.

Validation, claims, ledger

Validation

  • Safari 26.6.2 on this Mac (M5 Max), served locally by site-dasllama/serve.py with require-corp: river_run and storywish run on the lowered, no-relaxed builds (the relaxed build was refused at validation on f32x4.relaxed_max, op 270, function 298). Chrome: river_run, storyteller, storywish and parrot (to the microphone gate) run; storywish maps its image in 17 ms, writes story 1 and reads it (dasLLAMA tts: ... rtf 0.167-0.171), the same figures as the relaxed build - the record is the PERF_LEDGER entry. iOS was not tried.
  • The emitted JS now requires node 22 (it was 23 under true memory64); the lowered dlim_config probe ran under node 25 here. The removed setup-node step gave the runner node 24; ubuntu-latest ships 22, which the module now accepts.
  • daspkg build --wasm then daspkg release wasm for river_run, storyteller, storywish, parrot and dlim_config ran on macOS (emsdk 5.0.7, the libc++ host from web/build_wasm_host.sh), and each artifact's memory is a 32-bit shared import with no relaxed-simd feature.
  • The playground module rail (-exe --jit-target=wasm64-unknown-emscripten --jit-runtime-lib, the C++ link_wasm): fib_loop builds to a 32-bit-memory standalone module and prints under the playground's own WASI shim in node (exit 0).
  • --jit-check-abi was not run on a lowered bundle: the objects and archives keep every 8-byte layout the check reads, and only the memory index width changed.
  • Suites: modules/dasLLVM/tests (green, 177 s), tests/jit_tests/wasm_idot_lowering.das (4 cells, the new target-features cell included) and cross_target_folds.das (green), utils/daspkg/test_daspkg.das (248 green), site-dasllama/test_metadata.py (11 green), examples/dasLLAMA/wasm/test_mint_models.py (green), tests-cpp-small emitter pin (green with the new LLVM_JIT_EMITTER_HASH), lint on the changed .das/.md (0 issues). Negative controls run by the TDD audit: inverting a shell's isolation predicate passes the shell test (the predicate's truth is untested, its text is), re-adding a memory64 probe fails it.
  • dasllama-deploy.sh caddy_apply's reconcile was exercised against a fake Caddyfile with caddy and systemctl stubbed: a differing block is replaced, a matching one left alone, an absent one inserted, the daslang.io vhost untouched; the box itself was not run.
  • site/tests/playground/engine-toggle.spec.js: the six un-skipped tests stub the build service and instantiate no daslang runtime, so the per-PR playground-e2e.yml lane runs them on this PR's head; no local WASM-staged run was made.
  • daslang.io's examples page on Safari through the service worker was not tested locally (it needs the staged _site); the first proof is the deploy.
  • The [arch] citers of the two edited sections of ARCHITECTURE_TARGET_FEATURES.md were audited: wasm_target_features matches sec.12 string for string, and idot_wasm_simd128 / intrinsic_lattice_idot emit no relaxed opcode, so sec.9 still describes them.
  • gc.zgo.at answers access-control-allow-origin: * with no CORP header, so crossorigin on the tag is what lets it load under require-corp.
  • Woodpecker: two rounds (the first tip, and the tip after the deploy-script and test additions), exec traces cover every changed file, no findings.

Claims - stated, not tested

  • storyteller and parrot on Safari: the same shell, link and archives as storywish, which was seen running there; a break would be the SharedArrayBuffer note or a validation error on the page.
  • The examples.html copy on dasllama.io ("any current browser") and both news posts describe the deploy that follows this merge; they were checked against the local builds above, not the deployed site.

Not done

  • The three dasllama shells' gate block (isolation probe, notes, bfcache reload) is now byte-identical across them; the fold into one /files/ script was declined here because it moves the shell test's needles and three shell rules with it - its own change.
  • No WebKit Playwright project: eight of the arc's branches are untested by any lane because the repo runs chromium only; a webkit project in site/tests/playground/playwright.config.js would make engine-toggle.spec.js the distinguishing test.
  • MAXIMUM_MEMORY stays emscripten's 2 GB default for a lowered build; raise it deliberately if a model set outgrows it.
  • The site's Google Fonts and docsearch still fall back on Safari under require-corp until they are self-hosted.
  • The wasm host on zen4 (dasweb-buildd) carries the old link_wasm until the toolchain roll named at the top.

Copilot AI lite review requested due to automatic review settings September 16, 2026 20:59
@borisbat
borisbat force-pushed the bbatkin/wasm-memory64-lowering branch from 45e7f69 to 91bd3e7 Compare September 16, 2026 20:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

site-dasllama/test_metadata.py’s new cross-origin subresource assertion misclassifies same-origin relative URLs as cross-origin, making the test incorrectly fail on valid markup changes.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This PR updates the web/wasm toolchain and both daslang.io + dasllama.io site surfaces so the compiled browser artifacts run on Safari/iOS by linking wasm64 builds with memory lowered to wasm32 at link time (-sMEMORY64=2) and by removing +relaxed-simd, while also aligning cross-origin isolation (COOP/COEP) behavior and removing browser-feature gating.

Changes:

  • Switch wasm64 link paths to -sMEMORY64=2 (keep 8-byte pointers, lower memory to 32-bit at link) and drop +relaxed-simd from the wasm target feature string (plus codegen/cache version bumps).
  • Remove memory64/Safari gating across the playground UI, examples page, service worker, and Playwright tests; update dasllama.io Caddy snippet + deploy script to enforce COEP require-corp.
  • Add/adjust tests and documentation to lock in invariants (no memory64 gates, no relaxed-simd, cross-origin subresources require crossorigin under require-corp).
File summaries
File Description
web/examples/ui/src/main.js Removes memory64 probe gating for enabling the wasm engine; relies on build service availability only.
web/examples/ui/REVIEW.md Updates checklist language for how this UI is deployed/staged and what validation must be stated.
web/CMakeLists.txt Changes wasm64 link flag to -sMEMORY64=2 and documents the “compile=1/link=2” approach.
utils/internal/dasllama-ladder/REVIEW.md Tightens operational rules around Caddy snippet truth + COEP must be require-corp.
utils/internal/dasllama-ladder/README.md Documents why /examples/* needs COOP/COEP and how deploy reconciles the header block.
utils/internal/dasllama-ladder/dasllama-deploy.sh Makes caddy_apply replace /examples/* header block when it differs (not just insert if missing).
utils/internal/dasllama-ladder/caddy.snippet Switches /examples/* COEP from credentialless to require-corp.
utils/daspkg/REVIEW.md Clarifies review requirements for changes on the wasm release path and clarg doc consistency.
utils/daspkg/README.md Updates --wasm description to reflect link-time lowering and broader browser support.
utils/daspkg/commands.das Switches wasm release link flags to -sMEMORY64=2 and updates documentation comments.
tests/jit_tests/wasm_idot_lowering.das Adds a test that inspects emitted object “target_features” to ensure no relaxed-simd and simd128 present.
src/builtin/module_jit.cpp Updates link_wasm to pass -sMEMORY64=2 when targeting wasm64.
skills/daspkg.md Updates daspkg skill docs to describe link-time lowering and removal of relaxed SIMD for WebKit reach.
site/tests/playground/REVIEW.md Adds rule: tests must not skip/branch by browser-engine capability; stub build service instead.
site/tests/playground/engine-toggle.spec.js Removes memory64-based test.skip gates now that artifacts should run on all engines.
site/REVIEW.md Updates review rules for Playwright run statements and sample coverage wording.
site/playground/index.html Removes “memory64-only registration” claim from COI service worker comment.
site/files/examples.js Removes wasm64 detection; switches to “compiled by default, ?force=interp for QA” and renames flags to compiledOnly.
site/examples/_interp.html Updates comment to reflect ?force=interp rather than a required Safari fallback.
site/examples.html Removes “memory64-only registration” claim from COI service worker comment.
site/coi-serviceworker.js Removes memory64 registration gate so /examples and /playground isolate on every engine (with require-corp on WebKit).
site/_news/2026-09-16-the-browser-examples-now-run-on-safari-too.md Adds daslang.io news stub announcing Safari/iOS support for compiled examples.
site-dasllama/test_metadata.py Updates shell invariants (no memory64 gates, isolation probe ordering) and adds COEP/crossorigin checks.
site-dasllama/serve.py Mirrors vhost change: sends COEP require-corp for /examples/ in local preview server.
site-dasllama/REVIEW.md Strengthens rules around not weakening metadata/shell assertions in test_metadata.py.
site-dasllama/examples.html Updates example cards to “any current browser” and replaces wasm64 tags/wording with wasm.
site-dasllama/_news/2026-09-16-every-browser.md Adds dasllama.io news post explaining the change (lowered memory + relaxed SIMD removed).
modules/dasLLVM/REVIEW.md Clarifies review requirements for cross-target branches and feature-set changes.
modules/dasLLVM/daslib/llvm_jit_run.das Updates LLVM_JIT_EMITTER_HASH to match emitter source changes.
modules/dasLLVM/daslib/llvm_jit_plan.das Bumps LLVM_JIT_CODEGEN_VERSION to invalidate cached codegen artifacts after feature-string change.
modules/dasLLVM/daslib/llvm_jit_common.das Drops +relaxed-simd from wasm_target_features().
modules/dasLLVM/ARCHITECTURE_TARGET_FEATURES.md Updates architecture rationale to remove relaxed-simd for WebKit reach and explain consequences.
modules/dasLLAMA/REVIEW.md Minor checklist wording updates (PERF ledger rule and followup naming).
modules/dasLLAMA/PERF_LEDGER.md Adds a landed entry documenting the relaxed-simd removal and reach/perf implications.
examples/REVIEW.md Broadens rule: all files in a folder with web_shell.html answer to dasLLAMA review rules.
examples/dasLLAMA/storywish/web_shell.html Removes memory64 probe; adds crossorigin="anonymous" to analytics script; gates only on isolation.
examples/dasLLAMA/storyteller/web_shell.html Same: remove memory64 gate; add crossorigin="anonymous" to analytics script; isolation-only gating.
examples/dasLLAMA/parrot/web_shell.html Same: remove memory64 gate; add crossorigin="anonymous" to analytics script; isolation-only gating.
examples/dasLLAMA/REVIEW.md Updates browser-example rules (input handling, canvas sizing, and forbids wasm feature probes for gating).
doc/source/reference/utils/daspkg.rst Updates docs for --wasm option to reflect link-time lowering.
CHANGELIST.md Adds an entry describing “Every browser” milestone and the main technical shifts.
.github/workflows/REVIEW.md Clarifies what counts as weakening a per-PR check and notes provisioning steps vs checks.
.github/workflows/pages.yml Removes Node setup step and updates deployment/build comments to match lowered wasm64 behavior.
Review details
  • Files reviewed: 43/43 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread site-dasllama/test_metadata.py
Copilot AI review requested due to automatic review settings September 16, 2026 21:05
@borisbat
borisbat force-pushed the bbatkin/wasm-memory64-lowering branch from 91bd3e7 to cb8d81a Compare September 16, 2026 21:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes the wasm link ABI/feature set and cross-origin isolation behavior across build tooling, runtime linkage, deployment scripts, and both sites, so it needs final human review despite no specific defects found in the reviewed diffs.

Review details
  • Files reviewed: 43/43 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

…axed SIMD out, the Safari gates gone

Every compiled web artifact stays a wasm64 cross-compile inside - host and target pointer
widths match, so the baked layouts stay honest - and now links -sMEMORY64=2: the objects and
archives keep their 8-byte pointers, the JS boundary still passes them as BigInt, and Binaryen
lowers the memory itself to 32-bit, so an engine without memory64 runs the module. WebKit is
that engine, on every Mac, iPhone and iPad. daspkg release wasm, dasLLVM's link_wasm (the
playground's module rail) and the web tree all say so in one place each.

+relaxed-simd leaves the wasm feature string. WebKit implements none of the relaxed opcodes,
and the feature put f32x4.relaxed_max - the backend's lowering of an nnan vector max, which
sec.12 believed it never emitted - into every release, so Safari refused the whole module at
validation once memory64 was out of the way. The one thing the feature bought,
f32x4.relaxed_madd, costs nothing to lose: Pocket TTS on the storywish page reads the same
real-time factor (0.167-0.171) with and without it. The codegen version moves so no cached
object keeps the old string.

The gates that named memory64 are gone: the three dasllama.io shells, the daslang.io examples
page and its coi service worker, the playground's engine radio and its tests, and the node 24
step pages.yml needed only because a true memory64 module refuses node 22. dasllama.io's
/examples/* sends COEP require-corp, the one value WebKit implements; the analytics script,
the only cross-origin subresource, loads with crossorigin since its host allows CORS.
test_metadata.py now fails a shell that names memory64 or Safari. Both sites get a news post.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 16, 2026 21:28
@borisbat
borisbat force-pushed the bbatkin/wasm-memory64-lowering branch from cb8d81a to bf86331 Compare September 16, 2026 21:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

dasllama-deploy.sh’s new examples_block() parsing won’t terminate on indented } lines, which can make the snippet-vs-vhost comparison always differ and force unnecessary rewrites/reloads on every deploy run.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 46/46 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread utils/internal/dasllama-ladder/dasllama-deploy.sh
Comment thread tests/jit_tests/wasm_idot_lowering.das
@borisbat
borisbat merged commit e57e5e7 into master Sep 16, 2026
43 checks passed
@borisbat
borisbat deleted the bbatkin/wasm-memory64-lowering branch September 16, 2026 22:35
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