feat: JSPI test suite for the wasm32-unknown-emscripten target - #8285
Open
guybedford wants to merge 6 commits into
Open
feat: JSPI test suite for the wasm32-unknown-emscripten target#8285guybedford wants to merge 6 commits into
guybedford wants to merge 6 commits into
Conversation
guybedford
force-pushed
the
emscripten-jspi
branch
from
July 15, 2026 19:19
5f0e22c to
eaab129
Compare
Darksonn
reviewed
Jul 16, 2026
guybedford
force-pushed
the
emscripten-jspi
branch
from
July 18, 2026 02:41
eaab129 to
6f1cc4d
Compare
guybedford
force-pushed
the
emscripten-jspi
branch
2 times, most recently
from
July 18, 2026 03:34
6121ff9 to
3258304
Compare
Integrates the #[tokio::test] suite for wasm32-unknown-emscripten using the canonical current_thread scheduler, drivers, and task system on top of JSPI, including the native block_on drive loop. The only platform-specific code is the JSPI park, where inside a JSPI promising wrapper (entered by the #[tokio::test] expansion via the jspi crate's enter_promising) a timed park suspends the whole stack on a host timer while the host event loop runs, so that waits are real. This JSPI suspension path is guarded by an activation wrapper which is only enabled by the test suite currently. Outside an activation, or for a wait nothing could ever wake (no reactor here, and host timers are the only mid-park wake source), the leaf panics with a targeted error instead of deadlocking the host loop. spawn_blocking remains unsupported (no threads). CI runs the contract tests in two lanes: -sJSPI (waits suspend) and without (waits panic).
guybedford
force-pushed
the
emscripten-jspi
branch
from
July 28, 2026 01:53
25e78d4 to
54a7119
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Support the
wasm32-unknown-emscriptenplatform test suite and async timers using JSPI, so that async#[tokio::test]tests run end-to-end.Solution
This extends #8281 (the single-threaded wasm32-unknown-emscripten target) with JavaScript Promise Integration (JSPI)-based suspension.
Under a single-threaded build Emscripten shares the host event loop with JavaScript, so a
block_onthat would have to block panics with a targeted error.With
-sJSPI, blocking can be supported since we can yield to the JS evet loop. To support real work happening in the Tokio test suite,tokio::testnow uses-sJSPIto run real IO in the JS single-threaded mode. The soundness property here is that we ban reentrancy to ensure Rust code invariants are not broken. Even though the JS event loop is able to do real blocking work, the entire Wasm binary is suspended until that blocking work completes, and no new operations are performed while suspended. A debug-only internal guard asserts this non-reentrancy invariant and compiles out in release.The runtime otherwise remains the same - the scheduler, task system, and time driver are unchanged. The Emscripten-specific piece is just the park leaf, handled by an internal
runtime::jspimodule (~100 lines) holding the one suspending__asyncjs__timer import, with JSPI availability detected throughemscripten_has_asyncify() == 2. The scheduler's existingevent_intervalmaintenance park arrives as a zero-duration park and becomes a 0ms host turn, so greedy self-waking tasks cannot starve host timers.Scope is
rt,time,sync,macros,io-util,test-util.fs/io-std(inline blocking, as Emscripten's FS syscalls are synchronous) andnet(epoll, over tokio-rs/mio#1969) are planned follow-ups on top of this base.Tests run in Node.js in two CI lanes:
rt_emscripten_jspi.rsfile.rt_emscripten_block_onverifies fixed-point drives and the targeted would-block panics — 4 passed, 0 failed.