diff --git a/Cargo.lock b/Cargo.lock index e1ce6ee89369..7a99ff1f27ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4378,7 +4378,6 @@ dependencies = [ "criterion", "env_logger 0.11.5", "filecheck", - "futures", "gimli", "http", "http-body-util", diff --git a/Cargo.toml b/Cargo.toml index 2ac25f7b1c9b..59af7375b6e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,7 +92,7 @@ rustix = { workspace = true, features = ["mm", "process"] } [dev-dependencies] # depend again on wasmtime to activate its default features for tests -wasmtime = { workspace = true, features = ['default', 'winch', 'pulley', 'all-arch', 'call-hook', 'memory-protection-keys', 'component-model-async'] } +wasmtime = { workspace = true, features = ['default', 'winch', 'pulley', 'all-arch', 'call-hook', 'memory-protection-keys'] } env_logger = { workspace = true } log = { workspace = true } filecheck = { workspace = true } @@ -129,7 +129,6 @@ wasmtime-test-macros = { path = "crates/test-macros" } pulley-interpreter = { workspace = true, features = ["disas"] } wasm-encoder = { workspace = true } cranelift-native = { workspace = true } -futures = { workspace = true } [target.'cfg(windows)'.dev-dependencies] windows-sys = { workspace = true, features = ["Win32_System_Memory"] } @@ -324,7 +323,6 @@ io-extras = "0.18.1" rustix = "1.0.3" # wit-bindgen: wit-bindgen = { version = "0.43.0", default-features = false } -wit-bindgen-rt = { version = "0.43.0", default-features = false } wit-bindgen-rust-macro = { version = "0.43.0", default-features = false } # wasm-tools family: @@ -338,7 +336,6 @@ wasm-mutate = "0.235.0" wit-parser = "0.235.0" wit-component = "0.235.0" wasm-wave = "0.235.0" -wasm-compose = "0.235.0" # Non-Bytecode Alliance maintained dependencies: # -------------------------- @@ -382,7 +379,7 @@ tempfile = "3.1.0" filecheck = "0.5.0" libc = { version = "0.2.112", default-features = true } file-per-thread-logger = "0.2.0" -tokio = { version = "1.43.0", features = [ "rt", "time" ] } +tokio = { version = "1.30.0", features = [ "rt", "time" ] } hyper = "1.0.1" http = "1.0.0" http-body = "1.0.0" diff --git a/crates/c-api/src/component/val.rs b/crates/c-api/src/component/val.rs index c11a7c7b65d5..d25f78b1b0f9 100644 --- a/crates/c-api/src/component/val.rs +++ b/crates/c-api/src/component/val.rs @@ -307,9 +307,6 @@ impl From<&Val> for wasmtime_component_val_t { Val::Result(x) => wasmtime_component_val_t::Result(x.into()), Val::Flags(x) => wasmtime_component_val_t::Flags(x.as_slice().into()), Val::Resource(_resource_any) => todo!(), - Val::Future(_) => todo!(), - Val::Stream(_) => todo!(), - Val::ErrorContext(_) => todo!(), } } } diff --git a/crates/component-macro/tests/expanded/char_concurrent.rs b/crates/component-macro/tests/expanded/char_concurrent.rs index 8cf9326e0d59..cd22e028c176 100644 --- a/crates/component-macro/tests/expanded/char_concurrent.rs +++ b/crates/component-macro/tests/expanded/char_concurrent.rs @@ -342,11 +342,10 @@ pub mod exports { (char,), >::new_unchecked(self.return_char) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/flags_concurrent.rs b/crates/component-macro/tests/expanded/flags_concurrent.rs index fe2d3574b3e8..bf6d6c1ee84d 100644 --- a/crates/component-macro/tests/expanded/flags_concurrent.rs +++ b/crates/component-macro/tests/expanded/flags_concurrent.rs @@ -771,12 +771,10 @@ pub mod exports { (Flag1,), >::new_unchecked(self.roundtrip_flag1) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_roundtrip_flag2( &self, @@ -794,12 +792,10 @@ pub mod exports { (Flag2,), >::new_unchecked(self.roundtrip_flag2) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_roundtrip_flag4( &self, @@ -817,12 +813,10 @@ pub mod exports { (Flag4,), >::new_unchecked(self.roundtrip_flag4) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_roundtrip_flag8( &self, @@ -840,12 +834,10 @@ pub mod exports { (Flag8,), >::new_unchecked(self.roundtrip_flag8) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_roundtrip_flag16( &self, @@ -863,12 +855,10 @@ pub mod exports { (Flag16,), >::new_unchecked(self.roundtrip_flag16) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_roundtrip_flag32( &self, @@ -886,12 +876,10 @@ pub mod exports { (Flag32,), >::new_unchecked(self.roundtrip_flag32) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_roundtrip_flag64( &self, @@ -909,12 +897,10 @@ pub mod exports { (Flag64,), >::new_unchecked(self.roundtrip_flag64) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/floats_concurrent.rs b/crates/component-macro/tests/expanded/floats_concurrent.rs index b7d5d0b51279..7cff1c3a1406 100644 --- a/crates/component-macro/tests/expanded/floats_concurrent.rs +++ b/crates/component-macro/tests/expanded/floats_concurrent.rs @@ -409,11 +409,10 @@ pub mod exports { (f32,), >::new_unchecked(self.f32_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_f64_result( &self, @@ -430,11 +429,10 @@ pub mod exports { (f64,), >::new_unchecked(self.f64_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/integers_concurrent.rs b/crates/component-macro/tests/expanded/integers_concurrent.rs index ccacabc82593..2e8d79f39f06 100644 --- a/crates/component-macro/tests/expanded/integers_concurrent.rs +++ b/crates/component-macro/tests/expanded/integers_concurrent.rs @@ -921,11 +921,10 @@ pub mod exports { (u8,), >::new_unchecked(self.r1) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_r2( &self, @@ -942,11 +941,10 @@ pub mod exports { (i8,), >::new_unchecked(self.r2) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_r3( &self, @@ -963,11 +961,10 @@ pub mod exports { (u16,), >::new_unchecked(self.r3) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_r4( &self, @@ -984,11 +981,10 @@ pub mod exports { (i16,), >::new_unchecked(self.r4) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_r5( &self, @@ -1005,11 +1001,10 @@ pub mod exports { (u32,), >::new_unchecked(self.r5) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_r6( &self, @@ -1026,11 +1021,10 @@ pub mod exports { (i32,), >::new_unchecked(self.r6) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_r7( &self, @@ -1047,11 +1041,10 @@ pub mod exports { (u64,), >::new_unchecked(self.r7) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_r8( &self, @@ -1068,11 +1061,10 @@ pub mod exports { (i64,), >::new_unchecked(self.r8) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_pair_ret( &self, @@ -1089,11 +1081,10 @@ pub mod exports { ((i64, u8),), >::new_unchecked(self.pair_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/lists_concurrent.rs b/crates/component-macro/tests/expanded/lists_concurrent.rs index ea67301f4218..af246a851796 100644 --- a/crates/component-macro/tests/expanded/lists_concurrent.rs +++ b/crates/component-macro/tests/expanded/lists_concurrent.rs @@ -1764,11 +1764,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_u8_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_u16_ret( &self, @@ -1787,11 +1786,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_u16_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_u32_ret( &self, @@ -1810,11 +1808,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_u32_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_u64_ret( &self, @@ -1833,11 +1830,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_u64_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_s8_ret( &self, @@ -1856,11 +1852,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_s8_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_s16_ret( &self, @@ -1879,11 +1874,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_s16_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_s32_ret( &self, @@ -1902,11 +1896,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_s32_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_s64_ret( &self, @@ -1925,11 +1918,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_s64_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_f32_ret( &self, @@ -1948,11 +1940,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_f32_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_list_f64_ret( &self, @@ -1971,11 +1962,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.list_f64_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_tuple_list( &self, @@ -1995,12 +1985,10 @@ pub mod exports { (wasmtime::component::__internal::Vec<(i64, u32)>,), >::new_unchecked(self.tuple_list) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_string_list_arg( &self, @@ -2049,11 +2037,10 @@ pub mod exports { ), >::new_unchecked(self.string_list_ret) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_tuple_string_list( &self, @@ -2085,12 +2072,10 @@ pub mod exports { ), >::new_unchecked(self.tuple_string_list) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_string_list( &self, @@ -2122,12 +2107,10 @@ pub mod exports { ), >::new_unchecked(self.string_list) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_record_list( &self, @@ -2147,12 +2130,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.record_list) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_record_list_reverse( &self, @@ -2172,12 +2153,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.record_list_reverse) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_variant_list( &self, @@ -2197,12 +2176,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.variant_list) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_load_store_everything( &self, @@ -2220,12 +2197,10 @@ pub mod exports { (LoadStoreAllSizes,), >::new_unchecked(self.load_store_everything) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/multi-return.rs b/crates/component-macro/tests/expanded/multi-return.rs index 9414ffa0b4f0..3ef8c1341061 100644 --- a/crates/component-macro/tests/expanded/multi-return.rs +++ b/crates/component-macro/tests/expanded/multi-return.rs @@ -197,17 +197,21 @@ pub mod foo { } pub trait GetHost< T, - >: Fn(T) -> >::Host + Send + Sync + Copy + 'static { + D, + >: Fn(T) -> >::Host + Send + Sync + Copy + 'static { type Host: Host; } - impl GetHost for F + impl GetHost for F where F: Fn(T) -> O + Send + Sync + Copy + 'static, O: Host, { type Host = O; } - pub fn add_to_linker_get_host GetHost<&'a mut T, Host: Host>>( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host>, + >( linker: &mut wasmtime::component::Linker, host_getter: G, ) -> wasmtime::Result<()> { diff --git a/crates/component-macro/tests/expanded/multi-return_async.rs b/crates/component-macro/tests/expanded/multi-return_async.rs index cad8821bf23b..048b5dd2a72d 100644 --- a/crates/component-macro/tests/expanded/multi-return_async.rs +++ b/crates/component-macro/tests/expanded/multi-return_async.rs @@ -205,10 +205,11 @@ pub mod foo { } pub trait GetHost< T, - >: Fn(T) -> >::Host + Send + Sync + Copy + 'static { + D, + >: Fn(T) -> >::Host + Send + Sync + Copy + 'static { type Host: Host + Send; } - impl GetHost for F + impl GetHost for F where F: Fn(T) -> O + Send + Sync + Copy + 'static, O: Host + Send, @@ -217,7 +218,7 @@ pub mod foo { } pub fn add_to_linker_get_host< T, - G: for<'a> GetHost<&'a mut T, Host: Host + Send>, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, >( linker: &mut wasmtime::component::Linker, host_getter: G, diff --git a/crates/component-macro/tests/expanded/multi-return_concurrent.rs b/crates/component-macro/tests/expanded/multi-return_concurrent.rs deleted file mode 100644 index fb578d746454..000000000000 --- a/crates/component-macro/tests/expanded/multi-return_concurrent.rs +++ /dev/null @@ -1,767 +0,0 @@ -/// Auto-generated bindings for a pre-instantiated version of a -/// component which implements the world `the-world`. -/// -/// This structure is created through [`TheWorldPre::new`] which -/// takes a [`InstancePre`](wasmtime::component::InstancePre) that -/// has been created through a [`Linker`](wasmtime::component::Linker). -/// -/// For more information see [`TheWorld`] as well. -pub struct TheWorldPre { - instance_pre: wasmtime::component::InstancePre, - indices: TheWorldIndices, -} -impl Clone for TheWorldPre { - fn clone(&self) -> Self { - Self { - instance_pre: self.instance_pre.clone(), - indices: self.indices.clone(), - } - } -} -impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then - /// be used to instantiate into a particular store. - /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. - pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, - ) -> wasmtime::Result { - let indices = TheWorldIndices::new(instance_pre.component())?; - Ok(Self { instance_pre, indices }) - } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. - /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( - &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let instance = self.instance_pre.instantiate_async(&mut store).await?; - self.indices.load(&mut store, &instance) - } -} -/// Auto-generated bindings for index of the exports of -/// `the-world`. -/// -/// This is an implementation detail of [`TheWorldPre`] and can -/// be constructed if needed as well. -/// -/// For more information see [`TheWorld`] as well. -#[derive(Clone)] -pub struct TheWorldIndices { - interface0: exports::foo::foo::multi_return::GuestIndices, -} -/// Auto-generated bindings for an instance a component which -/// implements the world `the-world`. -/// -/// This structure can be created through a number of means -/// depending on your requirements and what you have on hand: -/// -/// * The most convenient way is to use -/// [`TheWorld::instantiate_async`] which only needs a -/// [`Store`], [`Component`], and [`Linker`]. -/// -/// * Alternatively you can create a [`TheWorldPre`] ahead of -/// time with a [`Component`] to front-load string lookups -/// of exports once instead of per-instantiation. This -/// method then uses [`TheWorldPre::instantiate_async`] to -/// create a [`TheWorld`]. -/// -/// * If you've instantiated the instance yourself already -/// then you can use [`TheWorld::new`]. -/// -/// * You can also access the guts of instantiation through -/// [`TheWorldIndices::new_instance`] followed -/// by [`TheWorldIndices::load`] to crate an instance of this -/// type. -/// -/// These methods are all equivalent to one another and move -/// around the tradeoff of what work is performed when. -/// -/// [`Store`]: wasmtime::Store -/// [`Component`]: wasmtime::component::Component -/// [`Linker`]: wasmtime::component::Linker -pub struct TheWorld { - interface0: exports::foo::foo::multi_return::Guest, -} -const _: () = { - #[allow(unused_imports)] - use wasmtime::component::__internal::anyhow; - impl TheWorldIndices { - /// Creates a new copy of `TheWorldIndices` bindings which can then - /// be used to instantiate into a particular store. - /// - /// This method may fail if the component does not have the - /// required exports. - pub fn new( - component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; - let interface0 = exports::foo::foo::multi_return::GuestIndices::new( - _component, - )?; - Ok(TheWorldIndices { interface0 }) - } - /// Creates a new instance of [`TheWorldIndices`] from an - /// instantiated component. - /// - /// This method of creating a [`TheWorld`] will perform string - /// lookups for all exports when this method is called. This - /// will only succeed if the provided instance matches the - /// requirements of [`TheWorld`]. - pub fn new_instance( - mut store: impl wasmtime::AsContextMut, - instance: &wasmtime::component::Instance, - ) -> wasmtime::Result { - let _instance = instance; - let interface0 = exports::foo::foo::multi_return::GuestIndices::new_instance( - &mut store, - _instance, - )?; - Ok(TheWorldIndices { interface0 }) - } - /// Uses the indices stored in `self` to load an instance - /// of [`TheWorld`] from the instance provided. - /// - /// Note that at this time this method will additionally - /// perform type-checks of all exports. - pub fn load( - &self, - mut store: impl wasmtime::AsContextMut, - instance: &wasmtime::component::Instance, - ) -> wasmtime::Result { - let _instance = instance; - let interface0 = self.interface0.load(&mut store, &_instance)?; - Ok(TheWorld { interface0 }) - } - } - impl TheWorld { - /// Convenience wrapper around [`TheWorldPre::new`] and - /// [`TheWorldPre::instantiate_async`]. - pub async fn instantiate_async<_T>( - mut store: impl wasmtime::AsContextMut, - component: &wasmtime::component::Component, - linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result - where - _T: Send, - { - let pre = linker.instantiate_pre(component)?; - TheWorldPre::new(pre)?.instantiate_async(store).await - } - /// Convenience wrapper around [`TheWorldIndices::new_instance`] and - /// [`TheWorldIndices::load`]. - pub fn new( - mut store: impl wasmtime::AsContextMut, - instance: &wasmtime::component::Instance, - ) -> wasmtime::Result { - let indices = TheWorldIndices::new_instance(&mut store, instance)?; - indices.load(store, instance) - } - pub fn add_to_linker( - linker: &mut wasmtime::component::Linker, - get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, - ) -> wasmtime::Result<()> - where - T: Send + 'static, - U: foo::foo::multi_return::Host + Send, - { - foo::foo::multi_return::add_to_linker(linker, get)?; - Ok(()) - } - pub fn foo_foo_multi_return(&self) -> &exports::foo::foo::multi_return::Guest { - &self.interface0 - } - } -}; -pub mod foo { - pub mod foo { - #[allow(clippy::all)] - pub mod multi_return { - #[allow(unused_imports)] - use wasmtime::component::__internal::{anyhow, Box}; - #[wasmtime::component::__internal::trait_variant_make(::core::marker::Send)] - pub trait Host: Send { - fn mra( - accessor: &mut wasmtime::component::Accessor, - ) -> impl ::core::future::Future + Send + Sync - where - Self: Sized; - fn mrb( - accessor: &mut wasmtime::component::Accessor, - ) -> impl ::core::future::Future + Send + Sync - where - Self: Sized; - fn mrc( - accessor: &mut wasmtime::component::Accessor, - ) -> impl ::core::future::Future + Send + Sync - where - Self: Sized; - fn mrd( - accessor: &mut wasmtime::component::Accessor, - ) -> impl ::core::future::Future + Send + Sync - where - Self: Sized; - fn mre( - accessor: &mut wasmtime::component::Accessor, - ) -> impl ::core::future::Future + Send + Sync - where - Self: Sized; - } - struct State { - host: *mut u8, - store: *mut u8, - spawned: Vec, - } - thread_local! { - static STATE : wasmtime::component::__internal::RefCell < Option < State - >> = wasmtime::component::__internal::RefCell::new(None); - } - struct ResetState(Option); - impl Drop for ResetState { - fn drop(&mut self) { - STATE - .with(|v| { - *v.borrow_mut() = self.0.take(); - }) - } - } - fn get_host_and_store() -> (*mut u8, *mut u8) { - STATE - .with(|v| { - v - .borrow() - .as_ref() - .map(|State { host, store, .. }| (*host, *store)) - }) - .unwrap() - } - fn spawn_task(task: wasmtime::component::__internal::Spawned) { - STATE.with(|v| v.borrow_mut().as_mut().unwrap().spawned.push(task)); - } - fn poll_with_state< - T, - G: for<'a> GetHost<&'a mut T>, - F: wasmtime::component::__internal::Future + ?Sized, - >( - getter: G, - store: wasmtime::VMStoreRawPtr, - cx: &mut wasmtime::component::__internal::Context, - future: wasmtime::component::__internal::Pin<&mut F>, - ) -> wasmtime::component::__internal::Poll { - use wasmtime::component::__internal::{SpawnedInner, mem, DerefMut, Poll}; - let mut store_cx = unsafe { - wasmtime::StoreContextMut::new(&mut *store.0.as_ptr().cast()) - }; - let (result, spawned) = { - let host = &mut getter(store_cx.data_mut()); - let old = STATE - .with(|v| { - v - .replace( - Some(State { - host: (host as *mut G::Host).cast(), - store: store.0.as_ptr().cast(), - spawned: Vec::new(), - }), - ) - }); - let _reset = ResetState(old); - (future.poll(cx), STATE.with(|v| v.take()).unwrap().spawned) - }; - for spawned in spawned { - store_cx - .spawn( - wasmtime::component::__internal::poll_fn(move |cx| { - let mut spawned = spawned.try_lock().unwrap(); - let inner = mem::replace( - DerefMut::deref_mut(&mut spawned), - SpawnedInner::Aborted, - ); - if let SpawnedInner::Unpolled(mut future) - | SpawnedInner::Polled { mut future, .. } = inner { - let result = poll_with_state( - getter, - store, - cx, - future.as_mut(), - ); - *DerefMut::deref_mut(&mut spawned) = SpawnedInner::Polled { - future, - waker: cx.waker().clone(), - }; - result - } else { - Poll::Ready(Ok(())) - } - }), - ) - } - result - } - pub trait GetHost< - T, - >: Fn(T) -> >::Host + Send + Sync + Copy + 'static { - type Host: Host + Send; - } - impl GetHost for F - where - F: Fn(T) -> O + Send + Sync + Copy + 'static, - O: Host + Send, - { - type Host = O; - } - pub fn add_to_linker_get_host< - T, - G: for<'a> GetHost<&'a mut T, Host: Host + Send>, - >( - linker: &mut wasmtime::component::Linker, - host_getter: G, - ) -> wasmtime::Result<()> - where - T: Send + 'static, - { - let mut inst = linker.instance("foo:foo/multi-return")?; - inst.func_wrap_concurrent( - "mra", - move |caller: wasmtime::StoreContextMut<'_, T>, (): ()| { - let mut accessor = unsafe { - wasmtime::component::Accessor::< - T, - _, - >::new(get_host_and_store, spawn_task) - }; - let mut future = wasmtime::component::__internal::Box::pin(async move { - let r = ::mra(&mut accessor).await; - Ok(r) - }); - let store = wasmtime::VMStoreRawPtr(caller.traitobj()); - wasmtime::component::__internal::Box::pin( - wasmtime::component::__internal::poll_fn(move |cx| poll_with_state( - host_getter, - store, - cx, - future.as_mut(), - )), - ) - }, - )?; - inst.func_wrap_concurrent( - "mrb", - move |caller: wasmtime::StoreContextMut<'_, T>, (): ()| { - let mut accessor = unsafe { - wasmtime::component::Accessor::< - T, - _, - >::new(get_host_and_store, spawn_task) - }; - let mut future = wasmtime::component::__internal::Box::pin(async move { - let r = ::mrb(&mut accessor).await; - Ok(r) - }); - let store = wasmtime::VMStoreRawPtr(caller.traitobj()); - wasmtime::component::__internal::Box::pin( - wasmtime::component::__internal::poll_fn(move |cx| poll_with_state( - host_getter, - store, - cx, - future.as_mut(), - )), - ) - }, - )?; - inst.func_wrap_concurrent( - "mrc", - move |caller: wasmtime::StoreContextMut<'_, T>, (): ()| { - let mut accessor = unsafe { - wasmtime::component::Accessor::< - T, - _, - >::new(get_host_and_store, spawn_task) - }; - let mut future = wasmtime::component::__internal::Box::pin(async move { - let r = ::mrc(&mut accessor).await; - Ok((r,)) - }); - let store = wasmtime::VMStoreRawPtr(caller.traitobj()); - wasmtime::component::__internal::Box::pin( - wasmtime::component::__internal::poll_fn(move |cx| poll_with_state( - host_getter, - store, - cx, - future.as_mut(), - )), - ) - }, - )?; - inst.func_wrap_concurrent( - "mrd", - move |caller: wasmtime::StoreContextMut<'_, T>, (): ()| { - let mut accessor = unsafe { - wasmtime::component::Accessor::< - T, - _, - >::new(get_host_and_store, spawn_task) - }; - let mut future = wasmtime::component::__internal::Box::pin(async move { - let r = ::mrd(&mut accessor).await; - Ok((r,)) - }); - let store = wasmtime::VMStoreRawPtr(caller.traitobj()); - wasmtime::component::__internal::Box::pin( - wasmtime::component::__internal::poll_fn(move |cx| poll_with_state( - host_getter, - store, - cx, - future.as_mut(), - )), - ) - }, - )?; - inst.func_wrap_concurrent( - "mre", - move |caller: wasmtime::StoreContextMut<'_, T>, (): ()| { - let mut accessor = unsafe { - wasmtime::component::Accessor::< - T, - _, - >::new(get_host_and_store, spawn_task) - }; - let mut future = wasmtime::component::__internal::Box::pin(async move { - let r = ::mre(&mut accessor).await; - Ok(r) - }); - let store = wasmtime::VMStoreRawPtr(caller.traitobj()); - wasmtime::component::__internal::Box::pin( - wasmtime::component::__internal::poll_fn(move |cx| poll_with_state( - host_getter, - store, - cx, - future.as_mut(), - )), - ) - }, - )?; - Ok(()) - } - pub fn add_to_linker( - linker: &mut wasmtime::component::Linker, - get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, - ) -> wasmtime::Result<()> - where - U: Host + Send, - T: Send + 'static, - { - add_to_linker_get_host(linker, get) - } - impl<_T: Host + Send> Host for &mut _T { - async fn mra( - accessor: &mut wasmtime::component::Accessor, - ) -> () { - struct Task {} - impl wasmtime::component::AccessorTask - for Task { - async fn run( - self, - accessor: &mut wasmtime::component::Accessor, - ) -> () { - ::mra(accessor).await - } - } - accessor.forward(|v| *v, Task {}).await - } - async fn mrb( - accessor: &mut wasmtime::component::Accessor, - ) -> () { - struct Task {} - impl wasmtime::component::AccessorTask - for Task { - async fn run( - self, - accessor: &mut wasmtime::component::Accessor, - ) -> () { - ::mrb(accessor).await - } - } - accessor.forward(|v| *v, Task {}).await - } - async fn mrc( - accessor: &mut wasmtime::component::Accessor, - ) -> u32 { - struct Task {} - impl< - T: 'static, - U: Host, - > wasmtime::component::AccessorTask for Task { - async fn run( - self, - accessor: &mut wasmtime::component::Accessor, - ) -> u32 { - ::mrc(accessor).await - } - } - accessor.forward(|v| *v, Task {}).await - } - async fn mrd( - accessor: &mut wasmtime::component::Accessor, - ) -> u32 { - struct Task {} - impl< - T: 'static, - U: Host, - > wasmtime::component::AccessorTask for Task { - async fn run( - self, - accessor: &mut wasmtime::component::Accessor, - ) -> u32 { - ::mrd(accessor).await - } - } - accessor.forward(|v| *v, Task {}).await - } - async fn mre( - accessor: &mut wasmtime::component::Accessor, - ) -> (u32, f32) { - struct Task {} - impl< - T: 'static, - U: Host, - > wasmtime::component::AccessorTask for Task { - async fn run( - self, - accessor: &mut wasmtime::component::Accessor, - ) -> (u32, f32) { - ::mre(accessor).await - } - } - accessor.forward(|v| *v, Task {}).await - } - } - } - } -} -pub mod exports { - pub mod foo { - pub mod foo { - #[allow(clippy::all)] - pub mod multi_return { - #[allow(unused_imports)] - use wasmtime::component::__internal::{anyhow, Box}; - pub struct Guest { - mra: wasmtime::component::Func, - mrb: wasmtime::component::Func, - mrc: wasmtime::component::Func, - mrd: wasmtime::component::Func, - mre: wasmtime::component::Func, - } - #[derive(Clone)] - pub struct GuestIndices { - mra: wasmtime::component::ComponentExportIndex, - mrb: wasmtime::component::ComponentExportIndex, - mrc: wasmtime::component::ComponentExportIndex, - mrd: wasmtime::component::ComponentExportIndex, - mre: wasmtime::component::ComponentExportIndex, - } - impl GuestIndices { - /// Constructor for [`GuestIndices`] which takes a - /// [`Component`](wasmtime::component::Component) as input and can be executed - /// before instantiation. - /// - /// This constructor can be used to front-load string lookups to find exports - /// within a component. - pub fn new( - component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let (_, instance) = component - .export_index(None, "foo:foo/multi-return") - .ok_or_else(|| { - anyhow::anyhow!( - "no exported instance named `foo:foo/multi-return`" - ) - })?; - Self::_new(|name| { - component.export_index(Some(&instance), name).map(|p| p.1) - }) - } - /// This constructor is similar to [`GuestIndices::new`] except that it - /// performs string lookups after instantiation time. - pub fn new_instance( - mut store: impl wasmtime::AsContextMut, - instance: &wasmtime::component::Instance, - ) -> wasmtime::Result { - let instance_export = instance - .get_export(&mut store, None, "foo:foo/multi-return") - .ok_or_else(|| { - anyhow::anyhow!( - "no exported instance named `foo:foo/multi-return`" - ) - })?; - Self::_new(|name| { - instance.get_export(&mut store, Some(&instance_export), name) - }) - } - fn _new( - mut lookup: impl FnMut( - &str, - ) -> Option, - ) -> wasmtime::Result { - let mut lookup = move |name| { - lookup(name) - .ok_or_else(|| { - anyhow::anyhow!( - "instance export `foo:foo/multi-return` does \ - not have export `{name}`" - ) - }) - }; - let _ = &mut lookup; - let mra = lookup("mra")?; - let mrb = lookup("mrb")?; - let mrc = lookup("mrc")?; - let mrd = lookup("mrd")?; - let mre = lookup("mre")?; - Ok(GuestIndices { - mra, - mrb, - mrc, - mrd, - mre, - }) - } - pub fn load( - &self, - mut store: impl wasmtime::AsContextMut, - instance: &wasmtime::component::Instance, - ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _ = &mut store; - let _instance = instance; - let mra = *_instance - .get_typed_func::<(), ()>(&mut store, &self.mra)? - .func(); - let mrb = *_instance - .get_typed_func::<(), ()>(&mut store, &self.mrb)? - .func(); - let mrc = *_instance - .get_typed_func::<(), (u32,)>(&mut store, &self.mrc)? - .func(); - let mrd = *_instance - .get_typed_func::<(), (u32,)>(&mut store, &self.mrd)? - .func(); - let mre = *_instance - .get_typed_func::<(), (u32, f32)>(&mut store, &self.mre)? - .func(); - Ok(Guest { mra, mrb, mrc, mrd, mre }) - } - } - impl Guest { - pub async fn call_mra( - &self, - mut store: S, - ) -> wasmtime::Result> - where - ::Data: Send, - { - let callee = unsafe { - wasmtime::component::TypedFunc::< - (), - (), - >::new_unchecked(self.mra) - }; - let promise = callee - .call_concurrent(store.as_context_mut(), ()) - .await?; - Ok(promise) - } - pub async fn call_mrb( - &self, - mut store: S, - ) -> wasmtime::Result> - where - ::Data: Send, - { - let callee = unsafe { - wasmtime::component::TypedFunc::< - (), - (), - >::new_unchecked(self.mrb) - }; - let promise = callee - .call_concurrent(store.as_context_mut(), ()) - .await?; - Ok(promise) - } - pub async fn call_mrc( - &self, - mut store: S, - ) -> wasmtime::Result> - where - ::Data: Send, - { - let callee = unsafe { - wasmtime::component::TypedFunc::< - (), - (u32,), - >::new_unchecked(self.mrc) - }; - let promise = callee - .call_concurrent(store.as_context_mut(), ()) - .await?; - Ok(promise.map(|(v,)| v)) - } - pub async fn call_mrd( - &self, - mut store: S, - ) -> wasmtime::Result> - where - ::Data: Send, - { - let callee = unsafe { - wasmtime::component::TypedFunc::< - (), - (u32,), - >::new_unchecked(self.mrd) - }; - let promise = callee - .call_concurrent(store.as_context_mut(), ()) - .await?; - Ok(promise.map(|(v,)| v)) - } - pub async fn call_mre( - &self, - mut store: S, - ) -> wasmtime::Result> - where - ::Data: Send, - { - let callee = unsafe { - wasmtime::component::TypedFunc::< - (), - (u32, f32), - >::new_unchecked(self.mre) - }; - let promise = callee - .call_concurrent(store.as_context_mut(), ()) - .await?; - Ok(promise) - } - } - } - } - } -} diff --git a/crates/component-macro/tests/expanded/multi-return_tracing_async.rs b/crates/component-macro/tests/expanded/multi-return_tracing_async.rs index 5f667313aa33..aa0f428f6ea9 100644 --- a/crates/component-macro/tests/expanded/multi-return_tracing_async.rs +++ b/crates/component-macro/tests/expanded/multi-return_tracing_async.rs @@ -205,10 +205,11 @@ pub mod foo { } pub trait GetHost< T, - >: Fn(T) -> >::Host + Send + Sync + Copy + 'static { + D, + >: Fn(T) -> >::Host + Send + Sync + Copy + 'static { type Host: Host + Send; } - impl GetHost for F + impl GetHost for F where F: Fn(T) -> O + Send + Sync + Copy + 'static, O: Host + Send, @@ -217,7 +218,7 @@ pub mod foo { } pub fn add_to_linker_get_host< T, - G: for<'a> GetHost<&'a mut T, Host: Host + Send>, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, >( linker: &mut wasmtime::component::Linker, host_getter: G, diff --git a/crates/component-macro/tests/expanded/records_concurrent.rs b/crates/component-macro/tests/expanded/records_concurrent.rs index ede803246a57..a8cc4cae1d0a 100644 --- a/crates/component-macro/tests/expanded/records_concurrent.rs +++ b/crates/component-macro/tests/expanded/records_concurrent.rs @@ -942,11 +942,10 @@ pub mod exports { ((char, u32),), >::new_unchecked(self.tuple_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_empty_arg( &self, @@ -981,11 +980,10 @@ pub mod exports { (Empty,), >::new_unchecked(self.empty_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_scalar_arg( &self, @@ -1020,11 +1018,10 @@ pub mod exports { (Scalars,), >::new_unchecked(self.scalar_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_flags_arg( &self, @@ -1059,11 +1056,10 @@ pub mod exports { (ReallyFlags,), >::new_unchecked(self.flags_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_aggregate_arg( &self, @@ -1098,11 +1094,10 @@ pub mod exports { (Aggregates,), >::new_unchecked(self.aggregate_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_typedef_inout( &self, @@ -1120,12 +1115,10 @@ pub mod exports { (i32,), >::new_unchecked(self.typedef_inout) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/resources-export_concurrent.rs b/crates/component-macro/tests/expanded/resources-export_concurrent.rs index cf698b092680..becc796fd58a 100644 --- a/crates/component-macro/tests/expanded/resources-export_concurrent.rs +++ b/crates/component-macro/tests/expanded/resources-export_concurrent.rs @@ -382,11 +382,10 @@ pub mod exports { (wasmtime::component::ResourceAny,), >::new_unchecked(self.funcs.constructor_a_constructor) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_static_a( &self, @@ -403,11 +402,10 @@ pub mod exports { (u32,), >::new_unchecked(self.funcs.static_a_static_a) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_method_a( &self, @@ -425,12 +423,10 @@ pub mod exports { (u32,), >::new_unchecked(self.funcs.method_a_method_a) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } } } @@ -479,7 +475,7 @@ pub mod exports { .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-import` does \ - not have export `{name}`" + not have export `{name}`" ) }) }; @@ -553,12 +549,10 @@ pub mod exports { (wasmtime::component::ResourceAny,), >::new_unchecked(self.funcs.constructor_a_constructor) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } pub fn call_static_a( &self, @@ -575,11 +569,10 @@ pub mod exports { (wasmtime::component::Resource,), >::new_unchecked(self.funcs.static_a_static_a) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_method_a( &self, @@ -601,12 +594,10 @@ pub mod exports { (wasmtime::component::Resource,), >::new_unchecked(self.funcs.method_a_method_a) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0, arg1)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0, arg1)), + |v| v.map(|(v,)| v), + ) } } } @@ -650,7 +641,7 @@ pub mod exports { .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-export1` does \ - not have export `{name}`" + not have export `{name}`" ) }) }; @@ -700,11 +691,10 @@ pub mod exports { (wasmtime::component::ResourceAny,), >::new_unchecked(self.funcs.constructor_a_constructor) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } } } @@ -749,7 +739,7 @@ pub mod exports { .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-export2` does \ - not have export `{name}`" + not have export `{name}`" ) }) }; @@ -800,12 +790,10 @@ pub mod exports { (wasmtime::component::ResourceAny,), >::new_unchecked(self.funcs.constructor_b_constructor) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/resources-import_concurrent.rs b/crates/component-macro/tests/expanded/resources-import_concurrent.rs index b8cb429a1245..21e05f152afc 100644 --- a/crates/component-macro/tests/expanded/resources-import_concurrent.rs +++ b/crates/component-macro/tests/expanded/resources-import_concurrent.rs @@ -371,11 +371,10 @@ const _: () = { (wasmtime::component::Resource,), >::new_unchecked(self.some_world_func2) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn foo_foo_uses_resource_transitively( &self, @@ -1168,7 +1167,7 @@ pub mod exports { .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/uses-resource-transitively` does \ - not have export `{name}`" + not have export `{name}`" ) }) }; diff --git a/crates/component-macro/tests/expanded/share-types_concurrent.rs b/crates/component-macro/tests/expanded/share-types_concurrent.rs index af813d784dd9..955c1dc55f56 100644 --- a/crates/component-macro/tests/expanded/share-types_concurrent.rs +++ b/crates/component-macro/tests/expanded/share-types_concurrent.rs @@ -368,11 +368,10 @@ pub mod exports { (Response,), >::new_unchecked(self.handle_request) }; - let future = callee.call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/simple-functions_concurrent.rs b/crates/component-macro/tests/expanded/simple-functions_concurrent.rs index 9810222f22d6..c9cc0b5c7efd 100644 --- a/crates/component-macro/tests/expanded/simple-functions_concurrent.rs +++ b/crates/component-macro/tests/expanded/simple-functions_concurrent.rs @@ -476,11 +476,10 @@ pub mod exports { (u32,), >::new_unchecked(self.f4) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_f5( &self, @@ -497,11 +496,10 @@ pub mod exports { ((u32, u32),), >::new_unchecked(self.f5) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_f6( &self, @@ -521,12 +519,14 @@ pub mod exports { ((u32, u32, u32),), >::new_unchecked(self.f6) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0, arg1, arg2)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee + .call_concurrent( + store.as_context_mut(), + (arg0, arg1, arg2), + ), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/simple-lists_concurrent.rs b/crates/component-macro/tests/expanded/simple-lists_concurrent.rs index 95f8471f1c3d..cd3350cee4f3 100644 --- a/crates/component-macro/tests/expanded/simple-lists_concurrent.rs +++ b/crates/component-macro/tests/expanded/simple-lists_concurrent.rs @@ -449,11 +449,10 @@ pub mod exports { (wasmtime::component::__internal::Vec,), >::new_unchecked(self.simple_list2) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_simple_list3( &self, @@ -485,12 +484,10 @@ pub mod exports { ), >::new_unchecked(self.simple_list3) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0, arg1)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0, arg1)), + |v| v.map(|(v,)| v), + ) } pub fn call_simple_list4( &self, @@ -522,12 +519,10 @@ pub mod exports { ), >::new_unchecked(self.simple_list4) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0,)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0,)), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/small-anonymous_concurrent.rs b/crates/component-macro/tests/expanded/small-anonymous_concurrent.rs index 9787c271ef7e..157973786b61 100644 --- a/crates/component-macro/tests/expanded/small-anonymous_concurrent.rs +++ b/crates/component-macro/tests/expanded/small-anonymous_concurrent.rs @@ -409,11 +409,10 @@ pub mod exports { ), >::new_unchecked(self.option_test) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/strings_concurrent.rs b/crates/component-macro/tests/expanded/strings_concurrent.rs index f81500004779..2a1d6c81bc93 100644 --- a/crates/component-macro/tests/expanded/strings_concurrent.rs +++ b/crates/component-macro/tests/expanded/strings_concurrent.rs @@ -377,11 +377,10 @@ pub mod exports { (wasmtime::component::__internal::String,), >::new_unchecked(self.b) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_c( &self, @@ -405,12 +404,10 @@ pub mod exports { (wasmtime::component::__internal::String,), >::new_unchecked(self.c) }; - let future = callee - .call_concurrent(store.as_context_mut(), (arg0, arg1)); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), (arg0, arg1)), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/variants_concurrent.rs b/crates/component-macro/tests/expanded/variants_concurrent.rs index dd697e8ddbc6..c25a2cf1600f 100644 --- a/crates/component-macro/tests/expanded/variants_concurrent.rs +++ b/crates/component-macro/tests/expanded/variants_concurrent.rs @@ -1586,11 +1586,10 @@ pub mod exports { (E1,), >::new_unchecked(self.e1_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_v1_arg( &self, @@ -1625,11 +1624,10 @@ pub mod exports { (V1,), >::new_unchecked(self.v1_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_bool_arg( &self, @@ -1664,11 +1662,10 @@ pub mod exports { (bool,), >::new_unchecked(self.bool_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_option_arg( &self, @@ -1737,11 +1734,10 @@ pub mod exports { ), >::new_unchecked(self.option_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_casts( &self, @@ -1766,15 +1762,14 @@ pub mod exports { ((Casts1, Casts2, Casts3, Casts4, Casts5, Casts6),), >::new_unchecked(self.casts) }; - let future = callee - .call_concurrent( - store.as_context_mut(), - (arg0, arg1, arg2, arg3, arg4, arg5), - ); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee + .call_concurrent( + store.as_context_mut(), + (arg0, arg1, arg2, arg3, arg4, arg5), + ), + |v| v.map(|(v,)| v), + ) } pub fn call_result_arg( &self, @@ -1855,11 +1850,10 @@ pub mod exports { ), >::new_unchecked(self.result_result) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_return_result_sugar( &self, @@ -1876,11 +1870,10 @@ pub mod exports { (Result,), >::new_unchecked(self.return_result_sugar) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_return_result_sugar2( &self, @@ -1897,11 +1890,10 @@ pub mod exports { (Result<(), MyErrno>,), >::new_unchecked(self.return_result_sugar2) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_return_result_sugar3( &self, @@ -1918,11 +1910,10 @@ pub mod exports { (Result,), >::new_unchecked(self.return_result_sugar3) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_return_result_sugar4( &self, @@ -1939,11 +1930,10 @@ pub mod exports { (Result<(i32, u32), MyErrno>,), >::new_unchecked(self.return_result_sugar4) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_return_option_sugar( &self, @@ -1960,11 +1950,10 @@ pub mod exports { (Option,), >::new_unchecked(self.return_option_sugar) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_return_option_sugar2( &self, @@ -1981,11 +1970,10 @@ pub mod exports { (Option,), >::new_unchecked(self.return_option_sugar2) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_result_simple( &self, @@ -2002,11 +1990,10 @@ pub mod exports { (Result,), >::new_unchecked(self.result_simple) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } pub fn call_is_clone_arg( &self, @@ -2041,11 +2028,10 @@ pub mod exports { (IsClone,), >::new_unchecked(self.is_clone_return) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } } } diff --git a/crates/component-macro/tests/expanded/worlds-with-types_concurrent.rs b/crates/component-macro/tests/expanded/worlds-with-types_concurrent.rs index c98265405a98..d3999daf1ae1 100644 --- a/crates/component-macro/tests/expanded/worlds-with-types_concurrent.rs +++ b/crates/component-macro/tests/expanded/worlds-with-types_concurrent.rs @@ -215,11 +215,10 @@ const _: () = { let callee = unsafe { wasmtime::component::TypedFunc::<(), ((T, U, R),)>::new_unchecked(self.f) }; - let future = callee.call_concurrent(store.as_context_mut(), ()); - async move { - let (ret0,) = future.await?; - Ok(ret0) - } + wasmtime::component::__internal::FutureExt::map( + callee.call_concurrent(store.as_context_mut(), ()), + |v| v.map(|(v,)| v), + ) } } }; diff --git a/crates/environ/src/component.rs b/crates/environ/src/component.rs index cb0f4be780cb..673abb68c30e 100644 --- a/crates/environ/src/component.rs +++ b/crates/environ/src/component.rs @@ -124,7 +124,7 @@ macro_rules! foreach_builtin_component_function { string_encoding: u32, result_count_or_max_if_async: u32, storage: ptr_u8, - storage_len: size + torage_len: size ) -> bool; #[cfg(feature = "component-model-async")] sync_start(vmctx: vmctx, callback: ptr_u8, callee: ptr_u8, param_count: u32, storage: ptr_u8, storage_len: size) -> bool; diff --git a/crates/environ/src/component/info.rs b/crates/environ/src/component/info.rs index 91784b7045ad..6fb536cce366 100644 --- a/crates/environ/src/component/info.rs +++ b/crates/environ/src/component/info.rs @@ -856,14 +856,14 @@ pub enum Trampoline { async_: bool, }, - /// A `stream.drop-readable` intrinsic to drop the readable end of a + /// A `stream.drop-readable` intrinsic to close the readable end of a /// `stream` of the specified type. StreamDropReadable { /// The table index for the specific `stream` type and caller instance. ty: TypeStreamTableIndex, }, - /// A `stream.drop-writable` intrinsic to drop the writable end of a + /// A `stream.drop-writable` intrinsic to close the writable end of a /// `stream` of the specified type. StreamDropWritable { /// The table index for the specific `stream` type and caller instance. @@ -917,14 +917,14 @@ pub enum Trampoline { async_: bool, }, - /// A `future.drop-readable` intrinsic to drop the readable end of a + /// A `future.drop-readable` intrinsic to close the readable end of a /// `future` of the specified type. FutureDropReadable { /// The table index for the specific `future` type and caller instance. ty: TypeFutureTableIndex, }, - /// A `future.drop-writable` intrinsic to drop the writable end of a + /// A `future.drop-writable` intrinsic to close the writable end of a /// `future` of the specified type. FutureDropWritable { /// The table index for the specific `future` type and caller instance. @@ -1081,15 +1081,15 @@ impl Trampoline { StreamWrite { .. } => format!("stream-write"), StreamCancelRead { .. } => format!("stream-cancel-read"), StreamCancelWrite { .. } => format!("stream-cancel-write"), - StreamDropReadable { .. } => format!("stream-drop-readable"), - StreamDropWritable { .. } => format!("stream-drop-writable"), + StreamDropReadable { .. } => format!("stream.drop-readable"), + StreamDropWritable { .. } => format!("stream.drop-writable"), FutureNew { .. } => format!("future-new"), FutureRead { .. } => format!("future-read"), FutureWrite { .. } => format!("future-write"), FutureCancelRead { .. } => format!("future-cancel-read"), FutureCancelWrite { .. } => format!("future-cancel-write"), - FutureDropReadable { .. } => format!("future-drop-readable"), - FutureDropWritable { .. } => format!("future-drop-writable"), + FutureDropReadable { .. } => format!("future.drop-readable"), + FutureDropWritable { .. } => format!("future.drop-writable"), ErrorContextNew { .. } => format!("error-context-new"), ErrorContextDebugMessage { .. } => format!("error-context-debug-message"), ErrorContextDrop { .. } => format!("error-context-drop"), diff --git a/crates/fuzzing/src/generators/component_types.rs b/crates/fuzzing/src/generators/component_types.rs index 045bebd1851f..0fef1296a7d7 100644 --- a/crates/fuzzing/src/generators/component_types.rs +++ b/crates/fuzzing/src/generators/component_types.rs @@ -108,10 +108,8 @@ pub fn arbitrary_val(ty: &component::Type, input: &mut Unstructured) -> arbitrar .collect::>()?, ), - // Resources, futures, streams, and error contexts aren't fuzzed at this time. - Type::Own(_) | Type::Borrow(_) | Type::Future(_) | Type::Stream(_) | Type::ErrorContext => { - unreachable!() - } + // Resources aren't fuzzed at this time. + Type::Own(_) | Type::Borrow(_) => unreachable!(), }) } @@ -122,26 +120,8 @@ pub fn static_api_test<'a, P, R>( declarations: &Declarations, ) -> arbitrary::Result<()> where - P: ComponentNamedList - + Lift - + Lower - + Clone - + PartialEq - + Debug - + Arbitrary<'a> - + Send - + Sync - + 'static, - R: ComponentNamedList - + Lift - + Lower - + Clone - + PartialEq - + Debug - + Arbitrary<'a> - + Send - + Sync - + 'static, + P: ComponentNamedList + Lift + Lower + Clone + PartialEq + Debug + Arbitrary<'a> + 'static, + R: ComponentNamedList + Lift + Lower + Clone + PartialEq + Debug + Arbitrary<'a> + 'static, { crate::init_fuzzing(); @@ -158,7 +138,7 @@ where .root() .func_wrap( IMPORT_FUNCTION, - |cx: StoreContextMut<'_, Box>, params: P| { + |cx: StoreContextMut<'_, Box>, params: P| { log::trace!("received parameters {params:?}"); let data: &(P, R) = cx.data().downcast_ref().unwrap(); let (expected_params, result) = data; @@ -168,7 +148,7 @@ where }, ) .unwrap(); - let mut store: Store> = Store::new(&engine, Box::new(())); + let mut store: Store> = Store::new(&engine, Box::new(())); let instance = linker.instantiate(&mut store, &component).unwrap(); let func = instance .get_typed_func::(&mut store, EXPORT_FUNCTION) diff --git a/crates/fuzzing/src/oracles.rs b/crates/fuzzing/src/oracles.rs index 5caa9446aaf6..9e868d3ab93a 100644 --- a/crates/fuzzing/src/oracles.rs +++ b/crates/fuzzing/src/oracles.rs @@ -702,13 +702,12 @@ pub fn wast_test(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<()> { let mut fuzz_config: generators::Config = u.arbitrary()?; let test: generators::WastTest = u.arbitrary()?; - - let test = &test.test; - - if test.config.component_model_async() || u.arbitrary()? { + if u.arbitrary()? { fuzz_config.enable_async(u)?; } + let test = &test.test; + // Discard tests that allocate a lot of memory as we don't want to OOM the // fuzzer and we also limit memory growth which would cause the test to // fail. diff --git a/crates/test-util/src/component.rs b/crates/test-util/src/component.rs index 733854451547..ba991e23c936 100644 --- a/crates/test-util/src/component.rs +++ b/crates/test-util/src/component.rs @@ -8,19 +8,15 @@ use wasmtime::component::{ComponentNamedList, ComponentType, Func, Lift, Lower, use wasmtime::{AsContextMut, Config, Engine}; pub trait TypedFuncExt { - fn call_and_post_return(&self, store: impl AsContextMut, params: P) -> Result; + fn call_and_post_return(&self, store: impl AsContextMut, params: P) -> Result; } impl TypedFuncExt for TypedFunc where P: ComponentNamedList + Lower, - R: ComponentNamedList + Lift + Send + Sync + 'static, + R: ComponentNamedList + Lift, { - fn call_and_post_return( - &self, - mut store: impl AsContextMut, - params: P, - ) -> Result { + fn call_and_post_return(&self, mut store: impl AsContextMut, params: P) -> Result { let result = self.call(&mut store, params)?; self.post_return(&mut store)?; Ok(result) @@ -30,7 +26,7 @@ where pub trait FuncExt { fn call_and_post_return( &self, - store: impl AsContextMut, + store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()>; @@ -39,7 +35,7 @@ pub trait FuncExt { impl FuncExt for Func { fn call_and_post_return( &self, - mut store: impl AsContextMut, + mut store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()> { diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index dd3d9c44e31f..88f0b80b1eef 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -391,4 +391,5 @@ component-model-async = [ "component-model", "std", "wasmtime-component-macro?/component-model-async", + "dep:futures" ] diff --git a/crates/wasmtime/src/runtime/component/concurrent.rs b/crates/wasmtime/src/runtime/component/concurrent.rs index 8252d7b70946..b6c0bc044f6f 100644 --- a/crates/wasmtime/src/runtime/component/concurrent.rs +++ b/crates/wasmtime/src/runtime/component/concurrent.rs @@ -1,131 +1,88 @@ -use crate::component::{Component, Func, HasData, HasSelf, Instance}; -use crate::store::{StoreInner, StoreOpaque}; -use crate::vm::{VMFuncRef, VMMemoryDefinition, VMStore, component::ComponentInstance}; -use crate::{AsContextMut, StoreContextMut, ValRaw}; -use anyhow::Result; -use std::any::Any; -use std::boxed::Box; -use std::future::Future; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::pin::{Pin, pin}; -use std::task::{Context, Poll, Waker}; -use wasmtime_environ::component::{ - RuntimeComponentInstanceIndex, TypeComponentLocalErrorContextTableIndex, TypeFutureTableIndex, - TypeStreamTableIndex, TypeTupleIndex, +use { + crate::{ + AsContextMut, ValRaw, + component::{HasData, HasSelf, Instance}, + store::StoreInner, + vm::{VMFuncRef, VMMemoryDefinition, VMStore, component::ComponentInstance}, + }, + anyhow::Result, + futures::{FutureExt, stream::FuturesUnordered}, + std::{boxed::Box, future::Future, mem::MaybeUninit, pin::Pin}, + wasmtime_environ::component::{ + RuntimeComponentInstanceIndex, TypeComponentLocalErrorContextTableIndex, + TypeFutureTableIndex, TypeStreamTableIndex, TypeTupleIndex, + }, }; pub(crate) use futures_and_streams::ResourcePair; -pub use futures_and_streams::{ - ErrorContext, FutureReader, FutureWriter, HostFuture, HostStream, StreamReader, StreamWriter, -}; -pub(crate) use futures_and_streams::{ - lower_error_context_to_index, lower_future_to_index, lower_stream_to_index, -}; +pub use futures_and_streams::{ErrorContext, FutureReader, StreamReader}; mod futures_and_streams; -#[allow(dead_code)] -pub enum Status { - Starting = 0, - Started = 1, - Returned = 2, - StartCancelled = 3, - ReturnCancelled = 4, -} - -impl Status { - /// Packs this status and the optional `waitable` provided into a 32-bit - /// result that the canonical ABI requires. - /// - /// The low 4 bits are reserved for the status while the upper 28 bits are - /// the waitable, if present. - pub fn pack(self, waitable: Option) -> u32 { - _ = waitable; - todo!() - } -} - -pub(crate) struct ConcurrentState {} - -impl ConcurrentState { - pub(crate) fn new(component: &Component) -> Self { - _ = component; - Self {} - } +/// Represents the result of a concurrent operation. +/// +/// This is similar to a [`std::future::Future`] except that it represents an +/// operation which requires exclusive access to a store in order to make +/// progress -- without monopolizing that store for the lifetime of the +/// operation. +pub struct Promise(Pin + Send + Sync + 'static>>); - /// Implements the `context.get` intrinsic. - pub(crate) fn context_get(&mut self, slot: u32) -> Result { - _ = slot; - todo!() +impl Promise { + /// Map the result of this `Promise` from one value to another. + pub fn map(self, fun: impl FnOnce(T) -> U + Send + Sync + 'static) -> Promise { + Promise(Box::pin(self.0.map(fun))) } - /// Implements the `context.set` intrinsic. - pub(crate) fn context_set(&mut self, slot: u32, val: u32) -> Result<()> { - _ = (slot, val); + /// Convert this `Promise` to a future which may be `await`ed for its + /// result. + /// + /// The returned future will require exclusive use of the store until it + /// completes. If you need to await more than one `Promise` concurrently, + /// use [`PromisesUnordered`]. + pub async fn get(self, store: impl AsContextMut) -> Result { + _ = store; todo!() } - /// Implements the `backpressure.set` intrinsic. - pub(crate) fn backpressure_set( - &mut self, - caller_instance: RuntimeComponentInstanceIndex, - enabled: u32, - ) -> Result<()> { - _ = (caller_instance, enabled); - todo!() + /// Convert this `Promise` to a future which may be `await`ed for its + /// result. + /// + /// Unlike [`Self::get`], this does _not_ take a store parameter, meaning + /// the returned future will not make progress until and unless the event + /// loop for the store it came from is polled. Thus, this method should + /// only be used from within host functions and not from top-level embedder + /// code. + pub fn into_future(self) -> Pin + Send + Sync + 'static>> { + self.0 } +} - /// Implements the `waitable-set.new` intrinsic. - pub(crate) fn waitable_set_new( - &mut self, - caller_instance: RuntimeComponentInstanceIndex, - ) -> Result { - _ = caller_instance; - todo!() - } +/// Represents a collection of zero or more concurrent operations. +/// +/// Similar to [`futures::stream::FuturesUnordered`], this type supports +/// `await`ing more than one [`Promise`]s concurrently. +pub struct PromisesUnordered( + FuturesUnordered + Send + Sync + 'static>>>, +); - /// Implements the `waitable-set.drop` intrinsic. - pub(crate) fn waitable_set_drop( - &mut self, - caller_instance: RuntimeComponentInstanceIndex, - set: u32, - ) -> Result<()> { - _ = (caller_instance, set); - todo!() +impl PromisesUnordered { + /// Create a new `PromisesUnordered` with no entries. + pub fn new() -> Self { + Self(FuturesUnordered::new()) } - /// Implements the `waitable.join` intrinsic. - pub(crate) fn waitable_join( - &mut self, - caller_instance: RuntimeComponentInstanceIndex, - waitable_handle: u32, - set_handle: u32, - ) -> Result<()> { - _ = (caller_instance, waitable_handle, set_handle); - todo!() + /// Add the specified [`Promise`] to this collection. + pub fn push(&mut self, promise: Promise) { + self.0.push(promise.0) } - /// Implements the `subtask.drop` intrinsic. - pub(crate) fn subtask_drop( - &mut self, - caller_instance: RuntimeComponentInstanceIndex, - task_id: u32, - ) -> Result<()> { - _ = (caller_instance, task_id); + /// Get the next result from this collection, if any. + pub async fn next(&mut self, store: impl AsContextMut) -> Result> { + _ = store; todo!() } } -/// Provides access to either store data (via the `get` method) or the store -/// itself (via [`AsContext`]/[`AsContextMut`]), as well as the component -/// instance to which the current host task belongs. -/// -/// See [`Accessor::with`] for details. -pub struct Access<'a, T: 'static, D: HasData = HasSelf> { - _phantom: PhantomData<(&'a (), T, D)>, -} - /// Provides scoped mutable access to store data in the context of a concurrent /// host task future. /// @@ -157,213 +114,9 @@ where } } -impl Instance { - /// Wrap the specified host function in a future which will call it, passing - /// it an `&mut Accessor`. - /// - /// See the `Accessor` documentation for details. - pub(crate) fn wrap_call( - self, - store: StoreContextMut, - closure: F, - ) -> impl Future> + 'static - where - T: 'static, - F: FnOnce(&mut Accessor) -> Pin> + Send + '_>> - + Send - + Sync - + 'static, - R: Send + Sync + 'static, - { - _ = (store, closure); - async { todo!() } - } - - /// Poll the specified future once on behalf of a guest->host call using an - /// async-lowered import. - /// - /// If it returns `Ready`, return `Ok(None)`. Otherwise, if it returns - /// `Pending`, add it to the set of futures to be polled as part of this - /// instance's event loop until it completes, and then return - /// `Ok(Some(handle))` where `handle` is the waitable handle to return. - /// - /// Whether the future returns `Ready` immediately or later, the `lower` - /// function will be used to lower the result, if any, into the guest caller's - /// stack and linear memory unless the task has been cancelled. - pub(crate) fn first_poll( - self, - mut store: StoreContextMut, - future: impl Future> + Send + 'static, - caller_instance: RuntimeComponentInstanceIndex, - lower: impl FnOnce(StoreContextMut, Instance, R) -> Result<()> + Send + 'static, - ) -> Result> { - _ = (&mut store, future, caller_instance, lower); - todo!() - } - - /// Poll the specified future until it completes on behalf of a guest->host - /// call using a sync-lowered import. - /// - /// This is similar to `Self::first_poll` except it's for sync-lowered - /// imports, meaning we don't need to handle cancellation and we can block - /// the caller until the task completes, at which point the caller can - /// handle lowering the result to the guest's stack and linear memory. - pub(crate) fn poll_and_block( - self, - store: &mut dyn VMStore, - future: impl Future> + Send + 'static, - caller_instance: RuntimeComponentInstanceIndex, - ) -> Result { - _ = (store, caller_instance); - match pin!(future).poll(&mut Context::from_waker(Waker::noop())) { - Poll::Ready(result) => result, - Poll::Pending => { - todo!() - } - } - } - - /// TODO: docs - pub async fn run(&self, mut store: impl AsContextMut, fut: F) -> Result - where - F: Future, - { - _ = (&mut store, fut); - todo!() - } - - /// Implements the `task.return` intrinsic, lifting the result for the - /// current guest task. - /// - /// SAFETY: The `memory` and `storage` pointers must be valid, and `storage` - /// must contain at least `storage_len` items. - pub(crate) unsafe fn task_return( - self, - store: &mut dyn VMStore, - ty: TypeTupleIndex, - memory: *mut VMMemoryDefinition, - string_encoding: u8, - storage: *mut ValRaw, - storage_len: usize, - ) -> Result<()> { - _ = (store, ty, memory, string_encoding, storage, storage_len); - todo!() - } - - /// Implements the `task.cancel` intrinsic. - pub(crate) fn task_cancel( - self, - store: &mut dyn VMStore, - _caller_instance: RuntimeComponentInstanceIndex, - ) -> Result<()> { - _ = store; - todo!() - } - - /// Implements the `waitable-set.wait` intrinsic. - pub(crate) fn waitable_set_wait( - self, - store: &mut dyn VMStore, - caller_instance: RuntimeComponentInstanceIndex, - async_: bool, - memory: *mut VMMemoryDefinition, - set: u32, - payload: u32, - ) -> Result { - _ = (store, caller_instance, async_, memory, set, payload); - todo!() - } - - /// Implements the `waitable-set.poll` intrinsic. - pub(crate) fn waitable_set_poll( - self, - store: &mut dyn VMStore, - caller_instance: RuntimeComponentInstanceIndex, - async_: bool, - memory: *mut VMMemoryDefinition, - set: u32, - payload: u32, - ) -> Result { - _ = (store, caller_instance, async_, memory, set, payload); - todo!() - } - - /// Implements the `yield` intrinsic. - pub(crate) fn yield_(self, store: &mut dyn VMStore, async_: bool) -> Result { - _ = (store, async_); - todo!() - } - - /// Implements the `subtask.cancel` intrinsic. - pub(crate) fn subtask_cancel( - self, - store: &mut dyn VMStore, - caller_instance: RuntimeComponentInstanceIndex, - async_: bool, - task_id: u32, - ) -> Result { - _ = (store, caller_instance, async_, task_id); - todo!() - } - - /// Convenience function to reduce boilerplate. - pub(crate) fn concurrent_state_mut<'a>( - &self, - store: &'a mut StoreOpaque, - ) -> &'a mut ConcurrentState { - _ = store; - todo!() - } -} - /// Trait representing component model ABI async intrinsics and fused adapter /// helper functions. pub unsafe trait VMComponentAsyncStore { - /// A helper function for fused adapter modules involving calls where the - /// one of the caller or callee is async. - /// - /// This helper is not used when the caller and callee both use the sync - /// ABI, only when at least one is async is this used. - unsafe fn prepare_call( - &mut self, - instance: Instance, - memory: *mut VMMemoryDefinition, - start: *mut VMFuncRef, - return_: *mut VMFuncRef, - caller_instance: RuntimeComponentInstanceIndex, - callee_instance: RuntimeComponentInstanceIndex, - task_return_type: TypeTupleIndex, - string_encoding: u8, - result_count: u32, - storage: *mut ValRaw, - storage_len: usize, - ) -> Result<()>; - - /// A helper function for fused adapter modules involving calls where the - /// caller is sync-lowered but the callee is async-lifted. - unsafe fn sync_start( - &mut self, - instance: Instance, - callback: *mut VMFuncRef, - callee: *mut VMFuncRef, - param_count: u32, - storage: *mut MaybeUninit, - storage_len: usize, - ) -> Result<()>; - - /// A helper function for fused adapter modules involving calls where the - /// caller is async-lowered. - unsafe fn async_start( - &mut self, - instance: Instance, - callback: *mut VMFuncRef, - post_return: *mut VMFuncRef, - callee: *mut VMFuncRef, - param_count: u32, - result_count: u32, - flags: u32, - ) -> Result; - /// The `backpressure.set` intrinsic. fn backpressure_set( &mut self, @@ -491,40 +244,85 @@ pub unsafe trait VMComponentAsyncStore { flags: u32, ) -> Result; + /// The `future.new` intrinsic. + fn future_new( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + ) -> Result; + /// The `future.write` intrinsic. - unsafe fn future_write( + fn future_write( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, - async_: bool, ty: TypeFutureTableIndex, future: u32, address: u32, ) -> Result; /// The `future.read` intrinsic. - unsafe fn future_read( + fn future_read( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, - async_: bool, ty: TypeFutureTableIndex, future: u32, address: u32, ) -> Result; + /// The `future.cancel-write` intrinsic. + fn future_cancel_write( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + async_: bool, + writer: u32, + ) -> Result; + + /// The `future.cancel-read` intrinsic. + fn future_cancel_read( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + async_: bool, + reader: u32, + ) -> Result; + + /// The `future.drop-writable` intrinsic. + fn future_drop_writable( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + writer: u32, + ) -> Result<()>; + + /// The `future.drop-readable` intrinsic. + fn future_drop_readable( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + reader: u32, + ) -> Result<()>; + + /// The `stream.new` intrinsic. + fn stream_new( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + ) -> Result; + /// The `stream.write` intrinsic. - unsafe fn stream_write( + fn stream_write( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, - async_: bool, ty: TypeStreamTableIndex, stream: u32, address: u32, @@ -532,27 +330,59 @@ pub unsafe trait VMComponentAsyncStore { ) -> Result; /// The `stream.read` intrinsic. - unsafe fn stream_read( + fn stream_read( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, - async_: bool, ty: TypeStreamTableIndex, stream: u32, address: u32, count: u32, ) -> Result; + /// The `stream.cancel-write` intrinsic. + fn stream_cancel_write( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + async_: bool, + writer: u32, + ) -> Result; + + /// The `stream.cancel-read` intrinsic. + fn stream_cancel_read( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + async_: bool, + reader: u32, + ) -> Result; + + /// The `stream.drop-writable` intrinsic. + fn stream_drop_writable( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + writer: u32, + ) -> Result<()>; + + /// The `stream.drop-readable` intrinsic. + fn stream_drop_readable( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + reader: u32, + ) -> Result<()>; + /// The "fast-path" implementation of the `stream.write` intrinsic for /// "flat" (i.e. memcpy-able) payloads. - unsafe fn flat_stream_write( + fn flat_stream_write( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, - async_: bool, ty: TypeStreamTableIndex, payload_size: u32, payload_align: u32, @@ -563,12 +393,11 @@ pub unsafe trait VMComponentAsyncStore { /// The "fast-path" implementation of the `stream.read` intrinsic for "flat" /// (i.e. memcpy-able) payloads. - unsafe fn flat_stream_read( + fn flat_stream_read( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, - async_: bool, ty: TypeStreamTableIndex, payload_size: u32, payload_align: u32, @@ -577,92 +406,40 @@ pub unsafe trait VMComponentAsyncStore { count: u32, ) -> Result; - /// The `error-context.debug-message` intrinsic. - unsafe fn error_context_debug_message( + /// The `error-context.new` intrinsic. + fn error_context_new( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, ty: TypeComponentLocalErrorContextTableIndex, - err_ctx_handle: u32, debug_msg_address: u32, - ) -> Result<()>; -} + debug_msg_len: u32, + ) -> Result; -unsafe impl VMComponentAsyncStore for StoreInner { - unsafe fn prepare_call( + /// The `error-context.debug-message` intrinsic. + fn error_context_debug_message( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, - start: *mut VMFuncRef, - return_: *mut VMFuncRef, - caller_instance: RuntimeComponentInstanceIndex, - callee_instance: RuntimeComponentInstanceIndex, - task_return_type: TypeTupleIndex, + realloc: *mut VMFuncRef, string_encoding: u8, - result_count: u32, - storage: *mut ValRaw, - storage_len: usize, - ) -> Result<()> { - _ = ( - instance, - memory, - start, - return_, - caller_instance, - callee_instance, - task_return_type, - string_encoding, - result_count, - storage, - storage_len, - ); - todo!() - } - - unsafe fn sync_start( - &mut self, - instance: Instance, - callback: *mut VMFuncRef, - callee: *mut VMFuncRef, - param_count: u32, - storage: *mut MaybeUninit, - storage_len: usize, - ) -> Result<()> { - _ = ( - instance, - callback, - callee, - param_count, - storage, - storage_len, - ); - todo!() - } + ty: TypeComponentLocalErrorContextTableIndex, + err_ctx_handle: u32, + debug_msg_address: u32, + ) -> Result<()>; - unsafe fn async_start( + /// The `error-context.drop` intrinsic. + fn error_context_drop( &mut self, - instance: Instance, - callback: *mut VMFuncRef, - post_return: *mut VMFuncRef, - callee: *mut VMFuncRef, - param_count: u32, - result_count: u32, - flags: u32, - ) -> Result { - _ = ( - instance, - callback, - post_return, - callee, - param_count, - result_count, - flags, - ); - todo!() - } + instance: &mut ComponentInstance, + ty: TypeComponentLocalErrorContextTableIndex, + err_ctx_handle: u32, + ) -> Result<()>; +} +unsafe impl VMComponentAsyncStore for StoreInner { fn backpressure_set( &mut self, caller_instance: RuntimeComponentInstanceIndex, @@ -846,13 +623,21 @@ unsafe impl VMComponentAsyncStore for StoreInner { todo!() } - unsafe fn future_write( + fn future_new( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + ) -> Result { + _ = (instance, ty); + todo!() + } + + fn future_write( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, - async_: bool, ty: TypeFutureTableIndex, future: u32, address: u32, @@ -862,7 +647,6 @@ unsafe impl VMComponentAsyncStore for StoreInner { memory, realloc, string_encoding, - async_, ty, future, address, @@ -870,13 +654,12 @@ unsafe impl VMComponentAsyncStore for StoreInner { todo!() } - unsafe fn future_read( + fn future_read( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, - async_: bool, ty: TypeFutureTableIndex, future: u32, address: u32, @@ -886,7 +669,6 @@ unsafe impl VMComponentAsyncStore for StoreInner { memory, realloc, string_encoding, - async_, ty, future, address, @@ -894,13 +676,63 @@ unsafe impl VMComponentAsyncStore for StoreInner { todo!() } - unsafe fn stream_write( + fn future_cancel_write( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + async_: bool, + writer: u32, + ) -> Result { + _ = (instance, ty, async_, writer); + todo!() + } + + fn future_cancel_read( &mut self, - instance: Instance, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + async_: bool, + reader: u32, + ) -> Result { + _ = (instance, ty, async_, reader); + todo!() + } + + fn future_drop_writable( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + writer: u32, + ) -> Result<()> { + _ = (instance, ty, writer); + todo!() + } + + fn future_drop_readable( + &mut self, + instance: &mut ComponentInstance, + ty: TypeFutureTableIndex, + reader: u32, + ) -> Result<()> { + _ = (instance, ty, reader); + todo!() + } + + fn stream_new( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + ) -> Result { + _ = (instance, ty); + todo!() + } + + fn stream_write( + &mut self, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, - async_: bool, ty: TypeStreamTableIndex, stream: u32, address: u32, @@ -911,7 +743,6 @@ unsafe impl VMComponentAsyncStore for StoreInner { memory, realloc, string_encoding, - async_, ty, stream, address, @@ -920,13 +751,12 @@ unsafe impl VMComponentAsyncStore for StoreInner { todo!() } - unsafe fn stream_read( + fn stream_read( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, - async_: bool, ty: TypeStreamTableIndex, stream: u32, address: u32, @@ -937,7 +767,6 @@ unsafe impl VMComponentAsyncStore for StoreInner { memory, realloc, string_encoding, - async_, ty, stream, address, @@ -946,12 +775,53 @@ unsafe impl VMComponentAsyncStore for StoreInner { todo!() } - unsafe fn flat_stream_write( + fn stream_cancel_write( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + async_: bool, + writer: u32, + ) -> Result { + _ = (instance, ty, async_, writer); + todo!() + } + + fn stream_cancel_read( &mut self, - instance: Instance, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + async_: bool, + reader: u32, + ) -> Result { + _ = (instance, ty, async_, reader); + todo!() + } + + fn stream_drop_writable( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + writer: u32, + ) -> Result<()> { + _ = (instance, ty, writer); + todo!() + } + + fn stream_drop_readable( + &mut self, + instance: &mut ComponentInstance, + ty: TypeStreamTableIndex, + reader: u32, + ) -> Result<()> { + _ = (instance, ty, reader); + todo!() + } + + fn flat_stream_write( + &mut self, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, - async_: bool, ty: TypeStreamTableIndex, payload_size: u32, payload_align: u32, @@ -963,7 +833,6 @@ unsafe impl VMComponentAsyncStore for StoreInner { instance, memory, realloc, - async_, ty, payload_size, payload_align, @@ -974,12 +843,11 @@ unsafe impl VMComponentAsyncStore for StoreInner { todo!() } - unsafe fn flat_stream_read( + fn flat_stream_read( &mut self, - instance: Instance, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, - async_: bool, ty: TypeStreamTableIndex, payload_size: u32, payload_align: u32, @@ -991,7 +859,6 @@ unsafe impl VMComponentAsyncStore for StoreInner { instance, memory, realloc, - async_, ty, payload_size, payload_align, @@ -1002,9 +869,31 @@ unsafe impl VMComponentAsyncStore for StoreInner { todo!() } - unsafe fn error_context_debug_message( + fn error_context_new( &mut self, - instance: Instance, + instance: &mut ComponentInstance, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeComponentLocalErrorContextTableIndex, + debug_msg_address: u32, + debug_msg_len: u32, + ) -> Result { + _ = ( + instance, + memory, + realloc, + string_encoding, + ty, + debug_msg_address, + debug_msg_len, + ); + todo!() + } + + fn error_context_debug_message( + &mut self, + instance: &mut ComponentInstance, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, @@ -1023,59 +912,14 @@ unsafe impl VMComponentAsyncStore for StoreInner { ); todo!() } -} -pub(crate) struct PreparedCall { - _phantom: PhantomData, -} - -/// Prepare a call to the specified exported Wasm function, providing functions -/// for lowering the parameters and lifting the result. -/// -/// To enqueue the returned `PreparedCall` in the `ComponentInstance`'s event -/// loop, use `queue_call`. -/// -/// Note that this function is used in `TypedFunc::call_async`, which accepts -/// parameters of a generic type which might not be `'static`. However the -/// `GuestTask` created by this function must be `'static`, so it can't safely -/// close over those parameters. Instead, `PreparedCall` has a `params` field -/// of type `Arc>`, which the caller is responsible for setting to -/// a valid, non-null pointer to the params prior to polling the event loop (at -/// least until the parameters have been lowered), and then resetting back to -/// null afterward. That ensures that the lowering code never sees a stale -/// pointer, even if the application `drop`s or `mem::forget`s the future -/// returned by `TypedFunc::call_async`. -/// -/// In the case where the parameters are passed using a type that _is_ -/// `'static`, they can be boxed and stored in `PreparedCall::params` -/// indefinitely; `drop_params` will be called when they are no longer needed. -pub(crate) fn prepare_call( - mut store: StoreContextMut, - lower_params: impl FnOnce(Func, StoreContextMut, &mut [MaybeUninit]) -> Result<()> - + Send - + Sync - + 'static, - lift_result: impl FnOnce(Func, &mut StoreOpaque, &[ValRaw]) -> Result> - + Send - + Sync - + 'static, - handle: Func, - param_count: usize, -) -> Result> { - let _ = (&mut store, lower_params, lift_result, handle, param_count); - todo!() -} - -/// Queue a call previously prepared using `prepare_call` to be run as part of -/// the associated `ComponentInstance`'s event loop. -/// -/// The returned future will resolve to the result once it is available, but -/// must only be polled via the instance's event loop. See `Instance::run` for -/// details. -pub(crate) fn queue_call( - mut store: StoreContextMut, - prepared: PreparedCall, -) -> Result> + Send + 'static + use> { - _ = (&mut store, prepared); - Ok(async { todo!() }) + fn error_context_drop( + &mut self, + instance: &mut ComponentInstance, + ty: TypeComponentLocalErrorContextTableIndex, + err_ctx_handle: u32, + ) -> Result<()> { + _ = (instance, ty, err_ctx_handle); + todo!() + } } diff --git a/crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs b/crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs index 5f476f24a74c..767c7436eae7 100644 --- a/crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs +++ b/crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs @@ -1,454 +1,19 @@ -use super::ConcurrentState; -use crate::component::func::{self, LiftContext, LowerContext}; -use crate::component::matching::InstanceType; -use crate::component::{Instance, Val}; -use crate::store::StoreOpaque; -use crate::vm::{VMFuncRef, VMMemoryDefinition, VMStore}; -use anyhow::Result; -use std::{marker::PhantomData, mem::MaybeUninit}; -use wasmtime_environ::component::{ - CanonicalAbiInfo, InterfaceType, TypeComponentLocalErrorContextTableIndex, - TypeFutureTableIndex, TypeStreamTableIndex, -}; - -/// Represents the readable end of a Component Model `future`. -/// -/// In order to actually read from or drop this `future`, first convert it to a -/// [`FutureReader`] using the `into_reader` method. -/// -/// Note that if a value of this type is dropped without either being converted -/// to a `FutureReader` or passed to the guest, any writes on the write end may -/// block forever. -pub struct HostFuture { - _phantom: PhantomData, -} - -impl HostFuture { - /// Convert this `HostFuture` into a [`Val`]. - // See TODO comment for `FutureAny`; this is prone to handle leakage. - pub fn into_val(self) -> Val { - todo!() - } -} - -// SAFETY: This relies on the `ComponentType` implementation for `u32` being -// safe and correct since we lift and lower future handles as `u32`s. -unsafe impl func::ComponentType for HostFuture { - const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4; - - type Lower = ::Lower; - - fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> { - _ = ty; - todo!() - } -} - -// SAFETY: See the comment on the `ComponentType` `impl` for this type. -unsafe impl func::Lower for HostFuture { - fn linear_lower_to_flat( - &self, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, - dst: &mut MaybeUninit, - ) -> Result<()> { - _ = (cx, ty, dst); - todo!() - } - - fn linear_lower_to_memory( - &self, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, - offset: usize, - ) -> Result<()> { - _ = (cx, ty, offset); - todo!() - } -} - -// SAFETY: See the comment on the `ComponentType` `impl` for this type. -unsafe impl func::Lift for HostFuture { - fn linear_lift_from_flat( - cx: &mut LiftContext<'_>, - ty: InterfaceType, - src: &Self::Lower, - ) -> Result { - _ = (cx, ty, src); - todo!() - } - - fn linear_lift_from_memory( - cx: &mut LiftContext<'_>, - ty: InterfaceType, - bytes: &[u8], - ) -> Result { - _ = (cx, ty, bytes); - todo!() - } -} - -/// Transfer ownership of the read end of a future from the host to a guest. -pub(crate) fn lower_future_to_index( - rep: u32, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, -) -> Result { - _ = (rep, cx, ty); - todo!() -} +use std::marker::PhantomData; /// Represents the readable end of a Component Model `future`. pub struct FutureReader { _phantom: PhantomData, } -/// Represents the readable end of a Component Model `stream`. -/// -/// In order to actually read from or drop this `stream`, first convert it to a -/// [`FutureReader`] using the `into_reader` method. -/// -/// Note that if a value of this type is dropped without either being converted -/// to a `StreamReader` or passed to the guest, any writes on the write end may -/// block forever. -pub struct HostStream { - _phantom: PhantomData, -} - -impl HostStream { - /// Convert this `HostStream` into a [`Val`]. - // See TODO comment for `StreamAny`; this is prone to handle leakage. - pub fn into_val(self) -> Val { - todo!() - } -} - -// SAFETY: This relies on the `ComponentType` implementation for `u32` being -// safe and correct since we lift and lower stream handles as `u32`s. -unsafe impl func::ComponentType for HostStream { - const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4; - - type Lower = ::Lower; - - fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> { - _ = ty; - todo!() - } -} - -// SAFETY: See the comment on the `ComponentType` `impl` for this type. -unsafe impl func::Lower for HostStream { - fn linear_lower_to_flat( - &self, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, - dst: &mut MaybeUninit, - ) -> Result<()> { - _ = (cx, ty, dst); - todo!() - } - - fn linear_lower_to_memory( - &self, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, - offset: usize, - ) -> Result<()> { - _ = (cx, ty, offset); - todo!() - } -} - -// SAFETY: See the comment on the `ComponentType` `impl` for this type. -unsafe impl func::Lift for HostStream { - fn linear_lift_from_flat( - cx: &mut LiftContext<'_>, - ty: InterfaceType, - src: &Self::Lower, - ) -> Result { - _ = (cx, ty, src); - todo!() - } - - fn linear_lift_from_memory( - cx: &mut LiftContext<'_>, - ty: InterfaceType, - bytes: &[u8], - ) -> Result { - _ = (cx, ty, bytes); - todo!() - } -} - -/// Transfer ownership of the read end of a stream from the host to a guest. -pub(crate) fn lower_stream_to_index( - rep: u32, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, -) -> Result { - _ = (rep, cx, ty); - todo!() -} - /// Represents the readable end of a Component Model `stream`. pub struct StreamReader { _phantom: PhantomData, } -/// Represents the writable end of a Component Model `future`. -pub struct FutureWriter { - _phantom: PhantomData, -} - -/// Represents the writable end of a Component Model `stream`. -pub struct StreamWriter { - _phantom: PhantomData, -} - /// Represents a Component Model `error-context`. pub struct ErrorContext {} -impl ErrorContext { - /// Convert this `ErrorContext` into a [`Val`]. - pub fn into_val(self) -> Val { - todo!() - } -} - -// SAFETY: This relies on the `ComponentType` implementation for `u32` being -// safe and correct since we lift and lower future handles as `u32`s. -unsafe impl func::ComponentType for ErrorContext { - const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4; - - type Lower = ::Lower; - - fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> { - _ = ty; - todo!() - } -} - -// SAFETY: See the comment on the `ComponentType` `impl` for this type. -unsafe impl func::Lower for ErrorContext { - fn linear_lower_to_flat( - &self, - cx: &mut LowerContext<'_, T>, - ty: InterfaceType, - dst: &mut MaybeUninit, - ) -> Result<()> { - _ = (cx, ty, dst); - todo!() - } - - fn linear_lower_to_memory( - &self, - cx: &mut LowerContext<'_, T>, - ty: InterfaceType, - offset: usize, - ) -> Result<()> { - _ = (cx, ty, offset); - todo!() - } -} - -// SAFETY: See the comment on the `ComponentType` `impl` for this type. -unsafe impl func::Lift for ErrorContext { - fn linear_lift_from_flat( - cx: &mut LiftContext<'_>, - ty: InterfaceType, - src: &Self::Lower, - ) -> Result { - _ = (cx, ty, src); - todo!() - } - - fn linear_lift_from_memory( - cx: &mut LiftContext<'_>, - ty: InterfaceType, - bytes: &[u8], - ) -> Result { - _ = (cx, ty, bytes); - todo!() - } -} - -/// Transfer ownership of an error-context from the host to a guest. -pub(crate) fn lower_error_context_to_index( - rep: u32, - cx: &mut LowerContext<'_, U>, - ty: InterfaceType, -) -> Result { - _ = (rep, cx, ty); - todo!() -} - pub(crate) struct ResourcePair { pub(crate) write: u32, pub(crate) read: u32, } - -impl ConcurrentState { - pub(crate) fn future_new(&mut self, ty: TypeFutureTableIndex) -> Result { - _ = ty; - todo!() - } - - /// Implements the `future.cancel-write` intrinsic. - pub(crate) fn future_cancel_write( - &mut self, - ty: TypeFutureTableIndex, - async_: bool, - writer: u32, - ) -> Result { - _ = (ty, async_, writer); - todo!() - } - - /// Implements the `future.cancel-read` intrinsic. - pub(crate) fn future_cancel_read( - &mut self, - ty: TypeFutureTableIndex, - async_: bool, - reader: u32, - ) -> Result { - _ = (ty, async_, reader); - todo!() - } - - /// Implements the `future.drop-writable` intrinsic. - pub(crate) fn future_drop_writable( - &mut self, - ty: TypeFutureTableIndex, - writer: u32, - ) -> Result<()> { - _ = (ty, writer); - todo!() - } - - /// Implements the `stream.new` intrinsic. - pub(crate) fn stream_new(&mut self, ty: TypeStreamTableIndex) -> Result { - _ = ty; - todo!() - } - - /// Implements the `stream.cancel-write` intrinsic. - pub(crate) fn stream_cancel_write( - &mut self, - ty: TypeStreamTableIndex, - async_: bool, - writer: u32, - ) -> Result { - _ = (ty, async_, writer); - todo!() - } - - /// Implements the `stream.cancel-read` intrinsic. - pub(crate) fn stream_cancel_read( - &mut self, - ty: TypeStreamTableIndex, - async_: bool, - reader: u32, - ) -> Result { - _ = (ty, async_, reader); - todo!() - } - - /// Implements the `stream.drop-writable` intrinsic. - pub(crate) fn stream_drop_writable( - &mut self, - ty: TypeStreamTableIndex, - writer: u32, - ) -> Result<()> { - _ = (ty, writer); - todo!() - } - - pub(crate) fn future_transfer( - &mut self, - src_idx: u32, - src: TypeFutureTableIndex, - dst: TypeFutureTableIndex, - ) -> Result { - _ = (src_idx, src, dst); - todo!() - } - - pub(crate) fn stream_transfer( - &mut self, - src_idx: u32, - src: TypeStreamTableIndex, - dst: TypeStreamTableIndex, - ) -> Result { - _ = (src_idx, src, dst); - todo!() - } - - pub(crate) fn error_context_transfer( - &mut self, - src_idx: u32, - src: TypeComponentLocalErrorContextTableIndex, - dst: TypeComponentLocalErrorContextTableIndex, - ) -> Result { - _ = (src_idx, src, dst); - todo!() - } - - pub(crate) fn error_context_drop( - &mut self, - ty: TypeComponentLocalErrorContextTableIndex, - error_context: u32, - ) -> Result<()> { - _ = (ty, error_context); - todo!() - } -} - -impl Instance { - /// Implements the `future.drop-readable` intrinsic. - pub(crate) fn future_drop_readable( - self, - store: &mut dyn VMStore, - ty: TypeFutureTableIndex, - reader: u32, - ) -> Result<()> { - _ = (store, ty, reader); - todo!() - } - - /// Implements the `stream.drop-readable` intrinsic. - pub(crate) fn stream_drop_readable( - self, - store: &mut dyn VMStore, - ty: TypeStreamTableIndex, - reader: u32, - ) -> Result<()> { - _ = (store, ty, reader); - todo!() - } - - /// Create a new error context for the given component. - /// - /// SAFETY: `memory` and `realloc` must be valid pointers to their - /// respective guest entities. - pub(crate) unsafe fn error_context_new( - self, - store: &mut StoreOpaque, - memory: *mut VMMemoryDefinition, - realloc: *mut VMFuncRef, - string_encoding: u8, - ty: TypeComponentLocalErrorContextTableIndex, - debug_msg_address: u32, - debug_msg_len: u32, - ) -> Result { - _ = ( - store, - memory, - realloc, - string_encoding, - ty, - debug_msg_address, - debug_msg_len, - ); - todo!() - } -} diff --git a/crates/wasmtime/src/runtime/component/concurrent_disabled.rs b/crates/wasmtime/src/runtime/component/concurrent_disabled.rs deleted file mode 100644 index 1a661dd4da0e..000000000000 --- a/crates/wasmtime/src/runtime/component/concurrent_disabled.rs +++ /dev/null @@ -1,135 +0,0 @@ -use crate::Uninhabited; -use crate::component::func::{ComponentType, LiftContext, LowerContext}; -use crate::component::{Instance, Val}; -use crate::runtime::vm::VMStore; -use anyhow::{Result, anyhow}; -use core::future::Future; -use core::marker::PhantomData; -use core::pin::pin; -use core::task::{Context, Poll, Waker}; -use wasmtime_environ::component::{InterfaceType, RuntimeComponentInstanceIndex}; - -fn should_have_failed_validation(what: &str) -> Result { - // This should be unreachable; if we trap here, it indicates a - // bug in Wasmtime rather than in the guest. - Err(anyhow!( - "{what} should have failed validation \ - when `component-model-async` feature disabled" - )) -} - -impl Instance { - pub(crate) fn poll_and_block( - self, - _store: &mut dyn VMStore, - future: impl Future> + Send + 'static, - _caller_instance: RuntimeComponentInstanceIndex, - ) -> Result { - match pin!(future).poll(&mut Context::from_waker(Waker::noop())) { - Poll::Ready(result) => result, - Poll::Pending => should_have_failed_validation("async lowered import"), - } - } -} - -pub(crate) fn lower_future_to_index( - _rep: u32, - _cx: &mut LowerContext<'_, U>, - _ty: InterfaceType, -) -> Result { - should_have_failed_validation("use of `future`") -} - -pub(crate) fn lower_stream_to_index( - _rep: u32, - _cx: &mut LowerContext<'_, U>, - _ty: InterfaceType, -) -> Result { - should_have_failed_validation("use of `stream`") -} - -pub(crate) fn lower_error_context_to_index( - _rep: u32, - _cx: &mut LowerContext<'_, U>, - _ty: InterfaceType, -) -> Result { - should_have_failed_validation("use of `error-context`") -} - -pub struct ErrorContext(Uninhabited); - -impl ErrorContext { - pub(crate) fn into_val(self) -> Val { - match self.0 {} - } - - pub(crate) fn linear_lift_from_flat( - _cx: &mut LiftContext<'_>, - _ty: InterfaceType, - _src: &::Lower, - ) -> Result { - should_have_failed_validation("use of `error-context`") - } - - pub(crate) fn linear_lift_from_memory( - _cx: &mut LiftContext<'_>, - _ty: InterfaceType, - _bytes: &[u8], - ) -> Result { - should_have_failed_validation("use of `error-context`") - } -} - -pub struct HostStream

{ - uninhabited: Uninhabited, - _phantom: PhantomData

, -} - -impl

HostStream

{ - pub(crate) fn into_val(self) -> Val { - match self.uninhabited {} - } - - pub(crate) fn linear_lift_from_flat( - _cx: &mut LiftContext<'_>, - _ty: InterfaceType, - _src: &::Lower, - ) -> Result { - should_have_failed_validation("use of `stream`") - } - - pub(crate) fn linear_lift_from_memory( - _cx: &mut LiftContext<'_>, - _ty: InterfaceType, - _bytes: &[u8], - ) -> Result { - should_have_failed_validation("use of `stream`") - } -} - -pub struct HostFuture

{ - uninhabited: Uninhabited, - _phantom: PhantomData

, -} - -impl

HostFuture

{ - pub(crate) fn into_val(self) -> Val { - match self.uninhabited {} - } - - pub(crate) fn linear_lift_from_flat( - _cx: &mut LiftContext<'_>, - _ty: InterfaceType, - _src: &::Lower, - ) -> Result { - should_have_failed_validation("use of `future`") - } - - pub(crate) fn linear_lift_from_memory( - _cx: &mut LiftContext<'_>, - _ty: InterfaceType, - _bytes: &[u8], - ) -> Result { - should_have_failed_validation("use of `future`") - } -} diff --git a/crates/wasmtime/src/runtime/component/func.rs b/crates/wasmtime/src/runtime/component/func.rs index 47574c02eb37..2d021369216d 100644 --- a/crates/wasmtime/src/runtime/component/func.rs +++ b/crates/wasmtime/src/runtime/component/func.rs @@ -4,24 +4,17 @@ use crate::component::storage::storage_as_slice; use crate::component::types::Type; use crate::component::values::Val; use crate::prelude::*; -use crate::runtime::vm::component::{ComponentInstance, InstanceFlags, ResourceTables}; -use crate::runtime::vm::{Export, VMFuncRef}; +use crate::runtime::vm::component::{ComponentInstance, ResourceTables}; +use crate::runtime::vm::{Export, ExportFunction}; use crate::store::StoreOpaque; use crate::{AsContext, AsContextMut, StoreContextMut, ValRaw}; use core::mem::{self, MaybeUninit}; use core::ptr::NonNull; use wasmtime_environ::component::{ - CanonicalOptions, CanonicalOptionsDataModel, ExportIndex, InterfaceType, MAX_FLAT_PARAMS, - MAX_FLAT_RESULTS, TypeFuncIndex, TypeTuple, + CanonicalOptionsDataModel, ExportIndex, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, + TypeFuncIndex, TypeTuple, }; -#[cfg(feature = "component-model-async")] -use crate::component::concurrent::{self, PreparedCall}; -#[cfg(feature = "component-model-async")] -use core::future::Future; -#[cfg(feature = "component-model-async")] -use core::pin::Pin; - mod host; mod options; mod typed; @@ -29,6 +22,12 @@ pub use self::host::*; pub use self::options::*; pub use self::typed::*; +#[repr(C)] +union ParamsAndResults { + params: Params, + ret: Return, +} + /// A WebAssembly component function which can be called. /// /// This type is the dual of [`wasmtime::Func`](crate::Func) for component @@ -289,198 +288,70 @@ impl Func { .await? } - fn check_param_count(&self, store: StoreContextMut, count: usize) -> Result<()> { - let param_tys = self.params(&store); - if param_tys.len() != count { - bail!("expected {} argument(s), got {count}", param_tys.len()); - } - - Ok(()) - } - - /// Start a concurrent call to this function. - /// - /// Unlike [`Self::call`] and [`Self::call_async`] (both of which require - /// exclusive access to the store until the completion of the call), calls - /// made using this method may run concurrently with other calls to the same - /// instance. - /// - /// Note that the `Future` returned by this method will panic if polled or - /// `.await`ed outside of the event loop of the component instance this - /// function belongs to; use `Instance::run`, `Instance::run_with`, or - /// `Instance::spawn` to poll it from within the event loop. See - /// [`Instance::run`] for examples. - #[cfg(feature = "component-model-async")] - pub fn call_concurrent( - self, - mut store: impl AsContextMut, - params: Vec, - ) -> Pin>> + Send + 'static>> { - let mut store = store.as_context_mut(); - assert!( - store.0.async_support(), - "cannot use `call_concurrent` when async support is not enabled on the config" - ); - - let result = (|| { - self.check_param_count(store.as_context_mut(), params.len())?; - let prepared = self.prepare_call_dynamic(store.as_context_mut(), params)?; - concurrent::queue_call(store, prepared) - })(); - - Box::pin(async move { result?.await }) - } - - /// Calls `concurrent::prepare_call` with monomorphized functions for - /// lowering the parameters and lifting the result. - #[cfg(feature = "component-model-async")] - fn prepare_call_dynamic<'a, T: Send + 'static>( - self, - mut store: StoreContextMut<'a, T>, - params: Vec, - ) -> Result>> { - let store = store.as_context_mut(); - - concurrent::prepare_call( - store, - move |func, store, params_out| { - func.with_lower_context(store, |cx, ty| { - Self::lower_args(cx, ¶ms, ty, params_out) - }) - }, - move |func, store, results| { - let max_flat = if func.abi_async(store) { - MAX_FLAT_PARAMS - } else { - MAX_FLAT_RESULTS - }; - let results = func.with_lift_context(store, |cx, ty| { - Self::lift_results(cx, ty, results, max_flat)?.collect::>>() - })?; - Ok(Box::new(results)) - }, - self, - MAX_FLAT_PARAMS, - ) - } - fn call_impl( &self, mut store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()> { - let mut store = store.as_context_mut(); - - self.check_param_count(store.as_context_mut(), params.len())?; + let store = &mut store.as_context_mut(); + let param_tys = self.params(&store); let result_tys = self.results(&store); + if param_tys.len() != params.len() { + bail!( + "expected {} argument(s), got {}", + param_tys.len(), + params.len() + ); + } if result_tys.len() != results.len() { bail!( - "expected {} result(s), got {}", + "expected {} results(s), got {}", result_tys.len(), results.len() ); } - if self.abi_async(store.0) { - unreachable!( - "async-lifted exports should have failed validation \ - when `component-model-async` feature disabled" - ); - } + self.call_raw( + store, + params, + |cx, params, params_ty, dst: &mut MaybeUninit<[ValRaw; MAX_FLAT_PARAMS]>| { + let params_ty = match params_ty { + InterfaceType::Tuple(i) => &cx.types[i], + _ => unreachable!(), + }; + if params_ty.abi.flat_count(MAX_FLAT_PARAMS).is_some() { + let dst = &mut unsafe { + mem::transmute::<_, &mut [MaybeUninit; MAX_FLAT_PARAMS]>(dst) + } + .iter_mut(); - // SAFETY: the chosen representations of type parameters to `call_raw` - // here should be generally safe to work with: - // - // * parameters use `MaybeUninit<[MaybeUninit; MAX_FLAT_PARAMS]>` - // which represents the maximal possible number of parameters that can - // be passed to lifted component functions. This is modeled with - // `MaybeUninit` to represent how it all starts as uninitialized and - // thus can't be safely read during lowering. - // - // * results are modeled as `[ValRaw; MAX_FLAT_RESULTS]` which - // represents the maximal size of values that can be returned. Note - // that if the function doesn't actually have a return value then the - // `ValRaw` inside the array will have undefined contents. That is - // safe in Rust, however, due to `ValRaw` being a `union`. The - // contents should dynamically not be read due to the type of the - // function used here matching the actual lift. - unsafe { - self.call_raw( - store, - |cx, ty, dst: &mut MaybeUninit<[MaybeUninit; MAX_FLAT_PARAMS]>| { - // SAFETY: it's safe to assume that - // `MaybeUninit` is initialized because - // each individual element is still considered uninitialized. - let dst: &mut [MaybeUninit] = dst.assume_init_mut(); - Self::lower_args(cx, params, ty, dst) - }, - |cx, results_ty, src: &[ValRaw; MAX_FLAT_RESULTS]| { - let max_flat = MAX_FLAT_RESULTS; - for (result, slot) in - Self::lift_results(cx, results_ty, src, max_flat)?.zip(results) - { - *slot = result?; + params + .iter() + .zip(params_ty.types.iter()) + .try_for_each(|(param, ty)| param.lower(cx, *ty, dst)) + } else { + self.store_args(cx, ¶ms_ty, params, dst) + } + }, + |cx, results_ty, src: &[ValRaw; MAX_FLAT_RESULTS]| { + let results_ty = match results_ty { + InterfaceType::Tuple(i) => &cx.types[i], + _ => unreachable!(), + }; + if results_ty.abi.flat_count(MAX_FLAT_RESULTS).is_some() { + let mut flat = src.iter(); + for (ty, slot) in results_ty.types.iter().zip(results) { + *slot = Val::lift(cx, *ty, &mut flat)?; } Ok(()) - }, - ) - } - } - - pub(crate) fn lifted_core_func(&self, store: &mut StoreOpaque) -> NonNull { - let def = { - let instance = self.instance.id().get(store); - let (_ty, def, _options) = instance.component().export_lifted_function(self.index); - def.clone() - }; - match self.instance.lookup_vmdef(store, &def) { - Export::Function(f) => f.func_ref, - _ => unreachable!(), - } - } - - pub(crate) fn post_return_core_func(&self, store: &StoreOpaque) -> Option> { - let instance = self.instance.id().get(store); - let (_ty, _def, options) = instance.component().export_lifted_function(self.index); - options.post_return.map(|i| instance.runtime_post_return(i)) - } - - pub(crate) fn abi_async(&self, store: &StoreOpaque) -> bool { - let instance = self.instance.id().get(store); - let (_ty, _def, options) = instance.component().export_lifted_function(self.index); - options.async_ - } - - pub(crate) fn abi_info<'a>( - &self, - store: &'a StoreOpaque, - ) -> (Options, InstanceFlags, TypeFuncIndex, &'a CanonicalOptions) { - let vminstance = self.instance.id().get(store); - let (ty, _def, raw_options) = vminstance.component().export_lifted_function(self.index); - let mem_opts = match raw_options.data_model { - CanonicalOptionsDataModel::Gc {} => todo!("CM+GC"), - CanonicalOptionsDataModel::LinearMemory(opts) => opts, - }; - let memory = mem_opts - .memory - .map(|i| NonNull::new(vminstance.runtime_memory(i)).unwrap()); - let realloc = mem_opts.realloc.map(|i| vminstance.runtime_realloc(i)); - let flags = vminstance.instance_flags(raw_options.instance); - let callback = raw_options.callback.map(|i| vminstance.runtime_callback(i)); - let options = unsafe { - Options::new( - store.id(), - memory, - realloc, - raw_options.string_encoding, - raw_options.async_, - callback, - ) - }; - (options, flags, ty, raw_options) + } else { + Self::load_results(cx, results_ty, results, &mut src.iter()) + } + }, + ) } /// Invokes the underlying wasm function, lowering arguments and lifting the @@ -491,18 +362,13 @@ impl Func { /// are what will be allocated on the stack for this function call. They /// should be appropriately sized for the lowering/lifting operation /// happening. - /// - /// # Safety - /// - /// The safety of this function relies on the correct definitions of the - /// `LowerParams` and `LowerReturn` type. They must match the type of `self` - /// for the params/results that are going to be produced. Additionally - /// these types must be representable with a sequence of `ValRaw` values. - unsafe fn call_raw( + fn call_raw( &self, - mut store: StoreContextMut<'_, T>, + store: &mut StoreContextMut<'_, T>, + params: &Params, lower: impl FnOnce( &mut LowerContext<'_, T>, + &Params, InterfaceType, &mut MaybeUninit, ) -> Result<()>, @@ -512,15 +378,29 @@ impl Func { LowerParams: Copy, LowerReturn: Copy, { - let export = self.lifted_core_func(store.0); + let vminstance = self.instance.id().get(store.0); + let component = vminstance.component().clone(); + let (ty, def, options) = component.export_lifted_function(self.index); - #[repr(C)] - union Union { - params: Params, - ret: Return, - } + let mem_opts = match options.data_model { + CanonicalOptionsDataModel::Gc {} => todo!("CM+GC"), + CanonicalOptionsDataModel::LinearMemory(opts) => opts, + }; - let space = &mut MaybeUninit::>::uninit(); + let export = match self.instance.lookup_vmdef(store.0, def) { + Export::Function(f) => f, + _ => unreachable!(), + }; + let vminstance = self.instance.id().get(store.0); + let component_instance = options.instance; + let memory = mem_opts + .memory + .map(|i| NonNull::new(vminstance.runtime_memory(i)).unwrap()); + let realloc = mem_opts.realloc.map(|i| vminstance.runtime_realloc(i)); + let options = + unsafe { Options::new(store.0.id(), memory, realloc, options.string_encoding) }; + + let space = &mut MaybeUninit::>::uninit(); // Double-check the size/alignment of `space`, just in case. // @@ -537,62 +417,86 @@ impl Func { assert!(mem::align_of_val(map_maybe_uninit!(space.params)) == val_align); assert!(mem::align_of_val(map_maybe_uninit!(space.ret)) == val_align); - self.with_lower_context(store.as_context_mut(), |cx, ty| { - cx.enter_call(); - lower(cx, ty, map_maybe_uninit!(space.params)) - })?; - - // SAFETY: We are providing the guarantee that all the inputs are valid. - // The various pointers passed in for the function are all valid since - // they're coming from our store, and the `params_and_results` should - // have the correct layout for the core wasm function we're calling. - // Note that this latter point relies on the correctness of this module - // and `ComponentType` implementations, hence `ComponentType` being an - // `unsafe` trait. + let types = component.types(); + let mut flags = vminstance.instance_flags(component_instance); + unsafe { + // Test the "may enter" flag which is a "lock" on this instance. + // This is immediately set to `false` afterwards and note that + // there's no on-cleanup setting this flag back to true. That's an + // intentional design aspect where if anything goes wrong internally + // from this point on the instance is considered "poisoned" and can + // never be entered again. The only time this flag is set to `true` + // again is after post-return logic has completed successfully. + if !flags.may_enter() { + bail!(crate::Trap::CannotEnterComponent); + } + flags.set_may_enter(false); + + debug_assert!(flags.may_leave()); + flags.set_may_leave(false); + let mut cx = LowerContext::new(store.as_context_mut(), &options, &types, self.instance); + cx.enter_call(); + let result = lower( + &mut cx, + params, + InterfaceType::Tuple(types[ty].params), + map_maybe_uninit!(space.params), + ); + flags.set_may_leave(true); + result?; + + // This is unsafe as we are providing the guarantee that all the + // inputs are valid. The various pointers passed in for the function + // are all valid since they're coming from our store, and the + // `params_and_results` should have the correct layout for the core + // wasm function we're calling. Note that this latter point relies + // on the correctness of this module and `ComponentType` + // implementations, hence `ComponentType` being an `unsafe` trait. crate::Func::call_unchecked_raw( - &mut store, - export, + store, + export.func_ref, NonNull::new(core::ptr::slice_from_raw_parts_mut( space.as_mut_ptr().cast(), mem::size_of_val(space) / mem::size_of::(), )) .unwrap(), )?; - } - // SAFETY: We're relying on the correctness of the structure of - // `LowerReturn` and the type-checking performed to acquire the - // `TypedFunc` to make this safe. It should be the case that - // `LowerReturn` is the exact representation of the return value when - // interpreted as `[ValRaw]`, and additionally they should have the - // correct types for the function we just called (which filled in the - // return values). - let ret: &LowerReturn = unsafe { map_maybe_uninit!(space.ret).assume_init_ref() }; - - // Lift the result into the host while managing post-return state - // here as well. - // - // After a successful lift the return value of the function, which - // is currently required to be 0 or 1 values according to the - // canonical ABI, is saved within the `Store`'s `FuncData`. This'll - // later get used in post-return. - // flags.set_needs_post_return(true); - let val = self.with_lift_context(store.0, |cx, ty| lift(cx, ty, ret))?; - - // SAFETY: it's a contract of this function that `LowerReturn` is an - // appropriate representation of the result of this function. - let ret_slice = unsafe { storage_as_slice(ret) }; - - self.instance.id().get_mut(store.0).post_return_arg_set( - self.index, - match ret_slice.len() { - 0 => ValRaw::i32(0), - 1 => ret_slice[0], - _ => unreachable!(), - }, - ); - return Ok(val); + // Note that `.assume_init_ref()` here is unsafe but we're relying + // on the correctness of the structure of `LowerReturn` and the + // type-checking performed to acquire the `TypedFunc` to make this + // safe. It should be the case that `LowerReturn` is the exact + // representation of the return value when interpreted as + // `[ValRaw]`, and additionally they should have the correct types + // for the function we just called (which filled in the return + // values). + let ret = map_maybe_uninit!(space.ret).assume_init_ref(); + + // Lift the result into the host while managing post-return state + // here as well. + // + // After a successful lift the return value of the function, which + // is currently required to be 0 or 1 values according to the + // canonical ABI, is saved within the `Store`'s `FuncData`. This'll + // later get used in post-return. + flags.set_needs_post_return(true); + let val = lift( + &mut LiftContext::new(store.0, &options, &types, self.instance), + InterfaceType::Tuple(types[ty].results), + ret, + )?; + let ret_slice = storage_as_slice(ret); + self.instance.id().get_mut(store.0).post_return_arg_set( + self.index, + match ret_slice.len() { + 0 => ValRaw::i32(0), + 1 => ret_slice[0], + _ => unreachable!(), + }, + ); + return Ok(val); + } } /// Invokes the `post-return` canonical ABI option, if specified, after a @@ -653,11 +557,13 @@ impl Func { fn post_return_impl(&self, mut store: impl AsContextMut) -> Result<()> { let mut store = store.as_context_mut(); - let index = self.index; let vminstance = self.instance.id().get(store.0); let (_ty, _def, options) = vminstance.component().export_lifted_function(index); - let post_return = self.post_return_core_func(store.0); + let post_return = options.post_return.map(|i| { + let func_ref = vminstance.runtime_post_return(i); + ExportFunction { func_ref } + }); let mut flags = vminstance.instance_flags(options.instance); let mut instance = self.instance.id().get_mut(store.0); let post_return_arg = instance.as_mut().post_return_arg_take(index); @@ -702,7 +608,7 @@ impl Func { if let Some(func) = post_return { crate::Func::call_unchecked_raw( &mut store, - func, + func.func_ref, NonNull::new(core::ptr::slice_from_raw_parts(&post_return_arg, 1).cast_mut()) .unwrap(), )?; @@ -726,33 +632,12 @@ impl Func { Ok(()) } - fn lower_args( - cx: &mut LowerContext<'_, T>, - params: &[Val], - params_ty: InterfaceType, - dst: &mut [MaybeUninit], - ) -> Result<()> { - let params_ty = match params_ty { - InterfaceType::Tuple(i) => &cx.types[i], - _ => unreachable!(), - }; - if params_ty.abi.flat_count(MAX_FLAT_PARAMS).is_some() { - let dst = &mut dst.iter_mut(); - - params - .iter() - .zip(params_ty.types.iter()) - .try_for_each(|(param, ty)| param.lower(cx, *ty, dst)) - } else { - Self::store_args(cx, ¶ms_ty, params, dst) - } - } - fn store_args( + &self, cx: &mut LowerContext<'_, T>, params_ty: &TypeTuple, args: &[Val], - dst: &mut [MaybeUninit], + dst: &mut MaybeUninit<[ValRaw; MAX_FLAT_PARAMS]>, ) -> Result<()> { let size = usize::try_from(params_ty.abi.size32).unwrap(); let ptr = cx.realloc(0, 0, params_ty.abi.align32, size)?; @@ -762,40 +647,17 @@ impl Func { arg.store(cx, *ty, abi.next_field32_size(&mut offset))?; } - dst[0].write(ValRaw::i64(ptr as i64)); + map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64)); Ok(()) } - fn lift_results<'a, 'b>( - cx: &'a mut LiftContext<'b>, - results_ty: InterfaceType, - src: &'a [ValRaw], - max_flat: usize, - ) -> Result> + 'a>> { - let results_ty = match results_ty { - InterfaceType::Tuple(i) => &cx.types[i], - _ => unreachable!(), - }; - if results_ty.abi.flat_count(max_flat).is_some() { - let mut flat = src.iter(); - Ok(Box::new( - results_ty - .types - .iter() - .map(move |ty| Val::lift(cx, *ty, &mut flat)), - )) - } else { - let iter = Self::load_results(cx, results_ty, &mut src.iter())?; - Ok(Box::new(iter)) - } - } - - fn load_results<'a, 'b>( - cx: &'a mut LiftContext<'b>, - results_ty: &'a TypeTuple, + fn load_results( + cx: &mut LiftContext<'_>, + results_ty: &TypeTuple, + results: &mut [Val], src: &mut core::slice::Iter<'_, ValRaw>, - ) -> Result> + use<'a, 'b>> { + ) -> Result<()> { // FIXME(#4311): needs to read an i64 for memory64 let ptr = usize::try_from(src.next().unwrap().get_u32())?; if ptr % usize::try_from(results_ty.abi.align32)? != 0 { @@ -809,82 +671,11 @@ impl Func { .ok_or_else(|| anyhow::anyhow!("pointer out of bounds of memory"))?; let mut offset = 0; - Ok(results_ty.types.iter().map(move |ty| { + for (ty, slot) in results_ty.types.iter().zip(results) { let abi = cx.types.canonical_abi(ty); let offset = abi.next_field32_size(&mut offset); - Val::load(cx, *ty, &bytes[offset..][..abi.size32 as usize]) - })) - } - - /// Creates a `LowerContext` using the configuration values of this lifted - /// function. - /// - /// The `lower` closure provided should perform the actual lowering and - /// return the result of the lowering operation which is then returned from - /// this function as well. - fn with_lower_context( - self, - mut store: StoreContextMut, - lower: impl FnOnce(&mut LowerContext, InterfaceType) -> Result<()>, - ) -> Result<()> { - let types = self.instance.id().get(store.0).component().types().clone(); - let (options, mut flags, ty, _) = self.abi_info(store.0); - - // Test the "may enter" flag which is a "lock" on this instance. - // This is immediately set to `false` afterwards and note that - // there's no on-cleanup setting this flag back to true. That's an - // intentional design aspect where if anything goes wrong internally - // from this point on the instance is considered "poisoned" and can - // never be entered again. The only time this flag is set to `true` - // again is after post-return logic has completed successfully. - unsafe { - if !flags.may_enter() { - bail!(crate::Trap::CannotEnterComponent); - } - flags.set_may_enter(false); - } - - // Perform the actual lowering, where while this is running the - // component is forbidden from calling imports. - unsafe { - debug_assert!(flags.may_leave()); - flags.set_may_leave(false); - } - let mut cx = LowerContext::new(store.as_context_mut(), &options, &types, self.instance); - let result = lower(&mut cx, InterfaceType::Tuple(types[ty].params)); - unsafe { flags.set_may_leave(true) }; - result?; - - // If this is an async function then we're allowed to reenter the - // component at this point, and otherwise flag a post-return call being - // required as we're about to enter wasm and afterwards need a - // post-return. - unsafe { - if options.async_() { - flags.set_may_enter(true); - } else { - flags.set_needs_post_return(true); - } + *slot = Val::load(cx, *ty, &bytes[offset..][..abi.size32 as usize])?; } - Ok(()) } - - /// Creates a `LiftContext` using the configuration values with this lifted - /// function. - /// - /// The closure `lift` provided should actually perform the lift itself and - /// the result of that closure is returned from this function call as well. - fn with_lift_context( - self, - store: &mut StoreOpaque, - lift: impl FnOnce(&mut LiftContext, InterfaceType) -> Result, - ) -> Result { - let (options, _flags, ty, _) = self.abi_info(store); - let types = self.instance.id().get(store).component().types().clone(); - lift( - &mut LiftContext::new(store, &options, &types, self.instance), - InterfaceType::Tuple(types[ty].results), - ) - } } diff --git a/crates/wasmtime/src/runtime/component/func/host.rs b/crates/wasmtime/src/runtime/component/func/host.rs index bd0b58329383..59e44784f09b 100644 --- a/crates/wasmtime/src/runtime/component/func/host.rs +++ b/crates/wasmtime/src/runtime/component/func/host.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "component-model-async")] -use crate::component::concurrent::{Accessor, Status}; use crate::component::func::{LiftContext, LowerContext, Options}; use crate::component::matching::InstanceType; use crate::component::storage::slice_to_storage_mut; @@ -8,19 +6,15 @@ use crate::prelude::*; use crate::runtime::vm::component::{ ComponentInstance, InstanceFlags, VMComponentContext, VMLowering, VMLoweringCallee, }; -use crate::runtime::vm::{ - SendSyncPtr, VMFuncRef, VMGlobalDefinition, VMMemoryDefinition, VMOpaqueContext, VMStore, -}; +use crate::runtime::vm::{VMFuncRef, VMGlobalDefinition, VMMemoryDefinition, VMOpaqueContext}; use crate::{AsContextMut, CallHook, StoreContextMut, ValRaw}; use alloc::sync::Arc; use core::any::Any; -use core::future::Future; use core::mem::{self, MaybeUninit}; -use core::pin::Pin; use core::ptr::NonNull; use wasmtime_environ::component::{ - CanonicalAbiInfo, ComponentTypes, InterfaceType, MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, - MAX_FLAT_RESULTS, RuntimeComponentInstanceIndex, StringEncoding, TypeFuncIndex, TypeTuple, + CanonicalAbiInfo, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, StringEncoding, + TypeFuncIndex, }; pub struct HostFunc { @@ -35,16 +29,10 @@ impl core::fmt::Debug for HostFunc { } } -enum HostResult { - Done(Result), - #[cfg(feature = "component-model-async")] - Future(Pin> + Send>>), -} - impl HostFunc { - fn from_canonical(func: F) -> Arc + pub(crate) fn from_closure(func: F) -> Arc where - F: Fn(StoreContextMut<'_, T>, Instance, P) -> HostResult + Send + Sync + 'static, + F: Fn(StoreContextMut, P) -> Result + Send + Sync + 'static, P: ComponentNamedList + Lift + 'static, R: ComponentNamedList + Lower + 'static, T: 'static, @@ -57,42 +45,11 @@ impl HostFunc { }) } - pub(crate) fn from_closure(func: F) -> Arc - where - F: Fn(StoreContextMut, P) -> Result + Send + Sync + 'static, - P: ComponentNamedList + Lift + 'static, - R: ComponentNamedList + Lower + 'static, - { - Self::from_canonical::(move |store, _, params| { - HostResult::Done(func(store, params)) - }) - } - - #[cfg(feature = "component-model-async")] - pub(crate) fn from_concurrent(func: F) -> Arc - where - T: 'static, - F: Fn(&mut Accessor, P) -> Pin> + Send + '_>> - + Send - + Sync - + 'static, - P: ComponentNamedList + Lift + 'static, - R: ComponentNamedList + Lower + 'static, - { - let func = Arc::new(func); - Self::from_canonical::(move |store, instance, params| { - let func = func.clone(); - HostResult::Future(Box::pin( - instance.wrap_call(store, move |accessor| func(accessor, params)), - )) - }) - } - - extern "C" fn entrypoint( + extern "C" fn entrypoint( cx: NonNull, data: NonNull, ty: u32, - caller_instance: u32, + _caller_instance: u32, flags: NonNull, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, @@ -102,42 +59,33 @@ impl HostFunc { storage_len: usize, ) -> bool where - F: Fn(StoreContextMut<'_, T>, Instance, P) -> HostResult + Send + Sync + 'static, - P: ComponentNamedList + Lift, + F: Fn(StoreContextMut, P) -> Result, + P: ComponentNamedList + Lift + 'static, R: ComponentNamedList + Lower + 'static, T: 'static, { - let data = SendSyncPtr::new(NonNull::new(data.as_ptr() as *mut F).unwrap()); + let data = data.as_ptr() as *const F; unsafe { call_host_and_handle_result::(cx, |store, instance| { call_host( store, instance, TypeFuncIndex::from_u32(ty), - RuntimeComponentInstanceIndex::from_u32(caller_instance), InstanceFlags::from_raw(flags), memory, realloc, StringEncoding::from_u8(string_encoding).unwrap(), async_ != 0, NonNull::slice_from_raw_parts(storage, storage_len).as_mut(), - move |store, instance, args| (*data.as_ptr())(store, instance, args), + |store, args| (*data)(store, args), ) }) } } - fn new_dynamic_canonical(func: F) -> Arc + pub(crate) fn new_dynamic(func: F) -> Arc where - F: Fn( - StoreContextMut<'_, T>, - Instance, - Vec, - usize, - ) -> Pin>> + Send + 'static>> - + Send - + Sync - + 'static, + F: Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static, T: 'static, { Arc::new(HostFunc { @@ -150,47 +98,6 @@ impl HostFunc { }) } - pub(crate) fn new_dynamic(func: F) -> Arc - where - F: Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static, - { - Self::new_dynamic_canonical::( - move |store, _, mut params_and_results, result_start| { - let (params, results) = params_and_results.split_at_mut(result_start); - let result = func(store, params, results).map(move |()| params_and_results); - Box::pin(async move { result }) - }, - ) - } - - #[cfg(feature = "component-model-async")] - pub(crate) fn new_dynamic_concurrent(func: F) -> Arc - where - T: 'static, - F: for<'a> Fn( - &'a mut Accessor, - &'a [Val], - &'a mut [Val], - ) -> Pin> + Send + 'a>> - + Send - + Sync - + 'static, - { - let func = Arc::new(func); - Self::new_dynamic_canonical::( - move |store, instance, mut params_and_results, result_start| { - let func = func.clone(); - Box::pin(instance.wrap_call(store, move |accessor| { - Box::pin(async move { - let (params, results) = params_and_results.split_at_mut(result_start); - func(accessor, params, results).await?; - Ok(params_and_results) - }) - })) - }, - ) - } - pub fn typecheck(&self, ty: TypeFuncIndex, types: &InstanceType<'_>) -> Result<()> { (self.typecheck)(ty, types) } @@ -241,7 +148,6 @@ unsafe fn call_host( mut store: StoreContextMut<'_, T>, instance: Instance, ty: TypeFuncIndex, - caller_instance: RuntimeComponentInstanceIndex, mut flags: InstanceFlags, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, @@ -251,17 +157,19 @@ unsafe fn call_host( closure: F, ) -> Result<()> where - F: Fn(StoreContextMut<'_, T>, Instance, Params) -> HostResult + Send + Sync + 'static, Params: Lift, - Return: Lower + 'static, + Return: Lower, + F: FnOnce(StoreContextMut<'_, T>, Params) -> Result, { + if async_ { + todo!() + } + let options = Options::new( - store.0.store_opaque().id(), + store.0.id(), NonNull::new(memory), NonNull::new(realloc), string_encoding, - async_, - None, ); // Perform a dynamic check that this instance can indeed be left. Exiting @@ -276,99 +184,18 @@ where let param_tys = InterfaceType::Tuple(ty.params); let result_tys = InterfaceType::Tuple(ty.results); - if async_ { - #[cfg(feature = "component-model-async")] - { - let mut storage = Storage::<'_, Params, u32>::new_async::(storage); - - // Lift the parameters, either from flat storage or from linear - // memory. - let lift = - &mut LiftContext::new(store.0.store_opaque_mut(), &options, &types, instance); - lift.enter_call(); - let params = storage.lift_params(lift, param_tys)?; - - // Load the return pointer, if present. - let retptr = match storage.async_retptr() { - Some(ptr) => { - let mut lower = - LowerContext::new(store.as_context_mut(), &options, &types, instance); - validate_inbounds::(lower.as_slice_mut(), ptr)? - } - // If there's no return pointer then `Return` should have an - // empty flat representation. In this situation pretend the - // return pointer was 0 so we have something to shepherd along - // into the closure below. - None => { - assert_eq!(Return::flatten_count(), 0); - 0 - } - }; - - let host_result = closure(store.as_context_mut(), instance, params); - - let mut lower_result = { - let types = types.clone(); - move |store: StoreContextMut, instance: Instance, ret: Return| { - flags.set_may_leave(false); - let mut lower = LowerContext::new(store, &options, &types, instance); - ret.linear_lower_to_memory(&mut lower, result_tys, retptr)?; - flags.set_may_leave(true); - lower.exit_call()?; - Ok(()) - } - }; - let task = match host_result { - HostResult::Done(result) => { - lower_result(store.as_context_mut(), instance, result?)?; - None - } - #[cfg(feature = "component-model-async")] - HostResult::Future(future) => instance.first_poll( - store.as_context_mut(), - future, - caller_instance, - lower_result, - )?, - }; - - let status = if let Some(task) = task { - Status::Started.pack(Some(task)) - } else { - Status::Returned.pack(None) - }; - - let mut lower = LowerContext::new(store, &options, &types, instance); - storage.lower_results(&mut lower, InterfaceType::U32, status)?; - } - #[cfg(not(feature = "component-model-async"))] - { - let _ = caller_instance; - unreachable!( - "async-lowered imports should have failed validation \ - when `component-model-async` feature disabled" - ); - } - } else { - let mut storage = Storage::<'_, Params, Return>::new_sync(storage); - let mut lift = LiftContext::new(store.0.store_opaque_mut(), &options, &types, instance); - lift.enter_call(); - let params = storage.lift_params(&mut lift, param_tys)?; - - let ret = match closure(store.as_context_mut(), instance, params) { - HostResult::Done(result) => result?, - #[cfg(feature = "component-model-async")] - HostResult::Future(future) => { - instance.poll_and_block(store.0.traitobj_mut(), future, caller_instance)? - } - }; + let mut storage = Storage::<'_, Params, Return>::new_sync(storage); + let mut lift = LiftContext::new(store.0, &options, &types, instance); + lift.enter_call(); + let params = storage.lift_params(&mut lift, param_tys)?; - flags.set_may_leave(false); - let mut lower = LowerContext::new(store, &options, &types, instance); - storage.lower_results(&mut lower, result_tys, ret)?; - flags.set_may_leave(true); - lower.exit_call()?; - } + let ret = closure(store.as_context_mut(), params)?; + + flags.set_may_leave(false); + let mut lower = LowerContext::new(store, &options, &types, instance); + storage.lower_results(&mut lower, result_tys, ret)?; + flags.set_may_leave(true); + lower.exit_call()?; return Ok(()); @@ -407,10 +234,6 @@ where /// specified as a `ValRaw` to represent the argument that's being given /// to the host from WebAssembly. /// - /// * Ar - async results - means that the parameters to this call - /// additionally include an async result pointer. Async results are always - /// transmitted via a pointer so this is always a `ValRaw`. - /// /// Internally this type makes liberal use of `Union` and `Pair` helpers /// below which are simple `#[repr(C)]` wrappers around a pair of types that /// are a union or a pair. @@ -445,20 +268,6 @@ where /// Here the two parameters are laid out sequentially one after the /// other. PiRi(&'a Pair), - - /// Params: direct + async result, Results: direct - /// - /// This is like `PdRd` except that the parameters additionally include - /// a pointer for where to store the result. - #[cfg(feature = "component-model-async")] - PdArRd(&'a mut Union, MaybeUninit>), - - /// Params: indirect + async result, Results: direct - /// - /// This is like `PiRd` except that the parameters additionally include - /// a pointer for where to store the result. - #[cfg(feature = "component-model-async")] - PiArRd(&'a mut Union, MaybeUninit>), } // Helper structure used above in `Storage` to represent two consecutive @@ -574,12 +383,8 @@ where // to access. Storage::PdRd(storage) => unsafe { Src::Direct(&storage.a) }, Storage::PdRi(storage) => Src::Direct(&storage.a), - #[cfg(feature = "component-model-async")] - Storage::PdArRd(storage) => unsafe { Src::Direct(&storage.a.a) }, Storage::PiRd(storage) => unsafe { Src::Indirect(&storage.a) }, Storage::PiRi(storage) => Src::Indirect(&storage.a), - #[cfg(feature = "component-model-async")] - Storage::PiArRd(storage) => unsafe { Src::Indirect(&storage.a.a) }, } } @@ -609,67 +414,14 @@ where // help make this safe. Storage::PdRd(storage) => unsafe { Dst::Direct(&mut storage.b) }, Storage::PiRd(storage) => unsafe { Dst::Direct(&mut storage.b) }, - #[cfg(feature = "component-model-async")] - Storage::PdArRd(storage) => unsafe { Dst::Direct(&mut storage.b) }, - #[cfg(feature = "component-model-async")] - Storage::PiArRd(storage) => unsafe { Dst::Direct(&mut storage.b) }, Storage::PdRi(storage) => Dst::Indirect(&storage.b), Storage::PiRi(storage) => Dst::Indirect(&storage.b), } } - - #[cfg(feature = "component-model-async")] - fn async_retptr(&self) -> Option<&ValRaw> { - match self { - // SAFETY: like above these are `unsafe` due to accessing a - // `union` field. This should be safe via the construction of - // `Storage` which should correctly determine whether or not an - // async return pointer is provided and classify the args/rets - // appropriately. - Storage::PdArRd(storage) => unsafe { Some(&storage.a.b) }, - Storage::PiArRd(storage) => unsafe { Some(&storage.a.b) }, - Storage::PdRd(_) | Storage::PiRd(_) | Storage::PdRi(_) | Storage::PiRi(_) => None, - } - } - } - - #[cfg(feature = "component-model-async")] - impl

Storage<'_, P, u32> - where - P: ComponentType + Lift, - { - /// Classifies a new `Storage` suitable for use with async functions. - /// - /// # Safety - /// - /// Requires that the `storage` provided does indeed match an `async` - /// wasm function with the signature of `P` and `R` as params/results. - unsafe fn new_async(storage: &mut [MaybeUninit]) -> Storage<'_, P, u32> - where - R: ComponentType + Lower, - { - // SAFETY: see `Storage::new` for discussion on why this should be - // safe given the unsafe contract of the `ComponentType` trait. - unsafe { - if P::flatten_count() <= wasmtime_environ::component::MAX_FLAT_ASYNC_PARAMS { - if R::flatten_count() == 0 { - Storage::PdRd(slice_to_storage_mut(storage).assume_init_mut()) - } else { - Storage::PdArRd(slice_to_storage_mut(storage).assume_init_mut()) - } - } else { - if R::flatten_count() == 0 { - Storage::PiRd(slice_to_storage_mut(storage).assume_init_mut()) - } else { - Storage::PiArRd(slice_to_storage_mut(storage).assume_init_mut()) - } - } - } - } } } -pub(crate) fn validate_inbounds(memory: &[u8], ptr: &ValRaw) -> Result { +fn validate_inbounds(memory: &[u8], ptr: &ValRaw) -> Result { // FIXME(#4311): needs memory64 support let ptr = usize::try_from(ptr.get_u32())?; if ptr % usize::try_from(T::ALIGN32)? != 0 { @@ -709,7 +461,6 @@ unsafe fn call_host_dynamic( mut store: StoreContextMut<'_, T>, instance: Instance, ty: TypeFuncIndex, - caller_instance: RuntimeComponentInstanceIndex, mut flags: InstanceFlags, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, @@ -719,24 +470,18 @@ unsafe fn call_host_dynamic( closure: F, ) -> Result<()> where - F: Fn( - StoreContextMut<'_, T>, - Instance, - Vec, - usize, - ) -> Pin>> + Send + 'static>> - + Send - + Sync - + 'static, + F: FnOnce(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()>, T: 'static, { + if async_ { + todo!() + } + let options = Options::new( - store.0.store_opaque().id(), + store.0.id(), NonNull::new(memory), NonNull::new(realloc), string_encoding, - async_, - None, ); // Perform a dynamic check that this instance can indeed be left. Exiting @@ -746,174 +491,73 @@ where bail!("cannot leave component instance"); } + let args; + let ret_index; + let types = instance.id().get(store.0).component().types().clone(); let func_ty = &types[ty]; let param_tys = &types[func_ty.params]; let result_tys = &types[func_ty.results]; - - let mut params_and_results = Vec::new(); - let mut lift = &mut LiftContext::new(store.0.store_opaque_mut(), &options, &types, instance); - lift.enter_call(); - let max_flat = if async_ { - MAX_FLAT_ASYNC_PARAMS + let mut cx = LiftContext::new(store.0, &options, &types, instance); + cx.enter_call(); + if let Some(param_count) = param_tys.abi.flat_count(MAX_FLAT_PARAMS) { + // NB: can use `MaybeUninit::slice_assume_init_ref` when that's stable + let mut iter = + mem::transmute::<&[MaybeUninit], &[ValRaw]>(&storage[..param_count]).iter(); + args = param_tys + .types + .iter() + .map(|ty| Val::lift(&mut cx, *ty, &mut iter)) + .collect::>>()?; + ret_index = param_count; + assert!(iter.next().is_none()); } else { - MAX_FLAT_PARAMS + let mut offset = + validate_inbounds_dynamic(¶m_tys.abi, cx.memory(), storage[0].assume_init_ref())?; + args = param_tys + .types + .iter() + .map(|ty| { + let abi = types.canonical_abi(ty); + let size = usize::try_from(abi.size32).unwrap(); + let memory = &cx.memory()[abi.next_field32_size(&mut offset)..][..size]; + Val::load(&mut cx, *ty, memory) + }) + .collect::>>()?; + ret_index = 1; }; - let ret_index = dynamic_params_load( - &mut lift, - &types, - storage, - param_tys, - &mut params_and_results, - max_flat, - )?; - let result_start = params_and_results.len(); - for _ in 0..result_tys.types.len() { - params_and_results.push(Val::Bool(false)); + let mut result_vals = Vec::with_capacity(result_tys.types.len()); + for _ in result_tys.types.iter() { + result_vals.push(Val::Bool(false)); } - - if async_ { - #[cfg(feature = "component-model-async")] - { - let retptr = if result_tys.types.len() == 0 { - 0 - } else { - let retptr = storage[ret_index].assume_init(); - let mut lower = - LowerContext::new(store.as_context_mut(), &options, &types, instance); - validate_inbounds_dynamic(&result_tys.abi, lower.as_slice_mut(), &retptr)? - }; - - let future = closure( - store.as_context_mut(), - instance, - params_and_results, - result_start, - ); - - let task = instance.first_poll(store, future, caller_instance, { - let types = types.clone(); - let result_tys = func_ty.results; - move |store: StoreContextMut, instance: Instance, result_vals: Vec| { - let result_tys = &types[result_tys]; - let result_vals = &result_vals[result_start..]; - assert_eq!(result_vals.len(), result_tys.types.len()); - - flags.set_may_leave(false); - - let mut lower = LowerContext::new(store, &options, &types, instance); - let mut ptr = retptr; - for (val, ty) in result_vals.iter().zip(result_tys.types.iter()) { - let offset = types.canonical_abi(ty).next_field32_size(&mut ptr); - val.store(&mut lower, *ty, offset)?; - } - - flags.set_may_leave(true); - - lower.exit_call()?; - - Ok(()) - } - })?; - - let status = if let Some(task) = task { - Status::Started.pack(Some(task)) - } else { - Status::Returned.pack(None) - }; - - storage[0] = MaybeUninit::new(ValRaw::i32(status as i32)); - } - #[cfg(not(feature = "component-model-async"))] - { - unreachable!( - "async-lowered imports should have failed validation \ - when `component-model-async` feature disabled" - ); + closure(store.as_context_mut(), &args, &mut result_vals)?; + flags.set_may_leave(false); + + let mut cx = LowerContext::new(store, &options, &types, instance); + if let Some(cnt) = result_tys.abi.flat_count(MAX_FLAT_RESULTS) { + let mut dst = storage[..cnt].iter_mut(); + for (val, ty) in result_vals.iter().zip(result_tys.types.iter()) { + val.lower(&mut cx, *ty, &mut dst)?; } + assert!(dst.next().is_none()); } else { - let future = closure( - store.as_context_mut(), - instance, - params_and_results, - result_start, - ); - let result_vals = - instance.poll_and_block(store.0.traitobj_mut(), future, caller_instance)?; - let result_vals = &result_vals[result_start..]; - - flags.set_may_leave(false); - - let mut cx = LowerContext::new(store, &options, &types, instance); - if let Some(cnt) = result_tys.abi.flat_count(MAX_FLAT_RESULTS) { - let mut dst = storage[..cnt].iter_mut(); - for (val, ty) in result_vals.iter().zip(result_tys.types.iter()) { - val.lower(&mut cx, *ty, &mut dst)?; - } - assert!(dst.next().is_none()); - } else { - let ret_ptr = storage[ret_index].assume_init_ref(); - let mut ptr = validate_inbounds_dynamic(&result_tys.abi, cx.as_slice_mut(), ret_ptr)?; - for (val, ty) in result_vals.iter().zip(result_tys.types.iter()) { - let offset = types.canonical_abi(ty).next_field32_size(&mut ptr); - val.store(&mut cx, *ty, offset)?; - } + let ret_ptr = storage[ret_index].assume_init_ref(); + let mut ptr = validate_inbounds_dynamic(&result_tys.abi, cx.as_slice_mut(), ret_ptr)?; + for (val, ty) in result_vals.iter().zip(result_tys.types.iter()) { + let offset = types.canonical_abi(ty).next_field32_size(&mut ptr); + val.store(&mut cx, *ty, offset)?; } - - flags.set_may_leave(true); - - cx.exit_call()?; } - Ok(()) -} + flags.set_may_leave(true); -/// Loads the parameters for a dynamic host function call into `params` -/// -/// Returns the number of flat `storage` values consumed. -/// -/// # Safety -/// -/// Requires that `param_tys` matches the type signature of the `storage` that -/// was passed in. -unsafe fn dynamic_params_load( - cx: &mut LiftContext<'_>, - types: &ComponentTypes, - storage: &[MaybeUninit], - param_tys: &TypeTuple, - params: &mut Vec, - max_flat_params: usize, -) -> Result { - if let Some(param_count) = param_tys.abi.flat_count(max_flat_params) { - // NB: can use `MaybeUninit::slice_assume_init_ref` when that's stable - let storage = - unsafe { mem::transmute::<&[MaybeUninit], &[ValRaw]>(&storage[..param_count]) }; - let mut iter = storage.iter(); - for ty in param_tys.types.iter() { - params.push(Val::lift(cx, *ty, &mut iter)?); - } - assert!(iter.next().is_none()); - Ok(param_count) - } else { - let mut offset = validate_inbounds_dynamic(¶m_tys.abi, cx.memory(), unsafe { - storage[0].assume_init_ref() - })?; - for ty in param_tys.types.iter() { - let abi = types.canonical_abi(ty); - let size = usize::try_from(abi.size32).unwrap(); - let memory = &cx.memory()[abi.next_field32_size(&mut offset)..][..size]; - params.push(Val::load(cx, *ty, memory)?); - } - Ok(1) - } + cx.exit_call()?; + + return Ok(()); } -pub(crate) fn validate_inbounds_dynamic( - abi: &CanonicalAbiInfo, - memory: &[u8], - ptr: &ValRaw, -) -> Result { +fn validate_inbounds_dynamic(abi: &CanonicalAbiInfo, memory: &[u8], ptr: &ValRaw) -> Result { // FIXME(#4311): needs memory64 support let ptr = usize::try_from(ptr.get_u32())?; if ptr % usize::try_from(abi.align32)? != 0 { @@ -929,11 +573,11 @@ pub(crate) fn validate_inbounds_dynamic( Ok(ptr) } -extern "C" fn dynamic_entrypoint( +extern "C" fn dynamic_entrypoint( cx: NonNull, data: NonNull, ty: u32, - caller_instance: u32, + _caller_instance: u32, flags: NonNull, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, @@ -943,34 +587,23 @@ extern "C" fn dynamic_entrypoint( storage_len: usize, ) -> bool where - F: Fn( - StoreContextMut<'_, T>, - Instance, - Vec, - usize, - ) -> Pin>> + Send + 'static>> - + Send - + Sync - + 'static, + F: Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static, T: 'static, { - let data = SendSyncPtr::new(NonNull::new(data.as_ptr() as *mut F).unwrap()); + let data = data.as_ptr() as *const F; unsafe { call_host_and_handle_result(cx, |store, instance| { call_host_dynamic::( store, instance, TypeFuncIndex::from_u32(ty), - RuntimeComponentInstanceIndex::from_u32(caller_instance), InstanceFlags::from_raw(flags), memory, realloc, StringEncoding::from_u8(string_encoding).unwrap(), async_ != 0, NonNull::slice_from_raw_parts(storage, storage_len).as_mut(), - move |store, instance, params, results| { - (*data.as_ptr())(store, instance, params, results) - }, + |store, params, results| (*data)(store, params, results), ) }) } diff --git a/crates/wasmtime/src/runtime/component/func/options.rs b/crates/wasmtime/src/runtime/component/func/options.rs index 5c046d61ab2b..cff80b063681 100644 --- a/crates/wasmtime/src/runtime/component/func/options.rs +++ b/crates/wasmtime/src/runtime/component/func/options.rs @@ -44,13 +44,6 @@ pub struct Options { /// /// This defaults to utf-8 but can be changed if necessary. string_encoding: StringEncoding, - - /// Whether or not this the async option was set when lowering. - async_: bool, - - /// The callback for an async-lifted export, if specified. - #[cfg_attr(not(feature = "component-model-async"), expect(unused))] - callback: Option>, } // The `Options` structure stores raw pointers but they're never used unless a @@ -74,16 +67,12 @@ impl Options { memory: Option>, realloc: Option>, string_encoding: StringEncoding, - async_: bool, - callback: Option>, ) -> Options { Options { store_id, memory, realloc, string_encoding, - async_, - callback, } } @@ -171,20 +160,6 @@ impl Options { pub fn store_id(&self) -> StoreId { self.store_id } - - /// Returns whether this lifting or lowering uses the async ABI. - pub fn async_(&self) -> bool { - self.async_ - } - - #[cfg(feature = "component-model-async")] - #[expect( - dead_code, - reason = "won't be used until `component-model-async` is fully implemented" - )] - pub(crate) fn callback(&self) -> Option> { - self.callback - } } /// A helper structure which is a "package" of the context used during lowering diff --git a/crates/wasmtime/src/runtime/component/func/typed.rs b/crates/wasmtime/src/runtime/component/func/typed.rs index 8c24c3780106..c102913b9ffa 100644 --- a/crates/wasmtime/src/runtime/component/func/typed.rs +++ b/crates/wasmtime/src/runtime/component/func/typed.rs @@ -16,10 +16,6 @@ use wasmtime_environ::component::{ StringEncoding, VariantInfo, }; -#[cfg(feature = "component-model-async")] -use crate::component::concurrent::{self, PreparedCall}; -#[cfg(feature = "component-model-async")] -use core::future::Future; #[cfg(feature = "component-model-async")] use core::pin::Pin; @@ -180,47 +176,12 @@ where &self, mut store: impl AsContextMut, params: Params, - ) -> Result - where - Return: 'static, - { + ) -> Result { let mut store = store.as_context_mut(); assert!( store.0.async_support(), "cannot use `call_async` when async support is not enabled on the config" ); - - // FIXME: this'll get updated in #11127 but for now it's just showing - // that this can compile. - #[cfg(feature = "component-model-async")] - if false { - use crate::runtime::vm::SendSyncPtr; - use core::ptr::NonNull; - - let ptr = SendSyncPtr::from(NonNull::from(¶ms).cast::()); - let prepared = self.prepare_call(store.as_context_mut(), move |cx, ty, dst| { - // SAFETY: the goal here is to get `Params`, a non-`'static` - // value, to live long enough to the lowering of the - // parameters. We're guaranteed that `Params` lives in the - // future of the outer function (we're in an `async fn`) so it'll - // stay alive as long as the future itself. That is distinct, - // for example, from the signature of `call_concurrent` below. - // - // Here a pointer to `Params` is smuggled to this location - // through a `SendSyncPtr` to thwart the `'static` check of - // rustc and the signature of `prepare_call`. - let params = unsafe { ptr.cast::().as_ref() }; - Self::lower_args(cx, ty, dst, params) - })?; - - // TODO: need to place a dtor on the stack referencing the store - // which removes `prepared.task` from the store to ensure that the - // future is for sure 100% gone when this stack frame goes away. - - let result = concurrent::queue_call(store.as_context_mut(), prepared)?; - return self.func.instance.run(store, result).await?; - } - store .on_fiber(|store| self.call_impl(store, params)) .await? @@ -238,137 +199,22 @@ where /// function belongs to; use `Instance::run`, `Instance::run_with`, or /// `Instance::spawn` to poll it from within the event loop. See /// [`Instance::run`] for examples. - // - // FIXME: this function should return `impl Future` but that forces - // capturing all type parameters in scope at this time. The future - // intentionally does not close over `store` but returning `impl Future` - // implicitly does so. In a future version of Rust maybe this limitation - // will be lifted? Maybe rust-lang/rust#130043. Unsure. #[cfg(feature = "component-model-async")] pub fn call_concurrent( self, - mut store: impl AsContextMut, + store: impl AsContextMut, params: Params, - ) -> Pin> + Send>> + ) -> Pin> + Send + 'static>> where Params: 'static, Return: 'static, { - let mut store = store.as_context_mut(); - assert!( - store.0.async_support(), - "cannot use `call_concurrent` when async support is not enabled on the config" - ); - - let result = (|| { - let prepared = self.prepare_call(store.as_context_mut(), move |cx, ty, dst| { - Self::lower_args(cx, ty, dst, ¶ms) - })?; - concurrent::queue_call(store, prepared) - })(); - - Box::pin(async move { result?.await }) - } - - fn lower_args( - cx: &mut LowerContext, - ty: InterfaceType, - dst: &mut [MaybeUninit], - params: &Params, - ) -> Result<()> { - use crate::component::storage::slice_to_storage_mut; - - if Params::flatten_count() <= MAX_FLAT_PARAMS { - // SAFETY: the safety of `slice_to_storage_mut` relies on - // `Params::Lower` being represented by a sequence of - // `ValRaw`, and that's a guarantee upheld by the `Lower` - // trait itself. - let dst: &mut MaybeUninit = unsafe { slice_to_storage_mut(dst) }; - Self::lower_stack_args(cx, ¶ms, ty, dst) - } else { - Self::lower_heap_args(cx, ¶ms, ty, &mut dst[0]) - } - } - - /// Calls `concurrent::prepare_call` with monomorphized functions for - /// lowering the parameters and lifting the result according to the number - /// of core Wasm parameters and results in the signature of the function to - /// be called. - #[cfg(feature = "component-model-async")] - fn prepare_call( - self, - store: StoreContextMut<'_, T>, - lower: impl FnOnce( - &mut LowerContext, - InterfaceType, - &mut [MaybeUninit], - ) -> Result<()> - + Send - + Sync - + 'static, - ) -> Result> - where - Return: 'static, - { - use crate::component::storage::slice_to_storage; - - let param_count = if Params::flatten_count() <= MAX_FLAT_PARAMS { - Params::flatten_count() - } else { - 1 - }; - let max_results = if self.func.abi_async(store.0) { - MAX_FLAT_PARAMS - } else { - MAX_FLAT_RESULTS - }; - concurrent::prepare_call( - store, - move |func, store, params_out| { - func.with_lower_context(store, |cx, ty| lower(cx, ty, params_out)) - }, - move |func, store, results| { - let result = if Return::flatten_count() <= max_results { - func.with_lift_context(store, |cx, ty| { - // SAFETY: Per the safety requiments documented for the - // `ComponentType` trait, `Return::Lower` must be - // compatible at the binary level with a `[ValRaw; N]`, - // where `N` is `mem::size_of::() / - // mem::size_of::()`. And since this function - // is only used when `Return::flatten_count() <= - // MAX_FLAT_RESULTS` and `MAX_FLAT_RESULTS == 1`, `N` - // can only either be 0 or 1. - // - // See `ComponentInstance::exit_call` for where we use - // the result count passed from - // `wasmtime_environ::fact::trampoline`-generated code - // to ensure the slice has the correct length, and also - // `concurrent::start_call` for where we conservatively - // use a slice length of 1 unconditionally. Also note - // that, as of this writing `slice_to_storage` - // double-checks the slice length is sufficient. - let results: &Return::Lower = unsafe { slice_to_storage(results) }; - Self::lift_stack_result(cx, ty, results) - })? - } else { - func.with_lift_context(store, |cx, ty| { - Self::lift_heap_result(cx, ty, &results[0]) - })? - }; - Ok(Box::new(result)) - }, - self.func, - param_count, - ) + let _ = (self, store, params); + todo!() } fn call_impl(&self, mut store: impl AsContextMut, params: Params) -> Result { - let store = store.as_context_mut(); - - if self.func.abi_async(store.0) { - bail!("must enable the `component-model-async` feature to call async-lifted exports") - } - + let store = &mut store.as_context_mut(); // Note that this is in theory simpler than it might read at this time. // Here we're doing a runtime dispatch on the `flatten_count` for the // params/results to see whether they're inbounds. This creates 4 cases @@ -379,42 +225,35 @@ where // space reserved for the params/results is always of the appropriate // size (as the params/results needed differ depending on the "flatten" // count) - // - // SAFETY: the safety of these invocations of `call_raw` depends on the - // correctness of the ascription of the `LowerParams` and `LowerReturn` - // types on the `call_raw` function. That's upheld here through the - // safety requirements of `Lift` and `Lower` on `Params` and `Return` in - // combination with checking the various possible branches here and - // dispatching to appropriately typed functions. - unsafe { - // This type is used as `LowerParams` for `call_raw` which is either - // `Params::Lower` or `ValRaw` representing it's either on the stack - // or it's on the heap. This allocates 1 extra `ValRaw` on the stack - // if `Params` is empty and `Return` is also empty, but that's a - // reasonable enough price to pay for now given the current code - // organization. - #[derive(Copy, Clone)] - union Union { - _a: T, - _b: U, + if Params::flatten_count() <= MAX_FLAT_PARAMS { + if Return::flatten_count() <= MAX_FLAT_RESULTS { + self.func.call_raw( + store, + ¶ms, + Self::lower_stack_args, + Self::lift_stack_result, + ) + } else { + self.func.call_raw( + store, + ¶ms, + Self::lower_stack_args, + Self::lift_heap_result, + ) } - + } else { if Return::flatten_count() <= MAX_FLAT_RESULTS { self.func.call_raw( store, - |cx, ty, dst: &mut MaybeUninit>| { - let dst = storage_as_slice_mut(dst); - Self::lower_args(cx, ty, dst, ¶ms) - }, + ¶ms, + Self::lower_heap_args, Self::lift_stack_result, ) } else { self.func.call_raw( store, - |cx, ty, dst: &mut MaybeUninit>| { - let dst = storage_as_slice_mut(dst); - Self::lower_args(cx, ty, dst, ¶ms) - }, + ¶ms, + Self::lower_heap_args, Self::lift_heap_result, ) } @@ -450,6 +289,8 @@ where ty: InterfaceType, dst: &mut MaybeUninit, ) -> Result<()> { + assert!(Params::flatten_count() > MAX_FLAT_PARAMS); + // Memory must exist via validation if the arguments are stored on the // heap, so we can create a `MemoryMut` at this point. Afterwards // `realloc` is used to allocate space for all the arguments and then @@ -484,6 +325,7 @@ where ty: InterfaceType, dst: &Return::Lower, ) -> Result { + assert!(Return::flatten_count() <= MAX_FLAT_RESULTS); Return::linear_lift_from_flat(cx, ty, dst) } @@ -850,37 +692,21 @@ pub unsafe trait Lift: Sized + ComponentType { ) -> Result; /// Converts `list` into a `Vec`, used in `Lift for Vec`. - #[doc(hidden)] - fn linear_lift_list_from_memory( - cx: &mut LiftContext<'_>, - list: &WasmList, - ) -> Result> - where - Self: Sized, - { - let mut dst = Vec::with_capacity(list.len); - Self::linear_lift_into_from_memory(cx, list, &mut dst)?; - Ok(dst) - } - - /// Load no more than `max_count` items from `list` into `dst`. /// /// This is primarily here to get overridden for implementations of integers /// which can avoid some extra fluff and use a pattern that's more easily /// optimizable by LLVM. #[doc(hidden)] - fn linear_lift_into_from_memory( + fn linear_lift_list_from_memory( cx: &mut LiftContext<'_>, list: &WasmList, - dst: &mut impl Extend, - ) -> Result<()> + ) -> Result> where Self: Sized, { - for i in 0..list.len { - dst.extend(Some(list.get_from_store(cx, i).unwrap()?)); - } - Ok(()) + (0..list.len) + .map(|index| list.get_from_store(cx, index).unwrap()) + .collect() } } @@ -1084,18 +910,13 @@ macro_rules! integers { Ok($primitive::from_le_bytes(bytes.try_into().unwrap())) } - fn linear_lift_into_from_memory( - cx: &mut LiftContext<'_>, - list: &WasmList, - dst: &mut impl Extend, - ) -> Result<()> - where - Self: Sized, - { - dst.extend(list._as_le_slice(cx.memory()) - .iter() - .map(|i| Self::from_le(*i))); - Ok(()) + fn linear_lift_list_from_memory(cx: &mut LiftContext<'_>, list: &WasmList) -> Result> { + Ok( + list._as_le_slice(cx.memory()) + .iter() + .map(|i| Self::from_le(*i)) + .collect(), + ) } } )*) @@ -2388,7 +2209,7 @@ pub unsafe fn lower_payload( let typed_len = storage_as_slice(typed).len(); let payload = storage_as_slice_mut(payload); for slot in payload[typed_len..].iter_mut() { - slot.write(ValRaw::u64(0)); + *slot = ValRaw::u64(0); } Ok(()) } diff --git a/crates/wasmtime/src/runtime/component/linker.rs b/crates/wasmtime/src/runtime/component/linker.rs index 1e0059385080..30c5fe6b9356 100644 --- a/crates/wasmtime/src/runtime/component/linker.rs +++ b/crates/wasmtime/src/runtime/component/linker.rs @@ -392,7 +392,7 @@ impl LinkerInstance<'_, T> { } } - /// Defines a new host-provided function into this [`LinkerInstance`]. + /// Defines a new host-provided function into this [`Linker`]. /// /// This method is used to give host functions to wasm components. The /// `func` provided will be callable from linked components with the type @@ -408,19 +408,6 @@ impl LinkerInstance<'_, T> { /// type parameter from [`Store`](crate::Store) which is accessible /// through the leading [`StoreContextMut<'_, T>`](crate::StoreContextMut) /// argument which can be provided to the `func` given here. - /// - /// # Blocking / Async Behavior - /// - /// The host function `func` provided here is a blocking function from the - /// perspective of WebAssembly, regardless of how [`Config::async_support`] - /// is defined. This function can be used both with sync and async stores - /// and will always define a blocking function. - /// - /// To define a function which is async on the host, but blocking to the - /// guest, see the [`func_wrap_async`] method. - /// - /// [`Config::async_support`]: crate::Config::async_support - /// [`func_wrap_async`]: LinkerInstance::func_wrap_async // // TODO: needs more words and examples pub fn func_wrap(&mut self, name: &str, func: F) -> Result<()> @@ -433,48 +420,17 @@ impl LinkerInstance<'_, T> { Ok(()) } - /// Defines a new host-provided async function into this [`LinkerInstance`]. - /// - /// This function is similar to [`Self::func_wrap`] except it takes an async - /// host function instead of a blocking host function. The `F` function here - /// is intended to be: - /// - /// ```ignore - /// F: AsyncFn(StoreContextMut<'_, T>, Params) -> Result - /// ``` - /// - /// however the returned future must be `Send` which is not possible to - /// bound at this time. This will be switched to an async closure once Rust - /// supports it. - /// - /// # Blocking / Async Behavior - /// - /// This function can only be called when [`Config::async_support`] is - /// enabled. The function defined which WebAssembly calls will still appear - /// as blocking from the perspective of WebAssembly itself. The host, - /// however, can perform asynchronous operations without blocking the thread - /// performing a call. - /// - /// When [`Config::async_support`] is enabled then all WebAssembly is - /// invoked on a separate stack within a Wasmtime-managed fiber. This means - /// that if the future returned by `F` is not immediately ready then the - /// fiber will be suspended to block WebAssembly but not the host. When the - /// future becomes ready again the fiber will be resumed to continue - /// execution within WebAssembly. - /// - /// # Panics - /// - /// This function panics if [`Config::async_support`] is set to `false`. + /// Defines a new host-provided async function into this [`Linker`]. /// - /// [`Config::async_support`]: crate::Config::async_support - /// [`func_wrap_async`]: LinkerInstance::func_wrap_async + /// This is exactly like [`Self::func_wrap`] except it takes an async + /// host function. #[cfg(feature = "async")] pub fn func_wrap_async(&mut self, name: &str, f: F) -> Result<()> where - F: Fn( - StoreContextMut<'_, T>, + F: for<'a> Fn( + StoreContextMut<'a, T>, Params, - ) -> Box> + Send + '_> + ) -> Box> + Send + 'a> + Send + Sync + 'static, @@ -493,77 +449,28 @@ impl LinkerInstance<'_, T> { /// Defines a new host-provided async function into this [`LinkerInstance`]. /// - /// This function defines a host function available to call from - /// WebAssembly. WebAssembly may additionally make multiple invocations of - /// this function concurrently all at the same time. This function requires - /// the [`Config::wasm_component_model_async`] feature to be enabled. - /// - /// The function `f` provided will be invoked when called by WebAssembly. - /// WebAssembly components may then call `f` multiple times while previous - /// invocations of `f` are already running. Additionally while `f` is - /// running other host functions may be invoked. - /// - /// The `F` function here is intended to be: - /// - /// ```ignore - /// F: AsyncFn(&mut Accessor, Params) -> Result - /// ``` - /// - /// however the returned future must be `Send` which is not possible to - /// bound at this time. This will be switched to an async closure once Rust - /// supports it. - /// - /// The closure `f` is provided an [`Accessor`] which can be used to acquire - /// temporary, blocking, access to a [`StoreContextMut`] (through - /// [`Access`]). This models how a store is not available to `f` across - /// `await` points but it is temporarily available while actively being - /// polled. - /// - /// # Blocking / Async Behavior - /// - /// This function can only be called when [`Config::async_support`] is - /// enabled. Unlike [`Self::func_wrap`] and [`Self::func_wrap_async`] this - /// function is asynchronous even from the perspective of guest WebAssembly. - /// This means that if `f` is not immediately resolved then the call from - /// WebAssembly will still return immediately (assuming it was lowered with - /// `async`). The closure `f` should not block the current thread and should - /// only perform blocking via `async` meaning that `f` won't block either - /// WebAssembly nor the host. - /// - /// Note that WebAssembly components can lower host functions both with and - /// without `async`. That means that even if a host function is defined in - /// the "concurrent" mode here a guest may still lower it synchronously. In - /// this situation Wasmtime will manage blocking the guest while the closure - /// `f` provided here completes. If a guest lowers this function with - /// `async`, though, then no blocking will happen. - /// - /// # Panics - /// - /// This function panics if [`Config::async_support`] is set to `false`. - /// - /// [`Config::async_support`]: crate::Config::async_support - /// [`Config::wasm_component_model_async`]: crate::Config::wasm_component_model_async - /// [`func_wrap_async`]: LinkerInstance::func_wrap_async + /// This allows the caller to register host functions with the + /// LinkerInstance such that multiple calls to such functions can run + /// concurrently. This isn't possible with the existing func_wrap_async + /// method because it takes a function which returns a future that owns a + /// unique reference to the Store, meaning the Store can't be used for + /// anything else until the future resolves. #[cfg(feature = "component-model-async")] pub fn func_wrap_concurrent(&mut self, name: &str, f: F) -> Result<()> where T: 'static, - F: Fn( - &mut Accessor, + F: for<'a> Fn( + &'a mut Accessor, Params, - ) -> Pin> + Send + '_>> + ) -> Pin> + Send + 'a>> + Send + Sync + 'static, - Params: ComponentNamedList + Lift + 'static, - Return: ComponentNamedList + Lower + 'static, + Params: ComponentNamedList + Lift + Send + Sync + 'static, + Return: ComponentNamedList + Lower + Send + Sync + 'static, { - assert!( - self.engine.config().async_support, - "cannot use `func_wrap_concurrent` without enabling async support in the config" - ); - self.insert(name, Definition::Func(HostFunc::from_concurrent(f)))?; - Ok(()) + let _ = (name, f); + todo!() } /// Define a new host-provided function using dynamically typed values. @@ -676,10 +583,8 @@ impl LinkerInstance<'_, T> { /// Define a new host-provided async function using dynamic types. /// - /// As [`Self::func_wrap_async`] is a dual of [`Self::func_wrap`], this - /// function is the dual of [`Self::func_new`]. - /// - /// For documentation on blocking behavior see [`Self::func_wrap_async`]. + /// This is exactly like [`Self::func_new`] except it takes an async + /// host function. #[cfg(feature = "async")] pub fn func_new_async(&mut self, name: &str, f: F) -> Result<()> where @@ -702,34 +607,6 @@ impl LinkerInstance<'_, T> { return self.func_new(name, ff); } - /// Define a new host-provided async function using dynamic types. - /// - /// As [`Self::func_wrap_concurrent`] is a dual of [`Self::func_wrap`], this - /// function is the dual of [`Self::func_new`]. - /// - /// For documentation on async/blocking behavior see - /// [`Self::func_wrap_concurrent`]. - #[cfg(feature = "component-model-async")] - pub fn func_new_concurrent(&mut self, name: &str, f: F) -> Result<()> - where - T: 'static, - F: for<'a> Fn( - &'a mut Accessor, - &'a [Val], - &'a mut [Val], - ) -> Pin> + Send + 'a>> - + Send - + Sync - + 'static, - { - assert!( - self.engine.config().async_support, - "cannot use `func_wrap_concurrent` without enabling async support in the config" - ); - self.insert(name, Definition::Func(HostFunc::new_dynamic_concurrent(f)))?; - Ok(()) - } - /// Defines a [`Module`] within this instance. /// /// This can be used to provide a core wasm [`Module`] as an import to a @@ -780,7 +657,10 @@ impl LinkerInstance<'_, T> { #[cfg(feature = "async")] pub fn resource_async(&mut self, name: &str, ty: ResourceType, dtor: F) -> Result<()> where - F: Fn(StoreContextMut<'_, T>, u32) -> Box> + Send + '_> + F: for<'a> Fn( + StoreContextMut<'a, T>, + u32, + ) -> Box> + Send + 'a> + Send + Sync + 'static, diff --git a/crates/wasmtime/src/runtime/component/matching.rs b/crates/wasmtime/src/runtime/component/matching.rs index 24e006d35575..916c0260bfc7 100644 --- a/crates/wasmtime/src/runtime/component/matching.rs +++ b/crates/wasmtime/src/runtime/component/matching.rs @@ -2,7 +2,6 @@ use crate::Module; use crate::component::ResourceType; use crate::component::func::HostFunc; use crate::component::linker::{Definition, Strings}; -use crate::component::types::{FutureType, StreamType}; use crate::runtime::vm::component::ComponentInstance; use crate::types::matching; use crate::{Engine, prelude::*}; @@ -10,7 +9,7 @@ use alloc::sync::Arc; use wasmtime_environ::PrimaryMap; use wasmtime_environ::component::{ ComponentTypes, NameMap, ResourceIndex, TypeComponentInstance, TypeDef, TypeFuncIndex, - TypeFutureTableIndex, TypeModule, TypeResourceTableIndex, TypeStreamTableIndex, + TypeModule, TypeResourceTableIndex, }; pub struct TypeChecker<'a> { @@ -199,12 +198,4 @@ impl<'a> InstanceType<'a> { .copied() .unwrap_or_else(|| ResourceType::uninstantiated(&self.types, index)) } - - pub fn future_type(&self, index: TypeFutureTableIndex) -> FutureType { - FutureType::from(self.types[index].ty, self) - } - - pub fn stream_type(&self, index: TypeStreamTableIndex) -> StreamType { - StreamType::from(self.types[index].ty, self) - } } diff --git a/crates/wasmtime/src/runtime/component/mod.rs b/crates/wasmtime/src/runtime/component/mod.rs index 685ce7ace17b..6585148d7c45 100644 --- a/crates/wasmtime/src/runtime/component/mod.rs +++ b/crates/wasmtime/src/runtime/component/mod.rs @@ -117,8 +117,8 @@ mod values; pub use self::component::{Component, ComponentExportIndex}; #[cfg(feature = "component-model-async")] pub use self::concurrent::{ - Access, Accessor, ErrorContext, FutureReader, FutureWriter, HostFuture, HostStream, - StreamReader, StreamWriter, VMComponentAsyncStore, + Accessor, ErrorContext, FutureReader, Promise, PromisesUnordered, StreamReader, + VMComponentAsyncStore, }; pub use self::func::{ ComponentNamedList, ComponentType, Func, Lift, Lower, TypedFunc, WasmList, WasmStr, @@ -159,6 +159,8 @@ pub mod __internal { pub use core::cell::RefCell; pub use core::future::Future; pub use core::mem::transmute; + #[cfg(feature = "component-model-async")] + pub use futures::future::FutureExt; #[cfg(feature = "async")] pub use trait_variant::make as trait_variant_make; pub use wasmtime_environ; @@ -681,9 +683,3 @@ pub mod bindgen_examples; #[cfg(not(any(docsrs, test, doctest)))] #[doc(hidden)] pub mod bindgen_examples {} - -#[cfg(not(feature = "component-model-async"))] -pub(crate) mod concurrent_disabled; - -#[cfg(not(feature = "component-model-async"))] -pub(crate) use concurrent_disabled as concurrent; diff --git a/crates/wasmtime/src/runtime/component/storage.rs b/crates/wasmtime/src/runtime/component/storage.rs index d471c75e7213..01537b42984d 100644 --- a/crates/wasmtime/src/runtime/component/storage.rs +++ b/crates/wasmtime/src/runtime/component/storage.rs @@ -19,11 +19,11 @@ pub unsafe fn storage_as_slice(storage: &T) -> &[ValRaw] { } /// Same as `storage_as_slice`, but mutable. -pub unsafe fn storage_as_slice_mut(storage: &mut MaybeUninit) -> &mut [MaybeUninit] { +pub unsafe fn storage_as_slice_mut(storage: &mut T) -> &mut [ValRaw] { assert_raw_slice_compat::(); slice::from_raw_parts_mut( - (storage as *mut MaybeUninit).cast(), + (storage as *mut T).cast(), mem::size_of_val(storage) / mem::size_of::(), ) } @@ -37,29 +37,7 @@ pub unsafe fn slice_to_storage_mut(slice: &mut [MaybeUninit]) -> &mut // stay within the bounds of the number of actual values given rather than // reading past the end of an array. This shouldn't actually trip unless // there's a bug in Wasmtime though. - assert!( - mem::size_of_val(slice) >= mem::size_of::(), - "needed {}; got {}", - mem::size_of::(), - mem::size_of_val(slice) - ); + assert!(mem::size_of_val(slice) >= mem::size_of::()); &mut *slice.as_mut_ptr().cast() } - -/// Same as `storage_as_slice`, but in reverse -#[cfg(feature = "component-model-async")] -pub unsafe fn slice_to_storage(slice: &[ValRaw]) -> &T { - assert_raw_slice_compat::(); - - // See notes above in `slice_to_storage_mut` about how this is an actual - // runtime assertion. - assert!( - mem::size_of_val(slice) >= mem::size_of::(), - "needed {}; got {}", - mem::size_of::(), - mem::size_of_val(slice) - ); - - &*slice.as_ptr().cast() -} diff --git a/crates/wasmtime/src/runtime/component/types.rs b/crates/wasmtime/src/runtime/component/types.rs index ec1ae0aceb3a..68b9f9b7b5b7 100644 --- a/crates/wasmtime/src/runtime/component/types.rs +++ b/crates/wasmtime/src/runtime/component/types.rs @@ -9,9 +9,8 @@ use wasmtime_environ::PrimaryMap; use wasmtime_environ::component::{ ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex, TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex, - TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeModuleIndex, TypeOptionIndex, - TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeStreamIndex, - TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, + TypeListIndex, TypeModuleIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, + TypeResultIndex, TypeTupleIndex, TypeVariantIndex, }; pub use crate::component::resources::ResourceType; @@ -146,16 +145,9 @@ impl TypeChecker<'_> { (InterfaceType::String, _) => false, (InterfaceType::Char, InterfaceType::Char) => true, (InterfaceType::Char, _) => false, - (InterfaceType::Future(t1), InterfaceType::Future(t2)) => { - self.future_table_types_equal(t1, t2) - } - (InterfaceType::Future(_), _) => false, - (InterfaceType::Stream(t1), InterfaceType::Stream(t2)) => { - self.stream_table_types_equal(t1, t2) - } - (InterfaceType::Stream(_), _) => false, - (InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true, - (InterfaceType::ErrorContext(_), _) => false, + (InterfaceType::Future(_), _) + | (InterfaceType::Stream(_), _) + | (InterfaceType::ErrorContext(_), _) => todo!(), } } @@ -255,34 +247,6 @@ impl TypeChecker<'_> { let b = &self.b_types[f2]; a.names == b.names } - - fn future_table_types_equal(&self, t1: TypeFutureTableIndex, t2: TypeFutureTableIndex) -> bool { - self.futures_equal(self.a_types[t1].ty, self.b_types[t2].ty) - } - - fn futures_equal(&self, t1: TypeFutureIndex, t2: TypeFutureIndex) -> bool { - let a = &self.a_types[t1]; - let b = &self.b_types[t2]; - match (a.payload, b.payload) { - (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2), - (None, None) => true, - _ => false, - } - } - - fn stream_table_types_equal(&self, t1: TypeStreamTableIndex, t2: TypeStreamTableIndex) -> bool { - self.streams_equal(self.a_types[t1].ty, self.b_types[t2].ty) - } - - fn streams_equal(&self, t1: TypeStreamIndex, t2: TypeStreamIndex) -> bool { - let a = &self.a_types[t1]; - let b = &self.b_types[t2]; - match (a.payload, b.payload) { - (Some(t1), Some(t2)) => self.interface_types_equal(t1, t2), - (None, None) => true, - _ => false, - } - } } /// A `list` interface type @@ -455,7 +419,7 @@ impl PartialEq for OptionType { impl Eq for OptionType {} -/// A `result` interface type +/// An `expected` interface type #[derive(Clone, Debug)] pub struct ResultType(Handle); @@ -515,58 +479,6 @@ impl PartialEq for Flags { impl Eq for Flags {} -/// An `future` interface type -#[derive(Clone, Debug)] -pub struct FutureType(Handle); - -impl FutureType { - pub(crate) fn from(index: TypeFutureIndex, ty: &InstanceType<'_>) -> Self { - FutureType(Handle::new(index, ty)) - } - - /// Retrieve the type parameter for this `future`. - pub fn ty(&self) -> Option { - Some(Type::from( - self.0.types[self.0.index].payload.as_ref()?, - &self.0.instance(), - )) - } -} - -impl PartialEq for FutureType { - fn eq(&self, other: &Self) -> bool { - self.0.equivalent(&other.0, TypeChecker::futures_equal) - } -} - -impl Eq for FutureType {} - -/// An `stream` interface type -#[derive(Clone, Debug)] -pub struct StreamType(Handle); - -impl StreamType { - pub(crate) fn from(index: TypeStreamIndex, ty: &InstanceType<'_>) -> Self { - StreamType(Handle::new(index, ty)) - } - - /// Retrieve the type parameter for this `stream`. - pub fn ty(&self) -> Option { - Some(Type::from( - self.0.types[self.0.index].payload.as_ref()?, - &self.0.instance(), - )) - } -} - -impl PartialEq for StreamType { - fn eq(&self, other: &Self) -> bool { - self.0.equivalent(&other.0, TypeChecker::streams_equal) - } -} - -impl Eq for StreamType {} - /// Represents a component model interface type #[derive(Clone, PartialEq, Eq, Debug)] #[allow(missing_docs)] @@ -594,9 +506,6 @@ pub enum Type { Flags(Flags), Own(ResourceType), Borrow(ResourceType), - Future(FutureType), - Stream(StreamType), - ErrorContext, } impl Type { @@ -754,9 +663,9 @@ impl Type { InterfaceType::Flags(index) => Type::Flags(Flags::from(*index, instance)), InterfaceType::Own(index) => Type::Own(instance.resource_type(*index)), InterfaceType::Borrow(index) => Type::Borrow(instance.resource_type(*index)), - InterfaceType::Future(index) => Type::Future(instance.future_type(*index)), - InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)), - InterfaceType::ErrorContext(_) => Type::ErrorContext, + InterfaceType::Future(_) + | InterfaceType::Stream(_) + | InterfaceType::ErrorContext(_) => todo!(), } } @@ -785,9 +694,6 @@ impl Type { Type::Flags(_) => "flags", Type::Own(_) => "own", Type::Borrow(_) => "borrow", - Type::Future(_) => "future", - Type::Stream(_) => "stream", - Type::ErrorContext => "error-context", } } } diff --git a/crates/wasmtime/src/runtime/component/values.rs b/crates/wasmtime/src/runtime/component/values.rs index 0535829382bf..ef010de12984 100644 --- a/crates/wasmtime/src/runtime/component/values.rs +++ b/crates/wasmtime/src/runtime/component/values.rs @@ -1,6 +1,5 @@ use crate::ValRaw; use crate::component::ResourceAny; -use crate::component::concurrent::{self, ErrorContext, HostFuture, HostStream}; use crate::component::func::{Lift, LiftContext, Lower, LowerContext, desc}; use crate::prelude::*; use core::mem::MaybeUninit; @@ -87,9 +86,6 @@ pub enum Val { Result(Result>, Option>>), Flags(Vec), Resource(ResourceAny), - Future(FutureAny), - Stream(StreamAny), - ErrorContext(ErrorContextAny), } impl Val { @@ -206,15 +202,9 @@ impl Val { Val::Flags(flags) } - InterfaceType::Future(_) => { - HostFuture::<()>::linear_lift_from_flat(cx, ty, next(src))?.into_val() - } - InterfaceType::Stream(_) => { - HostStream::<()>::linear_lift_from_flat(cx, ty, next(src))?.into_val() - } - InterfaceType::ErrorContext(_) => { - ErrorContext::linear_lift_from_flat(cx, ty, next(src))?.into_val() - } + InterfaceType::Future(_) + | InterfaceType::Stream(_) + | InterfaceType::ErrorContext(_) => todo!(), }) } @@ -336,15 +326,9 @@ impl Val { } Val::Flags(flags) } - InterfaceType::Future(_) => { - HostFuture::<()>::linear_lift_from_memory(cx, ty, bytes)?.into_val() - } - InterfaceType::Stream(_) => { - HostStream::<()>::linear_lift_from_memory(cx, ty, bytes)?.into_val() - } - InterfaceType::ErrorContext(_) => { - ErrorContext::linear_lift_from_memory(cx, ty, bytes)?.into_val() - } + InterfaceType::Future(_) + | InterfaceType::Stream(_) + | InterfaceType::ErrorContext(_) => todo!(), }) } @@ -479,30 +463,9 @@ impl Val { Ok(()) } (InterfaceType::Flags(_), _) => unexpected(ty, self), - (InterfaceType::Future(_), Val::Future(FutureAny(rep))) => { - concurrent::lower_future_to_index(*rep, cx, ty)?.linear_lower_to_flat( - cx, - InterfaceType::U32, - next_mut(dst), - ) - } - (InterfaceType::Future(_), _) => unexpected(ty, self), - (InterfaceType::Stream(_), Val::Stream(StreamAny(rep))) => { - concurrent::lower_stream_to_index(*rep, cx, ty)?.linear_lower_to_flat( - cx, - InterfaceType::U32, - next_mut(dst), - ) - } - (InterfaceType::Stream(_), _) => unexpected(ty, self), - (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => { - concurrent::lower_error_context_to_index(*rep, cx, ty)?.linear_lower_to_flat( - cx, - InterfaceType::U32, - next_mut(dst), - ) - } - (InterfaceType::ErrorContext(_), _) => unexpected(ty, self), + (InterfaceType::Future(_), _) + | (InterfaceType::Stream(_), _) + | (InterfaceType::ErrorContext(_), _) => todo!(), } } @@ -644,34 +607,13 @@ impl Val { Ok(()) } (InterfaceType::Flags(_), _) => unexpected(ty, self), - (InterfaceType::Future(_), Val::Future(FutureAny(rep))) => { - concurrent::lower_future_to_index::(*rep, cx, ty)?.linear_lower_to_memory( - cx, - InterfaceType::U32, - offset, - ) - } - (InterfaceType::Future(_), _) => unexpected(ty, self), - (InterfaceType::Stream(_), Val::Stream(StreamAny(rep))) => { - concurrent::lower_stream_to_index::(*rep, cx, ty)?.linear_lower_to_memory( - cx, - InterfaceType::U32, - offset, - ) - } - (InterfaceType::Stream(_), _) => unexpected(ty, self), - (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => { - concurrent::lower_error_context_to_index(*rep, cx, ty)?.linear_lower_to_memory( - cx, - InterfaceType::U32, - offset, - ) - } - (InterfaceType::ErrorContext(_), _) => unexpected(ty, self), + (InterfaceType::Future(_), _) + | (InterfaceType::Stream(_), _) + | (InterfaceType::ErrorContext(_), _) => todo!(), } } - pub(crate) fn desc(&self) -> &'static str { + fn desc(&self) -> &'static str { match self { Val::Bool(_) => "bool", Val::U8(_) => "u8", @@ -695,9 +637,6 @@ impl Val { Val::Result(_) => "result", Val::Resource(_) => "resource", Val::Flags(_) => "flags", - Val::Future(_) => "future", - Val::Stream(_) => "stream", - Val::ErrorContext(_) => "error-context", } } @@ -776,12 +715,6 @@ impl PartialEq for Val { (Self::Flags(_), _) => false, (Self::Resource(l), Self::Resource(r)) => l == r, (Self::Resource(_), _) => false, - (Self::Future(l), Self::Future(r)) => l == r, - (Self::Future(_), _) => false, - (Self::Stream(l), Self::Stream(r)) => l == r, - (Self::Stream(_), _) => false, - (Self::ErrorContext(l), Self::ErrorContext(r)) => l == r, - (Self::ErrorContext(_), _) => false, } } } @@ -1110,37 +1043,3 @@ fn unexpected(ty: InterfaceType, val: &Val) -> Result { val.desc() ) } - -/// Represents a component model `future`. -/// -/// Note that this type is not usable at this time as its implementation has not -/// been filled out. There are no operations on this and there's additionally no -/// ability to "drop" or deallocate this index. This means that from the -/// perspective of wasm it'll appear that this handle has "leaked" without ever -/// being dropped or read from. -// -// FIXME(#11161) this needs to be filled out implementation-wise -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FutureAny(pub(crate) u32); - -/// Represents a component model `stream`. -/// -/// Note that this type is not usable at this time as its implementation has not -/// been filled out. There are no operations on this and there's additionally no -/// ability to "drop" or deallocate this index. This means that from the -/// perspective of wasm it'll appear that this handle has "leaked" without ever -/// being dropped or read from. -// -// FIXME(#11161) this needs to be filled out implementation-wise -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StreamAny(pub(crate) u32); - -/// Represents a component model `error-context`. -/// -/// Note that this type is not usable at this time as its implementation has not -/// been filled out. There are no operations on this and there's additionally no -/// ability to "drop" or deallocate this index. -// -// FIXME(#11161) this needs to be filled out implementation-wise -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ErrorContextAny(pub(crate) u32); diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs index acb1e0deffab..c037cb072166 100644 --- a/crates/wasmtime/src/runtime/func.rs +++ b/crates/wasmtime/src/runtime/func.rs @@ -1485,14 +1485,13 @@ pub(crate) fn invoke_wasm_and_catch_traps( // restored upon exiting Wasm. Note that the `CallThreadState` that is // created by the `catch_traps` call below will store a pointer to this // stack-allocated `previous_runtime_state`. - let mut previous_runtime_state = - EntryStoreContext::enter_wasm(store, &mut initial_stack_csi); + let previous_runtime_state = EntryStoreContext::enter_wasm(store, &mut initial_stack_csi); if let Err(trap) = store.0.call_hook(CallHook::CallingWasm) { // `previous_runtime_state` implicitly dropped here return Err(trap); } - let result = crate::runtime::vm::catch_traps(store, &mut previous_runtime_state, closure); + let result = crate::runtime::vm::catch_traps(store, &previous_runtime_state, closure); core::mem::drop(previous_runtime_state); store.0.call_hook(CallHook::ReturningFromWasm)?; result.map_err(|t| crate::trap::from_runtime_box(store.0, t)) @@ -1630,7 +1629,7 @@ impl EntryStoreContext { /// This function restores the values stored in this struct. We invoke this /// function through this type's `Drop` implementation. This ensures that we /// even restore the values if we unwind the stack (e.g., because we are - /// panicking out of a Wasm execution). + /// panicing out of a Wasm execution). #[inline] fn exit_wasm(&mut self) { unsafe { @@ -2317,7 +2316,6 @@ impl HostContext { drop(store); let r = func(caller.sub_caller(), params); - if let Err(trap) = caller.store.0.call_hook(CallHook::ReturningFromHost) { break 'ret R::fallible_from_error(trap); } diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs index 5b69c7ffe19a..d5e6ead6a260 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs @@ -1932,7 +1932,6 @@ at https://bytecodealliance.org/security. self.num_component_instances += 1; } - #[inline] #[cfg(feature = "component-model")] pub(crate) fn component_resource_state_with_instance( &mut self, diff --git a/crates/wasmtime/src/runtime/vm/component.rs b/crates/wasmtime/src/runtime/vm/component.rs index d9babb593ae9..0b1ae63e71f8 100644 --- a/crates/wasmtime/src/runtime/vm/component.rs +++ b/crates/wasmtime/src/runtime/vm/component.rs @@ -36,9 +36,6 @@ pub use self::resources::{ CallContexts, ResourceTable, ResourceTables, TypedResource, TypedResourceIndex, }; -#[cfg(feature = "component-model-async")] -use crate::component::concurrent; - /// Runtime representation of a component instance and all state necessary for /// the instance itself. /// @@ -80,11 +77,6 @@ pub struct ComponentInstance { /// is how this field is manipulated. instance_resource_tables: PrimaryMap, - /// State related to async for this component, e.g. futures, streams, tasks, - /// etc. - #[cfg(feature = "component-model-async")] - concurrent_state: concurrent::ConcurrentState, - /// What all compile-time-identified core instances are mapped to within the /// `Store` that this component belongs to. instances: PrimaryMap, @@ -261,7 +253,6 @@ impl ComponentInstance { for _ in 0..num_instances { instance_resource_tables.push(ResourceTable::default()); } - let mut ret = OwnedInstance::new(ComponentInstance { id, offsets, @@ -278,8 +269,6 @@ impl ComponentInstance { imports: imports.clone(), store: VMStoreRawPtr(store), post_return_arg: None, - #[cfg(feature = "component-model-async")] - concurrent_state: concurrent::ConcurrentState::new(component), vmctx: OwnedVMContext::new(), }); unsafe { @@ -343,18 +332,6 @@ impl ComponentInstance { } } - /// Returns the async callback pointer corresponding to the index provided. - /// - /// This can only be called after `idx` has been initialized at runtime - /// during the instantiation process of a component. - pub fn runtime_callback(&self, idx: RuntimeCallbackIndex) -> NonNull { - unsafe { - let ret = *self.vmctx_plus_offset::>(self.offsets.runtime_callback(idx)); - debug_assert!(ret.as_ptr() as usize != INVALID_PTR); - ret.as_non_null() - } - } - /// Returns the post-return pointer corresponding to the index provided. /// /// This can only be called after `idx` has been initialized at runtime diff --git a/crates/wasmtime/src/runtime/vm/component/libcalls.rs b/crates/wasmtime/src/runtime/vm/component/libcalls.rs index fa58249f99a7..34b08d1f49fd 100644 --- a/crates/wasmtime/src/runtime/vm/component/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/component/libcalls.rs @@ -1,5 +1,10 @@ //! Implementation of string transcoding required by the component model. +#![cfg_attr( + feature = "component-model-async", + expect(unused_variables, reason = "trying to reduce merge conflicts") +)] + use crate::component::Instance; use crate::prelude::*; #[cfg(feature = "component-model-async")] @@ -664,10 +669,7 @@ fn backpressure_set( caller_instance: u32, enabled: u32, ) -> Result<()> { - instance.concurrent_state_mut(store).backpressure_set( - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - enabled, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -680,22 +682,12 @@ unsafe fn task_return( storage: *mut u8, storage_len: usize, ) -> Result<()> { - instance.task_return( - store, - wasmtime_environ::component::TypeTupleIndex::from_u32(ty), - memory.cast::(), - string_encoding, - storage.cast::(), - storage_len, - ) + todo!() } #[cfg(feature = "component-model-async")] fn task_cancel(store: &mut dyn VMStore, instance: Instance, caller_instance: u32) -> Result<()> { - instance.task_cancel( - store, - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -704,9 +696,7 @@ fn waitable_set_new( instance: Instance, caller_instance: u32, ) -> Result { - instance.concurrent_state_mut(store).waitable_set_new( - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -719,14 +709,7 @@ unsafe fn waitable_set_wait( set: u32, payload: u32, ) -> Result { - instance.waitable_set_wait( - store, - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - async_ != 0, - memory.cast::(), - set, - payload, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -739,14 +722,7 @@ unsafe fn waitable_set_poll( set: u32, payload: u32, ) -> Result { - instance.waitable_set_poll( - store, - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - async_ != 0, - memory.cast::(), - set, - payload, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -756,10 +732,7 @@ fn waitable_set_drop( caller_instance: u32, set: u32, ) -> Result<()> { - instance.concurrent_state_mut(store).waitable_set_drop( - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - set, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -770,16 +743,12 @@ fn waitable_join( waitable: u32, set: u32, ) -> Result<()> { - instance.concurrent_state_mut(store).waitable_join( - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - waitable, - set, - ) + todo!() } #[cfg(feature = "component-model-async")] fn yield_(store: &mut dyn VMStore, instance: Instance, async_: u8) -> Result { - instance.yield_(store, async_ != 0) + todo!() } #[cfg(feature = "component-model-async")] @@ -789,10 +758,7 @@ fn subtask_drop( caller_instance: u32, task_id: u32, ) -> Result<()> { - instance.concurrent_state_mut(store).subtask_drop( - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - task_id, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -803,12 +769,7 @@ fn subtask_cancel( async_: u8, task_id: u32, ) -> Result { - instance.subtask_cancel( - store, - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - async_ != 0, - task_id, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -826,19 +787,7 @@ unsafe fn prepare_call( storage: *mut u8, storage_len: usize, ) -> Result<()> { - store.component_async_store().prepare_call( - instance, - memory.cast::(), - start.cast::(), - return_.cast::(), - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance), - wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(callee_instance), - wasmtime_environ::component::TypeTupleIndex::from_u32(task_return_type), - u8::try_from(string_encoding).unwrap(), - result_count_or_max_if_async, - storage.cast::(), - storage_len, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -851,14 +800,7 @@ unsafe fn sync_start( storage: *mut u8, storage_len: usize, ) -> Result<()> { - store.component_async_store().sync_start( - instance, - callback.cast::(), - callee.cast::(), - param_count, - storage.cast::>(), - storage_len, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -872,15 +814,7 @@ unsafe fn async_start( result_count: u32, flags: u32, ) -> Result { - store.component_async_store().async_start( - instance, - callback.cast::(), - post_return.cast::(), - callee.cast::(), - param_count, - result_count, - flags, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -891,11 +825,7 @@ fn future_transfer( src_table: u32, dst_table: u32, ) -> Result { - instance.concurrent_state_mut(store).future_transfer( - src_idx, - wasmtime_environ::component::TypeFutureTableIndex::from_u32(src_table), - wasmtime_environ::component::TypeFutureTableIndex::from_u32(dst_table), - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -906,11 +836,7 @@ fn stream_transfer( src_table: u32, dst_table: u32, ) -> Result { - instance.concurrent_state_mut(store).stream_transfer( - src_idx, - wasmtime_environ::component::TypeStreamTableIndex::from_u32(src_table), - wasmtime_environ::component::TypeStreamTableIndex::from_u32(dst_table), - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -921,13 +847,7 @@ fn error_context_transfer( src_table: u32, dst_table: u32, ) -> Result { - let src_table = - wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(src_table); - let dst_table = - wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(dst_table); - instance - .concurrent_state_mut(store) - .error_context_transfer(src_idx, src_table, dst_table) + todo!() } #[cfg(feature = "component-model-async")] @@ -943,9 +863,7 @@ unsafe impl HostResultHasUnwindSentinel for ResourcePair { #[cfg(feature = "component-model-async")] fn future_new(store: &mut dyn VMStore, instance: Instance, ty: u32) -> Result { - instance.concurrent_state_mut(store).future_new( - wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty), - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -960,16 +878,7 @@ unsafe fn future_write( future: u32, address: u32, ) -> Result { - store.component_async_store().future_write( - instance, - memory.cast::(), - realloc.cast::(), - string_encoding, - async_ != 0, - wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty), - future, - address, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -984,16 +893,7 @@ unsafe fn future_read( future: u32, address: u32, ) -> Result { - store.component_async_store().future_read( - instance, - memory.cast::(), - realloc.cast::(), - string_encoding, - async_ != 0, - wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty), - future, - address, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1004,11 +904,7 @@ fn future_cancel_write( async_: u8, writer: u32, ) -> Result { - instance.concurrent_state_mut(store).future_cancel_write( - wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty), - async_ != 0, - writer, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1019,11 +915,7 @@ fn future_cancel_read( async_: u8, reader: u32, ) -> Result { - instance.concurrent_state_mut(store).future_cancel_read( - wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty), - async_ != 0, - reader, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1033,10 +925,7 @@ fn future_drop_writable( ty: u32, writer: u32, ) -> Result<()> { - instance.concurrent_state_mut(store).future_drop_writable( - wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty), - writer, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1046,18 +935,12 @@ fn future_drop_readable( ty: u32, reader: u32, ) -> Result<()> { - instance.future_drop_readable( - store, - wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty), - reader, - ) + todo!() } #[cfg(feature = "component-model-async")] fn stream_new(store: &mut dyn VMStore, instance: Instance, ty: u32) -> Result { - instance.concurrent_state_mut(store).stream_new( - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1073,17 +956,7 @@ unsafe fn stream_write( address: u32, count: u32, ) -> Result { - store.component_async_store().stream_write( - instance, - memory.cast::(), - realloc.cast::(), - string_encoding, - async_ != 0, - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - stream, - address, - count, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1099,17 +972,7 @@ unsafe fn stream_read( address: u32, count: u32, ) -> Result { - store.component_async_store().stream_read( - instance, - memory.cast::(), - realloc.cast::(), - string_encoding, - async_ != 0, - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - stream, - address, - count, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1120,11 +983,7 @@ fn stream_cancel_write( async_: u8, writer: u32, ) -> Result { - instance.concurrent_state_mut(store).stream_cancel_write( - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - async_ != 0, - writer, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1135,11 +994,7 @@ fn stream_cancel_read( async_: u8, reader: u32, ) -> Result { - instance.concurrent_state_mut(store).stream_cancel_read( - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - async_ != 0, - reader, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1149,10 +1004,7 @@ fn stream_drop_writable( ty: u32, writer: u32, ) -> Result<()> { - instance.concurrent_state_mut(store).stream_drop_writable( - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - writer, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1162,11 +1014,7 @@ fn stream_drop_readable( ty: u32, reader: u32, ) -> Result<()> { - instance.stream_drop_readable( - store, - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - reader, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1183,18 +1031,7 @@ unsafe fn flat_stream_write( address: u32, count: u32, ) -> Result { - store.component_async_store().flat_stream_write( - instance, - memory.cast::(), - realloc.cast::(), - async_ != 0, - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - payload_size, - payload_align, - stream, - address, - count, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1211,18 +1048,7 @@ unsafe fn flat_stream_read( address: u32, count: u32, ) -> Result { - store.component_async_store().flat_stream_read( - instance, - memory.cast::(), - realloc.cast::(), - async_ != 0, - wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty), - payload_size, - payload_align, - stream, - address, - count, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1236,15 +1062,7 @@ unsafe fn error_context_new( debug_msg_address: u32, debug_msg_len: u32, ) -> Result { - instance.error_context_new( - store.store_opaque_mut(), - memory.cast::(), - realloc.cast::(), - string_encoding, - wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(ty), - debug_msg_address, - debug_msg_len, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1258,15 +1076,7 @@ unsafe fn error_context_debug_message( err_ctx_handle: u32, debug_msg_address: u32, ) -> Result<()> { - store.component_async_store().error_context_debug_message( - instance, - memory.cast::(), - realloc.cast::(), - string_encoding, - wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(ty), - err_ctx_handle, - debug_msg_address, - ) + todo!() } #[cfg(feature = "component-model-async")] @@ -1276,18 +1086,15 @@ fn error_context_drop( ty: u32, err_ctx_handle: u32, ) -> Result<()> { - instance.concurrent_state_mut(store).error_context_drop( - wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(ty), - err_ctx_handle, - ) + todo!() } #[cfg(feature = "component-model-async")] fn context_get(store: &mut dyn VMStore, instance: Instance, slot: u32) -> Result { - instance.concurrent_state_mut(store).context_get(slot) + todo!() } #[cfg(feature = "component-model-async")] fn context_set(store: &mut dyn VMStore, instance: Instance, slot: u32, val: u32) -> Result<()> { - instance.concurrent_state_mut(store).context_set(slot, val) + todo!() } diff --git a/crates/wasmtime/src/runtime/vm/component/resources.rs b/crates/wasmtime/src/runtime/vm/component/resources.rs index b5e1acfdfc18..b4de6428e217 100644 --- a/crates/wasmtime/src/runtime/vm/component/resources.rs +++ b/crates/wasmtime/src/runtime/vm/component/resources.rs @@ -215,19 +215,8 @@ pub struct CallContexts { scopes: Vec, } -impl CallContexts { - pub fn push(&mut self, cx: CallContext) { - self.scopes.push(cx); - } - - pub fn pop(&mut self) -> Option { - self.scopes.pop() - } -} - -/// State related to borrows for a specific call. #[derive(Default)] -pub struct CallContext { +struct CallContext { lenders: Vec, borrow_count: u32, } diff --git a/crates/wasmtime/src/runtime/vm/stack_switching/stack/unix.rs b/crates/wasmtime/src/runtime/vm/stack_switching/stack/unix.rs index de27bafd45ae..81a293c1c6e1 100644 --- a/crates/wasmtime/src/runtime/vm/stack_switching/stack/unix.rs +++ b/crates/wasmtime/src/runtime/vm/stack_switching/stack/unix.rs @@ -349,7 +349,7 @@ cfg_if::cfg_if! { if #[cfg(target_arch = "x86_64")] { mod x86_64; } else { - // Note that this should be unreachable: In stack.rs, we currently select + // Note that this shoul be unreachable: In stack.rs, we currently select // the module defined in the current file only if we are on unix AND // x86_64. compile_error!("the stack switching feature is not supported on this CPU architecture"); diff --git a/crates/wasmtime/src/runtime/vm/traphandlers.rs b/crates/wasmtime/src/runtime/vm/traphandlers.rs index d1dad2f4ff63..a96a747efe67 100644 --- a/crates/wasmtime/src/runtime/vm/traphandlers.rs +++ b/crates/wasmtime/src/runtime/vm/traphandlers.rs @@ -380,7 +380,7 @@ impl From for TrapReason { /// longjmp'd over and none of its destructors on the stack may be run. pub unsafe fn catch_traps( store: &mut StoreContextMut<'_, T>, - old_state: &mut EntryStoreContext, + old_state: &EntryStoreContext, mut closure: F, ) -> Result<(), Box> where @@ -485,7 +485,7 @@ mod call_thread_state { // same store and `self.vm_store_context == self.prev.vm_store_context`) and we must to // maintain the list of contiguous-Wasm-frames stack regions for // backtracing purposes. - old_state: *mut EntryStoreContext, + old_state: *const EntryStoreContext, } impl Drop for CallThreadState { @@ -502,7 +502,7 @@ mod call_thread_state { #[inline] pub(super) fn new( store: &mut StoreOpaque, - old_state: *mut EntryStoreContext, + old_state: *const EntryStoreContext, ) -> CallThreadState { CallThreadState { unwind: Cell::new(None), @@ -575,38 +575,6 @@ mod call_thread_state { let head = tls::raw::replace(prev); assert!(core::ptr::eq(head, self)); } - - /// Swaps the state in this `CallThreadState`'s `VMStoreContext` with - /// the state in `EntryStoreContext` that was saved when this - /// activation was created. - /// - /// This method is using during suspension of a fiber to restore the - /// store back to what it originally was and prepare it to be resumed - /// later on. This takes various fields of `VMStoreContext` and swaps - /// them with what was saved in `EntryStoreContext`. That restores - /// a store to just before this activation was called but saves off the - /// fields of this activation to get restored/resumed at a later time. - #[cfg(feature = "async")] - pub(super) unsafe fn swap(&self) { - unsafe fn swap(a: &core::cell::UnsafeCell, b: &mut T) { - core::mem::swap(&mut *a.get(), b) - } - - let cx = self.vm_store_context.as_ref(); - swap( - &cx.last_wasm_exit_fp, - &mut (*self.old_state).last_wasm_exit_fp, - ); - swap( - &cx.last_wasm_exit_pc, - &mut (*self.old_state).last_wasm_exit_pc, - ); - swap( - &cx.last_wasm_entry_fp, - &mut (*self.old_state).last_wasm_entry_fp, - ); - swap(&cx.stack_chain, &mut (*self.old_state).stack_chain); - } } } pub use call_thread_state::*; @@ -1009,28 +977,10 @@ pub(crate) mod tls { /// that this doesn't push stale data and the data is popped /// appropriately. pub unsafe fn push(self) -> PreviousAsyncWasmCallState { - // First save the state of TLS as-is so when this state is popped - // off later on we know where to stop. - let ret = PreviousAsyncWasmCallState { state: raw::get() }; - - // The oldest activation, if present, has various `VMStoreContext` - // fields saved within it. These fields were the state for the - // *youngest* activation when a suspension previously happened. By - // swapping them back into the store this is an O(1) way of - // restoring the state of a store's metadata fields at the time of - // the suspension. - // - // The store's previous values before this function will all get - // saved in the oldest activation's state on the stack. The store's - // current state then describes the youngest activation which is - // restored via the loop below. - if let Some(state) = self.state.as_ref() { - state.swap(); - } - // Our `state` pointer is a linked list of oldest-to-youngest so by // pushing in order of the list we restore the youngest-to-oldest // list as stored in the state of this current thread. + let ret = PreviousAsyncWasmCallState { state: raw::get() }; let mut ptr = self.state; while let Some(state) = ptr.as_ref() { ptr = state.prev.replace(core::ptr::null_mut()); @@ -1090,37 +1040,16 @@ pub(crate) mod tls { loop { // If the current TLS state is as we originally found it, then // this loop is finished. - // - // Note, though, that before exiting, if the oldest - // `CallThreadState` is present, the current state of - // `VMStoreContext` is saved off within it. This will save the - // current state, before this function, of `VMStoreContext` - // into the `EntryStoreContext` stored with the oldest - // activation. This is a bit counter-intuitive where the state - // for the youngest activation is stored in the "old" state - // of the oldest activation. - // - // What this does is restores the state of the store to just - // before this async fiber was started. The fiber's state will - // be entirely self-contained in the fiber itself and the - // returned `AsyncWasmCallState`. Resumption above in - // `AsyncWasmCallState::push` will perform the swap back into - // the store to hook things up again. let ptr = raw::get(); if ptr == thread_head { - if let Some(state) = ret.state.as_ref() { - state.swap(); - } - break ret; } // Pop this activation from the current thread's TLS state, and // then afterwards push it onto our own linked list within this - // `AsyncWasmCallState`. Note that the linked list in - // `AsyncWasmCallState` is stored in reverse order so a - // subsequent `push` later on pushes everything in the right - // order. + // `AsyncWasmCallState`. Note that the linked list in `AsyncWasmCallState` is stored + // in reverse order so a subsequent `push` later on pushes + // everything in the right order. (*ptr).pop(); if let Some(state) = ret.state.as_ref() { (*ptr).prev.set(state); diff --git a/crates/wasmtime/src/runtime/wave/component.rs b/crates/wasmtime/src/runtime/wave/component.rs index 9849bb455bf6..a12460e5cf22 100644 --- a/crates/wasmtime/src/runtime/wave/component.rs +++ b/crates/wasmtime/src/runtime/wave/component.rs @@ -41,11 +41,7 @@ impl WasmType for component::Type { Self::Result(_) => WasmTypeKind::Result, Self::Flags(_) => WasmTypeKind::Flags, - Self::Own(_) - | Self::Borrow(_) - | Self::Stream(_) - | Self::Future(_) - | Self::ErrorContext => WasmTypeKind::Unsupported, + Self::Own(_) | Self::Borrow(_) => WasmTypeKind::Unsupported, } } @@ -138,9 +134,7 @@ impl WasmValue for component::Val { Self::Option(_) => WasmTypeKind::Option, Self::Result(_) => WasmTypeKind::Result, Self::Flags(_) => WasmTypeKind::Flags, - Self::Resource(_) | Self::Stream(_) | Self::Future(_) | Self::ErrorContext(_) => { - WasmTypeKind::Unsupported - } + Self::Resource(_) => WasmTypeKind::Unsupported, } } diff --git a/crates/wast/src/component.rs b/crates/wast/src/component.rs index f9a1478f7e29..69ebebe1401d 100644 --- a/crates/wast/src/component.rs +++ b/crates/wast/src/component.rs @@ -281,9 +281,6 @@ fn mismatch(expected: &WastVal<'_>, actual: &Val) -> Result<()> { Val::Result(..) => "result", Val::Flags(..) => "flags", Val::Resource(..) => "resource", - Val::Future(..) => "future", - Val::Stream(..) => "stream", - Val::ErrorContext(..) => "error-context", }; bail!("expected `{expected}` got `{actual}`") } diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 36e2165d4aa6..d94516dd1084 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -2837,7 +2837,7 @@ impl<'a> InterfaceGenerator<'a> { if concurrent { if func.result.is_some() { - uwrite!(self.src, "let future ="); + uwrite!(self.src, "{wt}::component::__internal::FutureExt::map("); } uwrite!(self.src, "callee.call_concurrent(store.as_context_mut(), ("); for (i, _) in func.params.iter().enumerate() { @@ -2846,15 +2846,7 @@ impl<'a> InterfaceGenerator<'a> { self.src.push_str("))"); if func.result.is_some() { - self.src.push_str(";\n"); - uwriteln!( - self.src, - "\ -async move {{ - let (ret0,) = future.await?; - Ok(ret0) -}}" - ); + self.src.push_str(", |v| v.map(|(v,)| v))"); } } else { self.src.push_str("let ("); diff --git a/tests/all/component_model/dynamic.rs b/tests/all/component_model/dynamic.rs index 8ca9cd273c48..21f6e9c69db9 100644 --- a/tests/all/component_model/dynamic.rs +++ b/tests/all/component_model/dynamic.rs @@ -87,7 +87,7 @@ fn primitives() -> Result<()> { .call_and_post_return(&mut store, &output, &mut []) .unwrap_err(); assert!( - err.to_string().contains("expected 1 result(s), got 0"), + err.to_string().contains("expected 1 results(s), got 0"), "{err}" );