Skip to content

Use streaming compilation on both Cross-Origin Storage paths - #27609

Merged
tomayac merged 2 commits into
emscripten-core:mainfrom
tomayac:cos-streaming
Aug 25, 2026
Merged

Use streaming compilation on both Cross-Origin Storage paths#27609
tomayac merged 2 commits into
emscripten-core:mainfrom
tomayac:cos-streaming

Conversation

@tomayac

@tomayac tomayac commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #27066. The Cross-Origin Storage integration read the module into an ArrayBuffer on both the cache-hit and cache-miss paths and called WebAssembly.instantiate(), so enabling -sCROSS_ORIGIN_STORAGE lost the download/compile overlap of the standard instantiateStreaming() path. Every first-visit user hit the slower miss path. (Thanks to @reillyeon for spotting this in WICG/cross-origin-storage#74.)

Cache hit: handle.getFile().stream() is wrapped in a Response with an application/wasm content type and passed to instantiateStreaming(). The bytes were hash-verified when written into COS, so the fixed type is safe.

Cache miss: the fetch body is tee()'d. One branch goes to instantiateStreaming() immediately; the other is pipeTo()'d into the COS writable in the background (pipeTo() closes the writable, and COS verifies the hash on close). If the store fails before consuming, the tee branch is cancelled so the body is not buffered indefinitely.

The server's MIME type is deliberately not forwarded on the miss path: the standard path recovers from a bad MIME type by re-downloading, but here the store branch is already consuming the body. A wrong file still fails compilation and falls through to the standard path as before. A non-OK response now throws early rather than being handed to the compiler.

Docs, the custom Module['instantiateWasm'] example, and the ChangeLog are updated to match. No test changes: the existing test_cross_origin_storage_* browser tests exercise both paths and the instrumentation callbacks fire at the same points.

The COS integration added in emscripten-core#27066 read the module into an ArrayBuffer
on both the cache-hit and cache-miss paths and called
WebAssembly.instantiate(), losing the download/compile overlap that the
standard instantiateStreaming() path provides.

Cache hit: wrap File.stream() in a Response with an application/wasm
content type and pass it to instantiateStreaming().

Cache miss: tee() the fetch body so one branch feeds
instantiateStreaming() while the other is piped into COS in the
background. pipeTo() closes the writable, and COS verifies the hash on
close. If the store fails before consuming, the tee branch is cancelled
so the body is not buffered indefinitely.

Also updates the docs and the custom instantiateWasm example to match.
Comment thread src/preamble.js
Comment thread src/preamble.js Outdated
Comment thread ChangeLog.md Outdated
@tomayac
tomayac enabled auto-merge (squash) August 25, 2026 18:30
@tomayac
tomayac merged commit 36feab3 into emscripten-core:main Aug 25, 2026
42 checks passed
@tomayac
tomayac deleted the cos-streaming branch August 25, 2026 21:23
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