Add async JavaScript API and JSPI support - #6843
Conversation
There was a problem hiding this comment.
Pull request overview
This PR ports async API work into main and extends the wasmer Rust API to support asynchronous module compilation and JSPI-backed async host/guest function calls on the JavaScript backend. It also improves the JS table element polyfills (preserving function types) and adds/adjusts tests to cover these behaviors across native and wasm32 targets.
Changes:
- Add
Module::new_asyncplumbed through backend/module internals, usingWebAssembly.compileon the JS backend. - Implement JSPI-backed async function support for the JS backend (async host functions + async
call_asyncbehavior). - Extend the wasm-types polyfill to translate element sections / table initializers and annotate imported table functions with preserved signatures, with new/updated JS-focused tests.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/api/tests/simple_greenthread.rs | Refactors greenthread test harness to work on native and wasm32; adds task cleanup and wasm-bindgen test coverage. |
| lib/api/tests/module.rs | Adds async module creation test and a JS table initializer type-preservation test. |
| lib/api/tests/jspi_async.rs | Restricts a native-only async test to non-wasm32. |
| lib/api/tests/jspi_async_js.rs | Adds wasm32 JSPI coverage for typed async host/guest calls. |
| lib/api/src/utils/polyfill.rs | Adds element section parsing + init expr support and records table initializers in the polyfill ModuleInfo. |
| lib/api/src/utils/native/typed_func.rs | Enables async typed calls on the JS backend via a JS-specific async path; updates async-backend error message. |
| lib/api/src/entities/module/mod.rs | Introduces public Module::new_async API. |
| lib/api/src/entities/module/inner.rs | Implements backend-aware async module construction, using JS async compilation on wasm32 JS backend. |
| lib/api/src/entities/function/inner.rs | Enables creating async functions on the JS backend and wires JS async calls through. |
| lib/api/src/entities/function/env/inner.rs | Simplifies as_store_async retrieval and adds JS async env variants (JS supported, V8 unsupported). |
| lib/api/src/entities/engine/mod.rs | Extends supports_async to report JS async capability based on JSPI support. |
| lib/api/src/backend/js/vm/function.rs | Annotates JS functions with encoded param/result types for later recovery. |
| lib/api/src/backend/js/mod.rs | Adds the jspi module behind experimental-async. |
| lib/api/src/backend/js/jspi.rs | Implements JSPI detection/wrappers and an active-store TLS registry used during async calls. |
| lib/api/src/backend/js/entities/table.rs | Reads preserved function types from JS function annotations when extracting table elements. |
| lib/api/src/backend/js/entities/module.rs | Adds async JS compilation, stores polyfilled ModuleInfo, and annotates imported table initializer functions. |
| lib/api/src/backend/js/entities/function/typed.rs | Adds JSPI-backed async typed-call plumbing and result conversion helpers. |
| lib/api/src/backend/js/entities/function/mod.rs | Implements JS async host function creation + JSPI-backed async guest calls. |
| lib/api/src/backend/js/entities/function/env.rs | Adds JS async function env types/handles and relaxes Send bounds for JS env accessors. |
| lib/api/Cargo.toml | Adds wasm-bindgen-futures to the JS feature set; adds wasm32 dev-dep on futures. |
| Cargo.lock | Updates lockfile to include wasm-bindgen-futures. |
Suppressed comments (1)
lib/api/tests/module.rs:18
- This test passes a WAT text string to
Module::new_async. On configurations where thewatfeature isn鈥檛 enabled (e.g.--no-default-features --features js-default),Module::new_asyncwon鈥檛 convert WAT to Wasm, so this will fail at runtime. Parse the WAT into Wasm bytes in the test (thewatcrate is already a dev-dependency) before callingnew_async.
let store = Store::default();
let module = Module::new_async(&store, "(module (func (export \"run\")))")
.await
.map_err(|error| format!("{error:?}"))?;
| #[cfg(feature = "js")] | ||
| use wasm_bindgen_test::*; |
| @@ -1,25 +1,76 @@ | |||
| #![cfg(feature = "experimental-async")] | |||
| Symbol::for_("wasmer.function-type") | ||
| } | ||
|
|
||
| fn encode_types(types: &[Type]) -> Array { |
There was a problem hiding this comment.
As Type is annotated with #[repr(u8)], we can use ty as u8 and use the value directly.
| })) | ||
| } | ||
|
|
||
| fn decode_types(types: &Array) -> Option<Vec<Type>> { |
| Ok(()) | ||
| } | ||
|
|
||
| fn parse_init_expr( |
There was a problem hiding this comment.
We should reuse the already existing function parse_serialized_init_expr.
| Ok(module_info) | ||
| } | ||
|
|
||
| fn parse_element_section( |
There was a problem hiding this comment.
The function likely duplicates already existing function wasmer_compiler::translator::sections::parse_element_section.
There was a problem hiding this comment.
I'm actually deleting that in further commits as is not really necessary and we can get by having proper externrefs support
|
As most of the changes are related to |
This PR takes the subset of changes of the
sdkimprovements that only affect the API: