Skip to content

Conversation

@Arshia001
Copy link
Member

Supersedes #5906. WIP as of now.

syrusakbary and others added 27 commits November 18, 2025 17:57
* Add proper trap code for suspending in non-async context
Copilot finished reviewing on behalf of Arshia001 November 26, 2025 23:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces comprehensive support for async execution and concurrent function calls in Wasmer. It implements a JSPI-like (JavaScript Promise Integration) async API that allows WebAssembly functions to suspend and resume execution using coroutines, enabling proper integration with async Rust ecosystems.

Key changes:

  • Adds StoreAsync type and async function APIs (Function::call_async, Function::new_async, etc.)
  • Implements a custom single-threaded LocalRwLock for efficient async-aware locking without atomics
  • Introduces coroutine-based async runtime using corosensei for suspending/resuming WASM execution
  • Adds comprehensive test coverage for async operations and greenthread-style context switching

Reviewed changes

Copilot reviewed 41 out of 42 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lib/api/src/entities/store/async_.rs Defines StoreAsync, AsStoreAsync trait, and async lock types for concurrent store access
lib/api/src/entities/store/local_rwlock.rs Custom single-threaded async-aware RwLock implementation (829 lines with comprehensive tests)
lib/api/src/entities/store/context.rs Thread-local store context stack management for tracking active stores during execution
lib/api/src/backend/sys/async_runtime.rs Coroutine-based async runtime for suspending/resuming WASM functions with host futures
lib/api/src/entities/function/mod.rs Adds call_async, new_async, new_typed_async APIs and related methods
lib/api/src/entities/function/async_host.rs Defines AsyncHostFunction trait and environment wrappers for async imports
lib/api/src/backend/sys/entities/function/mod.rs Core implementation of async function trampolines and host call handling
lib/api/tests/jspi_async.rs Comprehensive async tests including state management, typed functions, and multiple active coroutines
lib/api/tests/simple_greenthread.rs Green thread-style context switching tests with async spawning
lib/types/src/trapcode.rs Adds YieldOutsideAsyncContext trap code for error handling
lib/vm/src/trap/traphandlers.rs Adds Clone derive to VMConfig
tests/wasix/vfork/main.c Replaces function pointer trap with __builtin_trap()
Various documentation files Updates examples to use store.engine() and store.as_mut() patterns

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

self.0.data_and_store_mut()
}

/// Creates an [`AsStoreAsync`] from this [`AsyncFunctionEnvMut`] if the current
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Creates an [`AsStoreAsync`] from this [`AsyncFunctionEnvMut`] if the current
/// Creates an [`AsStoreAsync`] from this [`FunctionEnvMut`] if the current

@zebreus
Copy link
Contributor

zebreus commented Nov 28, 2025

Being able to upgrade a FunctionEnvMut to an AsyncStoreMut is nice, but a bit unwieldy, for example usage like

let (data, mut store) = ctx.data_and_store_mut();
... some sync stuff
let mut async_store = ctx.as_store_async().unwrap();
... do something with the async store

... do more sync stuff with store

does not compile as I can't access ctx while it's still borrowed from data_and_store_mut.

Comment on lines +13 to +14
pub(crate) id: StoreId,
pub(crate) inner: LocalRwLock<StoreInner>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Having these fields acccesible outside of this module makes a safe implementation (and review) of StoreAsync much more complex, as we need to consider all uses to ensure they don't change. Also, it makes it possible to construct new `StoreAsyncs outside this module.

Copy link
Member Author

Choose a reason for hiding this comment

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

A lot of the runtime code does the same thing where, instead of creating a huge number of functions, we just expose a type's internals to the entire crate. I don't see a reason why StoreAsync should be different.

pub(crate) _marker: PhantomData<&'a ()>,
}

impl<'a> AsyncStoreReadLock<'a> {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be named AsyncStoreReadGuard, because that's usually the pattern for the name of guards in RwLock

}
}

pub(crate) enum AsyncStoreReadLockInner {
Copy link
Contributor

Choose a reason for hiding this comment

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

Use either StoreAsync or AsyncStore consistently

impl StoreAsync {
/// Transform this [`StoreAsync`] back into a [`Store`]
/// if this is the only clone of it and is unlocked.
pub fn into_store(self) -> Result<Store, Self> {
Copy link
Contributor

Choose a reason for hiding this comment

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

The opposite is called into_async so I was somehow expecting this to be called into_sync

pub(crate) inner: LocalRwLock<StoreInner>,
}

impl StoreAsync {
Copy link
Contributor

Choose a reason for hiding this comment

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

StoreAsync does not implement Debug, so I can not unwrap the result of into_store.

* make the call_async future 'static
* Eliminate the ugly and now-impossible multiple active coroutines test in favor of the greenthreads test
* Remove lifetime bound on AsyncFunctionEnvHandle and friends, since it's a properly owned type now
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.

4 participants