Skip to content

Support the wasm32-wasip3 target - #37

Merged
tschneidereit merged 4 commits into
mainfrom
p3
Sep 23, 2026
Merged

tschneidereit merged 4 commits into
mainfrom
p3

Conversation

@tschneidereit

Copy link
Copy Markdown
Member

This is more complicated than I'd like, because with the p3 target, each time an export is called, a new task is created. Since a task is a thread, that means each export runs on its own thread, with its own TLS bucket. Or mozjs fork is already patched to not use TLS internally, emitting statics instead, but we need to do the same in StarlingMonkey as well.

To address this, the new js::instance_local! takes the shape of a thread_local! and expands to one on native targets and to a static on wasm ones. This is used in various places throughout the runtime:

The js crate's own keys are gathered into one JsTls struct behind a single
key, so the crate has one destructor and one declaration order to reason about.

The serve path holds a reference to its runtime for the life of the
instance rather than dropping it from thread-local destruction, which on
wasip3 reaches js thread-locals that may already be gone.

The Justfile gained support for a new WASM_TARGET={p2,p3} env var, defaulting to p2. All wasm-related recipes make use of this env var and work for either target.

P3 support isn't currently stable in Rust, so for that target, a Nightly toolchain is used.

This also includes two other commits that are required to make the included tests pass.

…nkey

We need to export our own `wasi:cli/run` function, and building as a binary means that collides with the one Rust emits.

On native, we of course still need to compile a binary. Somewhat annoyingly, that means that the cdylib needs to have a different name. So the binary target is now named `starlingmonkey`, with `starling` reserved for the cdylib. This results in the native CLI being `starlingmonkey` and the component being `starling.wasm`.

Oh well.
On wasm the monotonic clock is scoped to the instance, so an instance
resumed from a snapshot reads it from zero again while every reading taken
before the snapshot is still in its heap: timer deadlines, `performance`'s
time origin, and SpiderMonkey's GC phase timestamps, which mode 4's barrier
verifier trips a debug assertion on. `platform::clock` records the reading
as the snapshot is made and adds it to every reading a resumed instance
takes, and the first request passes the same offset to the engine through
`js::clock::advance_monotonic_clock`, glue the mozjs fork provides.

Timer deadlines and abort-signal timeouts use `platform::clock::Instant`
instead of `std::time::Instant`. `performance.timeOrigin` keeps its
monotonic half across a resume and re-anchors only the wall-clock half, so
`now()` counts on across the snapshot. The two wasm serve tests that ran
without GC zeal because of the engine's timestamps run with it again.
This is more complicated than I'd like, because with the p3 target, each time an export is called, a new task is created. Since a task is a thread, that means each export runs on its own thread, with its own TLS bucket. Or `mozjs` fork is already patched to not use TLS internally, emitting `static`s instead, but we need to do the same in StarlingMonkey as well.

To address this, the new `js::instance_local!` takes the shape of a `thread_local!` and expands to one on native targets and to a `static` on wasm ones. This is used in various places throughout the runtime:

The `js` crate's own keys are gathered into one `JsTls` struct behind a single
key, so the crate has one destructor and one declaration order to reason about.

The serve path holds a reference to its runtime for the life of the
instance rather than dropping it from thread-local destruction, which on
wasip3 reaches `js` thread-locals that may already be gone.

The `Justfile` gained support for a new `WASM_TARGET={p2,p3}` env var, defaulting to `p2`. All wasm-related recipes make use of this env var and work for either target.

P3 support isn't currently stable in Rust, so for that target, a Nightly toolchain is used.
@tschneidereit
tschneidereit merged commit f04fb86 into main Sep 23, 2026
19 of 20 checks passed
@tschneidereit
tschneidereit deleted the p3 branch September 23, 2026 21:18
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.

1 participant