Skip to content

Commit 92d77bb

Browse files
committed
Add Send/Sync bounds to ComponentType
This commit is extracted from from review of bytecodealliance#11123 and bytecodealliance#11127. While not literally present in those PRs it's my own personal conclusion that it's best to just go ahead and add these bounds at the "base" of the component trait hierarchy. The current implementation in bytecodealliance#11123 adds bounds in many locations and this would remove the need to add bounds everywhere and instead have everything inherited through the `Lift` and `Lower` traits. This raises the question of: why? The main conclusion that I've reached leading to this change is that Wasmtime currently will store `R`, a return value, on the stack during the lowering process back into linear memory. This might involve allocation, however, meaning that wasm can be invoked and a context switch could happen. For Wasmtime's `unsafe impl` of `Send` and `Sync` on fibers to be sound it requires that this stack-local variable is also `Send` and `Sync` as it's an entirely user-provided type. Thus I've concluded that for results it's always required for these to be both `Send` and `Sync` (or at the very least, `Send`). Given that I've gone ahead and updated to require both `Send` and `Sync` for both params and results. This is not expected to actually have any impact in practice since all primitives are already `Send`/`Sync` (minus `Rc` impls all removed here) and all `bindgen!`-generated types are compositions of `Send`/`Sync` primitives meaning that they're also `Send` and `Sync`.
1 parent 57ba95e commit 92d77bb

File tree

2 files changed

+26
-12
lines changed
  • crates/wasmtime/src/runtime/component/func
  • tests/all/component_model

2 files changed

+26
-12
lines changed

crates/wasmtime/src/runtime/component/func/typed.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ pub unsafe trait ComponentNamedList: ComponentType {}
422422
/// [d-cm]: macro@crate::component::ComponentType
423423
/// [f-m]: crate::component::flags
424424
///
425-
/// Rust standard library pointers such as `&T`, `Box<T>`, `Rc<T>`, and `Arc<T>`
425+
/// Rust standard library pointers such as `&T`, `Box<T>`, and `Arc<T>`
426426
/// additionally represent whatever type `T` represents in the component model.
427427
/// Note that types such as `record`, `variant`, `enum`, and `flags` are
428428
/// generated by the embedder at compile time. These macros derive
@@ -464,7 +464,29 @@ pub unsafe trait ComponentNamedList: ComponentType {}
464464
// Also note that this trait specifically is not sealed because we have a proc
465465
// macro that generates implementations of this trait for external types in a
466466
// `#[derive]`-like fashion.
467-
pub unsafe trait ComponentType {
467+
//
468+
// # Send and Sync
469+
//
470+
// While on the topic of safety it's worth discussing the `Send` and `Sync`
471+
// bounds here as well. These bounds might naively seem like they shouldn't be
472+
// required for all component types as they're host-level types not guest-level
473+
// types persisted anywhere. Various subtleties lead to these bounds, however:
474+
//
475+
// * Fibers require that all stack-local variables are `Send` and `Sync` for
476+
// fibers themselves to be send/sync. Unfortunately we have no help from the
477+
// compiler on this one so it's up to Wasmtime's discipline to maintain this.
478+
// One instance of this is that return values are placed on the stack as
479+
// they're lowered into guest memory. This lowering operation can involve
480+
// malloc and context switches, so return values must be Send/Sync.
481+
//
482+
// * In the implementation of component model async it's not uncommon for types
483+
// to be "buffered" in the store temporarily. For example parameters might
484+
// reside in a store temporarily while wasm has backpressure turned on.
485+
//
486+
// Overall it's generally easiest to require `Send` and `Sync` for all
487+
// component types. There additionally aren't known use case for non-`Send` or
488+
// non-`Sync` types at this time.
489+
pub unsafe trait ComponentType: Send + Sync {
468490
/// Representation of the "lowered" form of this component value.
469491
///
470492
/// Lowerings lower into core wasm values which are represented by `ValRaw`.
@@ -710,7 +732,6 @@ macro_rules! forward_type_impls {
710732
forward_type_impls! {
711733
(T: ComponentType + ?Sized) &'_ T => T,
712734
(T: ComponentType + ?Sized) Box<T> => T,
713-
(T: ComponentType + ?Sized) alloc::rc::Rc<T> => T,
714735
(T: ComponentType + ?Sized) alloc::sync::Arc<T> => T,
715736
() String => str,
716737
(T: ComponentType) Vec<T> => [T],
@@ -743,7 +764,6 @@ macro_rules! forward_lowers {
743764
forward_lowers! {
744765
(T: Lower + ?Sized) &'_ T => T,
745766
(T: Lower + ?Sized) Box<T> => T,
746-
(T: Lower + ?Sized) alloc::rc::Rc<T> => T,
747767
(T: Lower + ?Sized) alloc::sync::Arc<T> => T,
748768
() String => str,
749769
(T: Lower) Vec<T> => [T],
@@ -767,7 +787,6 @@ macro_rules! forward_string_lifts {
767787

768788
forward_string_lifts! {
769789
Box<str>,
770-
alloc::rc::Rc<str>,
771790
alloc::sync::Arc<str>,
772791
String,
773792
}
@@ -790,7 +809,6 @@ macro_rules! forward_list_lifts {
790809

791810
forward_list_lifts! {
792811
Box<[T]>,
793-
alloc::rc::Rc<[T]>,
794812
alloc::sync::Arc<[T]>,
795813
Vec<T>,
796814
}

tests/all/component_model/func.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
use super::{REALLOC_AND_FREE, TypedFuncExt};
44
use anyhow::Result;
5-
use std::rc::Rc;
65
use std::sync::Arc;
76
use wasmtime::component::*;
87
use wasmtime::{Engine, Store, StoreContextMut, Trap};
@@ -426,15 +425,12 @@ fn type_layers() -> Result<()> {
426425
instance
427426
.get_typed_func::<(&u32,), ()>(&mut store, "take-u32")?
428427
.call_and_post_return(&mut store, (&2,))?;
429-
instance
430-
.get_typed_func::<(Rc<u32>,), ()>(&mut store, "take-u32")?
431-
.call_and_post_return(&mut store, (Rc::new(2),))?;
432428
instance
433429
.get_typed_func::<(Arc<u32>,), ()>(&mut store, "take-u32")?
434430
.call_and_post_return(&mut store, (Arc::new(2),))?;
435431
instance
436-
.get_typed_func::<(&Box<Arc<Rc<u32>>>,), ()>(&mut store, "take-u32")?
437-
.call_and_post_return(&mut store, (&Box::new(Arc::new(Rc::new(2))),))?;
432+
.get_typed_func::<(&Box<Arc<Box<u32>>>,), ()>(&mut store, "take-u32")?
433+
.call_and_post_return(&mut store, (&Box::new(Arc::new(Box::new(2))),))?;
438434

439435
Ok(())
440436
}

0 commit comments

Comments
 (0)