diff --git a/Cargo.lock b/Cargo.lock index 882e30c199b1..c1b6a4bd75b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3769,8 +3769,7 @@ dependencies = [ [[package]] name = "wasm-encoder" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17a3bd88f2155da63a1f2fcb8a56377a24f0b6dfed12733bb5f544e86f690c5" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "leb128", "wasmparser 0.221.2", @@ -3795,8 +3794,7 @@ dependencies = [ [[package]] name = "wasm-metadata" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7018a96c4f55a8f339954c66e09728f2d6112689000e58f15f6a6d7436e8f" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "anyhow", "indexmap 2.2.6", @@ -3804,6 +3802,7 @@ dependencies = [ "serde_derive", "serde_json", "spdx", + "url", "wasm-encoder 0.221.2", "wasmparser 0.221.2", ] @@ -3811,8 +3810,7 @@ dependencies = [ [[package]] name = "wasm-mutate" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2512b64553d7c800b798e8e0d0e2e209e76f9330f66ed59991893590ae03cfa3" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "egg", "log", @@ -3825,8 +3823,7 @@ dependencies = [ [[package]] name = "wasm-smith" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebbaf9c781fb7091b79ad3baa40862b3afccb2949575bb73bdd77643ed40338c" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "anyhow", "arbitrary", @@ -3847,8 +3844,7 @@ dependencies = [ [[package]] name = "wasm-wave" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3bf15c65cc690791565c9f983bad120330e37f55ce2473161f2c0aaa534c7da" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "indexmap 2.2.6", "logos", @@ -3916,8 +3912,7 @@ dependencies = [ [[package]] name = "wasmparser" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "bitflags 2.6.0", "hashbrown 0.15.2", @@ -3938,8 +3933,7 @@ dependencies = [ [[package]] name = "wasmprinter" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a80742ff1b9e6d8c231ac7c7247782c6fc5bce503af760bca071811e5fc9ee56" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "anyhow", "termcolor", @@ -3959,6 +3953,7 @@ dependencies = [ "cfg-if", "encoding_rs", "env_logger 0.11.5", + "futures", "fxprof-processed-profile", "gimli", "hashbrown 0.14.3", @@ -4562,8 +4557,7 @@ dependencies = [ [[package]] name = "wast" version = "221.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc4470b9de917ba199157d1f0ae104f2ae362be728c43e68c571c7715bd629e" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "bumpalo", "leb128", @@ -4575,8 +4569,7 @@ dependencies = [ [[package]] name = "wat" version = "1.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1f3c6d82af47286494c6caea1d332037f5cbeeac82bbf5ef59cb8c201c466e" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "wast 221.0.2", ] @@ -5023,8 +5016,7 @@ dependencies = [ [[package]] name = "wit-component" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6b907a1af1f2cf2160d7fe2ff5967cef120dc5c034d22593a1f24e40272cb2" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -5060,8 +5052,7 @@ dependencies = [ [[package]] name = "wit-parser" version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe1538eea6ea5ddbe5defd0dc82539ad7ba751e1631e9185d24a931f0a5adc8" +source = "git+https://github.com/dicej/wasm-tools?branch=async#c8c3f47e46f8e1ef1cc95114cdf714281ca0a92e" dependencies = [ "anyhow", "id-arena", diff --git a/Cargo.toml b/Cargo.toml index e5d524207ad4..c59111ca0a56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -277,16 +277,16 @@ wit-bindgen = { version = "0.35.0", default-features = false } wit-bindgen-rust-macro = { version = "0.35.0", default-features = false } # wasm-tools family: -wasmparser = { version = "0.221.2", default-features = false, features = ['simd'] } -wat = "1.221.2" -wast = "221.0.2" -wasmprinter = "0.221.2" -wasm-encoder = "0.221.2" -wasm-smith = "0.221.2" -wasm-mutate = "0.221.2" -wit-parser = "0.221.2" -wit-component = "0.221.2" -wasm-wave = "0.221.2" +wasmparser = { git = "https://github.com/dicej/wasm-tools", branch = "async", default-features = false, features = ['simd'] } +wat = { git = "https://github.com/dicej/wasm-tools", branch = "async" } +wast = { git = "https://github.com/dicej/wasm-tools", branch = "async" } +wasmprinter = { git = "https://github.com/dicej/wasm-tools", branch = "async" } +wasm-encoder = { git = "https://github.com/dicej/wasm-tools", branch = "async" } +wasm-smith = { git = "https://github.com/dicej/wasm-tools", branch = "async" } +wasm-mutate = { git = "https://github.com/dicej/wasm-tools", branch = "async" } +wit-parser = { git = "https://github.com/dicej/wasm-tools", branch = "async" } +wit-component = { git = "https://github.com/dicej/wasm-tools", branch = "async" } +wasm-wave = { git = "https://github.com/dicej/wasm-tools", branch = "async" } # Non-Bytecode Alliance maintained dependencies: # -------------------------- diff --git a/benches/call.rs b/benches/call.rs index 8e7d95aa8ffb..4645d97fa38b 100644 --- a/benches/call.rs +++ b/benches/call.rs @@ -628,7 +628,8 @@ mod component { + PartialEq + Debug + Send - + Sync, + + Sync + + 'static, { // Benchmark the "typed" version. c.bench_function(&format!("component - host-to-wasm - typed - {name}"), |b| { diff --git a/crates/component-macro/Cargo.toml b/crates/component-macro/Cargo.toml index 79dbc6a27353..5e38dd2977ce 100644 --- a/crates/component-macro/Cargo.toml +++ b/crates/component-macro/Cargo.toml @@ -41,3 +41,4 @@ similar = { workspace = true } [features] async = [] std = ['wasmtime-wit-bindgen/std'] +component-model-async = ['std', 'async', 'wasmtime-wit-bindgen/component-model-async'] diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs index b33bbc5bcb7c..10b2c415bc15 100644 --- a/crates/component-macro/src/bindgen.rs +++ b/crates/component-macro/src/bindgen.rs @@ -1,14 +1,15 @@ use proc_macro2::{Span, TokenStream}; use quote::ToTokens; -use std::collections::HashMap; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::env; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; use syn::parse::{Error, Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::{braced, token, Token}; -use wasmtime_wit_bindgen::{AsyncConfig, Opts, Ownership, TrappableError, TrappableImports}; +use wasmtime_wit_bindgen::{ + AsyncConfig, CallStyle, Opts, Ownership, TrappableError, TrappableImports, +}; use wit_parser::{PackageId, Resolve, UnresolvedPackageGroup, WorldId}; pub struct Config { @@ -20,13 +21,22 @@ pub struct Config { } pub fn expand(input: &Config) -> Result { - if !cfg!(feature = "async") && input.opts.async_.maybe_async() { + if let (CallStyle::Async | CallStyle::Concurrent, false) = + (input.opts.call_style(), cfg!(feature = "async")) + { return Err(Error::new( Span::call_site(), "cannot enable async bindings unless `async` crate feature is active", )); } + if input.opts.concurrent_imports && !cfg!(feature = "component-model-async") { + return Err(Error::new( + Span::call_site(), + "cannot enable `concurrent_imports` option unless `component-model-async` crate feature is active", + )); + } + let mut src = match input.opts.generate(&input.resolve, input.world) { Ok(s) => s, Err(e) => return Err(Error::new(Span::call_site(), e.to_string())), @@ -40,7 +50,10 @@ pub fn expand(input: &Config) -> Result { // place a formatted version of the expanded code into a file. This file // will then show up in rustc error messages for any codegen issues and can // be inspected manually. - if input.include_generated_code_from_file || std::env::var("WASMTIME_DEBUG_BINDGEN").is_ok() { + if input.include_generated_code_from_file + || input.opts.debug + || std::env::var("WASMTIME_DEBUG_BINDGEN").is_ok() + { static INVOCATION: AtomicUsize = AtomicUsize::new(0); let root = Path::new(env!("DEBUG_OUTPUT_DIR")); let world_name = &input.resolve.worlds[input.world].name; @@ -107,6 +120,7 @@ impl Parse for Config { } Opt::Tracing(val) => opts.tracing = val, Opt::VerboseTracing(val) => opts.verbose_tracing = val, + Opt::Debug(val) => opts.debug = val, Opt::Async(val, span) => { if async_configured { return Err(Error::new(span, "cannot specify second async config")); @@ -114,6 +128,8 @@ impl Parse for Config { async_configured = true; opts.async_ = val; } + Opt::ConcurrentImports(val) => opts.concurrent_imports = val, + Opt::ConcurrentExports(val) => opts.concurrent_exports = val, Opt::TrappableErrorType(val) => opts.trappable_error_type = val, Opt::TrappableImports(val) => opts.trappable_imports = val, Opt::Ownership(val) => opts.ownership = val, @@ -138,7 +154,7 @@ impl Parse for Config { "cannot specify a world with `interfaces`", )); } - world = Some("interfaces".to_string()); + world = Some("wasmtime:component-macro-synthesized/interfaces".to_string()); opts.only_interfaces = true; } @@ -281,6 +297,9 @@ mod kw { syn::custom_keyword!(require_store_data_send); syn::custom_keyword!(wasmtime_crate); syn::custom_keyword!(include_generated_code_from_file); + syn::custom_keyword!(concurrent_imports); + syn::custom_keyword!(concurrent_exports); + syn::custom_keyword!(debug); } enum Opt { @@ -301,12 +320,19 @@ enum Opt { RequireStoreDataSend(bool), WasmtimeCrate(syn::Path), IncludeGeneratedCodeFromFile(bool), + ConcurrentImports(bool), + ConcurrentExports(bool), + Debug(bool), } impl Parse for Opt { fn parse(input: ParseStream<'_>) -> Result { let l = input.lookahead1(); - if l.peek(kw::path) { + if l.peek(kw::debug) { + input.parse::()?; + input.parse::()?; + Ok(Opt::Debug(input.parse::()?.value)) + } else if l.peek(kw::path) { input.parse::()?; input.parse::()?; @@ -380,6 +406,14 @@ impl Parse for Opt { span, )) } + } else if l.peek(kw::concurrent_imports) { + input.parse::()?; + input.parse::()?; + Ok(Opt::ConcurrentImports(input.parse::()?.value)) + } else if l.peek(kw::concurrent_exports) { + input.parse::()?; + input.parse::()?; + Ok(Opt::ConcurrentExports(input.parse::()?.value)) } else if l.peek(kw::ownership) { input.parse::()?; input.parse::()?; diff --git a/crates/component-macro/tests/expanded/char.rs b/crates/component-macro/tests/expanded/char.rs index c8e1b9436487..f1424dc05964 100644 --- a/crates/component-macro/tests/expanded/char.rs +++ b/crates/component-macro/tests/expanded/char.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -194,19 +197,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/chars")?; inst.func_wrap( @@ -354,7 +361,10 @@ pub mod exports { &self, mut store: S, arg0: char, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (char,), @@ -369,7 +379,10 @@ pub mod exports { pub fn call_return_char( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), diff --git a/crates/component-macro/tests/expanded/char_async.rs b/crates/component-macro/tests/expanded/char_async.rs index e2bb10590177..be4ca1fa5ea5 100644 --- a/crates/component-macro/tests/expanded/char_async.rs +++ b/crates/component-macro/tests/expanded/char_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -202,19 +199,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -373,7 +374,7 @@ pub mod exports { arg0: char, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -393,7 +394,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/char_tracing_async.rs b/crates/component-macro/tests/expanded/char_tracing_async.rs index dc7caf15fc8d..3c1df3d2ef55 100644 --- a/crates/component-macro/tests/expanded/char_tracing_async.rs +++ b/crates/component-macro/tests/expanded/char_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -202,19 +199,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -402,7 +403,7 @@ pub mod exports { arg0: char, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -431,7 +432,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/conventions.rs b/crates/component-macro/tests/expanded/conventions.rs index 631be530d8b8..817c81b47643 100644 --- a/crates/component-macro/tests/expanded/conventions.rs +++ b/crates/component-macro/tests/expanded/conventions.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -154,7 +154,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -242,19 +245,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/conventions")?; inst.func_wrap( @@ -646,7 +653,10 @@ pub mod exports { pub fn call_kebab_case( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -661,7 +671,10 @@ pub mod exports { &self, mut store: S, arg0: LudicrousSpeed, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (LudicrousSpeed,), @@ -675,7 +688,10 @@ pub mod exports { pub fn call_function_with_dashes( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -688,7 +704,10 @@ pub mod exports { } pub fn call_function_with_no_weird_characters< S: wasmtime::AsContextMut, - >(&self, mut store: S) -> wasmtime::Result<()> { + >(&self, mut store: S) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -702,7 +721,10 @@ pub mod exports { pub fn call_apple( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -716,7 +738,10 @@ pub mod exports { pub fn call_apple_pear( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -730,7 +755,10 @@ pub mod exports { pub fn call_apple_pear_grape( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -744,7 +772,10 @@ pub mod exports { pub fn call_a0( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -763,7 +794,10 @@ pub mod exports { pub fn call_is_xml( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -777,7 +811,10 @@ pub mod exports { pub fn call_explicit( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -791,7 +828,10 @@ pub mod exports { pub fn call_explicit_kebab( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -806,7 +846,10 @@ pub mod exports { pub fn call_bool( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), diff --git a/crates/component-macro/tests/expanded/conventions_async.rs b/crates/component-macro/tests/expanded/conventions_async.rs index f591169d80bf..fec45dca189f 100644 --- a/crates/component-macro/tests/expanded/conventions_async.rs +++ b/crates/component-macro/tests/expanded/conventions_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -250,19 +247,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -685,7 +686,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -703,7 +704,7 @@ pub mod exports { arg0: LudicrousSpeed, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -722,7 +723,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -738,7 +739,7 @@ pub mod exports { S: wasmtime::AsContextMut, >(&self, mut store: S) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -755,7 +756,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -772,7 +773,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -789,7 +790,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -806,7 +807,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -828,7 +829,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -845,7 +846,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -862,7 +863,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -880,7 +881,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/conventions_tracing_async.rs b/crates/component-macro/tests/expanded/conventions_tracing_async.rs index ac89ef41c553..18c875a3bc4b 100644 --- a/crates/component-macro/tests/expanded/conventions_tracing_async.rs +++ b/crates/component-macro/tests/expanded/conventions_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -250,19 +247,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -845,7 +846,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -874,7 +875,7 @@ pub mod exports { arg0: LudicrousSpeed, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -902,7 +903,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -929,7 +930,7 @@ pub mod exports { S: wasmtime::AsContextMut, >(&self, mut store: S) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -958,7 +959,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -986,7 +987,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1014,7 +1015,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1042,7 +1043,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1075,7 +1076,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1103,7 +1104,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1131,7 +1132,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1160,7 +1161,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/dead-code.rs b/crates/component-macro/tests/expanded/dead-code.rs index 30781af56403..7a7f24bb9186 100644 --- a/crates/component-macro/tests/expanded/dead-code.rs +++ b/crates/component-macro/tests/expanded/dead-code.rs @@ -18,7 +18,7 @@ impl Clone for ImportsPre { } } } -impl<_T> ImportsPre<_T> { +impl<_T: 'static> ImportsPre<_T> { /// Creates a new copy of `ImportsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; ImportsPre::new(pre)?.instantiate(store) } @@ -200,19 +203,23 @@ pub mod a { } 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("a:b/interface-with-live-type")?; inst.func_wrap( @@ -247,19 +254,23 @@ pub mod a { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("a:b/interface-with-dead-type")?; Ok(()) diff --git a/crates/component-macro/tests/expanded/dead-code_async.rs b/crates/component-macro/tests/expanded/dead-code_async.rs index 9ae5d387835d..5747d358d526 100644 --- a/crates/component-macro/tests/expanded/dead-code_async.rs +++ b/crates/component-macro/tests/expanded/dead-code_async.rs @@ -18,7 +18,7 @@ impl Clone for ImportsPre { } } } -impl<_T> ImportsPre<_T> { +impl<_T: Send + 'static> ImportsPre<_T> { /// Creates a new copy of `ImportsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> ImportsPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; ImportsPre::new(pre)?.instantiate_async(store).await @@ -208,19 +205,23 @@ pub mod a { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -263,19 +264,23 @@ pub mod a { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/dead-code_tracing_async.rs b/crates/component-macro/tests/expanded/dead-code_tracing_async.rs index fc670a943af6..3e750bfc6972 100644 --- a/crates/component-macro/tests/expanded/dead-code_tracing_async.rs +++ b/crates/component-macro/tests/expanded/dead-code_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for ImportsPre { } } } -impl<_T> ImportsPre<_T> { +impl<_T: Send + 'static> ImportsPre<_T> { /// Creates a new copy of `ImportsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> ImportsPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; ImportsPre::new(pre)?.instantiate_async(store).await @@ -208,19 +205,23 @@ pub mod a { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -276,19 +277,23 @@ pub mod a { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/direct-import.rs b/crates/component-macro/tests/expanded/direct-import.rs index 225fe6c9009f..eb1249d8bffb 100644 --- a/crates/component-macro/tests/expanded/direct-import.rs +++ b/crates/component-macro/tests/expanded/direct-import.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -162,7 +162,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate(store) } diff --git a/crates/component-macro/tests/expanded/direct-import_async.rs b/crates/component-macro/tests/expanded/direct-import_async.rs index 3eb3b163154f..ac5f36c0e8c1 100644 --- a/crates/component-macro/tests/expanded/direct-import_async.rs +++ b/crates/component-macro/tests/expanded/direct-import_async.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: Send + 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> FooPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -169,7 +166,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await diff --git a/crates/component-macro/tests/expanded/direct-import_tracing_async.rs b/crates/component-macro/tests/expanded/direct-import_tracing_async.rs index 464deae28bf9..d8185fd601b9 100644 --- a/crates/component-macro/tests/expanded/direct-import_tracing_async.rs +++ b/crates/component-macro/tests/expanded/direct-import_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: Send + 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> FooPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -169,7 +166,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await diff --git a/crates/component-macro/tests/expanded/empty.rs b/crates/component-macro/tests/expanded/empty.rs index 573b02c84e74..fb6e5d5e60ec 100644 --- a/crates/component-macro/tests/expanded/empty.rs +++ b/crates/component-macro/tests/expanded/empty.rs @@ -18,7 +18,7 @@ impl Clone for EmptyPre { } } } -impl<_T> EmptyPre<_T> { +impl<_T: 'static> EmptyPre<_T> { /// Creates a new copy of `EmptyPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; EmptyPre::new(pre)?.instantiate(store) } diff --git a/crates/component-macro/tests/expanded/empty_async.rs b/crates/component-macro/tests/expanded/empty_async.rs index d2eea87b72a0..264f37601052 100644 --- a/crates/component-macro/tests/expanded/empty_async.rs +++ b/crates/component-macro/tests/expanded/empty_async.rs @@ -18,7 +18,7 @@ impl Clone for EmptyPre { } } } -impl<_T> EmptyPre<_T> { +impl<_T: Send + 'static> EmptyPre<_T> { /// Creates a new copy of `EmptyPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> EmptyPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; EmptyPre::new(pre)?.instantiate_async(store).await diff --git a/crates/component-macro/tests/expanded/empty_tracing_async.rs b/crates/component-macro/tests/expanded/empty_tracing_async.rs index d2eea87b72a0..264f37601052 100644 --- a/crates/component-macro/tests/expanded/empty_tracing_async.rs +++ b/crates/component-macro/tests/expanded/empty_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for EmptyPre { } } } -impl<_T> EmptyPre<_T> { +impl<_T: Send + 'static> EmptyPre<_T> { /// Creates a new copy of `EmptyPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> EmptyPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; EmptyPre::new(pre)?.instantiate_async(store).await diff --git a/crates/component-macro/tests/expanded/flags.rs b/crates/component-macro/tests/expanded/flags.rs index c036a1a2d85b..931a6c8edd1e 100644 --- a/crates/component-macro/tests/expanded/flags.rs +++ b/crates/component-macro/tests/expanded/flags.rs @@ -18,7 +18,7 @@ impl Clone for TheFlagsPre { } } } -impl<_T> TheFlagsPre<_T> { +impl<_T: 'static> TheFlagsPre<_T> { /// Creates a new copy of `TheFlagsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheFlagsPre::new(pre)?.instantiate(store) } @@ -311,19 +314,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/flegs")?; inst.func_wrap( @@ -751,7 +758,10 @@ pub mod exports { &self, mut store: S, arg0: Flag1, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Flag1,), @@ -766,7 +776,10 @@ pub mod exports { &self, mut store: S, arg0: Flag2, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Flag2,), @@ -781,7 +794,10 @@ pub mod exports { &self, mut store: S, arg0: Flag4, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Flag4,), @@ -796,7 +812,10 @@ pub mod exports { &self, mut store: S, arg0: Flag8, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Flag8,), @@ -811,7 +830,10 @@ pub mod exports { &self, mut store: S, arg0: Flag16, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Flag16,), @@ -826,7 +848,10 @@ pub mod exports { &self, mut store: S, arg0: Flag32, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Flag32,), @@ -841,7 +866,10 @@ pub mod exports { &self, mut store: S, arg0: Flag64, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Flag64,), diff --git a/crates/component-macro/tests/expanded/flags_async.rs b/crates/component-macro/tests/expanded/flags_async.rs index d7f9786d0d75..3ce3671004cb 100644 --- a/crates/component-macro/tests/expanded/flags_async.rs +++ b/crates/component-macro/tests/expanded/flags_async.rs @@ -18,7 +18,7 @@ impl Clone for TheFlagsPre { } } } -impl<_T> TheFlagsPre<_T> { +impl<_T: Send + 'static> TheFlagsPre<_T> { /// Creates a new copy of `TheFlagsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheFlagsPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheFlagsPre::new(pre)?.instantiate_async(store).await @@ -319,19 +316,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -780,7 +781,7 @@ pub mod exports { arg0: Flag1, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -800,7 +801,7 @@ pub mod exports { arg0: Flag2, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -820,7 +821,7 @@ pub mod exports { arg0: Flag4, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -840,7 +841,7 @@ pub mod exports { arg0: Flag8, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -860,7 +861,7 @@ pub mod exports { arg0: Flag16, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -880,7 +881,7 @@ pub mod exports { arg0: Flag32, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -900,7 +901,7 @@ pub mod exports { arg0: Flag64, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/flags_tracing_async.rs b/crates/component-macro/tests/expanded/flags_tracing_async.rs index 8bec37487115..65fdedf0193b 100644 --- a/crates/component-macro/tests/expanded/flags_tracing_async.rs +++ b/crates/component-macro/tests/expanded/flags_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheFlagsPre { } } } -impl<_T> TheFlagsPre<_T> { +impl<_T: Send + 'static> TheFlagsPre<_T> { /// Creates a new copy of `TheFlagsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheFlagsPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheFlagsPre::new(pre)?.instantiate_async(store).await @@ -319,19 +316,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -892,7 +893,7 @@ pub mod exports { arg0: Flag1, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -921,7 +922,7 @@ pub mod exports { arg0: Flag2, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -950,7 +951,7 @@ pub mod exports { arg0: Flag4, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -979,7 +980,7 @@ pub mod exports { arg0: Flag8, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1008,7 +1009,7 @@ pub mod exports { arg0: Flag16, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1037,7 +1038,7 @@ pub mod exports { arg0: Flag32, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1066,7 +1067,7 @@ pub mod exports { arg0: Flag64, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/floats.rs b/crates/component-macro/tests/expanded/floats.rs index 50f7b3ca973f..1a8d0aa3bb9f 100644 --- a/crates/component-macro/tests/expanded/floats.rs +++ b/crates/component-macro/tests/expanded/floats.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -194,19 +197,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/floats")?; inst.func_wrap( @@ -386,7 +393,10 @@ pub mod exports { &self, mut store: S, arg0: f32, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (f32,), @@ -401,7 +411,10 @@ pub mod exports { &self, mut store: S, arg0: f64, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (f64,), @@ -415,7 +428,10 @@ pub mod exports { pub fn call_f32_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -429,7 +445,10 @@ pub mod exports { pub fn call_f64_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), diff --git a/crates/component-macro/tests/expanded/floats_async.rs b/crates/component-macro/tests/expanded/floats_async.rs index 268d10882964..46624464be17 100644 --- a/crates/component-macro/tests/expanded/floats_async.rs +++ b/crates/component-macro/tests/expanded/floats_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -202,19 +199,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -409,7 +410,7 @@ pub mod exports { arg0: f32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -429,7 +430,7 @@ pub mod exports { arg0: f64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -448,7 +449,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -467,7 +468,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/floats_tracing_async.rs b/crates/component-macro/tests/expanded/floats_tracing_async.rs index 254cdef3d299..9bd02bb8e720 100644 --- a/crates/component-macro/tests/expanded/floats_tracing_async.rs +++ b/crates/component-macro/tests/expanded/floats_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -202,19 +199,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -467,7 +468,7 @@ pub mod exports { arg0: f32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -496,7 +497,7 @@ pub mod exports { arg0: f64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -524,7 +525,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -552,7 +553,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/function-new.rs b/crates/component-macro/tests/expanded/function-new.rs index ca37b6668473..45c584d31fb0 100644 --- a/crates/component-macro/tests/expanded/function-new.rs +++ b/crates/component-macro/tests/expanded/function-new.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -154,7 +154,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate(store) } @@ -170,7 +173,10 @@ const _: () = { pub fn call_new( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::<(), ()>::new_unchecked(self.new) }; diff --git a/crates/component-macro/tests/expanded/function-new_async.rs b/crates/component-macro/tests/expanded/function-new_async.rs index 38a06794f9a6..84bad64ba974 100644 --- a/crates/component-macro/tests/expanded/function-new_async.rs +++ b/crates/component-macro/tests/expanded/function-new_async.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: Send + 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> FooPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await @@ -178,7 +175,7 @@ const _: () = { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::<(), ()>::new_unchecked(self.new) diff --git a/crates/component-macro/tests/expanded/function-new_tracing_async.rs b/crates/component-macro/tests/expanded/function-new_tracing_async.rs index da3f9d8c9596..c20a45c27d6a 100644 --- a/crates/component-macro/tests/expanded/function-new_tracing_async.rs +++ b/crates/component-macro/tests/expanded/function-new_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: Send + 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> FooPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await @@ -178,7 +175,7 @@ const _: () = { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/host-world.rs b/crates/component-macro/tests/expanded/host-world.rs index b5b514902114..40b4b6a1258c 100644 --- a/crates/component-macro/tests/expanded/host-world.rs +++ b/crates/component-macro/tests/expanded/host-world.rs @@ -18,7 +18,7 @@ impl Clone for Host_Pre { } } } -impl<_T> Host_Pre<_T> { +impl<_T: 'static> Host_Pre<_T> { /// Creates a new copy of `Host_Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -162,7 +162,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; Host_Pre::new(pre)?.instantiate(store) } diff --git a/crates/component-macro/tests/expanded/host-world_async.rs b/crates/component-macro/tests/expanded/host-world_async.rs index 79226375a941..5a41715dcdd5 100644 --- a/crates/component-macro/tests/expanded/host-world_async.rs +++ b/crates/component-macro/tests/expanded/host-world_async.rs @@ -18,7 +18,7 @@ impl Clone for Host_Pre { } } } -impl<_T> Host_Pre<_T> { +impl<_T: Send + 'static> Host_Pre<_T> { /// Creates a new copy of `Host_Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> Host_Pre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -169,7 +166,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; Host_Pre::new(pre)?.instantiate_async(store).await diff --git a/crates/component-macro/tests/expanded/host-world_tracing_async.rs b/crates/component-macro/tests/expanded/host-world_tracing_async.rs index 9ded0ccb6d54..681e72bb3702 100644 --- a/crates/component-macro/tests/expanded/host-world_tracing_async.rs +++ b/crates/component-macro/tests/expanded/host-world_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for Host_Pre { } } } -impl<_T> Host_Pre<_T> { +impl<_T: Send + 'static> Host_Pre<_T> { /// Creates a new copy of `Host_Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> Host_Pre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -169,7 +166,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; Host_Pre::new(pre)?.instantiate_async(store).await diff --git a/crates/component-macro/tests/expanded/integers.rs b/crates/component-macro/tests/expanded/integers.rs index a0ea4d42e45e..181cf562051b 100644 --- a/crates/component-macro/tests/expanded/integers.rs +++ b/crates/component-macro/tests/expanded/integers.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -218,19 +221,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/integers")?; inst.func_wrap( @@ -714,7 +721,10 @@ pub mod exports { &self, mut store: S, arg0: u8, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (u8,), @@ -729,7 +739,10 @@ pub mod exports { &self, mut store: S, arg0: i8, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (i8,), @@ -744,7 +757,10 @@ pub mod exports { &self, mut store: S, arg0: u16, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (u16,), @@ -759,7 +775,10 @@ pub mod exports { &self, mut store: S, arg0: i16, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (i16,), @@ -774,7 +793,10 @@ pub mod exports { &self, mut store: S, arg0: u32, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (u32,), @@ -789,7 +811,10 @@ pub mod exports { &self, mut store: S, arg0: i32, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (i32,), @@ -804,7 +829,10 @@ pub mod exports { &self, mut store: S, arg0: u64, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (u64,), @@ -819,7 +847,10 @@ pub mod exports { &self, mut store: S, arg0: i64, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (i64,), @@ -841,7 +872,10 @@ pub mod exports { arg5: i32, arg6: u64, arg7: i64, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (u8, i8, u16, i16, u32, i32, u64, i64), @@ -859,7 +893,10 @@ pub mod exports { pub fn call_r1( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -873,7 +910,10 @@ pub mod exports { pub fn call_r2( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -887,7 +927,10 @@ pub mod exports { pub fn call_r3( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -901,7 +944,10 @@ pub mod exports { pub fn call_r4( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -915,7 +961,10 @@ pub mod exports { pub fn call_r5( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -929,7 +978,10 @@ pub mod exports { pub fn call_r6( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -943,7 +995,10 @@ pub mod exports { pub fn call_r7( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -957,7 +1012,10 @@ pub mod exports { pub fn call_r8( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -971,7 +1029,10 @@ pub mod exports { pub fn call_pair_ret( &self, mut store: S, - ) -> wasmtime::Result<(i64, u8)> { + ) -> wasmtime::Result<(i64, u8)> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), diff --git a/crates/component-macro/tests/expanded/integers_async.rs b/crates/component-macro/tests/expanded/integers_async.rs index e0dc621675bb..276d4a1ae254 100644 --- a/crates/component-macro/tests/expanded/integers_async.rs +++ b/crates/component-macro/tests/expanded/integers_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -226,19 +223,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -766,7 +767,7 @@ pub mod exports { arg0: u8, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -786,7 +787,7 @@ pub mod exports { arg0: i8, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -806,7 +807,7 @@ pub mod exports { arg0: u16, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -826,7 +827,7 @@ pub mod exports { arg0: i16, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -846,7 +847,7 @@ pub mod exports { arg0: u32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -866,7 +867,7 @@ pub mod exports { arg0: i32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -886,7 +887,7 @@ pub mod exports { arg0: u64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -906,7 +907,7 @@ pub mod exports { arg0: i64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -933,7 +934,7 @@ pub mod exports { arg7: i64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -955,7 +956,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -974,7 +975,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -993,7 +994,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1012,7 +1013,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1031,7 +1032,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1050,7 +1051,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1069,7 +1070,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1088,7 +1089,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1107,7 +1108,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<(i64, u8)> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/integers_tracing_async.rs b/crates/component-macro/tests/expanded/integers_tracing_async.rs index b14b6f2d962c..6ce534344867 100644 --- a/crates/component-macro/tests/expanded/integers_tracing_async.rs +++ b/crates/component-macro/tests/expanded/integers_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -226,19 +223,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1031,7 +1032,7 @@ pub mod exports { arg0: u8, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1060,7 +1061,7 @@ pub mod exports { arg0: i8, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1089,7 +1090,7 @@ pub mod exports { arg0: u16, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1118,7 +1119,7 @@ pub mod exports { arg0: i16, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1147,7 +1148,7 @@ pub mod exports { arg0: u32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1176,7 +1177,7 @@ pub mod exports { arg0: i32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1205,7 +1206,7 @@ pub mod exports { arg0: u64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1234,7 +1235,7 @@ pub mod exports { arg0: i64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1270,7 +1271,7 @@ pub mod exports { arg7: i64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1301,7 +1302,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1329,7 +1330,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1357,7 +1358,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1385,7 +1386,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1413,7 +1414,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1441,7 +1442,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1469,7 +1470,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1497,7 +1498,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1525,7 +1526,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<(i64, u8)> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/lists.rs b/crates/component-macro/tests/expanded/lists.rs index d5067c796dc5..db311d6f16bb 100644 --- a/crates/component-macro/tests/expanded/lists.rs +++ b/crates/component-macro/tests/expanded/lists.rs @@ -18,7 +18,7 @@ impl Clone for TheListsPre { } } } -impl<_T> TheListsPre<_T> { +impl<_T: 'static> TheListsPre<_T> { /// Creates a new copy of `TheListsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheListsPre::new(pre)?.instantiate(store) } @@ -467,19 +470,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/lists")?; inst.func_wrap( @@ -1573,7 +1580,10 @@ pub mod exports { &self, mut store: S, arg0: &[u8], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[u8],), @@ -1588,7 +1598,10 @@ pub mod exports { &self, mut store: S, arg0: &[u16], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[u16],), @@ -1603,7 +1616,10 @@ pub mod exports { &self, mut store: S, arg0: &[u32], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[u32],), @@ -1618,7 +1634,10 @@ pub mod exports { &self, mut store: S, arg0: &[u64], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[u64],), @@ -1633,7 +1652,10 @@ pub mod exports { &self, mut store: S, arg0: &[i8], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[i8],), @@ -1648,7 +1670,10 @@ pub mod exports { &self, mut store: S, arg0: &[i16], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[i16],), @@ -1663,7 +1688,10 @@ pub mod exports { &self, mut store: S, arg0: &[i32], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[i32],), @@ -1678,7 +1706,10 @@ pub mod exports { &self, mut store: S, arg0: &[i64], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[i64],), @@ -1693,7 +1724,10 @@ pub mod exports { &self, mut store: S, arg0: &[f32], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[f32],), @@ -1708,7 +1742,10 @@ pub mod exports { &self, mut store: S, arg0: &[f64], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[f64],), @@ -1722,7 +1759,10 @@ pub mod exports { pub fn call_list_u8_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1736,7 +1776,10 @@ pub mod exports { pub fn call_list_u16_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1750,7 +1793,10 @@ pub mod exports { pub fn call_list_u32_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1764,7 +1810,10 @@ pub mod exports { pub fn call_list_u64_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1778,7 +1827,10 @@ pub mod exports { pub fn call_list_s8_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1792,7 +1844,10 @@ pub mod exports { pub fn call_list_s16_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1806,7 +1861,10 @@ pub mod exports { pub fn call_list_s32_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1820,7 +1878,10 @@ pub mod exports { pub fn call_list_s64_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1834,7 +1895,10 @@ pub mod exports { pub fn call_list_f32_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1848,7 +1912,10 @@ pub mod exports { pub fn call_list_f64_ret( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1865,7 +1932,10 @@ pub mod exports { arg0: &[(u8, i8)], ) -> wasmtime::Result< wasmtime::component::__internal::Vec<(i64, u32)>, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[(u8, i8)],), @@ -1880,7 +1950,10 @@ pub mod exports { &self, mut store: S, arg0: &[wasmtime::component::__internal::String], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[wasmtime::component::__internal::String],), @@ -1898,7 +1971,10 @@ pub mod exports { wasmtime::component::__internal::Vec< wasmtime::component::__internal::String, >, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1921,7 +1997,10 @@ pub mod exports { wasmtime::component::__internal::Vec< (wasmtime::component::__internal::String, u8), >, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[(u8, wasmtime::component::__internal::String)],), @@ -1944,7 +2023,10 @@ pub mod exports { wasmtime::component::__internal::Vec< wasmtime::component::__internal::String, >, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[wasmtime::component::__internal::String],), @@ -1965,7 +2047,10 @@ pub mod exports { arg0: &[SomeRecord], ) -> wasmtime::Result< wasmtime::component::__internal::Vec, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[SomeRecord],), @@ -1982,7 +2067,10 @@ pub mod exports { arg0: &[OtherRecord], ) -> wasmtime::Result< wasmtime::component::__internal::Vec, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[OtherRecord],), @@ -1999,7 +2087,10 @@ pub mod exports { arg0: &[SomeVariant], ) -> wasmtime::Result< wasmtime::component::__internal::Vec, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[SomeVariant],), @@ -2014,7 +2105,10 @@ pub mod exports { &self, mut store: S, arg0: &LoadStoreAllSizes, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&LoadStoreAllSizes,), diff --git a/crates/component-macro/tests/expanded/lists_async.rs b/crates/component-macro/tests/expanded/lists_async.rs index 219a469f9548..1336c89f702b 100644 --- a/crates/component-macro/tests/expanded/lists_async.rs +++ b/crates/component-macro/tests/expanded/lists_async.rs @@ -18,7 +18,7 @@ impl Clone for TheListsPre { } } } -impl<_T> TheListsPre<_T> { +impl<_T: Send + 'static> TheListsPre<_T> { /// Creates a new copy of `TheListsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheListsPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheListsPre::new(pre)?.instantiate_async(store).await @@ -495,19 +492,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1686,7 +1687,7 @@ pub mod exports { arg0: &[u8], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1706,7 +1707,7 @@ pub mod exports { arg0: &[u16], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1726,7 +1727,7 @@ pub mod exports { arg0: &[u32], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1746,7 +1747,7 @@ pub mod exports { arg0: &[u64], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1766,7 +1767,7 @@ pub mod exports { arg0: &[i8], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1786,7 +1787,7 @@ pub mod exports { arg0: &[i16], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1806,7 +1807,7 @@ pub mod exports { arg0: &[i32], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1826,7 +1827,7 @@ pub mod exports { arg0: &[i64], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1846,7 +1847,7 @@ pub mod exports { arg0: &[f32], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1866,7 +1867,7 @@ pub mod exports { arg0: &[f64], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1885,7 +1886,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1904,7 +1905,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1923,7 +1924,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1942,7 +1943,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1961,7 +1962,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1980,7 +1981,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1999,7 +2000,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2018,7 +2019,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2037,7 +2038,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2056,7 +2057,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2078,7 +2079,7 @@ pub mod exports { wasmtime::component::__internal::Vec<(i64, u32)>, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2098,7 +2099,7 @@ pub mod exports { arg0: &[wasmtime::component::__internal::String], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2121,7 +2122,7 @@ pub mod exports { >, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2149,7 +2150,7 @@ pub mod exports { >, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2177,7 +2178,7 @@ pub mod exports { >, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2203,7 +2204,7 @@ pub mod exports { wasmtime::component::__internal::Vec, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2225,7 +2226,7 @@ pub mod exports { wasmtime::component::__internal::Vec, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2247,7 +2248,7 @@ pub mod exports { wasmtime::component::__internal::Vec, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2267,7 +2268,7 @@ pub mod exports { arg0: &LoadStoreAllSizes, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/lists_tracing_async.rs b/crates/component-macro/tests/expanded/lists_tracing_async.rs index dece512b8e0a..8909a721e311 100644 --- a/crates/component-macro/tests/expanded/lists_tracing_async.rs +++ b/crates/component-macro/tests/expanded/lists_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheListsPre { } } } -impl<_T> TheListsPre<_T> { +impl<_T: Send + 'static> TheListsPre<_T> { /// Creates a new copy of `TheListsPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheListsPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheListsPre::new(pre)?.instantiate_async(store).await @@ -495,19 +492,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -2117,7 +2118,7 @@ pub mod exports { arg0: &[u8], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2146,7 +2147,7 @@ pub mod exports { arg0: &[u16], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2175,7 +2176,7 @@ pub mod exports { arg0: &[u32], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2204,7 +2205,7 @@ pub mod exports { arg0: &[u64], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2233,7 +2234,7 @@ pub mod exports { arg0: &[i8], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2262,7 +2263,7 @@ pub mod exports { arg0: &[i16], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2291,7 +2292,7 @@ pub mod exports { arg0: &[i32], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2320,7 +2321,7 @@ pub mod exports { arg0: &[i64], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2349,7 +2350,7 @@ pub mod exports { arg0: &[f32], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2378,7 +2379,7 @@ pub mod exports { arg0: &[f64], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2406,7 +2407,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2434,7 +2435,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2462,7 +2463,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2490,7 +2491,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2518,7 +2519,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2546,7 +2547,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2574,7 +2575,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2602,7 +2603,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2630,7 +2631,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2658,7 +2659,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2689,7 +2690,7 @@ pub mod exports { wasmtime::component::__internal::Vec<(i64, u32)>, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2718,7 +2719,7 @@ pub mod exports { arg0: &[wasmtime::component::__internal::String], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2750,7 +2751,7 @@ pub mod exports { >, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2787,7 +2788,7 @@ pub mod exports { >, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2824,7 +2825,7 @@ pub mod exports { >, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2859,7 +2860,7 @@ pub mod exports { wasmtime::component::__internal::Vec, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2890,7 +2891,7 @@ pub mod exports { wasmtime::component::__internal::Vec, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2921,7 +2922,7 @@ pub mod exports { wasmtime::component::__internal::Vec, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2950,7 +2951,7 @@ pub mod exports { arg0: &LoadStoreAllSizes, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/many-arguments.rs b/crates/component-macro/tests/expanded/many-arguments.rs index 86db694f8323..f9686edb15da 100644 --- a/crates/component-macro/tests/expanded/many-arguments.rs +++ b/crates/component-macro/tests/expanded/many-arguments.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -291,19 +294,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/manyarg")?; inst.func_wrap( @@ -659,7 +666,10 @@ pub mod exports { arg13: u64, arg14: u64, arg15: u64, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< ( @@ -712,7 +722,10 @@ pub mod exports { &self, mut store: S, arg0: &BigStruct, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&BigStruct,), diff --git a/crates/component-macro/tests/expanded/many-arguments_async.rs b/crates/component-macro/tests/expanded/many-arguments_async.rs index 3a55a6565f58..8efd4d152c73 100644 --- a/crates/component-macro/tests/expanded/many-arguments_async.rs +++ b/crates/component-macro/tests/expanded/many-arguments_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -299,19 +296,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -680,7 +681,7 @@ pub mod exports { arg15: u64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -737,7 +738,7 @@ pub mod exports { arg0: &BigStruct, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/many-arguments_tracing_async.rs b/crates/component-macro/tests/expanded/many-arguments_tracing_async.rs index ed87748a3f17..bcb0f0baefe6 100644 --- a/crates/component-macro/tests/expanded/many-arguments_tracing_async.rs +++ b/crates/component-macro/tests/expanded/many-arguments_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -299,19 +296,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -723,7 +724,7 @@ pub mod exports { arg15: u64, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -789,7 +790,7 @@ pub mod exports { arg0: &BigStruct, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/multi-return.rs b/crates/component-macro/tests/expanded/multi-return.rs index 7b42ddcaeb3c..1e00b26d0174 100644 --- a/crates/component-macro/tests/expanded/multi-return.rs +++ b/crates/component-macro/tests/expanded/multi-return.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -154,7 +154,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -197,19 +200,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/multi-return")?; inst.func_wrap( @@ -401,7 +408,10 @@ pub mod exports { pub fn call_mra( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -415,7 +425,10 @@ pub mod exports { pub fn call_mrb( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -429,7 +442,10 @@ pub mod exports { pub fn call_mrc( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -443,7 +459,10 @@ pub mod exports { pub fn call_mrd( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -457,7 +476,10 @@ pub mod exports { pub fn call_mre( &self, mut store: S, - ) -> wasmtime::Result<(u32, f32)> { + ) -> wasmtime::Result<(u32, f32)> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), diff --git a/crates/component-macro/tests/expanded/multi-return_async.rs b/crates/component-macro/tests/expanded/multi-return_async.rs index d0c44c782757..af69da11391b 100644 --- a/crates/component-macro/tests/expanded/multi-return_async.rs +++ b/crates/component-macro/tests/expanded/multi-return_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -205,19 +202,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -426,7 +427,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -443,7 +444,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -460,7 +461,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -479,7 +480,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -498,7 +499,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<(u32, f32)> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< 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 f24b6a347d29..5a61883cf57a 100644 --- a/crates/component-macro/tests/expanded/multi-return_tracing_async.rs +++ b/crates/component-macro/tests/expanded/multi-return_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -205,19 +202,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -491,7 +492,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -519,7 +520,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -547,7 +548,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -575,7 +576,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -603,7 +604,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<(u32, f32)> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/multiversion.rs b/crates/component-macro/tests/expanded/multiversion.rs index 44d9e429237e..cdc8daf9b46c 100644 --- a/crates/component-macro/tests/expanded/multiversion.rs +++ b/crates/component-macro/tests/expanded/multiversion.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -166,7 +166,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate(store) } @@ -209,19 +212,23 @@ pub mod my { } 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("my:dep/a@0.1.0")?; inst.func_wrap( @@ -260,19 +267,23 @@ pub mod my { } 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("my:dep/a@0.2.0")?; inst.func_wrap( @@ -390,7 +401,10 @@ pub mod exports { pub fn call_x( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -490,7 +504,10 @@ pub mod exports { pub fn call_x( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), diff --git a/crates/component-macro/tests/expanded/multiversion_async.rs b/crates/component-macro/tests/expanded/multiversion_async.rs index 9d730e2f643c..3f107ad52335 100644 --- a/crates/component-macro/tests/expanded/multiversion_async.rs +++ b/crates/component-macro/tests/expanded/multiversion_async.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: Send + 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> FooPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -171,7 +168,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await @@ -217,19 +214,23 @@ pub mod my { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -276,19 +277,23 @@ pub mod my { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -415,7 +420,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -518,7 +523,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/multiversion_tracing_async.rs b/crates/component-macro/tests/expanded/multiversion_tracing_async.rs index 11fa4d6cbbcc..2f863f432eb0 100644 --- a/crates/component-macro/tests/expanded/multiversion_tracing_async.rs +++ b/crates/component-macro/tests/expanded/multiversion_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: Send + 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> FooPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -171,7 +168,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await @@ -217,19 +214,23 @@ pub mod my { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -289,19 +290,23 @@ pub mod my { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -441,7 +446,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -555,7 +560,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/path1.rs b/crates/component-macro/tests/expanded/path1.rs index a4ce53636f65..a338608237fd 100644 --- a/crates/component-macro/tests/expanded/path1.rs +++ b/crates/component-macro/tests/expanded/path1.rs @@ -18,7 +18,7 @@ impl Clone for Path1Pre { } } } -impl<_T> Path1Pre<_T> { +impl<_T: 'static> Path1Pre<_T> { /// Creates a new copy of `Path1Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; Path1Pre::new(pre)?.instantiate(store) } @@ -176,19 +179,23 @@ pub mod paths { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("paths:path1/test")?; Ok(()) diff --git a/crates/component-macro/tests/expanded/path1_async.rs b/crates/component-macro/tests/expanded/path1_async.rs index 45f121cdd893..1c65ede05868 100644 --- a/crates/component-macro/tests/expanded/path1_async.rs +++ b/crates/component-macro/tests/expanded/path1_async.rs @@ -18,7 +18,7 @@ impl Clone for Path1Pre { } } } -impl<_T> Path1Pre<_T> { +impl<_T: Send + 'static> Path1Pre<_T> { /// Creates a new copy of `Path1Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> Path1Pre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; Path1Pre::new(pre)?.instantiate_async(store).await @@ -184,19 +181,23 @@ pub mod paths { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/path1_tracing_async.rs b/crates/component-macro/tests/expanded/path1_tracing_async.rs index 45f121cdd893..1c65ede05868 100644 --- a/crates/component-macro/tests/expanded/path1_tracing_async.rs +++ b/crates/component-macro/tests/expanded/path1_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for Path1Pre { } } } -impl<_T> Path1Pre<_T> { +impl<_T: Send + 'static> Path1Pre<_T> { /// Creates a new copy of `Path1Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> Path1Pre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; Path1Pre::new(pre)?.instantiate_async(store).await @@ -184,19 +181,23 @@ pub mod paths { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/path2.rs b/crates/component-macro/tests/expanded/path2.rs index 5d9fba7b1ba0..7ad7e7351c8e 100644 --- a/crates/component-macro/tests/expanded/path2.rs +++ b/crates/component-macro/tests/expanded/path2.rs @@ -18,7 +18,7 @@ impl Clone for Path2Pre { } } } -impl<_T> Path2Pre<_T> { +impl<_T: 'static> Path2Pre<_T> { /// Creates a new copy of `Path2Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; Path2Pre::new(pre)?.instantiate(store) } @@ -176,19 +179,23 @@ pub mod paths { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("paths:path2/test")?; Ok(()) diff --git a/crates/component-macro/tests/expanded/path2_async.rs b/crates/component-macro/tests/expanded/path2_async.rs index 0e07fe478658..b3a97ada5df1 100644 --- a/crates/component-macro/tests/expanded/path2_async.rs +++ b/crates/component-macro/tests/expanded/path2_async.rs @@ -18,7 +18,7 @@ impl Clone for Path2Pre { } } } -impl<_T> Path2Pre<_T> { +impl<_T: Send + 'static> Path2Pre<_T> { /// Creates a new copy of `Path2Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> Path2Pre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; Path2Pre::new(pre)?.instantiate_async(store).await @@ -184,19 +181,23 @@ pub mod paths { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/path2_tracing_async.rs b/crates/component-macro/tests/expanded/path2_tracing_async.rs index 0e07fe478658..b3a97ada5df1 100644 --- a/crates/component-macro/tests/expanded/path2_tracing_async.rs +++ b/crates/component-macro/tests/expanded/path2_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for Path2Pre { } } } -impl<_T> Path2Pre<_T> { +impl<_T: Send + 'static> Path2Pre<_T> { /// Creates a new copy of `Path2Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> Path2Pre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; Path2Pre::new(pre)?.instantiate_async(store).await @@ -184,19 +181,23 @@ pub mod paths { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/records.rs b/crates/component-macro/tests/expanded/records.rs index 5a6fed8dcbd3..38db67ea33dd 100644 --- a/crates/component-macro/tests/expanded/records.rs +++ b/crates/component-macro/tests/expanded/records.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -347,19 +350,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/records")?; inst.func_wrap( @@ -893,7 +900,10 @@ pub mod exports { &self, mut store: S, arg0: (char, u32), - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< ((char, u32),), @@ -907,7 +917,10 @@ pub mod exports { pub fn call_tuple_result( &self, mut store: S, - ) -> wasmtime::Result<(char, u32)> { + ) -> wasmtime::Result<(char, u32)> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -922,7 +935,10 @@ pub mod exports { &self, mut store: S, arg0: Empty, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Empty,), @@ -936,7 +952,10 @@ pub mod exports { pub fn call_empty_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -951,7 +970,10 @@ pub mod exports { &self, mut store: S, arg0: Scalars, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Scalars,), @@ -965,7 +987,10 @@ pub mod exports { pub fn call_scalar_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -980,7 +1005,10 @@ pub mod exports { &self, mut store: S, arg0: ReallyFlags, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (ReallyFlags,), @@ -994,7 +1022,10 @@ pub mod exports { pub fn call_flags_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1009,7 +1040,10 @@ pub mod exports { &self, mut store: S, arg0: &Aggregates, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&Aggregates,), @@ -1023,7 +1057,10 @@ pub mod exports { pub fn call_aggregate_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1038,7 +1075,10 @@ pub mod exports { &self, mut store: S, arg0: TupleTypedef2, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (TupleTypedef2,), diff --git a/crates/component-macro/tests/expanded/records_async.rs b/crates/component-macro/tests/expanded/records_async.rs index a7c2e82c405c..c9ce6ee1ce2b 100644 --- a/crates/component-macro/tests/expanded/records_async.rs +++ b/crates/component-macro/tests/expanded/records_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -355,19 +352,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -930,7 +931,7 @@ pub mod exports { arg0: (char, u32), ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -949,7 +950,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<(char, u32)> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -969,7 +970,7 @@ pub mod exports { arg0: Empty, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -988,7 +989,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1008,7 +1009,7 @@ pub mod exports { arg0: Scalars, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1027,7 +1028,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1047,7 +1048,7 @@ pub mod exports { arg0: ReallyFlags, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1066,7 +1067,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1086,7 +1087,7 @@ pub mod exports { arg0: &Aggregates, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1105,7 +1106,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1125,7 +1126,7 @@ pub mod exports { arg0: TupleTypedef2, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/records_tracing_async.rs b/crates/component-macro/tests/expanded/records_tracing_async.rs index 8bcfaffa0ea7..43344690ad1e 100644 --- a/crates/component-macro/tests/expanded/records_tracing_async.rs +++ b/crates/component-macro/tests/expanded/records_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -355,19 +352,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1091,7 +1092,7 @@ pub mod exports { arg0: (char, u32), ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1119,7 +1120,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<(char, u32)> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1148,7 +1149,7 @@ pub mod exports { arg0: Empty, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1176,7 +1177,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1205,7 +1206,7 @@ pub mod exports { arg0: Scalars, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1233,7 +1234,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1262,7 +1263,7 @@ pub mod exports { arg0: ReallyFlags, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1290,7 +1291,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1319,7 +1320,7 @@ pub mod exports { arg0: &Aggregates, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1347,7 +1348,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -1376,7 +1377,7 @@ pub mod exports { arg0: TupleTypedef2, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/rename.rs b/crates/component-macro/tests/expanded/rename.rs index 40ad51574259..97ca0e0c822f 100644 --- a/crates/component-macro/tests/expanded/rename.rs +++ b/crates/component-macro/tests/expanded/rename.rs @@ -18,7 +18,7 @@ impl Clone for NeptunePre { } } } -impl<_T> NeptunePre<_T> { +impl<_T: 'static> NeptunePre<_T> { /// Creates a new copy of `NeptunePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; NeptunePre::new(pre)?.instantiate(store) } @@ -182,19 +185,23 @@ pub mod foo { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/green")?; Ok(()) @@ -224,19 +231,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/red")?; inst.func_wrap( diff --git a/crates/component-macro/tests/expanded/rename_async.rs b/crates/component-macro/tests/expanded/rename_async.rs index e1966b08dc86..ddbb01ca8c33 100644 --- a/crates/component-macro/tests/expanded/rename_async.rs +++ b/crates/component-macro/tests/expanded/rename_async.rs @@ -18,7 +18,7 @@ impl Clone for NeptunePre { } } } -impl<_T> NeptunePre<_T> { +impl<_T: Send + 'static> NeptunePre<_T> { /// Creates a new copy of `NeptunePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> NeptunePre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; NeptunePre::new(pre)?.instantiate_async(store).await @@ -190,19 +187,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -238,19 +239,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/rename_tracing_async.rs b/crates/component-macro/tests/expanded/rename_tracing_async.rs index f8bc4e5e606c..dba8ab165e85 100644 --- a/crates/component-macro/tests/expanded/rename_tracing_async.rs +++ b/crates/component-macro/tests/expanded/rename_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for NeptunePre { } } } -impl<_T> NeptunePre<_T> { +impl<_T: Send + 'static> NeptunePre<_T> { /// Creates a new copy of `NeptunePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> NeptunePre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; NeptunePre::new(pre)?.instantiate_async(store).await @@ -190,19 +187,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -238,19 +239,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/resources-export.rs b/crates/component-macro/tests/expanded/resources-export.rs index 2df3c228fa37..14981a1039b4 100644 --- a/crates/component-macro/tests/expanded/resources-export.rs +++ b/crates/component-macro/tests/expanded/resources-export.rs @@ -18,7 +18,7 @@ impl Clone for WPre { } } } -impl<_T> WPre<_T> { +impl<_T: 'static> WPre<_T> { /// Creates a new copy of `WPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -199,7 +199,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; WPre::new(pre)?.instantiate(store) } @@ -249,7 +252,7 @@ pub mod foo { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; pub enum Y {} - pub trait HostY { + pub trait HostY: Sized { fn drop( &mut self, rep: wasmtime::component::Resource, @@ -263,22 +266,26 @@ pub mod foo { HostY::drop(*self, rep) } } - pub trait Host: HostY {} + pub trait Host: HostY + Sized {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/transitive-import")?; inst.resource( @@ -432,7 +439,10 @@ pub mod exports { pub fn call_constructor( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -446,7 +456,10 @@ pub mod exports { pub fn call_static_a( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -461,7 +474,10 @@ pub mod exports { &self, mut store: S, arg0: wasmtime::component::ResourceAny, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (wasmtime::component::ResourceAny,), @@ -602,7 +618,10 @@ pub mod exports { &self, mut store: S, arg0: wasmtime::component::Resource, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (wasmtime::component::Resource,), @@ -616,7 +635,10 @@ pub mod exports { pub fn call_static_a( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -632,7 +654,10 @@ pub mod exports { mut store: S, arg0: wasmtime::component::ResourceAny, arg1: wasmtime::component::Resource, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< ( @@ -747,7 +772,10 @@ pub mod exports { pub fn call_constructor( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -861,7 +889,10 @@ pub mod exports { &self, mut store: S, arg0: wasmtime::component::ResourceAny, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (wasmtime::component::ResourceAny,), diff --git a/crates/component-macro/tests/expanded/resources-export_async.rs b/crates/component-macro/tests/expanded/resources-export_async.rs index 09a3766b8731..cb41540c8165 100644 --- a/crates/component-macro/tests/expanded/resources-export_async.rs +++ b/crates/component-macro/tests/expanded/resources-export_async.rs @@ -18,7 +18,7 @@ impl Clone for WPre { } } } -impl<_T> WPre<_T> { +impl<_T: Send + 'static> WPre<_T> { /// Creates a new copy of `WPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> WPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -204,7 +201,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; WPre::new(pre)?.instantiate_async(store).await @@ -257,7 +254,7 @@ pub mod foo { use wasmtime::component::__internal::anyhow; pub enum Y {} #[wasmtime::component::__internal::async_trait] - pub trait HostY { + pub trait HostY: Sized { async fn drop( &mut self, rep: wasmtime::component::Resource, @@ -273,22 +270,26 @@ pub mod foo { } } #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostY {} + pub trait Host: Send + HostY + Sized {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -452,7 +453,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -471,7 +472,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -491,7 +492,7 @@ pub mod exports { arg0: wasmtime::component::ResourceAny, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -637,7 +638,7 @@ pub mod exports { arg0: wasmtime::component::Resource, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -656,7 +657,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -677,7 +678,7 @@ pub mod exports { arg1: wasmtime::component::Resource, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -797,7 +798,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -916,7 +917,7 @@ pub mod exports { arg0: wasmtime::component::ResourceAny, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/resources-export_tracing_async.rs b/crates/component-macro/tests/expanded/resources-export_tracing_async.rs index e25bebe52015..5a1afd37b39f 100644 --- a/crates/component-macro/tests/expanded/resources-export_tracing_async.rs +++ b/crates/component-macro/tests/expanded/resources-export_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for WPre { } } } -impl<_T> WPre<_T> { +impl<_T: Send + 'static> WPre<_T> { /// Creates a new copy of `WPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> WPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -204,7 +201,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; WPre::new(pre)?.instantiate_async(store).await @@ -257,7 +254,7 @@ pub mod foo { use wasmtime::component::__internal::anyhow; pub enum Y {} #[wasmtime::component::__internal::async_trait] - pub trait HostY { + pub trait HostY: Sized { async fn drop( &mut self, rep: wasmtime::component::Resource, @@ -273,22 +270,26 @@ pub mod foo { } } #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostY {} + pub trait Host: Send + HostY + Sized {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -452,7 +453,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -480,7 +481,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -509,7 +510,7 @@ pub mod exports { arg0: wasmtime::component::ResourceAny, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -664,7 +665,7 @@ pub mod exports { arg0: wasmtime::component::Resource, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -692,7 +693,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -723,7 +724,7 @@ pub mod exports { arg1: wasmtime::component::Resource, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -853,7 +854,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -981,7 +982,7 @@ pub mod exports { arg0: wasmtime::component::ResourceAny, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/resources-import.rs b/crates/component-macro/tests/expanded/resources-import.rs index cbea8b03f851..57b01dbee424 100644 --- a/crates/component-macro/tests/expanded/resources-import.rs +++ b/crates/component-macro/tests/expanded/resources-import.rs @@ -1,5 +1,5 @@ pub enum WorldResource {} -pub trait HostWorldResource { +pub trait HostWorldResource: Sized { fn new(&mut self) -> wasmtime::component::Resource; fn foo(&mut self, self_: wasmtime::component::Resource) -> (); fn static_foo(&mut self) -> (); @@ -45,7 +45,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -229,7 +229,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -321,7 +324,10 @@ const _: () = { pub fn call_some_world_func2( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -346,7 +352,7 @@ pub mod foo { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; pub enum Bar {} - pub trait HostBar { + pub trait HostBar: Sized { fn new(&mut self) -> wasmtime::component::Resource; fn static_a(&mut self) -> u32; fn method_a(&mut self, self_: wasmtime::component::Resource) -> u32; @@ -430,7 +436,7 @@ pub mod foo { 4 == < SomeHandle as wasmtime::component::ComponentType >::ALIGN32 ); }; - pub trait Host: HostBar { + pub trait Host: HostBar + Sized { fn bar_own_arg(&mut self, x: wasmtime::component::Resource) -> (); fn bar_borrow_arg( &mut self, @@ -492,19 +498,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/resources")?; inst.resource( @@ -862,7 +872,7 @@ pub mod foo { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; pub enum A {} - pub trait HostA { + pub trait HostA: Sized { fn drop( &mut self, rep: wasmtime::component::Resource, @@ -876,22 +886,26 @@ pub mod foo { HostA::drop(*self, rep) } } - pub trait Host: HostA {} + pub trait Host: HostA + Sized {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/long-use-chain1")?; inst.resource( @@ -925,19 +939,23 @@ pub mod foo { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/long-use-chain2")?; Ok(()) @@ -961,19 +979,23 @@ pub mod foo { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/long-use-chain3")?; Ok(()) @@ -999,19 +1021,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/long-use-chain4")?; inst.func_wrap( @@ -1044,7 +1070,7 @@ pub mod foo { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; pub enum Foo {} - pub trait HostFoo { + pub trait HostFoo: Sized { fn drop( &mut self, rep: wasmtime::component::Resource, @@ -1058,22 +1084,26 @@ pub mod foo { HostFoo::drop(*self, rep) } } - pub trait Host: HostFoo {} + pub trait Host: HostFoo + Sized {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker .instance("foo:foo/transitive-interface-with-resource")?; @@ -1199,7 +1229,10 @@ pub mod exports { &self, mut store: S, arg0: wasmtime::component::Resource, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (wasmtime::component::Resource,), diff --git a/crates/component-macro/tests/expanded/resources-import_async.rs b/crates/component-macro/tests/expanded/resources-import_async.rs index b54d0c283fdf..c440e35c01ac 100644 --- a/crates/component-macro/tests/expanded/resources-import_async.rs +++ b/crates/component-macro/tests/expanded/resources-import_async.rs @@ -1,6 +1,6 @@ pub enum WorldResource {} #[wasmtime::component::__internal::async_trait] -pub trait HostWorldResource { +pub trait HostWorldResource: Sized { async fn new(&mut self) -> wasmtime::component::Resource; async fn foo(&mut self, self_: wasmtime::component::Resource) -> (); async fn static_foo(&mut self) -> (); @@ -47,7 +47,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -75,10 +75,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -238,7 +235,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -349,7 +346,7 @@ const _: () = { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -376,7 +373,7 @@ pub mod foo { use wasmtime::component::__internal::anyhow; pub enum Bar {} #[wasmtime::component::__internal::async_trait] - pub trait HostBar { + pub trait HostBar: Sized { async fn new(&mut self) -> wasmtime::component::Resource; async fn static_a(&mut self) -> u32; async fn method_a( @@ -465,7 +462,7 @@ pub mod foo { ); }; #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostBar { + pub trait Host: Send + HostBar + Sized { async fn bar_own_arg( &mut self, x: wasmtime::component::Resource, @@ -532,19 +529,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -960,7 +961,7 @@ pub mod foo { use wasmtime::component::__internal::anyhow; pub enum A {} #[wasmtime::component::__internal::async_trait] - pub trait HostA { + pub trait HostA: Sized { async fn drop( &mut self, rep: wasmtime::component::Resource, @@ -976,22 +977,26 @@ pub mod foo { } } #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostA {} + pub trait Host: Send + HostA + Sized {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1034,19 +1039,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1076,19 +1085,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1120,19 +1133,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1173,7 +1190,7 @@ pub mod foo { use wasmtime::component::__internal::anyhow; pub enum Foo {} #[wasmtime::component::__internal::async_trait] - pub trait HostFoo { + pub trait HostFoo: Sized { async fn drop( &mut self, rep: wasmtime::component::Resource, @@ -1189,22 +1206,26 @@ pub mod foo { } } #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostFoo {} + pub trait Host: Send + HostFoo + Sized {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1340,7 +1361,7 @@ pub mod exports { arg0: wasmtime::component::Resource, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/resources-import_tracing_async.rs b/crates/component-macro/tests/expanded/resources-import_tracing_async.rs index 3a5f6ed8aea2..f2e54b19ce08 100644 --- a/crates/component-macro/tests/expanded/resources-import_tracing_async.rs +++ b/crates/component-macro/tests/expanded/resources-import_tracing_async.rs @@ -1,6 +1,6 @@ pub enum WorldResource {} #[wasmtime::component::__internal::async_trait] -pub trait HostWorldResource { +pub trait HostWorldResource: Sized { async fn new(&mut self) -> wasmtime::component::Resource; async fn foo(&mut self, self_: wasmtime::component::Resource) -> (); async fn static_foo(&mut self) -> (); @@ -47,7 +47,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -75,10 +75,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -238,7 +235,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -404,7 +401,7 @@ const _: () = { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -439,7 +436,7 @@ pub mod foo { use wasmtime::component::__internal::anyhow; pub enum Bar {} #[wasmtime::component::__internal::async_trait] - pub trait HostBar { + pub trait HostBar: Sized { async fn new(&mut self) -> wasmtime::component::Resource; async fn static_a(&mut self) -> u32; async fn method_a( @@ -528,7 +525,7 @@ pub mod foo { ); }; #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostBar { + pub trait Host: Send + HostBar + Sized { async fn bar_own_arg( &mut self, x: wasmtime::component::Resource, @@ -595,19 +592,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1351,7 +1352,7 @@ pub mod foo { use wasmtime::component::__internal::anyhow; pub enum A {} #[wasmtime::component::__internal::async_trait] - pub trait HostA { + pub trait HostA: Sized { async fn drop( &mut self, rep: wasmtime::component::Resource, @@ -1367,22 +1368,26 @@ pub mod foo { } } #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostA {} + pub trait Host: Send + HostA + Sized {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1425,19 +1430,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1467,19 +1476,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1511,19 +1524,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1577,7 +1594,7 @@ pub mod foo { use wasmtime::component::__internal::anyhow; pub enum Foo {} #[wasmtime::component::__internal::async_trait] - pub trait HostFoo { + pub trait HostFoo: Sized { async fn drop( &mut self, rep: wasmtime::component::Resource, @@ -1593,22 +1610,26 @@ pub mod foo { } } #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostFoo {} + pub trait Host: Send + HostFoo + Sized {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1744,7 +1765,7 @@ pub mod exports { arg0: wasmtime::component::Resource, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/share-types.rs b/crates/component-macro/tests/expanded/share-types.rs index 2e7bd33dfa35..904067c24e3b 100644 --- a/crates/component-macro/tests/expanded/share-types.rs +++ b/crates/component-macro/tests/expanded/share-types.rs @@ -18,7 +18,7 @@ impl Clone for HttpInterfacePre { } } } -impl<_T> HttpInterfacePre<_T> { +impl<_T: 'static> HttpInterfacePre<_T> { /// Creates a new copy of `HttpInterfacePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; HttpInterfacePre::new(pre)?.instantiate(store) } @@ -228,19 +231,23 @@ pub mod foo { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/http-types")?; Ok(()) @@ -277,19 +284,20 @@ pub mod http_fetch { } 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( + pub fn add_to_linker_get_host GetHost<&'a mut T, T, Host: Host>>( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("http-fetch")?; inst.func_wrap( @@ -413,7 +421,10 @@ pub mod exports { &self, mut store: S, arg0: &Request, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&Request,), diff --git a/crates/component-macro/tests/expanded/share-types_async.rs b/crates/component-macro/tests/expanded/share-types_async.rs index a622e2d7eb80..a4e51a01f52d 100644 --- a/crates/component-macro/tests/expanded/share-types_async.rs +++ b/crates/component-macro/tests/expanded/share-types_async.rs @@ -18,7 +18,7 @@ impl Clone for HttpInterfacePre { } } } -impl<_T> HttpInterfacePre<_T> { +impl<_T: Send + 'static> HttpInterfacePre<_T> { /// Creates a new copy of `HttpInterfacePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> HttpInterfacePre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; HttpInterfacePre::new(pre)?.instantiate_async(store).await @@ -236,19 +233,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -291,19 +292,23 @@ pub mod http_fetch { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -436,7 +441,7 @@ pub mod exports { arg0: &Request, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/share-types_tracing_async.rs b/crates/component-macro/tests/expanded/share-types_tracing_async.rs index 67c7eaf1646d..e7283b01e12c 100644 --- a/crates/component-macro/tests/expanded/share-types_tracing_async.rs +++ b/crates/component-macro/tests/expanded/share-types_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for HttpInterfacePre { } } } -impl<_T> HttpInterfacePre<_T> { +impl<_T: Send + 'static> HttpInterfacePre<_T> { /// Creates a new copy of `HttpInterfacePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> HttpInterfacePre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; HttpInterfacePre::new(pre)?.instantiate_async(store).await @@ -236,19 +233,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -291,19 +292,23 @@ pub mod http_fetch { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -452,7 +457,7 @@ pub mod exports { arg0: &Request, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/simple-functions.rs b/crates/component-macro/tests/expanded/simple-functions.rs index 16274afb8f98..6f50a15f646e 100644 --- a/crates/component-macro/tests/expanded/simple-functions.rs +++ b/crates/component-macro/tests/expanded/simple-functions.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -196,19 +199,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/simple")?; inst.func_wrap( @@ -427,7 +434,10 @@ pub mod exports { pub fn call_f1( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -442,7 +452,10 @@ pub mod exports { &self, mut store: S, arg0: u32, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (u32,), @@ -458,7 +471,10 @@ pub mod exports { mut store: S, arg0: u32, arg1: u32, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (u32, u32), @@ -472,7 +488,10 @@ pub mod exports { pub fn call_f4( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -486,7 +505,10 @@ pub mod exports { pub fn call_f5( &self, mut store: S, - ) -> wasmtime::Result<(u32, u32)> { + ) -> wasmtime::Result<(u32, u32)> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -503,7 +525,10 @@ pub mod exports { arg0: u32, arg1: u32, arg2: u32, - ) -> wasmtime::Result<(u32, u32, u32)> { + ) -> wasmtime::Result<(u32, u32, u32)> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (u32, u32, u32), diff --git a/crates/component-macro/tests/expanded/simple-functions_async.rs b/crates/component-macro/tests/expanded/simple-functions_async.rs index eb10075d88c8..264f5d6bdd67 100644 --- a/crates/component-macro/tests/expanded/simple-functions_async.rs +++ b/crates/component-macro/tests/expanded/simple-functions_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -204,19 +201,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -454,7 +455,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -472,7 +473,7 @@ pub mod exports { arg0: u32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -493,7 +494,7 @@ pub mod exports { arg1: u32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -512,7 +513,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -531,7 +532,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<(u32, u32)> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -553,7 +554,7 @@ pub mod exports { arg2: u32, ) -> wasmtime::Result<(u32, u32, u32)> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/simple-functions_tracing_async.rs b/crates/component-macro/tests/expanded/simple-functions_tracing_async.rs index 16d28903eab0..00361e05cdfe 100644 --- a/crates/component-macro/tests/expanded/simple-functions_tracing_async.rs +++ b/crates/component-macro/tests/expanded/simple-functions_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -204,19 +201,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -542,7 +543,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -571,7 +572,7 @@ pub mod exports { arg0: u32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -601,7 +602,7 @@ pub mod exports { arg1: u32, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -629,7 +630,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -657,7 +658,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<(u32, u32)> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -688,7 +689,7 @@ pub mod exports { arg2: u32, ) -> wasmtime::Result<(u32, u32, u32)> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/simple-lists.rs b/crates/component-macro/tests/expanded/simple-lists.rs index 0215d464ac38..1012a973cf85 100644 --- a/crates/component-macro/tests/expanded/simple-lists.rs +++ b/crates/component-macro/tests/expanded/simple-lists.rs @@ -18,7 +18,7 @@ impl Clone for MyWorldPre { } } } -impl<_T> MyWorldPre<_T> { +impl<_T: 'static> MyWorldPre<_T> { /// Creates a new copy of `MyWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -154,7 +154,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate(store) } @@ -213,19 +216,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/simple-lists")?; inst.func_wrap( @@ -464,7 +471,10 @@ pub mod exports { &self, mut store: S, arg0: &[u32], - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[u32],), @@ -478,7 +488,10 @@ pub mod exports { pub fn call_simple_list2( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -499,7 +512,10 @@ pub mod exports { wasmtime::component::__internal::Vec, wasmtime::component::__internal::Vec, ), - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[u32], &[u32]), @@ -523,7 +539,10 @@ pub mod exports { wasmtime::component::__internal::Vec< wasmtime::component::__internal::Vec, >, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&[wasmtime::component::__internal::Vec],), diff --git a/crates/component-macro/tests/expanded/simple-lists_async.rs b/crates/component-macro/tests/expanded/simple-lists_async.rs index e04e3e3299ff..110f3094e408 100644 --- a/crates/component-macro/tests/expanded/simple-lists_async.rs +++ b/crates/component-macro/tests/expanded/simple-lists_async.rs @@ -18,7 +18,7 @@ impl Clone for MyWorldPre { } } } -impl<_T> MyWorldPre<_T> { +impl<_T: Send + 'static> MyWorldPre<_T> { /// Creates a new copy of `MyWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> MyWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate_async(store).await @@ -223,19 +220,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -491,7 +492,7 @@ pub mod exports { arg0: &[u32], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -510,7 +511,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -536,7 +537,7 @@ pub mod exports { ), > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -565,7 +566,7 @@ pub mod exports { >, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/simple-lists_tracing_async.rs b/crates/component-macro/tests/expanded/simple-lists_tracing_async.rs index 69fd96ffeba3..b235ede9b69d 100644 --- a/crates/component-macro/tests/expanded/simple-lists_tracing_async.rs +++ b/crates/component-macro/tests/expanded/simple-lists_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for MyWorldPre { } } } -impl<_T> MyWorldPre<_T> { +impl<_T: Send + 'static> MyWorldPre<_T> { /// Creates a new copy of `MyWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> MyWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate_async(store).await @@ -223,19 +220,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -552,7 +553,7 @@ pub mod exports { arg0: &[u32], ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -580,7 +581,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -615,7 +616,7 @@ pub mod exports { ), > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -653,7 +654,7 @@ pub mod exports { >, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/simple-wasi.rs b/crates/component-macro/tests/expanded/simple-wasi.rs index 96d4a0bc2a94..ec1c062eecc1 100644 --- a/crates/component-macro/tests/expanded/simple-wasi.rs +++ b/crates/component-macro/tests/expanded/simple-wasi.rs @@ -18,7 +18,7 @@ impl Clone for WasiPre { } } } -impl<_T> WasiPre<_T> { +impl<_T: 'static> WasiPre<_T> { /// Creates a new copy of `WasiPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; WasiPre::new(pre)?.instantiate(store) } @@ -241,19 +244,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/wasi-filesystem")?; inst.func_wrap( @@ -299,19 +306,23 @@ pub mod foo { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/wall-clock")?; Ok(()) diff --git a/crates/component-macro/tests/expanded/simple-wasi_async.rs b/crates/component-macro/tests/expanded/simple-wasi_async.rs index 21f0e82575b3..79ea45fe3769 100644 --- a/crates/component-macro/tests/expanded/simple-wasi_async.rs +++ b/crates/component-macro/tests/expanded/simple-wasi_async.rs @@ -18,7 +18,7 @@ impl Clone for WasiPre { } } } -impl<_T> WasiPre<_T> { +impl<_T: Send + 'static> WasiPre<_T> { /// Creates a new copy of `WasiPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> WasiPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; WasiPre::new(pre)?.instantiate_async(store).await @@ -249,19 +246,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -317,19 +318,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/simple-wasi_tracing_async.rs b/crates/component-macro/tests/expanded/simple-wasi_tracing_async.rs index 6c6a92ca2eb4..8859c4c5a074 100644 --- a/crates/component-macro/tests/expanded/simple-wasi_tracing_async.rs +++ b/crates/component-macro/tests/expanded/simple-wasi_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for WasiPre { } } } -impl<_T> WasiPre<_T> { +impl<_T: Send + 'static> WasiPre<_T> { /// Creates a new copy of `WasiPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> WasiPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; WasiPre::new(pre)?.instantiate_async(store).await @@ -249,19 +246,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -343,19 +344,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/small-anonymous.rs b/crates/component-macro/tests/expanded/small-anonymous.rs index baa6463b58e8..83f3c7366997 100644 --- a/crates/component-macro/tests/expanded/small-anonymous.rs +++ b/crates/component-macro/tests/expanded/small-anonymous.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -238,19 +241,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/anon")?; inst.func_wrap( @@ -431,7 +438,10 @@ pub mod exports { mut store: S, ) -> wasmtime::Result< Result, Error>, - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), diff --git a/crates/component-macro/tests/expanded/small-anonymous_async.rs b/crates/component-macro/tests/expanded/small-anonymous_async.rs index 94a45355742e..511a03331075 100644 --- a/crates/component-macro/tests/expanded/small-anonymous_async.rs +++ b/crates/component-macro/tests/expanded/small-anonymous_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -246,19 +243,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -448,7 +449,7 @@ pub mod exports { Result, Error>, > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/small-anonymous_tracing_async.rs b/crates/component-macro/tests/expanded/small-anonymous_tracing_async.rs index 113ccf2700ae..0b0e3766d25f 100644 --- a/crates/component-macro/tests/expanded/small-anonymous_tracing_async.rs +++ b/crates/component-macro/tests/expanded/small-anonymous_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -246,19 +243,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -461,7 +462,7 @@ pub mod exports { Result, Error>, > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/smoke-default.rs b/crates/component-macro/tests/expanded/smoke-default.rs index e9ab3af1d8d4..7e2120dc5626 100644 --- a/crates/component-macro/tests/expanded/smoke-default.rs +++ b/crates/component-macro/tests/expanded/smoke-default.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -154,7 +154,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -170,7 +173,10 @@ const _: () = { pub fn call_y( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::<(), ()>::new_unchecked(self.y) }; diff --git a/crates/component-macro/tests/expanded/smoke-default_async.rs b/crates/component-macro/tests/expanded/smoke-default_async.rs index 30668f31d298..b44a971a5d8a 100644 --- a/crates/component-macro/tests/expanded/smoke-default_async.rs +++ b/crates/component-macro/tests/expanded/smoke-default_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -178,7 +175,7 @@ const _: () = { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::<(), ()>::new_unchecked(self.y) diff --git a/crates/component-macro/tests/expanded/smoke-default_tracing_async.rs b/crates/component-macro/tests/expanded/smoke-default_tracing_async.rs index 96f7792ceb76..de40b3c5991e 100644 --- a/crates/component-macro/tests/expanded/smoke-default_tracing_async.rs +++ b/crates/component-macro/tests/expanded/smoke-default_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -178,7 +175,7 @@ const _: () = { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/smoke-export.rs b/crates/component-macro/tests/expanded/smoke-export.rs index 9a9f8a25b18e..03b7ebd47685 100644 --- a/crates/component-macro/tests/expanded/smoke-export.rs +++ b/crates/component-macro/tests/expanded/smoke-export.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -250,7 +253,10 @@ pub mod exports { pub fn call_y( &self, mut store: S, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::<(), ()>::new_unchecked(self.y) }; diff --git a/crates/component-macro/tests/expanded/smoke-export_async.rs b/crates/component-macro/tests/expanded/smoke-export_async.rs index e21b8232c855..054130bbff4c 100644 --- a/crates/component-macro/tests/expanded/smoke-export_async.rs +++ b/crates/component-macro/tests/expanded/smoke-export_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -258,7 +255,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::<(), ()>::new_unchecked(self.y) diff --git a/crates/component-macro/tests/expanded/smoke-export_tracing_async.rs b/crates/component-macro/tests/expanded/smoke-export_tracing_async.rs index 9427cbcaa928..6dd91634d8b1 100644 --- a/crates/component-macro/tests/expanded/smoke-export_tracing_async.rs +++ b/crates/component-macro/tests/expanded/smoke-export_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -258,7 +255,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/smoke.rs b/crates/component-macro/tests/expanded/smoke.rs index f455ece5d3f7..35554d752ceb 100644 --- a/crates/component-macro/tests/expanded/smoke.rs +++ b/crates/component-macro/tests/expanded/smoke.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -176,19 +179,20 @@ pub mod imports { } 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( + pub fn add_to_linker_get_host GetHost<&'a mut T, T, Host: Host>>( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("imports")?; inst.func_wrap( diff --git a/crates/component-macro/tests/expanded/smoke_async.rs b/crates/component-macro/tests/expanded/smoke_async.rs index bfc70a8646fb..8dc220728ba9 100644 --- a/crates/component-macro/tests/expanded/smoke_async.rs +++ b/crates/component-macro/tests/expanded/smoke_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -184,19 +181,23 @@ pub mod imports { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/smoke_tracing_async.rs b/crates/component-macro/tests/expanded/smoke_tracing_async.rs index a3cd2582d13a..864ce2fa1800 100644 --- a/crates/component-macro/tests/expanded/smoke_tracing_async.rs +++ b/crates/component-macro/tests/expanded/smoke_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -184,19 +181,23 @@ pub mod imports { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/strings.rs b/crates/component-macro/tests/expanded/strings.rs index 743d69f5044c..bc34c8ae871d 100644 --- a/crates/component-macro/tests/expanded/strings.rs +++ b/crates/component-macro/tests/expanded/strings.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -197,19 +200,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/strings")?; inst.func_wrap( @@ -384,7 +391,10 @@ pub mod exports { &self, mut store: S, arg0: &str, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&str,), @@ -398,7 +408,10 @@ pub mod exports { pub fn call_b( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -414,7 +427,10 @@ pub mod exports { mut store: S, arg0: &str, arg1: &str, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&str, &str), diff --git a/crates/component-macro/tests/expanded/strings_async.rs b/crates/component-macro/tests/expanded/strings_async.rs index a597bb7f52ac..05188cf3b339 100644 --- a/crates/component-macro/tests/expanded/strings_async.rs +++ b/crates/component-macro/tests/expanded/strings_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -205,19 +202,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -405,7 +406,7 @@ pub mod exports { arg0: &str, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -424,7 +425,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -445,7 +446,7 @@ pub mod exports { arg1: &str, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/strings_tracing_async.rs b/crates/component-macro/tests/expanded/strings_tracing_async.rs index c7d2ae7f767f..cc877afaed92 100644 --- a/crates/component-macro/tests/expanded/strings_tracing_async.rs +++ b/crates/component-macro/tests/expanded/strings_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -205,19 +202,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -450,7 +451,7 @@ pub mod exports { arg0: &str, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -478,7 +479,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -508,7 +509,7 @@ pub mod exports { arg1: &str, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/unstable-features.rs b/crates/component-macro/tests/expanded/unstable-features.rs index c252a541394d..d6900dd1fa4d 100644 --- a/crates/component-macro/tests/expanded/unstable-features.rs +++ b/crates/component-macro/tests/expanded/unstable-features.rs @@ -62,7 +62,7 @@ impl LinkOptions { } } pub enum Baz {} -pub trait HostBaz { +pub trait HostBaz: Sized { fn foo(&mut self, self_: wasmtime::component::Resource) -> (); fn drop(&mut self, rep: wasmtime::component::Resource) -> wasmtime::Result<()>; } @@ -111,7 +111,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -255,7 +255,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } @@ -384,7 +387,7 @@ pub mod foo { } } pub enum Bar {} - pub trait HostBar { + pub trait HostBar: Sized { fn foo(&mut self, self_: wasmtime::component::Resource) -> (); fn drop( &mut self, @@ -402,25 +405,29 @@ pub mod foo { HostBar::drop(*self, rep) } } - pub trait Host: HostBar { + pub trait Host: HostBar + Sized { fn foo(&mut self) -> (); } 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( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host>, + >( linker: &mut wasmtime::component::Linker, options: &LinkOptions, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { if options.experimental_interface { let mut inst = linker.instance("foo:foo/the-interface")?; diff --git a/crates/component-macro/tests/expanded/unstable-features_async.rs b/crates/component-macro/tests/expanded/unstable-features_async.rs index 1b0da66840b2..805adabd31d4 100644 --- a/crates/component-macro/tests/expanded/unstable-features_async.rs +++ b/crates/component-macro/tests/expanded/unstable-features_async.rs @@ -63,7 +63,7 @@ impl LinkOptions { } pub enum Baz {} #[wasmtime::component::__internal::async_trait] -pub trait HostBaz { +pub trait HostBaz: Sized { async fn foo(&mut self, self_: wasmtime::component::Resource) -> (); async fn drop( &mut self, @@ -119,7 +119,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -147,10 +147,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -270,7 +267,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -412,7 +409,7 @@ pub mod foo { } pub enum Bar {} #[wasmtime::component::__internal::async_trait] - pub trait HostBar { + pub trait HostBar: Sized { async fn foo(&mut self, self_: wasmtime::component::Resource) -> (); async fn drop( &mut self, @@ -435,25 +432,29 @@ pub mod foo { } } #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostBar { + pub trait Host: Send + HostBar + Sized { async fn foo(&mut self) -> (); } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, options: &LinkOptions, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/unstable-features_tracing_async.rs b/crates/component-macro/tests/expanded/unstable-features_tracing_async.rs index d718adca7140..bf0e800c2b14 100644 --- a/crates/component-macro/tests/expanded/unstable-features_tracing_async.rs +++ b/crates/component-macro/tests/expanded/unstable-features_tracing_async.rs @@ -63,7 +63,7 @@ impl LinkOptions { } pub enum Baz {} #[wasmtime::component::__internal::async_trait] -pub trait HostBaz { +pub trait HostBaz: Sized { async fn foo(&mut self, self_: wasmtime::component::Resource) -> (); async fn drop( &mut self, @@ -119,7 +119,7 @@ impl Clone for TheWorldPre { } } } -impl<_T> TheWorldPre<_T> { +impl<_T: Send + 'static> TheWorldPre<_T> { /// Creates a new copy of `TheWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -147,10 +147,7 @@ impl<_T> TheWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -270,7 +267,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await @@ -441,7 +438,7 @@ pub mod foo { } pub enum Bar {} #[wasmtime::component::__internal::async_trait] - pub trait HostBar { + pub trait HostBar: Sized { async fn foo(&mut self, self_: wasmtime::component::Resource) -> (); async fn drop( &mut self, @@ -464,25 +461,29 @@ pub mod foo { } } #[wasmtime::component::__internal::async_trait] - pub trait Host: Send + HostBar { + pub trait Host: Send + HostBar + Sized { async fn foo(&mut self) -> (); } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, options: &LinkOptions, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/unversioned-foo.rs b/crates/component-macro/tests/expanded/unversioned-foo.rs index 20b394cf1bfb..facb0a7058f2 100644 --- a/crates/component-macro/tests/expanded/unversioned-foo.rs +++ b/crates/component-macro/tests/expanded/unversioned-foo.rs @@ -18,7 +18,7 @@ impl Clone for NopePre { } } } -impl<_T> NopePre<_T> { +impl<_T: 'static> NopePre<_T> { /// Creates a new copy of `NopePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; NopePre::new(pre)?.instantiate(store) } @@ -206,19 +209,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/a")?; inst.func_wrap( diff --git a/crates/component-macro/tests/expanded/unversioned-foo_async.rs b/crates/component-macro/tests/expanded/unversioned-foo_async.rs index fc83094285b6..3ca5d39c9bfb 100644 --- a/crates/component-macro/tests/expanded/unversioned-foo_async.rs +++ b/crates/component-macro/tests/expanded/unversioned-foo_async.rs @@ -18,7 +18,7 @@ impl Clone for NopePre { } } } -impl<_T> NopePre<_T> { +impl<_T: Send + 'static> NopePre<_T> { /// Creates a new copy of `NopePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> NopePre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; NopePre::new(pre)?.instantiate_async(store).await @@ -214,19 +211,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/unversioned-foo_tracing_async.rs b/crates/component-macro/tests/expanded/unversioned-foo_tracing_async.rs index 062ca5b258f7..265b3e8a4f18 100644 --- a/crates/component-macro/tests/expanded/unversioned-foo_tracing_async.rs +++ b/crates/component-macro/tests/expanded/unversioned-foo_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for NopePre { } } } -impl<_T> NopePre<_T> { +impl<_T: Send + 'static> NopePre<_T> { /// Creates a new copy of `NopePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> NopePre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; NopePre::new(pre)?.instantiate_async(store).await @@ -214,19 +211,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/use-paths.rs b/crates/component-macro/tests/expanded/use-paths.rs index 42e5e053aebc..44131d990a60 100644 --- a/crates/component-macro/tests/expanded/use-paths.rs +++ b/crates/component-macro/tests/expanded/use-paths.rs @@ -18,7 +18,7 @@ impl Clone for DPre { } } } -impl<_T> DPre<_T> { +impl<_T: 'static> DPre<_T> { /// Creates a new copy of `DPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -142,7 +142,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; DPre::new(pre)?.instantiate(store) } @@ -196,19 +199,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/a")?; inst.func_wrap( @@ -250,19 +257,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/b")?; inst.func_wrap( @@ -304,19 +315,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/c")?; inst.func_wrap( @@ -360,19 +375,20 @@ pub mod d { } 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( + pub fn add_to_linker_get_host GetHost<&'a mut T, T, Host: Host>>( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("d")?; inst.func_wrap( diff --git a/crates/component-macro/tests/expanded/use-paths_async.rs b/crates/component-macro/tests/expanded/use-paths_async.rs index 0aaae7b509aa..6a2406246b58 100644 --- a/crates/component-macro/tests/expanded/use-paths_async.rs +++ b/crates/component-macro/tests/expanded/use-paths_async.rs @@ -18,7 +18,7 @@ impl Clone for DPre { } } } -impl<_T> DPre<_T> { +impl<_T: Send + 'static> DPre<_T> { /// Creates a new copy of `DPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> DPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; DPre::new(pre)?.instantiate_async(store).await @@ -205,19 +202,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -267,19 +268,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -329,19 +334,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -393,19 +402,23 @@ pub mod d { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/use-paths_tracing_async.rs b/crates/component-macro/tests/expanded/use-paths_tracing_async.rs index 3affa9c4cbf7..61fc0b2324ba 100644 --- a/crates/component-macro/tests/expanded/use-paths_tracing_async.rs +++ b/crates/component-macro/tests/expanded/use-paths_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for DPre { } } } -impl<_T> DPre<_T> { +impl<_T: Send + 'static> DPre<_T> { /// Creates a new copy of `DPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> DPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -147,7 +144,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; DPre::new(pre)?.instantiate_async(store).await @@ -205,19 +202,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -280,19 +281,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -355,19 +360,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -432,19 +441,23 @@ pub mod d { } 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/variants.rs b/crates/component-macro/tests/expanded/variants.rs index 3e67dc0d976d..68af829ef994 100644 --- a/crates/component-macro/tests/expanded/variants.rs +++ b/crates/component-macro/tests/expanded/variants.rs @@ -18,7 +18,7 @@ impl Clone for MyWorldPre { } } } -impl<_T> MyWorldPre<_T> { +impl<_T: 'static> MyWorldPre<_T> { /// Creates a new copy of `MyWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -152,7 +152,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate(store) } @@ -532,19 +535,23 @@ 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/variants")?; inst.func_wrap( @@ -1613,7 +1620,10 @@ pub mod exports { &self, mut store: S, arg0: E1, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (E1,), @@ -1627,7 +1637,10 @@ pub mod exports { pub fn call_e1_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1642,7 +1655,10 @@ pub mod exports { &self, mut store: S, arg0: &V1, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&V1,), @@ -1656,7 +1672,10 @@ pub mod exports { pub fn call_v1_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1671,7 +1690,10 @@ pub mod exports { &self, mut store: S, arg0: bool, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (bool,), @@ -1685,7 +1707,10 @@ pub mod exports { pub fn call_bool_result( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1705,7 +1730,10 @@ pub mod exports { arg3: Option, arg4: Option, arg5: Option>, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< ( @@ -1739,7 +1767,10 @@ pub mod exports { Option, Option>, ), - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1770,7 +1801,10 @@ pub mod exports { arg5: Casts6, ) -> wasmtime::Result< (Casts1, Casts2, Casts3, Casts4, Casts5, Casts6), - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (Casts1, Casts2, Casts3, Casts4, Casts5, Casts6), @@ -1794,7 +1828,10 @@ pub mod exports { arg3: Result<(), ()>, arg4: Result, arg5: Result<&str, &[u8]>, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< ( @@ -1831,7 +1868,10 @@ pub mod exports { wasmtime::component::__internal::Vec, >, ), - > { + > + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1857,7 +1897,10 @@ pub mod exports { pub fn call_return_result_sugar( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1871,7 +1914,10 @@ pub mod exports { pub fn call_return_result_sugar2( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1885,7 +1931,10 @@ pub mod exports { pub fn call_return_result_sugar3( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1899,7 +1948,10 @@ pub mod exports { pub fn call_return_result_sugar4( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1913,7 +1965,10 @@ pub mod exports { pub fn call_return_option_sugar( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1927,7 +1982,10 @@ pub mod exports { pub fn call_return_option_sugar2( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1941,7 +1999,10 @@ pub mod exports { pub fn call_result_simple( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1956,7 +2017,10 @@ pub mod exports { &self, mut store: S, arg0: &IsClone, - ) -> wasmtime::Result<()> { + ) -> wasmtime::Result<()> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (&IsClone,), @@ -1970,7 +2034,10 @@ pub mod exports { pub fn call_is_clone_return( &self, mut store: S, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1984,7 +2051,10 @@ pub mod exports { pub fn call_return_named_option( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), @@ -1998,7 +2068,10 @@ pub mod exports { pub fn call_return_named_result( &self, mut store: S, - ) -> wasmtime::Result> { + ) -> wasmtime::Result> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::< (), diff --git a/crates/component-macro/tests/expanded/variants_async.rs b/crates/component-macro/tests/expanded/variants_async.rs index 36cf76daa580..f23b33b579ee 100644 --- a/crates/component-macro/tests/expanded/variants_async.rs +++ b/crates/component-macro/tests/expanded/variants_async.rs @@ -18,7 +18,7 @@ impl Clone for MyWorldPre { } } } -impl<_T> MyWorldPre<_T> { +impl<_T: Send + 'static> MyWorldPre<_T> { /// Creates a new copy of `MyWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> MyWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate_async(store).await @@ -540,19 +537,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1675,7 +1676,7 @@ pub mod exports { arg0: E1, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1694,7 +1695,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1714,7 +1715,7 @@ pub mod exports { arg0: &V1, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1733,7 +1734,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1753,7 +1754,7 @@ pub mod exports { arg0: bool, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1772,7 +1773,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1797,7 +1798,7 @@ pub mod exports { arg5: Option>, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1835,7 +1836,7 @@ pub mod exports { ), > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1871,7 +1872,7 @@ pub mod exports { (Casts1, Casts2, Casts3, Casts4, Casts5, Casts6), > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1899,7 +1900,7 @@ pub mod exports { arg5: Result<&str, &[u8]>, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1940,7 +1941,7 @@ pub mod exports { ), > where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1971,7 +1972,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -1990,7 +1991,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2009,7 +2010,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2028,7 +2029,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2047,7 +2048,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2066,7 +2067,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2085,7 +2086,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2105,7 +2106,7 @@ pub mod exports { arg0: &IsClone, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2124,7 +2125,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2143,7 +2144,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< @@ -2162,7 +2163,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::< diff --git a/crates/component-macro/tests/expanded/variants_tracing_async.rs b/crates/component-macro/tests/expanded/variants_tracing_async.rs index 792fd5815987..27160d255130 100644 --- a/crates/component-macro/tests/expanded/variants_tracing_async.rs +++ b/crates/component-macro/tests/expanded/variants_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for MyWorldPre { } } } -impl<_T> MyWorldPre<_T> { +impl<_T: Send + 'static> MyWorldPre<_T> { /// Creates a new copy of `MyWorldPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> MyWorldPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -157,7 +154,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate_async(store).await @@ -540,19 +537,23 @@ 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, @@ -1999,7 +2000,7 @@ pub mod exports { arg0: E1, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2027,7 +2028,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2056,7 +2057,7 @@ pub mod exports { arg0: &V1, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2084,7 +2085,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2113,7 +2114,7 @@ pub mod exports { arg0: bool, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2141,7 +2142,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2175,7 +2176,7 @@ pub mod exports { arg5: Option>, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2222,7 +2223,7 @@ pub mod exports { ), > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2267,7 +2268,7 @@ pub mod exports { (Casts1, Casts2, Casts3, Casts4, Casts5, Casts6), > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2304,7 +2305,7 @@ pub mod exports { arg5: Result<&str, &[u8]>, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2354,7 +2355,7 @@ pub mod exports { ), > where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2394,7 +2395,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2422,7 +2423,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2450,7 +2451,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2478,7 +2479,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2506,7 +2507,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2534,7 +2535,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2562,7 +2563,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2591,7 +2592,7 @@ pub mod exports { arg0: &IsClone, ) -> wasmtime::Result<()> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2619,7 +2620,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2647,7 +2648,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -2675,7 +2676,7 @@ pub mod exports { mut store: S, ) -> wasmtime::Result> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( diff --git a/crates/component-macro/tests/expanded/wat.rs b/crates/component-macro/tests/expanded/wat.rs index 14da6ff9efb6..4196504c6b9f 100644 --- a/crates/component-macro/tests/expanded/wat.rs +++ b/crates/component-macro/tests/expanded/wat.rs @@ -18,7 +18,7 @@ impl Clone for ExamplePre { } } } -impl<_T> ExamplePre<_T> { +impl<_T: 'static> ExamplePre<_T> { /// Creates a new copy of `ExamplePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -154,7 +154,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; ExamplePre::new(pre)?.instantiate(store) } diff --git a/crates/component-macro/tests/expanded/wat_async.rs b/crates/component-macro/tests/expanded/wat_async.rs index cad73611fe21..a5bf68e7a213 100644 --- a/crates/component-macro/tests/expanded/wat_async.rs +++ b/crates/component-macro/tests/expanded/wat_async.rs @@ -18,7 +18,7 @@ impl Clone for ExamplePre { } } } -impl<_T> ExamplePre<_T> { +impl<_T: Send + 'static> ExamplePre<_T> { /// Creates a new copy of `ExamplePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> ExamplePre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; ExamplePre::new(pre)?.instantiate_async(store).await diff --git a/crates/component-macro/tests/expanded/wat_tracing_async.rs b/crates/component-macro/tests/expanded/wat_tracing_async.rs index cad73611fe21..a5bf68e7a213 100644 --- a/crates/component-macro/tests/expanded/wat_tracing_async.rs +++ b/crates/component-macro/tests/expanded/wat_tracing_async.rs @@ -18,7 +18,7 @@ impl Clone for ExamplePre { } } } -impl<_T> ExamplePre<_T> { +impl<_T: Send + 'static> ExamplePre<_T> { /// Creates a new copy of `ExamplePre` bindings which can then /// be used to instantiate into a particular store. /// @@ -46,10 +46,7 @@ impl<_T> ExamplePre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -159,7 +156,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; ExamplePre::new(pre)?.instantiate_async(store).await diff --git a/crates/component-macro/tests/expanded/worlds-with-types.rs b/crates/component-macro/tests/expanded/worlds-with-types.rs index 2fd790395a13..544ce6a0e367 100644 --- a/crates/component-macro/tests/expanded/worlds-with-types.rs +++ b/crates/component-macro/tests/expanded/worlds-with-types.rs @@ -43,7 +43,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -181,7 +181,10 @@ const _: () = { mut store: impl wasmtime::AsContextMut, component: &wasmtime::component::Component, linker: &wasmtime::component::Linker<_T>, - ) -> wasmtime::Result { + ) -> wasmtime::Result + where + _T: 'static, + { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate(store) } @@ -207,7 +210,10 @@ const _: () = { pub fn call_f( &self, mut store: S, - ) -> wasmtime::Result<(T, U, R)> { + ) -> wasmtime::Result<(T, U, R)> + where + ::Data: Send + 'static, + { let callee = unsafe { wasmtime::component::TypedFunc::<(), ((T, U, R),)>::new_unchecked(self.f) }; @@ -231,19 +237,23 @@ pub mod foo { pub trait Host {} 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( + 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: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> { let mut inst = linker.instance("foo:foo/i")?; Ok(()) diff --git a/crates/component-macro/tests/expanded/worlds-with-types_async.rs b/crates/component-macro/tests/expanded/worlds-with-types_async.rs index 48f42f3a99b6..325bf3ba5c79 100644 --- a/crates/component-macro/tests/expanded/worlds-with-types_async.rs +++ b/crates/component-macro/tests/expanded/worlds-with-types_async.rs @@ -43,7 +43,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: Send + 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -71,10 +71,7 @@ impl<_T> FooPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -186,7 +183,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await @@ -216,7 +213,7 @@ const _: () = { mut store: S, ) -> wasmtime::Result<(T, U, R)> where - ::Data: Send, + ::Data: Send + 'static, { let callee = unsafe { wasmtime::component::TypedFunc::<(), ((T, U, R),)>::new_unchecked(self.f) @@ -242,19 +239,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/component-macro/tests/expanded/worlds-with-types_tracing_async.rs b/crates/component-macro/tests/expanded/worlds-with-types_tracing_async.rs index 63ed3ffff6e4..ab3b04473316 100644 --- a/crates/component-macro/tests/expanded/worlds-with-types_tracing_async.rs +++ b/crates/component-macro/tests/expanded/worlds-with-types_tracing_async.rs @@ -43,7 +43,7 @@ impl Clone for FooPre { } } } -impl<_T> FooPre<_T> { +impl<_T: Send + 'static> FooPre<_T> { /// Creates a new copy of `FooPre` bindings which can then /// be used to instantiate into a particular store. /// @@ -71,10 +71,7 @@ impl<_T> FooPre<_T> { pub async fn instantiate_async( &self, mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { + ) -> wasmtime::Result { let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate_async(&mut store).await?; self.indices.load(&mut store, &instance) @@ -186,7 +183,7 @@ const _: () = { linker: &wasmtime::component::Linker<_T>, ) -> wasmtime::Result where - _T: Send, + _T: Send + 'static, { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await @@ -216,7 +213,7 @@ const _: () = { mut store: S, ) -> wasmtime::Result<(T, U, R)> where - ::Data: Send, + ::Data: Send + 'static, { use tracing::Instrument; let span = tracing::span!( @@ -250,19 +247,23 @@ pub mod foo { pub trait Host: Send {} 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, { type Host = O; } - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host< + T, + G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>, + >( linker: &mut wasmtime::component::Linker, - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> wasmtime::Result<()> where T: Send, diff --git a/crates/cranelift/Cargo.toml b/crates/cranelift/Cargo.toml index 635a4eec91e8..f20a91139cbd 100644 --- a/crates/cranelift/Cargo.toml +++ b/crates/cranelift/Cargo.toml @@ -46,3 +46,4 @@ gc = ["wasmtime-environ/gc"] gc-drc = ["gc", "wasmtime-environ/gc-drc"] gc-null = ["gc", "wasmtime-environ/gc-null"] threads = ["wasmtime-environ/threads"] + diff --git a/crates/cranelift/src/compiler/component.rs b/crates/cranelift/src/compiler/component.rs index c3c84ad6bfc8..0fd399ba3648 100644 --- a/crates/cranelift/src/compiler/component.rs +++ b/crates/cranelift/src/compiler/component.rs @@ -3,7 +3,7 @@ use crate::{compiler::Compiler, TRAP_ALWAYS, TRAP_CANNOT_ENTER, TRAP_INTERNAL_ASSERT}; use anyhow::Result; use cranelift_codegen::ir::condcodes::IntCC; -use cranelift_codegen::ir::{self, InstBuilder, MemFlags}; +use cranelift_codegen::ir::{self, InstBuilder, MemFlags, Value}; use cranelift_codegen::isa::{CallConv, TargetIsa}; use cranelift_frontend::FunctionBuilder; use std::any::Any; @@ -97,24 +97,448 @@ impl<'a> TrampolineCompiler<'a> { Trampoline::ResourceNew(ty) => self.translate_resource_new(*ty), Trampoline::ResourceRep(ty) => self.translate_resource_rep(*ty), Trampoline::ResourceDrop(ty) => self.translate_resource_drop(*ty), + Trampoline::TaskBackpressure { instance } => { + self.translate_task_backpressure_call(*instance) + } + Trampoline::TaskReturn => self.translate_task_return_call(), + Trampoline::TaskWait { + instance, + async_, + memory, + } => self.translate_task_wait_or_poll_call( + *instance, + *async_, + *memory, + self.offsets.task_wait(), + ), + Trampoline::TaskPoll { + instance, + async_, + memory, + } => self.translate_task_wait_or_poll_call( + *instance, + *async_, + *memory, + self.offsets.task_poll(), + ), + Trampoline::TaskYield { async_ } => self.translate_task_yield_call(*async_), + Trampoline::SubtaskDrop { instance } => self.translate_subtask_drop_call(*instance), + Trampoline::StreamNew { ty } => self.translate_future_or_stream_call( + ty.as_u32(), + None, + self.offsets.stream_new(), + Vec::new(), + ir::types::I64, + ), + Trampoline::StreamRead { ty, options } => { + if let Some(info) = self.flat_stream_element_info(*ty) { + self.translate_flat_stream_call( + *ty, + options, + self.offsets.flat_stream_read(), + &info, + ) + } else { + self.translate_future_or_stream_call( + ty.as_u32(), + Some(options), + self.offsets.stream_read(), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I64, + ) + } + } + Trampoline::StreamWrite { ty, options } => { + if let Some(info) = self.flat_stream_element_info(*ty) { + self.translate_flat_stream_call( + *ty, + options, + self.offsets.flat_stream_write(), + &info, + ) + } else { + self.translate_future_or_stream_call( + ty.as_u32(), + Some(options), + self.offsets.stream_write(), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I64, + ) + } + } + Trampoline::StreamCancelRead { ty, async_ } => { + self.translate_cancel_call(ty.as_u32(), *async_, self.offsets.stream_cancel_read()) + } + Trampoline::StreamCancelWrite { ty, async_ } => { + self.translate_cancel_call(ty.as_u32(), *async_, self.offsets.stream_cancel_write()) + } + Trampoline::StreamCloseReadable { ty } => self.translate_future_or_stream_call( + ty.as_u32(), + None, + self.offsets.stream_close_readable(), + vec![ir::AbiParam::new(ir::types::I32)], + ir::types::I8, + ), + Trampoline::StreamCloseWritable { ty } => self.translate_future_or_stream_call( + ty.as_u32(), + None, + self.offsets.stream_close_writable(), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I8, + ), + Trampoline::FutureNew { ty } => self.translate_future_or_stream_call( + ty.as_u32(), + None, + self.offsets.future_new(), + Vec::new(), + ir::types::I64, + ), + Trampoline::FutureRead { ty, options } => self.translate_future_or_stream_call( + ty.as_u32(), + Some(&options), + self.offsets.future_read(), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I64, + ), + Trampoline::FutureWrite { ty, options } => self.translate_future_or_stream_call( + ty.as_u32(), + Some(options), + self.offsets.future_write(), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I64, + ), + Trampoline::FutureCancelRead { ty, async_ } => { + self.translate_cancel_call(ty.as_u32(), *async_, self.offsets.future_cancel_read()) + } + Trampoline::FutureCancelWrite { ty, async_ } => { + self.translate_cancel_call(ty.as_u32(), *async_, self.offsets.future_cancel_write()) + } + Trampoline::FutureCloseReadable { ty } => self.translate_future_or_stream_call( + ty.as_u32(), + None, + self.offsets.future_close_readable(), + vec![ir::AbiParam::new(ir::types::I32)], + ir::types::I8, + ), + Trampoline::FutureCloseWritable { ty } => self.translate_future_or_stream_call( + ty.as_u32(), + None, + self.offsets.future_close_writable(), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I8, + ), + Trampoline::ErrorContextNew { ty, options } => self.translate_error_context_call( + *ty, + options, + self.offsets.error_context_new(), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I64, + ), + Trampoline::ErrorContextDebugMessage { ty, options } => self + .translate_error_context_call( + *ty, + options, + self.offsets.error_context_debug_message(), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I8, + ), + Trampoline::ErrorContextDrop { ty } => self.translate_error_context_drop_call(*ty), Trampoline::ResourceTransferOwn => { - self.translate_resource_libcall(host::resource_transfer_own, |me, rets| { - rets[0] = me.raise_if_resource_trapped(rets[0]); + self.translate_host_libcall(host::resource_transfer_own, |me, rets| { + rets[0] = me.raise_if_i32_trapped(rets[0]); }) } Trampoline::ResourceTransferBorrow => { - self.translate_resource_libcall(host::resource_transfer_borrow, |me, rets| { - rets[0] = me.raise_if_resource_trapped(rets[0]); + self.translate_host_libcall(host::resource_transfer_borrow, |me, rets| { + rets[0] = me.raise_if_i32_trapped(rets[0]); }) } Trampoline::ResourceEnterCall => { - self.translate_resource_libcall(host::resource_enter_call, |_, _| {}) + self.translate_host_libcall(host::resource_enter_call, |_, _| {}) } Trampoline::ResourceExitCall => { - self.translate_resource_libcall(host::resource_exit_call, |me, rets| { + self.translate_host_libcall(host::resource_exit_call, |me, rets| { me.raise_if_host_trapped(rets.pop().unwrap()); }) } + Trampoline::AsyncEnterCall => { + let pointer_type = self.isa.pointer_type(); + self.translate_async_enter_or_exit( + self.offsets.async_enter(), + None, + vec![ + ir::AbiParam::new(pointer_type), + ir::AbiParam::new(pointer_type), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I8, + ) + } + Trampoline::AsyncExitCall(callback) => { + let pointer_type = self.isa.pointer_type(); + self.translate_async_enter_or_exit( + self.offsets.async_exit(), + Some(*callback), + vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(pointer_type), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + ir::types::I64, + ) + } + Trampoline::FutureTransfer => { + self.translate_host_libcall(host::future_transfer, |me, rets| { + rets[0] = me.raise_if_i32_trapped(rets[0]); + }) + } + Trampoline::StreamTransfer => { + self.translate_host_libcall(host::stream_transfer, |me, rets| { + rets[0] = me.raise_if_i32_trapped(rets[0]); + }) + } + Trampoline::ErrorContextTransfer => { + self.translate_host_libcall(host::error_context_transfer, |me, rets| { + rets[0] = me.raise_if_i32_trapped(rets[0]); + }) + } + } + } + + fn flat_stream_element_info(&self, ty: TypeStreamTableIndex) -> Option { + let payload = self.types[self.types[ty].ty].payload; + match payload { + InterfaceType::Bool + | InterfaceType::S8 + | InterfaceType::U8 + | InterfaceType::S16 + | InterfaceType::U16 + | InterfaceType::S32 + | InterfaceType::U32 + | InterfaceType::S64 + | InterfaceType::U64 + | InterfaceType::Float32 + | InterfaceType::Float64 + | InterfaceType::Char => Some(self.types.canonical_abi(&payload).clone()), + // TODO: Recursively check for other "flat" types (i.e. those without pointers or handles), + // e.g. `record`s, `variant`s, etc. which contain only flat types. + _ => None, + } + } + + fn store_wasm_arguments(&mut self, args: &[Value]) -> (Value, Value) { + let pointer_type = self.isa.pointer_type(); + let wasm_func_ty = &self.types[self.signature].unwrap_func(); + + // Start off by spilling all the wasm arguments into a stack slot to be + // passed to the host function. + match self.abi { + Abi::Wasm => { + let (ptr, len) = self.compiler.allocate_stack_array_and_spill_args( + wasm_func_ty, + &mut self.builder, + args, + ); + let len = self.builder.ins().iconst(pointer_type, i64::from(len)); + (ptr, len) + } + Abi::Array => { + let params = self.builder.func.dfg.block_params(self.block0); + (params[2], params[3]) + } + } + } + + fn translate_task_return_call(&mut self) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + + let (values_vec_ptr, values_vec_len) = self.store_wasm_arguments(&args[2..]); + + let mut callee_args = Vec::new(); + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + + // vmctx: *mut VMComponentContext + host_sig.params.push(ir::AbiParam::new(pointer_type)); + callee_args.push(vmctx); + + let params = self.types[self.signature] + .unwrap_func() + .params() + .iter() + .map(|&v| { + Some(match v { + WasmValType::I32 => FlatType::I32, + WasmValType::I64 => FlatType::I64, + WasmValType::F32 => FlatType::F32, + WasmValType::F64 => FlatType::F64, + _ => return None, + }) + }) + .collect::>(); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + callee_args.push( + self.builder.ins().iconst( + ir::types::I32, + i64::from( + params + .and_then(|params| { + self.types + .get_task_return_type(&TypeTaskReturn { params }) + .map(|v| v.as_u32()) + }) + .unwrap_or(u32::MAX), + ), + ), + ); + + // storage: *mut ValRaw + host_sig.params.push(ir::AbiParam::new(pointer_type)); + callee_args.push(values_vec_ptr); + + // storage_len: usize + host_sig.params.push(ir::AbiParam::new(pointer_type)); + callee_args.push(values_vec_len); + + host_sig.returns.push(ir::AbiParam::new(ir::types::I8)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.task_return()).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &callee_args); + + let succeeded = self.builder.func.dfg.inst_results(call)[0]; + self.raise_if_host_trapped(succeeded); + self.builder.ins().return_(&[]); + } + + fn translate_async_enter_or_exit( + &mut self, + offset: u32, + callback: Option>, + params: Vec, + result: ir::types::Type, + ) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + + let mut callee_args = Vec::new(); + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + + // vmctx: *mut VMComponentContext + host_sig.params.push(ir::AbiParam::new(pointer_type)); + callee_args.push(vmctx); + + if let Some(callback) = callback { + // callback: *mut VMFuncRef + host_sig.params.push(ir::AbiParam::new(pointer_type)); + if let Some(callback) = callback { + callee_args.push(self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.runtime_callback(callback)).unwrap(), + )); + } else { + callee_args.push(self.builder.ins().iconst(pointer_type, 0)); + } + } + + // remaining parameters + host_sig.params.extend(params); + callee_args.extend(args[2..].iter().copied()); + + host_sig.returns.push(ir::AbiParam::new(result)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(offset).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &callee_args); + + if result == ir::types::I64 { + let result = self.builder.func.dfg.inst_results(call)[0]; + let result = self.raise_if_i32_trapped(result); + self.abi_store_results(&[result]); + } else { + assert!(result == ir::types::I8); + let succeeded = self.builder.func.dfg.inst_results(call)[0]; + self.raise_if_host_trapped(succeeded); + self.builder.ins().return_(&[]); } } @@ -157,10 +581,14 @@ impl<'a> TrampolineCompiler<'a> { instance, memory, realloc, + callback, post_return, string_encoding, + async_, } = *options; + assert!(callback.is_none()); + // vmctx: *mut VMComponentContext host_sig.params.push(ir::AbiParam::new(pointer_type)); callee_args.push(vmctx); @@ -182,6 +610,14 @@ impl<'a> TrampolineCompiler<'a> { .iconst(ir::types::I32, i64::from(lower_ty.as_u32())), ); + // caller_instance: RuntimeComponentInstanceIndex + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + callee_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(instance.as_u32())), + ); + // flags: *mut VMGlobalDefinition host_sig.params.push(ir::AbiParam::new(pointer_type)); callee_args.push( @@ -227,6 +663,14 @@ impl<'a> TrampolineCompiler<'a> { .iconst(ir::types::I8, i64::from(string_encoding as u8)), ); + // async_: bool + host_sig.params.push(ir::AbiParam::new(ir::types::I8)); + callee_args.push( + self.builder + .ins() + .iconst(ir::types::I8, if async_ { 1 } else { 0 }), + ); + // storage: *mut ValRaw host_sig.params.push(ir::AbiParam::new(pointer_type)); callee_args.push(values_vec_ptr); @@ -330,7 +774,7 @@ impl<'a> TrampolineCompiler<'a> { ); let call = self.call_libcall(vmctx, host::resource_new32, &host_args); let result = self.builder.func.dfg.inst_results(call)[0]; - let result = self.raise_if_resource_trapped(result); + let result = self.raise_if_i32_trapped(result); self.abi_store_results(&[result]); } @@ -359,7 +803,7 @@ impl<'a> TrampolineCompiler<'a> { ); let call = self.call_libcall(vmctx, host::resource_rep32, &host_args); let result = self.builder.func.dfg.inst_results(call)[0]; - let result = self.raise_if_resource_trapped(result); + let result = self.raise_if_i32_trapped(result); self.abi_store_results(&[result]); } @@ -550,7 +994,7 @@ impl<'a> TrampolineCompiler<'a> { /// /// Only intended for simple trampolines and effectively acts as a bridge /// from the wasm abi to host. - fn translate_resource_libcall( + fn translate_host_libcall( &mut self, get_libcall: fn( &dyn TargetIsa, @@ -580,6 +1024,612 @@ impl<'a> TrampolineCompiler<'a> { self.builder.ins().return_(&results); } + fn translate_cancel_call(&mut self, ty: u32, async_: bool, offset: u32) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push(self.builder.ins().iconst(ir::types::I32, i64::from(ty))); + + // async_: bool + host_sig.params.push(ir::AbiParam::new(ir::types::I8)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I8, if async_ { 1 } else { 0 }), + ); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(offset).unwrap(), + ); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.extend(args[2..].iter().copied()); + + host_sig.returns.push(ir::AbiParam::new(ir::types::I64)); + + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + let result = self.builder.func.dfg.inst_results(call)[0]; + let result = self.raise_if_i32_trapped(result); + self.abi_store_results(&[result]); + } + + fn translate_future_or_stream_call( + &mut self, + ty: u32, + options: Option<&CanonicalOptions>, + offset: u32, + params: Vec, + result: ir::types::Type, + ) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + if let Some(options) = options { + // memory: *mut VMMemoryDefinition + host_sig.params.push(ir::AbiParam::new(pointer_type)); + host_args.push(self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.runtime_memory(options.memory.unwrap())).unwrap(), + )); + + // realloc: *mut VMFuncRef + host_sig.params.push(ir::AbiParam::new(pointer_type)); + host_args.push(match options.realloc { + Some(idx) => self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.runtime_realloc(idx)).unwrap(), + ), + None => self.builder.ins().iconst(pointer_type, 0), + }); + + // string_encoding: StringEncoding + host_sig.params.push(ir::AbiParam::new(ir::types::I8)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I8, i64::from(options.string_encoding as u8)), + ); + } + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push(self.builder.ins().iconst(ir::types::I32, i64::from(ty))); + + host_sig.params.extend(params); + host_args.extend(args[2..].iter().copied()); + + host_sig.returns.push(ir::AbiParam::new(result)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(offset).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + if result == ir::types::I64 { + let result = self.builder.func.dfg.inst_results(call)[0]; + let result = self.raise_if_i32_trapped(result); + self.abi_store_results(&[result]); + } else { + assert!(result == ir::types::I8); + let succeeded = self.builder.func.dfg.inst_results(call)[0]; + self.raise_if_host_trapped(succeeded); + self.builder.ins().return_(&[]); + } + } + + fn translate_flat_stream_call( + &mut self, + ty: TypeStreamTableIndex, + options: &CanonicalOptions, + offset: u32, + info: &CanonicalAbiInfo, + ) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + // memory: *mut VMMemoryDefinition + host_sig.params.push(ir::AbiParam::new(pointer_type)); + host_args.push(self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.runtime_memory(options.memory.unwrap())).unwrap(), + )); + + // realloc: *mut VMFuncRef + host_sig.params.push(ir::AbiParam::new(pointer_type)); + host_args.push(match options.realloc { + Some(idx) => self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.runtime_realloc(idx)).unwrap(), + ), + None => self.builder.ins().iconst(pointer_type, 0), + }); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(ty.as_u32())), + ); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(info.size32)), + ); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(info.align32)), + ); + + host_sig.params.extend(vec![ + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ]); + host_args.extend(args[2..].iter().copied()); + + host_sig + .returns + .extend(vec![ir::AbiParam::new(ir::types::I64)]); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(offset).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + let result = self.builder.func.dfg.inst_results(call)[0]; + let result = self.raise_if_i32_trapped(result); + self.abi_store_results(&[result]); + } + + fn translate_error_context_call( + &mut self, + ty: TypeErrorContextTableIndex, + options: &CanonicalOptions, + offset: u32, + params: Vec, + result: ir::types::Type, + ) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + // memory: *mut VMMemoryDefinition + host_sig.params.push(ir::AbiParam::new(pointer_type)); + host_args.push(self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.runtime_memory(options.memory.unwrap())).unwrap(), + )); + + // realloc: *mut VMFuncRef + host_sig.params.push(ir::AbiParam::new(pointer_type)); + host_args.push(match options.realloc { + Some(idx) => self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.runtime_realloc(idx)).unwrap(), + ), + None => self.builder.ins().iconst(pointer_type, 0), + }); + + // string_encoding: StringEncoding + host_sig.params.push(ir::AbiParam::new(ir::types::I8)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I8, i64::from(options.string_encoding as u8)), + ); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(ty.as_u32())), + ); + + host_sig.params.extend(params); + host_args.extend(args[2..].iter().copied()); + + host_sig.returns.push(ir::AbiParam::new(result)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(offset).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + if result == ir::types::I64 { + let result = self.builder.func.dfg.inst_results(call)[0]; + let result = self.raise_if_i32_trapped(result); + self.abi_store_results(&[result]); + } else { + assert!(result == ir::types::I8); + let succeeded = self.builder.func.dfg.inst_results(call)[0]; + self.raise_if_host_trapped(succeeded); + self.builder.ins().return_(&[]); + } + } + + fn translate_error_context_drop_call(&mut self, ty: TypeErrorContextTableIndex) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(ty.as_u32())), + ); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.extend(args[2..].iter().copied()); + + host_sig.returns.push(ir::AbiParam::new(ir::types::I8)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let offset = self.offsets.error_context_drop(); + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(offset).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + let succeeded = self.builder.func.dfg.inst_results(call)[0]; + self.raise_if_host_trapped(succeeded); + self.builder.ins().return_(&[]); + } + + fn translate_task_backpressure_call(&mut self, caller_instance: RuntimeComponentInstanceIndex) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(caller_instance.as_u32())), + ); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.extend(args[2..].iter().copied()); + + host_sig.returns.push(ir::AbiParam::new(ir::types::I8)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.task_backpressure()).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + let succeeded = self.builder.func.dfg.inst_results(call)[0]; + self.raise_if_host_trapped(succeeded); + self.builder.ins().return_(&[]); + } + + fn translate_subtask_drop_call(&mut self, caller_instance: RuntimeComponentInstanceIndex) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(caller_instance.as_u32())), + ); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.extend(args[2..].iter().copied()); + + host_sig.returns.push(ir::AbiParam::new(ir::types::I8)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.subtask_drop()).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + let succeeded = self.builder.func.dfg.inst_results(call)[0]; + self.raise_if_host_trapped(succeeded); + self.builder.ins().return_(&[]); + } + + fn translate_task_wait_or_poll_call( + &mut self, + caller_instance: RuntimeComponentInstanceIndex, + async_: bool, + memory: RuntimeMemoryIndex, + offset: u32, + ) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I32, i64::from(caller_instance.as_u32())), + ); + + host_sig.params.push(ir::AbiParam::new(ir::types::I8)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I8, if async_ { 1 } else { 0 }), + ); + + // memory: *mut VMMemoryDefinition + host_sig.params.push(ir::AbiParam::new(pointer_type)); + host_args.push(self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.runtime_memory(memory)).unwrap(), + )); + + host_sig.params.push(ir::AbiParam::new(ir::types::I32)); + host_args.extend(args[2..].iter().copied()); + + host_sig.returns.push(ir::AbiParam::new(ir::types::I64)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(offset).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + let result = self.builder.func.dfg.inst_results(call)[0]; + let result = self.raise_if_i32_trapped(result); + self.abi_store_results(&[result]); + } + + fn translate_task_yield_call(&mut self, async_: bool) { + match self.abi { + Abi::Wasm => {} + + // These trampolines can only actually be called by Wasm, so + // let's assert that here. + Abi::Array => { + self.builder.ins().trap(TRAP_INTERNAL_ASSERT); + return; + } + } + + let pointer_type = self.isa.pointer_type(); + let args = self.builder.func.dfg.block_params(self.block0).to_vec(); + let vmctx = args[0]; + let mut host_args = vec![vmctx]; + let mut host_sig = ir::Signature::new(CallConv::triple_default(self.isa.triple())); + host_sig.params.push(ir::AbiParam::new(pointer_type)); + + host_sig.params.push(ir::AbiParam::new(ir::types::I8)); + host_args.push( + self.builder + .ins() + .iconst(ir::types::I8, if async_ { 1 } else { 0 }), + ); + + host_sig.returns.push(ir::AbiParam::new(ir::types::I8)); + + // Load host function pointer from the vmcontext and then call that + // indirect function pointer with the list of arguments. + let host_fn = self.builder.ins().load( + pointer_type, + MemFlags::trusted(), + vmctx, + i32::try_from(self.offsets.task_yield()).unwrap(), + ); + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + let succeeded = self.builder.func.dfg.inst_results(call)[0]; + self.raise_if_host_trapped(succeeded); + self.builder.ins().return_(&[]); + } + /// Loads a host function pointer for a libcall stored at the `offset` /// provided in the libcalls array. /// @@ -672,7 +1722,7 @@ impl<'a> TrampolineCompiler<'a> { self.raise_if_host_trapped(succeeded); } - fn raise_if_resource_trapped(&mut self, ret: ir::Value) -> ir::Value { + fn raise_if_i32_trapped(&mut self, ret: ir::Value) -> ir::Value { let minus_one = self.builder.ins().iconst(ir::types::I64, -1); let succeeded = self.builder.ins().icmp(IntCC::NotEqual, ret, minus_one); self.raise_if_host_trapped(succeeded); diff --git a/crates/environ/examples/factc.rs b/crates/environ/examples/factc.rs index 2c692a926465..d1f94586f4fe 100644 --- a/crates/environ/examples/factc.rs +++ b/crates/environ/examples/factc.rs @@ -147,6 +147,8 @@ impl Factc { realloc: Some(dummy_def()), // Lowering never allows `post-return` post_return: None, + async_: false, + callback: None, }, lift_options: AdapterOptions { instance: RuntimeComponentInstanceIndex::from_u32(1), @@ -159,6 +161,8 @@ impl Factc { } else { None }, + async_: false, + callback: None, }, func: dummy_def(), }); diff --git a/crates/environ/src/component.rs b/crates/environ/src/component.rs index b3899b4caa03..6988e4db7431 100644 --- a/crates/environ/src/component.rs +++ b/crates/environ/src/component.rs @@ -83,6 +83,10 @@ macro_rules! foreach_builtin_component_function { resource_enter_call(vmctx: vmctx); resource_exit_call(vmctx: vmctx) -> bool; + future_transfer(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64; + stream_transfer(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64; + error_context_transfer(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64; + trap(vmctx: vmctx, code: u8); utf8_to_utf8(src: ptr_u8, len: size, dst: ptr_u8) -> bool; diff --git a/crates/environ/src/component/dfg.rs b/crates/environ/src/component/dfg.rs index be5bc41f2052..d4b714ed7778 100644 --- a/crates/environ/src/component/dfg.rs +++ b/crates/environ/src/component/dfg.rs @@ -57,6 +57,9 @@ pub struct ComponentDfg { /// used by the host) pub reallocs: Intern, + /// Same as `reallocs`, but for async-lifted functions. + pub callbacks: Intern, + /// Same as `reallocs`, but for post-return. pub post_returns: Intern, @@ -103,7 +106,7 @@ pub struct ComponentDfg { /// The values here are the module that the adapter is present within along /// as the core wasm index of the export corresponding to the lowered /// version of the adapter. - pub adapter_paritionings: PrimaryMap, + pub adapter_partitionings: PrimaryMap, /// Defined resources in this component sorted by index with metadata about /// each resource. @@ -122,6 +125,16 @@ pub struct ComponentDfg { /// this component. pub num_resource_tables: usize, + /// The total number of future tables that will be used by this component. + pub num_future_tables: usize, + + /// The total number of stream tables that will be used by this component. + pub num_stream_tables: usize, + + /// The total number of error-context tables that will be used by this + /// component. + pub num_error_context_tables: usize, + /// An ordered list of side effects induced by instantiating this component. /// /// Currently all side effects are either instantiating core wasm modules or @@ -163,6 +176,7 @@ id! { pub struct InstanceId(u32); pub struct MemoryId(u32); pub struct ReallocId(u32); + pub struct CallbackId(u32); pub struct AdapterId(u32); pub struct PostReturnId(u32); pub struct AdapterModuleId(u32); @@ -211,7 +225,7 @@ pub enum CoreDef { /// This is a special variant not present in `info::CoreDef` which /// represents that this definition refers to a fused adapter function. This /// adapter is fully processed after the initial translation and - /// identificatino of adapters. + /// identification of adapters. /// /// During translation into `info::CoreDef` this variant is erased and /// replaced by `info::CoreDef::Export` since adapters are always @@ -269,10 +283,110 @@ pub enum Trampoline { ResourceNew(TypeResourceTableIndex), ResourceRep(TypeResourceTableIndex), ResourceDrop(TypeResourceTableIndex), + TaskBackpressure { + instance: RuntimeComponentInstanceIndex, + }, + TaskReturn, + TaskWait { + instance: RuntimeComponentInstanceIndex, + async_: bool, + memory: MemoryId, + }, + TaskPoll { + instance: RuntimeComponentInstanceIndex, + async_: bool, + memory: MemoryId, + }, + TaskYield { + async_: bool, + }, + SubtaskDrop { + instance: RuntimeComponentInstanceIndex, + }, + StreamNew { + ty: TypeStreamTableIndex, + }, + StreamRead { + ty: TypeStreamTableIndex, + options: CanonicalOptions, + }, + StreamWrite { + ty: TypeStreamTableIndex, + options: CanonicalOptions, + }, + StreamCancelRead { + ty: TypeStreamTableIndex, + async_: bool, + }, + StreamCancelWrite { + ty: TypeStreamTableIndex, + async_: bool, + }, + StreamCloseReadable { + ty: TypeStreamTableIndex, + }, + StreamCloseWritable { + ty: TypeStreamTableIndex, + }, + FutureNew { + ty: TypeFutureTableIndex, + }, + FutureRead { + ty: TypeFutureTableIndex, + options: CanonicalOptions, + }, + FutureWrite { + ty: TypeFutureTableIndex, + options: CanonicalOptions, + }, + FutureCancelRead { + ty: TypeFutureTableIndex, + async_: bool, + }, + FutureCancelWrite { + ty: TypeFutureTableIndex, + async_: bool, + }, + FutureCloseReadable { + ty: TypeFutureTableIndex, + }, + FutureCloseWritable { + ty: TypeFutureTableIndex, + }, + ErrorContextNew { + ty: TypeErrorContextTableIndex, + options: CanonicalOptions, + }, + ErrorContextDebugMessage { + ty: TypeErrorContextTableIndex, + options: CanonicalOptions, + }, + ErrorContextDrop { + ty: TypeErrorContextTableIndex, + }, ResourceTransferOwn, ResourceTransferBorrow, ResourceEnterCall, ResourceExitCall, + AsyncEnterCall, + AsyncExitCall(Option), + FutureTransfer, + StreamTransfer, + ErrorContextTransfer, +} + +#[derive(Copy, Clone, Hash, Eq, PartialEq)] +#[allow(missing_docs, reason = "self-describing fields")] +pub struct FutureInfo { + pub instance: RuntimeComponentInstanceIndex, + pub payload_type: Option, +} + +#[derive(Copy, Clone, Hash, Eq, PartialEq)] +#[allow(missing_docs, reason = "self-describing fields")] +pub struct StreamInfo { + pub instance: RuntimeComponentInstanceIndex, + pub payload_type: InterfaceType, } /// Same as `info::CanonicalOptions` @@ -283,7 +397,9 @@ pub struct CanonicalOptions { pub string_encoding: StringEncoding, pub memory: Option, pub realloc: Option, + pub callback: Option, pub post_return: Option, + pub async_: bool, } /// Same as `info::Resource` @@ -348,7 +464,7 @@ impl Default for Intern { impl ComponentDfg { /// Consumes the intermediate `ComponentDfg` to produce a final `Component` - /// with a linear innitializer list. + /// with a linear initializer list. pub fn finish( self, wasmtime_types: &mut ComponentTypesBuilder, @@ -360,6 +476,7 @@ impl ComponentDfg { runtime_memories: Default::default(), runtime_post_return: Default::default(), runtime_reallocs: Default::default(), + runtime_callbacks: Default::default(), runtime_instances: Default::default(), num_lowerings: 0, trampolines: Default::default(), @@ -400,11 +517,15 @@ impl ComponentDfg { num_runtime_memories: linearize.runtime_memories.len() as u32, num_runtime_post_returns: linearize.runtime_post_return.len() as u32, num_runtime_reallocs: linearize.runtime_reallocs.len() as u32, + num_runtime_callbacks: linearize.runtime_callbacks.len() as u32, num_runtime_instances: linearize.runtime_instances.len() as u32, imports: self.imports, import_types: self.import_types, num_runtime_component_instances: self.num_runtime_component_instances, num_resource_tables: self.num_resource_tables, + num_future_tables: self.num_future_tables, + num_stream_tables: self.num_stream_tables, + num_error_context_tables: self.num_error_context_tables, num_resources: (self.resources.len() + self.imported_resources.len()) as u32, imported_resources: self.imported_resources, defined_resource_instances: self @@ -431,6 +552,7 @@ struct LinearizeDfg<'a> { trampoline_map: HashMap, runtime_memories: HashMap, runtime_reallocs: HashMap, + runtime_callbacks: HashMap, runtime_post_return: HashMap, runtime_instances: HashMap, num_lowerings: u32, @@ -539,13 +661,16 @@ impl LinearizeDfg<'_> { fn options(&mut self, options: &CanonicalOptions) -> info::CanonicalOptions { let memory = options.memory.map(|mem| self.runtime_memory(mem)); let realloc = options.realloc.map(|mem| self.runtime_realloc(mem)); + let callback = options.callback.map(|mem| self.runtime_callback(mem)); let post_return = options.post_return.map(|mem| self.runtime_post_return(mem)); info::CanonicalOptions { instance: options.instance, string_encoding: options.string_encoding, memory, realloc, + callback, post_return, + async_: options.async_, } } @@ -567,6 +692,15 @@ impl LinearizeDfg<'_> { ) } + fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex { + self.intern( + callback, + |me| &mut me.runtime_callbacks, + |me, callback| me.core_def(&me.dfg.callbacks[callback]), + |index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }), + ) + } + fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex { self.intern( post_return, @@ -625,10 +759,100 @@ impl LinearizeDfg<'_> { Trampoline::ResourceNew(ty) => info::Trampoline::ResourceNew(*ty), Trampoline::ResourceDrop(ty) => info::Trampoline::ResourceDrop(*ty), Trampoline::ResourceRep(ty) => info::Trampoline::ResourceRep(*ty), + Trampoline::TaskBackpressure { instance } => info::Trampoline::TaskBackpressure { + instance: *instance, + }, + Trampoline::TaskReturn => info::Trampoline::TaskReturn, + Trampoline::TaskWait { + instance, + async_, + memory, + } => info::Trampoline::TaskWait { + instance: *instance, + async_: *async_, + memory: self.runtime_memory(*memory), + }, + Trampoline::TaskPoll { + instance, + async_, + memory, + } => info::Trampoline::TaskPoll { + instance: *instance, + async_: *async_, + memory: self.runtime_memory(*memory), + }, + Trampoline::TaskYield { async_ } => info::Trampoline::TaskYield { async_: *async_ }, + Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop { + instance: *instance, + }, + Trampoline::StreamNew { ty } => info::Trampoline::StreamNew { ty: *ty }, + Trampoline::StreamRead { ty, options } => info::Trampoline::StreamRead { + ty: *ty, + options: self.options(options), + }, + Trampoline::StreamWrite { ty, options } => info::Trampoline::StreamWrite { + ty: *ty, + options: self.options(options), + }, + Trampoline::StreamCancelRead { ty, async_ } => info::Trampoline::StreamCancelRead { + ty: *ty, + async_: *async_, + }, + Trampoline::StreamCancelWrite { ty, async_ } => info::Trampoline::StreamCancelWrite { + ty: *ty, + async_: *async_, + }, + Trampoline::StreamCloseReadable { ty } => { + info::Trampoline::StreamCloseReadable { ty: *ty } + } + Trampoline::StreamCloseWritable { ty } => { + info::Trampoline::StreamCloseWritable { ty: *ty } + } + Trampoline::FutureNew { ty } => info::Trampoline::FutureNew { ty: *ty }, + Trampoline::FutureRead { ty, options } => info::Trampoline::FutureRead { + ty: *ty, + options: self.options(options), + }, + Trampoline::FutureWrite { ty, options } => info::Trampoline::FutureWrite { + ty: *ty, + options: self.options(options), + }, + Trampoline::FutureCancelRead { ty, async_ } => info::Trampoline::FutureCancelRead { + ty: *ty, + async_: *async_, + }, + Trampoline::FutureCancelWrite { ty, async_ } => info::Trampoline::FutureCancelWrite { + ty: *ty, + async_: *async_, + }, + Trampoline::FutureCloseReadable { ty } => { + info::Trampoline::FutureCloseReadable { ty: *ty } + } + Trampoline::FutureCloseWritable { ty } => { + info::Trampoline::FutureCloseWritable { ty: *ty } + } + Trampoline::ErrorContextNew { ty, options } => info::Trampoline::ErrorContextNew { + ty: *ty, + options: self.options(options), + }, + Trampoline::ErrorContextDebugMessage { ty, options } => { + info::Trampoline::ErrorContextDebugMessage { + ty: *ty, + options: self.options(options), + } + } + Trampoline::ErrorContextDrop { ty } => info::Trampoline::ErrorContextDrop { ty: *ty }, Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn, Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow, Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall, Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall, + Trampoline::AsyncEnterCall => info::Trampoline::AsyncEnterCall, + Trampoline::AsyncExitCall(callback) => { + info::Trampoline::AsyncExitCall(callback.map(|v| self.runtime_callback(v))) + } + Trampoline::FutureTransfer => info::Trampoline::FutureTransfer, + Trampoline::StreamTransfer => info::Trampoline::StreamTransfer, + Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer, }; let i1 = self.trampolines.push(*signature); let i2 = self.trampoline_defs.push(trampoline); @@ -650,7 +874,7 @@ impl LinearizeDfg<'_> { } fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport { - let (adapter_module, entity_index) = self.dfg.adapter_paritionings[adapter]; + let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter]; // Instantiates the adapter module if it hasn't already been // instantiated or otherwise returns the index that the module was diff --git a/crates/environ/src/component/info.rs b/crates/environ/src/component/info.rs index 8c5442a6d243..afb5f6098275 100644 --- a/crates/environ/src/component/info.rs +++ b/crates/environ/src/component/info.rs @@ -148,6 +148,10 @@ pub struct Component { /// `VMComponentContext`. pub num_runtime_reallocs: u32, + /// The number of runtime async callbacks (maximum `RuntimeCallbackIndex`) + /// needed to instantiate this component. + pub num_runtime_callbacks: u32, + /// Same as `num_runtime_reallocs`, but for post-return functions. pub num_runtime_post_returns: u32, @@ -158,7 +162,7 @@ pub struct Component { /// instantiate this component. pub num_lowerings: u32, - /// Maximal number of tables that required at runtime for resource-related + /// Maximal number of tables required at runtime for resource-related /// information in this component. pub num_resource_tables: usize, @@ -166,6 +170,18 @@ pub struct Component { /// component. pub num_resources: u32, + /// Maximal number of tables required at runtime for future-related + /// information in this component. + pub num_future_tables: usize, + + /// Maximal number of tables required at runtime for stream-related + /// information in this component. + pub num_stream_tables: usize, + + /// Maximal number of tables required at runtime for error-context-related + /// information in this component. + pub num_error_context_tables: usize, + /// Metadata about imported resources and where they are within the runtime /// imports array. /// @@ -252,6 +268,10 @@ pub enum GlobalInitializer { /// used as a `realloc` function. ExtractRealloc(ExtractRealloc), + /// Same as `ExtractMemory`, except it's extracting a function pointer to be + /// used as an async `callback` function. + ExtractCallback(ExtractCallback), + /// Same as `ExtractMemory`, except it's extracting a function pointer to be /// used as a `post-return` function. ExtractPostReturn(ExtractPostReturn), @@ -281,6 +301,15 @@ pub struct ExtractRealloc { pub def: CoreDef, } +/// Same as `ExtractMemory` but for the `callback` canonical option. +#[derive(Debug, Serialize, Deserialize)] +pub struct ExtractCallback { + /// The index of the callback being defined. + pub index: RuntimeCallbackIndex, + /// Where this callback is being extracted from. + pub def: CoreDef, +} + /// Same as `ExtractMemory` but for the `post-return` canonical option. #[derive(Debug, Serialize, Deserialize)] pub struct ExtractPostReturn { @@ -447,8 +476,14 @@ pub struct CanonicalOptions { /// The realloc function used by these options, if specified. pub realloc: Option, + /// The async callback function used by these options, if specified. + pub callback: Option, + /// The post-return function used by these options, if specified. pub post_return: Option, + + /// Whether to use the async ABI for lifting or lowering. + pub async_: bool, } /// Possible encodings of strings within the component model. @@ -644,6 +679,199 @@ pub enum Trampoline { /// Same as `ResourceNew`, but for the `resource.drop` intrinsic. ResourceDrop(TypeResourceTableIndex), + /// A `task.backpressure` intrinsic, which tells the host to enable or + /// disable backpressure for the caller's instance. + TaskBackpressure { + /// The specific component instance which is calling the intrinsic. + instance: RuntimeComponentInstanceIndex, + }, + + /// A `task.return` intrinsic, which returns a result to the caller of a + /// lifted export function. This allows the callee to continue executing + /// after returning a result. + TaskReturn, + + /// A `task.wait` intrinsic, which waits for at least one outstanding async + /// task/stream/future to make progress, returning the first such event. + TaskWait { + /// The specific component instance which is calling the intrinsic. + instance: RuntimeComponentInstanceIndex, + /// If `true`, indicates the caller instance maybe reentered. + async_: bool, + /// Memory to use when storing the event. + memory: RuntimeMemoryIndex, + }, + + /// A `task.poll` intrinsic, which checks whether any outstanding async + /// task/stream/future has made progress. Unlike `task.wait`, this does not + /// block and may return nothing if no such event has occurred. + TaskPoll { + /// The specific component instance which is calling the intrinsic. + instance: RuntimeComponentInstanceIndex, + /// If `true`, indicates the caller instance maybe reentered. + async_: bool, + /// Memory to use when storing the event. + memory: RuntimeMemoryIndex, + }, + + /// A `task.yield` intrinsic, which yields control to the host so that other + /// tasks are able to make progress, if any. + TaskYield { + /// If `true`, indicates the caller instance maybe reentered. + async_: bool, + }, + + /// A `subtask.drop` intrinsic to drop a specified task which has completed. + SubtaskDrop { + /// The specific component instance which is calling the intrinsic. + instance: RuntimeComponentInstanceIndex, + }, + + /// A `stream.new` intrinsic to create a new `stream` handle of the + /// specified type. + StreamNew { + /// The table index for the specific `stream` type and caller instance. + ty: TypeStreamTableIndex, + }, + + /// A `stream.read` intrinsic to read from a `stream` of the specified type. + StreamRead { + /// The table index for the specific `stream` type and caller instance. + ty: TypeStreamTableIndex, + /// Any options (e.g. string encoding) to use when storing values to + /// memory. + options: CanonicalOptions, + }, + + /// A `stream.write` intrinsic to write to a `stream` of the specified type. + StreamWrite { + /// The table index for the specific `stream` type and caller instance. + ty: TypeStreamTableIndex, + /// Any options (e.g. string encoding) to use when storing values to + /// memory. + options: CanonicalOptions, + }, + + /// A `stream.cancel-read` intrinsic to cancel an in-progress read from a + /// `stream` of the specified type. + StreamCancelRead { + /// The table index for the specific `stream` type and caller instance. + ty: TypeStreamTableIndex, + /// If `false`, block until cancellation completes rather than return + /// `BLOCKED`. + async_: bool, + }, + + /// A `stream.cancel-write` intrinsic to cancel an in-progress write from a + /// `stream` of the specified type. + StreamCancelWrite { + /// The table index for the specific `stream` type and caller instance. + ty: TypeStreamTableIndex, + /// If `false`, block until cancellation completes rather than return + /// `BLOCKED`. + async_: bool, + }, + + /// A `stream.close-readable` intrinsic to close the readable end of a + /// `stream` of the specified type. + StreamCloseReadable { + /// The table index for the specific `stream` type and caller instance. + ty: TypeStreamTableIndex, + }, + + /// A `stream.close-writable` intrinsic to close the writable end of a + /// `stream` of the specified type. + StreamCloseWritable { + /// The table index for the specific `stream` type and caller instance. + ty: TypeStreamTableIndex, + }, + + /// A `future.new` intrinsic to create a new `future` handle of the + /// specified type. + FutureNew { + /// The table index for the specific `future` type and caller instance. + ty: TypeFutureTableIndex, + }, + + /// A `future.read` intrinsic to read from a `future` of the specified type. + FutureRead { + /// The table index for the specific `future` type and caller instance. + ty: TypeFutureTableIndex, + /// Any options (e.g. string encoding) to use when storing values to + /// memory. + options: CanonicalOptions, + }, + + /// A `future.write` intrinsic to write to a `future` of the specified type. + FutureWrite { + /// The table index for the specific `future` type and caller instance. + ty: TypeFutureTableIndex, + /// Any options (e.g. string encoding) to use when storing values to + /// memory. + options: CanonicalOptions, + }, + + /// A `future.cancel-read` intrinsic to cancel an in-progress read from a + /// `future` of the specified type. + FutureCancelRead { + /// The table index for the specific `future` type and caller instance. + ty: TypeFutureTableIndex, + /// If `false`, block until cancellation completes rather than return + /// `BLOCKED`. + async_: bool, + }, + + /// A `future.cancel-write` intrinsic to cancel an in-progress write from a + /// `future` of the specified type. + FutureCancelWrite { + /// The table index for the specific `future` type and caller instance. + ty: TypeFutureTableIndex, + /// If `false`, block until cancellation completes rather than return + /// `BLOCKED`. + async_: bool, + }, + + /// A `future.close-readable` intrinsic to close the readable end of a + /// `future` of the specified type. + FutureCloseReadable { + /// The table index for the specific `future` type and caller instance. + ty: TypeFutureTableIndex, + }, + + /// A `future.close-writable` intrinsic to close the writable end of a + /// `future` of the specified type. + FutureCloseWritable { + /// The table index for the specific `future` type and caller instance. + ty: TypeFutureTableIndex, + }, + + /// A `error-context.new` intrinsic to create a new `error-context` with a + /// specified debug message. + ErrorContextNew { + /// The table index for the `error-context` type in the caller instance. + ty: TypeErrorContextTableIndex, + /// String encoding, memory, etc. to use when loading debug message. + options: CanonicalOptions, + }, + + /// A `error-context.debug-message` intrinsic to get the debug message for a + /// specified `error-context`. + /// + /// Note that the debug message might not necessarily match what was passed + /// to `error.new`. + ErrorContextDebugMessage { + /// The table index for the `error-context` type in the caller instance. + ty: TypeErrorContextTableIndex, + /// String encoding, memory, etc. to use when storing debug message. + options: CanonicalOptions, + }, + + /// A `error-context.drop` intrinsic to drop a specified `error-context`. + ErrorContextDrop { + /// The table index for the `error-context` type in the caller instance. + ty: TypeErrorContextTableIndex, + }, + /// An intrinsic used by FACT-generated modules which will transfer an owned /// resource from one table to another. Used in component-to-component /// adapter trampolines. @@ -661,6 +889,43 @@ pub enum Trampoline { /// Same as `ResourceEnterCall` except for when exiting a call. ResourceExitCall, + + /// An intrinsic used by FACT-generated modules to begin a call to an + /// async-lowered import function. + AsyncEnterCall, + + /// An intrinsic used by FACT-generated modules to complete a call to an + /// async-lowered import function. + /// + /// Note that `AsyncEnterCall` and `AsyncExitCall` could theoretically be + /// combined into a single `AsyncCall` intrinsic, but we separate them to + /// allow the FACT-generated module to optionally call the callee directly + /// without an intermediate host stack frame. + AsyncExitCall(Option), + + /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer + /// ownership of a `future`. + /// + /// Transfering a `future` can either mean giving away the readable end + /// while retaining the writable end or only the former, depending on the + /// ownership status of the `future`. + FutureTransfer, + + /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer + /// ownership of a `stream`. + /// + /// Transfering a `stream` can either mean giving away the readable end + /// while retaining the writable end or only the former, depending on the + /// ownership status of the `stream`. + StreamTransfer, + + /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer + /// ownership of an `error-context`. + /// + /// Unlike futures, streams, and resource handles, `error-context` handles + /// are reference counted, meaning that sharing the handle with another + /// component does not invalidate the handle in the original component. + ErrorContextTransfer, } impl Trampoline { @@ -684,10 +949,38 @@ impl Trampoline { ResourceNew(i) => format!("component-resource-new[{}]", i.as_u32()), ResourceRep(i) => format!("component-resource-rep[{}]", i.as_u32()), ResourceDrop(i) => format!("component-resource-drop[{}]", i.as_u32()), + TaskBackpressure { .. } => format!("task-backpressure"), + TaskReturn => format!("task-return"), + TaskWait { .. } => format!("task-wait"), + TaskPoll { .. } => format!("task-poll"), + TaskYield { .. } => format!("task-yield"), + SubtaskDrop { .. } => format!("subtask-drop"), + StreamNew { .. } => format!("stream-new"), + StreamRead { .. } => format!("stream-read"), + StreamWrite { .. } => format!("stream-write"), + StreamCancelRead { .. } => format!("stream-cancel-read"), + StreamCancelWrite { .. } => format!("stream-cancel-write"), + StreamCloseReadable { .. } => format!("stream-close-readable"), + StreamCloseWritable { .. } => format!("stream-close-writable"), + FutureNew { .. } => format!("future-new"), + FutureRead { .. } => format!("future-read"), + FutureWrite { .. } => format!("future-write"), + FutureCancelRead { .. } => format!("future-cancel-read"), + FutureCancelWrite { .. } => format!("future-cancel-write"), + FutureCloseReadable { .. } => format!("future-close-readable"), + FutureCloseWritable { .. } => format!("future-close-writable"), + ErrorContextNew { .. } => format!("error-context-new"), + ErrorContextDebugMessage { .. } => format!("error-context-debug-message"), + ErrorContextDrop { .. } => format!("error-context-drop"), ResourceTransferOwn => format!("component-resource-transfer-own"), ResourceTransferBorrow => format!("component-resource-transfer-borrow"), ResourceEnterCall => format!("component-resource-enter-call"), ResourceExitCall => format!("component-resource-exit-call"), + AsyncEnterCall => format!("component-async-enter-call"), + AsyncExitCall(_) => format!("component-async-exit-call"), + FutureTransfer => format!("future-transfer"), + StreamTransfer => format!("stream-transfer"), + ErrorContextTransfer => format!("error-context-transfer"), } } } diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs index 23eb2306b56b..014a1511652a 100644 --- a/crates/environ/src/component/translate.rs +++ b/crates/environ/src/component/translate.rs @@ -12,8 +12,8 @@ use indexmap::IndexMap; use std::collections::HashMap; use std::mem; use wasmparser::component_types::{ - AliasableResourceId, ComponentCoreModuleTypeId, ComponentEntityType, ComponentFuncTypeId, - ComponentInstanceTypeId, + AliasableResourceId, ComponentCoreModuleTypeId, ComponentDefinedTypeId, ComponentEntityType, + ComponentFuncTypeId, ComponentInstanceTypeId, }; use wasmparser::types::Types; use wasmparser::{Chunk, ComponentImportName, Encoding, Parser, Payload, Validator}; @@ -188,6 +188,105 @@ enum LocalInitializer<'data> { ResourceRep(AliasableResourceId, ModuleInternedTypeIndex), ResourceDrop(AliasableResourceId, ModuleInternedTypeIndex), + TaskBackpressure { + func: ModuleInternedTypeIndex, + }, + TaskReturn { + func: ModuleInternedTypeIndex, + }, + TaskWait { + func: ModuleInternedTypeIndex, + async_: bool, + memory: MemoryIndex, + }, + TaskPoll { + func: ModuleInternedTypeIndex, + async_: bool, + memory: MemoryIndex, + }, + TaskYield { + func: ModuleInternedTypeIndex, + async_: bool, + }, + SubtaskDrop { + func: ModuleInternedTypeIndex, + }, + StreamNew { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + }, + StreamRead { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + options: LocalCanonicalOptions, + }, + StreamWrite { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + options: LocalCanonicalOptions, + }, + StreamCancelRead { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + async_: bool, + }, + StreamCancelWrite { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + async_: bool, + }, + StreamCloseReadable { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + }, + StreamCloseWritable { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + }, + FutureNew { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + }, + FutureRead { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + options: LocalCanonicalOptions, + }, + FutureWrite { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + options: LocalCanonicalOptions, + }, + FutureCancelRead { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + async_: bool, + }, + FutureCancelWrite { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + async_: bool, + }, + FutureCloseReadable { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + }, + FutureCloseWritable { + ty: ComponentDefinedTypeId, + func: ModuleInternedTypeIndex, + }, + ErrorContextNew { + func: ModuleInternedTypeIndex, + options: LocalCanonicalOptions, + }, + ErrorContextDebugMessage { + func: ModuleInternedTypeIndex, + options: LocalCanonicalOptions, + }, + ErrorContextDrop { + func: ModuleInternedTypeIndex, + }, + // core wasm modules ModuleStatic(StaticModuleIndex, ComponentCoreModuleTypeId), @@ -255,6 +354,8 @@ struct LocalCanonicalOptions { memory: Option, realloc: Option, post_return: Option, + async_: bool, + callback: Option, } enum Action { @@ -471,7 +572,8 @@ impl<'a, 'data> Translator<'a, 'data> { // Entries in the canonical section will get initializers recorded // with the listed options for lifting/lowering. Payload::ComponentCanonicalSection(s) => { - let mut core_func_index = self.validator.types(0).unwrap().function_count(); + let types = self.validator.types(0).unwrap(); + let mut core_func_index = types.function_count(); self.validator.component_canonical_section(&s)?; for func in s { let types = self.validator.types(0).unwrap(); @@ -521,11 +623,153 @@ impl<'a, 'data> Translator<'a, 'data> { core_func_index += 1; LocalInitializer::ResourceRep(resource, ty) } - wasmparser::CanonicalFunction::ThreadSpawn { .. } | wasmparser::CanonicalFunction::ThreadHwConcurrency => { bail!("unsupported intrinsic") } + wasmparser::CanonicalFunction::TaskBackpressure => { + let core_type = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::TaskBackpressure { func: core_type } + } + wasmparser::CanonicalFunction::TaskReturn { .. } => { + let core_type = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::TaskReturn { func: core_type } + } + wasmparser::CanonicalFunction::TaskWait { async_, memory } => { + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::TaskWait { + func, + async_, + memory: MemoryIndex::from_u32(memory), + } + } + wasmparser::CanonicalFunction::TaskPoll { async_, memory } => { + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::TaskPoll { + func, + async_, + memory: MemoryIndex::from_u32(memory), + } + } + wasmparser::CanonicalFunction::TaskYield { async_ } => { + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::TaskYield { func, async_ } + } + wasmparser::CanonicalFunction::SubtaskDrop => { + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::SubtaskDrop { func } + } + wasmparser::CanonicalFunction::StreamNew { ty } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::StreamNew { ty, func } + } + wasmparser::CanonicalFunction::StreamRead { ty, options } => { + let ty = types.component_defined_type_at(ty); + let options = self.canonical_options(&options); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::StreamRead { ty, func, options } + } + wasmparser::CanonicalFunction::StreamWrite { ty, options } => { + let ty = types.component_defined_type_at(ty); + let options = self.canonical_options(&options); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::StreamWrite { ty, func, options } + } + wasmparser::CanonicalFunction::StreamCancelRead { ty, async_ } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::StreamCancelRead { ty, func, async_ } + } + wasmparser::CanonicalFunction::StreamCancelWrite { ty, async_ } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::StreamCancelWrite { ty, func, async_ } + } + wasmparser::CanonicalFunction::StreamCloseReadable { ty } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::StreamCloseReadable { ty, func } + } + wasmparser::CanonicalFunction::StreamCloseWritable { ty } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::StreamCloseWritable { ty, func } + } + wasmparser::CanonicalFunction::FutureNew { ty } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::FutureNew { ty, func } + } + wasmparser::CanonicalFunction::FutureRead { ty, options } => { + let ty = types.component_defined_type_at(ty); + let options = self.canonical_options(&options); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::FutureRead { ty, func, options } + } + wasmparser::CanonicalFunction::FutureWrite { ty, options } => { + let ty = types.component_defined_type_at(ty); + let options = self.canonical_options(&options); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::FutureWrite { ty, func, options } + } + wasmparser::CanonicalFunction::FutureCancelRead { ty, async_ } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::FutureCancelRead { ty, func, async_ } + } + wasmparser::CanonicalFunction::FutureCancelWrite { ty, async_ } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::FutureCancelWrite { ty, func, async_ } + } + wasmparser::CanonicalFunction::FutureCloseReadable { ty } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::FutureCloseReadable { ty, func } + } + wasmparser::CanonicalFunction::FutureCloseWritable { ty } => { + let ty = types.component_defined_type_at(ty); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::FutureCloseWritable { ty, func } + } + wasmparser::CanonicalFunction::ErrorContextNew { options } => { + let options = self.canonical_options(&options); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::ErrorContextNew { func, options } + } + wasmparser::CanonicalFunction::ErrorContextDebugMessage { options } => { + let options = self.canonical_options(&options); + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::ErrorContextDebugMessage { func, options } + } + wasmparser::CanonicalFunction::ErrorContextDrop => { + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::ErrorContextDrop { func } + } }; self.result.initializers.push(init); } @@ -896,6 +1140,8 @@ impl<'a, 'data> Translator<'a, 'data> { memory: None, realloc: None, post_return: None, + async_: false, + callback: None, }; for opt in opts { match opt { @@ -920,6 +1166,11 @@ impl<'a, 'data> Translator<'a, 'data> { let idx = FuncIndex::from_u32(*idx); ret.post_return = Some(idx); } + wasmparser::CanonicalOption::Async => ret.async_ = true, + wasmparser::CanonicalOption::Callback(idx) => { + let idx = FuncIndex::from_u32(*idx); + ret.callback = Some(idx); + } } } return ret; diff --git a/crates/environ/src/component/translate/adapt.rs b/crates/environ/src/component/translate/adapt.rs index 8989e6fce1a1..6f28c82198a5 100644 --- a/crates/environ/src/component/translate/adapt.rs +++ b/crates/environ/src/component/translate/adapt.rs @@ -157,8 +157,12 @@ pub struct AdapterOptions { pub memory64: bool, /// An optional definition of `realloc` to used. pub realloc: Option, + /// The async callback function used by these options, if specified. + pub callback: Option, /// An optional definition of a `post-return` to use. pub post_return: Option, + /// Whether to use the async ABI for lifting or lowering. + pub async_: bool, } impl<'data> Translator<'_, 'data> { @@ -192,6 +196,8 @@ impl<'data> Translator<'_, 'data> { names.push(name); } let wasm = module.encode(); + std::fs::write("/tmp/adapter.wasm", &wasm).unwrap(); + wasmparser::Validator::new().validate_all(&wasm).unwrap(); let imports = module.imports().to_vec(); // Extend the lifetime of the owned `wasm: Vec` on the stack to @@ -227,7 +233,7 @@ impl<'data> Translator<'_, 'data> { // in-order here as well. (with an assert to double-check) for (adapter, name) in adapter_module.adapters.iter().zip(&names) { let index = translation.module.exports[name]; - let i = component.adapter_paritionings.push((module_id, index)); + let i = component.adapter_partitionings.push((module_id, index)); assert_eq!(i, *adapter); } @@ -300,6 +306,15 @@ fn fact_import_to_core_def( } fact::Import::ResourceEnterCall => simple_intrinsic(dfg::Trampoline::ResourceEnterCall), fact::Import::ResourceExitCall => simple_intrinsic(dfg::Trampoline::ResourceExitCall), + fact::Import::AsyncEnterCall => simple_intrinsic(dfg::Trampoline::AsyncEnterCall), + fact::Import::AsyncExitCall(callback) => simple_intrinsic(dfg::Trampoline::AsyncExitCall( + callback.clone().map(|v| dfg.callbacks.push(v)), + )), + fact::Import::FutureTransfer => simple_intrinsic(dfg::Trampoline::FutureTransfer), + fact::Import::StreamTransfer => simple_intrinsic(dfg::Trampoline::StreamTransfer), + fact::Import::ErrorContextTransfer => { + simple_intrinsic(dfg::Trampoline::ErrorContextTransfer) + } } } @@ -363,6 +378,9 @@ impl PartitionAdapterModules { if let Some(def) = &options.realloc { self.core_def(dfg, def); } + if let Some(def) = &options.callback { + self.core_def(dfg, def); + } if let Some(def) = &options.post_return { self.core_def(dfg, def); } diff --git a/crates/environ/src/component/translate/inline.rs b/crates/environ/src/component/translate/inline.rs index 881cb7440f08..ba16cad9b70f 100644 --- a/crates/environ/src/component/translate/inline.rs +++ b/crates/environ/src/component/translate/inline.rs @@ -135,6 +135,9 @@ pub(super) fn run( } inliner.result.exports = export_map; inliner.result.num_resource_tables = types.num_resource_tables(); + inliner.result.num_future_tables = types.num_future_tables(); + inliner.result.num_stream_tables = types.num_stream_tables(); + inliner.result.num_error_context_tables = types.num_error_context_tables(); Ok(inliner.result) } @@ -667,6 +670,288 @@ impl<'a> Inliner<'a> { .push((*ty, dfg::Trampoline::ResourceDrop(id))); frame.funcs.push(dfg::CoreDef::Trampoline(index)); } + TaskBackpressure { func } => { + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::TaskBackpressure { + instance: frame.instance, + }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + TaskReturn { func } => { + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::TaskReturn)); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + TaskWait { + func, + async_, + memory, + } => { + let (memory, _) = self.memory(frame, types, *memory); + let memory = self.result.memories.push(memory); + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::TaskWait { + instance: frame.instance, + async_: *async_, + memory, + }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + TaskPoll { + func, + async_, + memory, + } => { + let (memory, _) = self.memory(frame, types, *memory); + let memory = self.result.memories.push(memory); + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::TaskPoll { + instance: frame.instance, + async_: *async_, + memory, + }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + TaskYield { func, async_ } => { + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::TaskYield { async_: *async_ })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + SubtaskDrop { func } => { + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::SubtaskDrop { + instance: frame.instance, + }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + StreamNew { ty, func } => { + let InterfaceType::Stream(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::StreamNew { ty })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + StreamRead { ty, func, options } => { + let InterfaceType::Stream(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let options = self.adapter_options(frame, types, options); + let options = self.canonical_options(options); + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::StreamRead { ty, options })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + StreamWrite { ty, func, options } => { + let InterfaceType::Stream(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let options = self.adapter_options(frame, types, options); + let options = self.canonical_options(options); + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::StreamWrite { ty, options })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + StreamCancelRead { ty, func, async_ } => { + let InterfaceType::Stream(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::StreamCancelRead { + ty, + async_: *async_, + }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + StreamCancelWrite { ty, func, async_ } => { + let InterfaceType::Stream(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::StreamCancelWrite { + ty, + async_: *async_, + }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + StreamCloseReadable { ty, func } => { + let InterfaceType::Stream(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::StreamCloseReadable { ty })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + StreamCloseWritable { ty, func } => { + let InterfaceType::Stream(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::StreamCloseWritable { ty })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + FutureNew { ty, func } => { + let InterfaceType::Future(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::FutureNew { ty })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + FutureRead { ty, func, options } => { + let InterfaceType::Future(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let options = self.adapter_options(frame, types, options); + let options = self.canonical_options(options); + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::FutureRead { ty, options })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + FutureWrite { ty, func, options } => { + let InterfaceType::Future(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let options = self.adapter_options(frame, types, options); + let options = self.canonical_options(options); + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::FutureWrite { ty, options })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + FutureCancelRead { ty, func, async_ } => { + let InterfaceType::Future(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::FutureCancelRead { + ty, + async_: *async_, + }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + FutureCancelWrite { ty, func, async_ } => { + let InterfaceType::Future(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::FutureCancelWrite { + ty, + async_: *async_, + }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + FutureCloseReadable { ty, func } => { + let InterfaceType::Future(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::FutureCloseReadable { ty })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + FutureCloseWritable { ty, func } => { + let InterfaceType::Future(ty) = + types.defined_type(frame.translation.types_ref(), *ty)? + else { + unreachable!() + }; + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::FutureCloseWritable { ty })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + ErrorContextNew { func, options } => { + let ty = types.error_context_type()?; + let options = self.adapter_options(frame, types, options); + let options = self.canonical_options(options); + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::ErrorContextNew { ty, options })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + ErrorContextDebugMessage { func, options } => { + let ty = types.error_context_type()?; + let options = self.adapter_options(frame, types, options); + let options = self.canonical_options(options); + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::ErrorContextDebugMessage { ty, options }, + )); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } + ErrorContextDrop { func } => { + let ty = types.error_context_type()?; + let index = self + .result + .trampolines + .push((*func, dfg::Trampoline::ErrorContextDrop { ty })); + frame.funcs.push(dfg::CoreDef::Trampoline(index)); + } ModuleStatic(idx, ty) => { frame.modules.push(ModuleDef::Static(*idx, *ty)); @@ -948,6 +1233,41 @@ impl<'a> Inliner<'a> { } } + fn memory( + &mut self, + frame: &InlinerFrame<'a>, + types: &ComponentTypesBuilder, + memory: MemoryIndex, + ) -> (dfg::CoreExport, bool) { + let memory = frame.memories[memory].clone().map_index(|i| match i { + EntityIndex::Memory(i) => i, + _ => unreachable!(), + }); + let memory64 = match &self.runtime_instances[memory.instance] { + InstanceModule::Static(idx) => match &memory.item { + ExportItem::Index(i) => { + let ty = &self.nested_modules[*idx].module.memories[*i]; + match ty.idx_type { + IndexType::I32 => false, + IndexType::I64 => true, + } + } + ExportItem::Name(_) => unreachable!(), + }, + InstanceModule::Import(ty) => match &memory.item { + ExportItem::Name(name) => match types[*ty].exports[name] { + EntityType::Memory(m) => match m.idx_type { + IndexType::I32 => false, + IndexType::I64 => true, + }, + _ => unreachable!(), + }, + ExportItem::Index(_) => unreachable!(), + }, + }; + (memory, memory64) + } + /// Translates a `LocalCanonicalOptions` which indexes into the `frame` /// specified into a runtime representation. fn adapter_options( @@ -988,6 +1308,7 @@ impl<'a> Inliner<'a> { None => false, }; let realloc = options.realloc.map(|i| frame.funcs[i].clone()); + let callback = options.callback.map(|i| frame.funcs[i].clone()); let post_return = options.post_return.map(|i| frame.funcs[i].clone()); AdapterOptions { instance: frame.instance, @@ -995,7 +1316,9 @@ impl<'a> Inliner<'a> { memory, memory64, realloc, + callback, post_return, + async_: options.async_, } } @@ -1008,6 +1331,7 @@ impl<'a> Inliner<'a> { .memory .map(|export| self.result.memories.push(export)); let realloc = options.realloc.map(|def| self.result.reallocs.push(def)); + let callback = options.callback.map(|def| self.result.callbacks.push(def)); let post_return = options .post_return .map(|def| self.result.post_returns.push(def)); @@ -1016,7 +1340,9 @@ impl<'a> Inliner<'a> { string_encoding: options.string_encoding, memory, realloc, + callback, post_return, + async_: options.async_, } } diff --git a/crates/environ/src/component/types.rs b/crates/environ/src/component/types.rs index de3896c18f04..7516c4425963 100644 --- a/crates/environ/src/component/types.rs +++ b/crates/environ/src/component/types.rs @@ -89,6 +89,28 @@ indices! { pub struct TypeResultIndex(u32); /// Index pointing to a list type in the component model. pub struct TypeListIndex(u32); + /// Index pointing to a future type in the component model. + pub struct TypeFutureIndex(u32); + /// Index pointing to a future table within a component. + /// + /// This is analogous to `TypeResourceTableIndex` in that it tracks + /// ownership of futures within each (sub)component instance. + pub struct TypeFutureTableIndex(u32); + /// Index pointing to a stream type in the component model. + pub struct TypeStreamIndex(u32); + /// Index pointing to a stream table within a component. + /// + /// This is analogous to `TypeResourceTableIndex` in that it tracks + /// ownership of stream within each (sub)component instance. + pub struct TypeStreamTableIndex(u32); + /// Index pointing to a error context table within a component. + /// + /// This is analogous to `TypeResourceTableIndex` in that it tracks + /// ownership of error contexts within each (sub)component instance. + pub struct TypeErrorContextTableIndex(u32); + + /// Index pointing to an interned `task.return` type within a component. + pub struct TypeTaskReturnIndex(u32); /// Index pointing to a resource table within a component. /// @@ -186,6 +208,9 @@ indices! { /// Same as `RuntimeMemoryIndex` except for the `realloc` function. pub struct RuntimeReallocIndex(u32); + /// Same as `RuntimeMemoryIndex` except for the `callback` function. + pub struct RuntimeCallbackIndex(u32); + /// Same as `RuntimeMemoryIndex` except for the `post-return` function. pub struct RuntimePostReturnIndex(u32); @@ -194,7 +219,7 @@ indices! { /// /// This is used to point to various bits of metadata within a compiled /// component and is stored in the final compilation artifact. This does not - /// have a direct corresponance to any wasm definition. + /// have a direct correspondence to any wasm definition. pub struct TrampolineIndex(u32); /// An index into `Component::export_items` at the end of compilation. @@ -237,8 +262,13 @@ pub struct ComponentTypes { pub(super) options: PrimaryMap, pub(super) results: PrimaryMap, pub(super) resource_tables: PrimaryMap, - pub(super) module_types: Option, + pub(super) futures: PrimaryMap, + pub(super) future_tables: PrimaryMap, + pub(super) streams: PrimaryMap, + pub(super) stream_tables: PrimaryMap, + pub(super) error_context_tables: PrimaryMap, + pub(super) task_returns: PrimaryMap, } impl ComponentTypes { @@ -261,7 +291,10 @@ impl ComponentTypes { | InterfaceType::Float32 | InterfaceType::Char | InterfaceType::Own(_) - | InterfaceType::Borrow(_) => &CanonicalAbiInfo::SCALAR4, + | InterfaceType::Borrow(_) + | InterfaceType::Future(_) + | InterfaceType::Stream(_) + | InterfaceType::ErrorContext(_) => &CanonicalAbiInfo::SCALAR4, InterfaceType::U64 | InterfaceType::S64 | InterfaceType::Float64 => { &CanonicalAbiInfo::SCALAR8 @@ -320,6 +353,11 @@ impl_index! { impl Index for ComponentTypes { TypeResult => results } impl Index for ComponentTypes { TypeList => lists } impl Index for ComponentTypes { TypeResourceTable => resource_tables } + impl Index for ComponentTypes { TypeFuture => futures } + impl Index for ComponentTypes { TypeStream => streams } + impl Index for ComponentTypes { TypeFutureTable => future_tables } + impl Index for ComponentTypes { TypeStreamTable => stream_tables } + impl Index for ComponentTypes { TypeErrorContextTable => error_context_tables } } // Additionally forward anything that can index `ModuleTypes` to `ModuleTypes` @@ -430,6 +468,20 @@ pub struct TypeFunc { pub params: TypeTupleIndex, /// Results of the function represented as a tuple. pub results: TypeTupleIndex, + /// Expected core func type for memory32 `task.return` calls for this function. + pub task_return_type32: TypeTaskReturnIndex, + /// Expected core func type for memory64 `task.return` calls for this function. + pub task_return_type64: TypeTaskReturnIndex, +} + +/// A core type representing the expected `task.return` signature for a +/// component function. +#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)] +pub struct TypeTaskReturn { + /// Core type parameters for the signature. + /// + /// Note that `task.return` never returns results. + pub params: Vec, } /// All possible interface types that values can have. @@ -464,6 +516,9 @@ pub enum InterfaceType { Result(TypeResultIndex), Own(TypeResourceTableIndex), Borrow(TypeResourceTableIndex), + Future(TypeFutureTableIndex), + Stream(TypeStreamTableIndex), + ErrorContext(TypeErrorContextTableIndex), } impl From<&wasmparser::PrimitiveValType> for InterfaceType { @@ -972,6 +1027,45 @@ pub struct TypeResult { pub info: VariantInfo, } +/// Shape of a "future" interface type. +#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)] +pub struct TypeFuture { + /// The `T` in `future` + pub payload: Option, +} + +/// Metadata about a future table added to a component. +#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)] +pub struct TypeFutureTable { + /// The specific future type this table is used for. + pub ty: TypeFutureIndex, + /// The specific component instance this table is used for. + pub instance: RuntimeComponentInstanceIndex, +} + +/// Shape of a "stream" interface type. +#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)] +pub struct TypeStream { + /// The `T` in `stream` + pub payload: InterfaceType, +} + +/// Metadata about a stream table added to a component. +#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)] +pub struct TypeStreamTable { + /// The specific stream type this table is used for. + pub ty: TypeStreamIndex, + /// The specific component instance this table is used for. + pub instance: RuntimeComponentInstanceIndex, +} + +/// Metadata about a error context table added to a component. +#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)] +pub struct TypeErrorContextTable { + /// The specific component instance this table is used for. + pub instance: RuntimeComponentInstanceIndex, +} + /// Metadata about a resource table added to a component. #[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)] pub struct TypeResourceTable { @@ -1049,7 +1143,7 @@ impl FlatTypes<'_> { // Note that this is intentionally duplicated here to keep the size to 1 byte // regardless to changes in the core wasm type system since this will only // ever use integers/floats for the foreseeable future. -#[derive(PartialEq, Eq, Copy, Clone)] +#[derive(Serialize, Deserialize, Hash, Debug, PartialEq, Eq, Copy, Clone)] #[allow(missing_docs, reason = "self-describing variants")] pub enum FlatType { I32, diff --git a/crates/environ/src/component/types_builder.rs b/crates/environ/src/component/types_builder.rs index 8defc7ac9ad4..1bc47c785584 100644 --- a/crates/environ/src/component/types_builder.rs +++ b/crates/environ/src/component/types_builder.rs @@ -31,7 +31,7 @@ pub use resources::ResourcesBuilder; /// Some more information about this can be found in #4814 const MAX_TYPE_DEPTH: u32 = 100; -/// Structured used to build a [`ComponentTypes`] during translation. +/// Structure used to build a [`ComponentTypes`] during translation. /// /// This contains tables to intern any component types found as well as /// managing building up core wasm [`ModuleTypes`] as well. @@ -45,6 +45,12 @@ pub struct ComponentTypesBuilder { flags: HashMap, options: HashMap, results: HashMap, + futures: HashMap, + streams: HashMap, + future_tables: HashMap, + stream_tables: HashMap, + error_context_tables: HashMap, + task_returns: HashMap, component_types: ComponentTypes, module_types: ModuleTypesBuilder, @@ -70,15 +76,16 @@ where macro_rules! intern_and_fill_flat_types { ($me:ident, $name:ident, $val:ident) => {{ if let Some(idx) = $me.$name.get(&$val) { - return *idx; + *idx + } else { + let idx = $me.component_types.$name.push($val.clone()); + let mut info = TypeInformation::new(); + info.$name($me, &$val); + let idx2 = $me.type_info.$name.push(info); + assert_eq!(idx, idx2); + $me.$name.insert($val, idx); + idx } - let idx = $me.component_types.$name.push($val.clone()); - let mut info = TypeInformation::new(); - info.$name($me, &$val); - let idx2 = $me.type_info.$name.push(info); - assert_eq!(idx, idx2); - $me.$name.insert($val, idx); - return idx; }}; } @@ -97,6 +104,12 @@ impl ComponentTypesBuilder { flags: HashMap::default(), options: HashMap::default(), results: HashMap::default(), + futures: HashMap::default(), + streams: HashMap::default(), + future_tables: HashMap::default(), + stream_tables: HashMap::default(), + error_context_tables: HashMap::default(), + task_returns: HashMap::default(), component_types: ComponentTypes::default(), type_info: TypeInformationCache::default(), resources: ResourcesBuilder::default(), @@ -184,6 +197,24 @@ impl ComponentTypesBuilder { self.component_types.resource_tables.len() } + /// Returns the number of future tables allocated so far, or the maximum + /// `TypeFutureTableIndex`. + pub fn num_future_tables(&self) -> usize { + self.component_types.future_tables.len() + } + + /// Returns the number of stream tables allocated so far, or the maximum + /// `TypeStreamTableIndex`. + pub fn num_stream_tables(&self) -> usize { + self.component_types.stream_tables.len() + } + + /// Returns the number of error-context tables allocated so far, or the maximum + /// `TypeErrorContextTableIndex`. + pub fn num_error_context_tables(&self) -> usize { + self.component_types.error_context_tables.len() + } + /// Returns a mutable reference to the underlying `ResourcesBuilder`. pub fn resources_mut(&mut self) -> &mut ResourcesBuilder { &mut self.resources @@ -215,10 +246,24 @@ impl ComponentTypesBuilder { .iter() .map(|(_name, ty)| self.valtype(types, ty)) .collect::>()?; + let params = self.new_tuple_type(params); + let results = self.new_tuple_type(results); + let (task_return_type32, task_return_type64) = + if let Some(types) = self.flat_types(&InterfaceType::Tuple(results)) { + (types.memory32.to_vec(), types.memory64.to_vec()) + } else { + (vec![FlatType::I32], vec![FlatType::I64]) + }; let ty = TypeFunc { param_names, - params: self.new_tuple_type(params), - results: self.new_tuple_type(results), + params, + results, + task_return_type32: self.add_task_return_type(TypeTaskReturn { + params: task_return_type32, + }), + task_return_type64: self.add_task_return_type(TypeTaskReturn { + params: task_return_type64, + }), }; Ok(self.add_func_type(ty)) } @@ -356,7 +401,8 @@ impl ComponentTypesBuilder { }) } - fn defined_type( + /// Convert a wasmparser `ComponentDefinedTypeId` into Wasmtime's type representation. + pub fn defined_type( &mut self, types: TypesRef<'_>, id: ComponentDefinedTypeId, @@ -380,6 +426,15 @@ impl ComponentTypesBuilder { ComponentDefinedType::Borrow(r) => { InterfaceType::Borrow(self.resource_id(r.resource())) } + ComponentDefinedType::Future(ty) => { + InterfaceType::Future(self.future_table_type(types, ty)?) + } + ComponentDefinedType::Stream(ty) => { + InterfaceType::Stream(self.stream_table_type(types, ty)?) + } + ComponentDefinedType::ErrorContext => { + InterfaceType::ErrorContext(self.error_context_table_type()?) + } }; let info = self.type_information(&ret); if info.depth > MAX_TYPE_DEPTH { @@ -388,6 +443,11 @@ impl ComponentTypesBuilder { Ok(ret) } + /// Retrieve Wasmtime's type representation of the `error-context` type. + pub fn error_context_type(&mut self) -> Result { + self.error_context_table_type() + } + fn valtype(&mut self, types: TypesRef<'_>, ty: &ComponentValType) -> Result { assert_eq!(types.id(), self.module_types.validator_id()); match ty { @@ -513,6 +573,38 @@ impl ComponentTypesBuilder { Ok(self.add_result_type(TypeResult { ok, err, abi, info })) } + fn future_table_type( + &mut self, + types: TypesRef<'_>, + ty: &Option, + ) -> Result { + let payload = ty.as_ref().map(|ty| self.valtype(types, ty)).transpose()?; + let ty = self.add_future_type(TypeFuture { payload }); + Ok(self.add_future_table_type(TypeFutureTable { + ty, + instance: self.resources.get_current_instance().unwrap(), + })) + } + + fn stream_table_type( + &mut self, + types: TypesRef<'_>, + ty: &ComponentValType, + ) -> Result { + let payload = self.valtype(types, ty)?; + let ty = self.add_stream_type(TypeStream { payload }); + Ok(self.add_stream_table_type(TypeStreamTable { + ty, + instance: self.resources.get_current_instance().unwrap(), + })) + } + + fn error_context_table_type(&mut self) -> Result { + Ok(self.add_error_context_table_type(TypeErrorContextTable { + instance: self.resources.get_current_instance().unwrap(), + })) + } + fn list_type(&mut self, types: TypesRef<'_>, ty: &ComponentValType) -> Result { assert_eq!(types.id(), self.module_types.validator_id()); let element = self.valtype(types, ty)?; @@ -565,11 +657,66 @@ impl ComponentTypesBuilder { intern_and_fill_flat_types!(self, results, ty) } - /// Interns a new type within this type information. + /// Interns a new list type within this type information. pub fn add_list_type(&mut self, ty: TypeList) -> TypeListIndex { intern_and_fill_flat_types!(self, lists, ty) } + /// Interns a new future type within this type information. + pub fn add_future_type(&mut self, ty: TypeFuture) -> TypeFutureIndex { + intern(&mut self.futures, &mut self.component_types.futures, ty) + } + + /// Interns a new future table type within this type information. + pub fn add_future_table_type(&mut self, ty: TypeFutureTable) -> TypeFutureTableIndex { + intern( + &mut self.future_tables, + &mut self.component_types.future_tables, + ty, + ) + } + + /// Interns a new stream type within this type information. + pub fn add_stream_type(&mut self, ty: TypeStream) -> TypeStreamIndex { + intern(&mut self.streams, &mut self.component_types.streams, ty) + } + + /// Interns a new stream table type within this type information. + pub fn add_stream_table_type(&mut self, ty: TypeStreamTable) -> TypeStreamTableIndex { + intern( + &mut self.stream_tables, + &mut self.component_types.stream_tables, + ty, + ) + } + + /// Interns a new error context table type within this type information. + pub fn add_error_context_table_type( + &mut self, + ty: TypeErrorContextTable, + ) -> TypeErrorContextTableIndex { + intern( + &mut self.error_context_tables, + &mut self.component_types.error_context_tables, + ty, + ) + } + + /// Interns a new task return type within this type information. + pub fn add_task_return_type(&mut self, ty: TypeTaskReturn) -> TypeTaskReturnIndex { + intern( + &mut self.task_returns, + &mut self.component_types.task_returns, + ty, + ) + } + + /// Gets a previously interned task return type within this type + /// information, if any. + pub fn get_task_return_type(&self, ty: &TypeTaskReturn) -> Option { + self.task_returns.get(ty).copied() + } + /// Returns the canonical ABI information about the specified type. pub fn canonical_abi(&self, ty: &InterfaceType) -> &CanonicalAbiInfo { self.component_types.canonical_abi(ty) @@ -600,7 +747,10 @@ impl ComponentTypesBuilder { | InterfaceType::U32 | InterfaceType::S32 | InterfaceType::Char - | InterfaceType::Own(_) => { + | InterfaceType::Own(_) + | InterfaceType::Future(_) + | InterfaceType::Stream(_) + | InterfaceType::ErrorContext(_) => { static INFO: TypeInformation = TypeInformation::primitive(FlatType::I32); &INFO } diff --git a/crates/environ/src/component/types_builder/resources.rs b/crates/environ/src/component/types_builder/resources.rs index d02426d49b6b..cba01c60747f 100644 --- a/crates/environ/src/component/types_builder/resources.rs +++ b/crates/environ/src/component/types_builder/resources.rs @@ -231,4 +231,9 @@ impl ResourcesBuilder { pub fn set_current_instance(&mut self, instance: RuntimeComponentInstanceIndex) { self.current_instance = Some(instance); } + + /// Retrieves the `current_instance` field. + pub fn get_current_instance(&self) -> Option { + self.current_instance + } } diff --git a/crates/environ/src/component/vmcomponent_offsets.rs b/crates/environ/src/component/vmcomponent_offsets.rs index a46b855461da..ca277c3b19d2 100644 --- a/crates/environ/src/component/vmcomponent_offsets.rs +++ b/crates/environ/src/component/vmcomponent_offsets.rs @@ -4,13 +4,40 @@ // magic: u32, // builtins: &'static VMComponentBuiltins, // store: *mut dyn Store, +// task_backpressure: VMTaskBackpressureCallback, +// task_return: VMTaskReturnCallback, +// task_wait: VMTaskWaitOrPollCallback, +// task_poll: VMTaskWaitOrPollCallback, +// task_yield: VMTaskYieldCallback, +// subtask_drop: VMSubtaskDropCallback, +// async_enter: VMAsyncEnterCallback, +// async_exit: VMAsyncExitCallback, +// future_new: VMFutureNewCallback, +// future_write: VMFutureTransmitCallback, +// future_read: VMFutureTransmitCallback, +// future_cancel_write: VMFutureCancelCallback, +// future_cancel_read: VMFutureCancelCallback, +// stream_cancel_write: VMStreamCancelCallback, +// stream_cancel_read: VMStreamCancelCallback, +// future_close_writable: VMFutureCloseWritableCallback, +// future_close_readable: VMFutureCloseReadableCallback, +// stream_close_writable: VMStreamCloseWritableCallback, +// stream_close_readable: VMStreamCloseReadableCallback, +// stream_new: VMStreamNewCallback, +// stream_write: VMStreamTransmitCallback, +// stream_read: VMStreamTransmitCallback, +// flat_stream_write: VMFlatStreamTransmitCallback, +// flat_stream_read: VMFlatStreamTransmitCallback, +// error_context_new: VMErrorContextNewCallback, +// error_context_debug_string: VMErrorContextDebugStringCallback, +// error_context_drop: VMErrorContextDropCallback, // limits: *const VMRuntimeLimits, // flags: [VMGlobalDefinition; component.num_runtime_component_instances], // trampoline_func_refs: [VMFuncRef; component.num_trampolines], // lowerings: [VMLowering; component.num_lowerings], -// memories: [*mut VMMemoryDefinition; component.num_memories], -// reallocs: [*mut VMFuncRef; component.num_reallocs], -// post_returns: [*mut VMFuncRef; component.num_post_returns], +// memories: [*mut VMMemoryDefinition; component.num_runtime_memories], +// reallocs: [*mut VMFuncRef; component.num_runtime_reallocs], +// post_returns: [*mut VMFuncRef; component.num_runtime_post_returns], // resource_destructors: [*mut VMFuncRef; component.num_resources], // } @@ -47,6 +74,8 @@ pub struct VMComponentOffsets

{ pub num_runtime_memories: u32, /// The number of reallocs which are recorded in this component for options. pub num_runtime_reallocs: u32, + /// The number of callbacks which are recorded in this component for options. + pub num_runtime_callbacks: u32, /// The number of post-returns which are recorded in this component for options. pub num_runtime_post_returns: u32, /// Number of component instances internally in the component (always at @@ -61,12 +90,40 @@ pub struct VMComponentOffsets

{ magic: u32, builtins: u32, store: u32, + task_backpressure: u32, + task_return: u32, + task_wait: u32, + task_poll: u32, + task_yield: u32, + subtask_drop: u32, + async_enter: u32, + async_exit: u32, + future_new: u32, + future_write: u32, + future_read: u32, + future_cancel_write: u32, + future_cancel_read: u32, + future_close_writable: u32, + future_close_readable: u32, + stream_new: u32, + stream_write: u32, + stream_read: u32, + stream_cancel_write: u32, + stream_cancel_read: u32, + stream_close_writable: u32, + stream_close_readable: u32, + flat_stream_write: u32, + flat_stream_read: u32, + error_context_new: u32, + error_context_debug_message: u32, + error_context_drop: u32, limits: u32, flags: u32, trampoline_func_refs: u32, lowerings: u32, memories: u32, reallocs: u32, + callbacks: u32, post_returns: u32, resource_destructors: u32, size: u32, @@ -87,6 +144,7 @@ impl VMComponentOffsets

{ num_lowerings: component.num_lowerings, num_runtime_memories: component.num_runtime_memories.try_into().unwrap(), num_runtime_reallocs: component.num_runtime_reallocs.try_into().unwrap(), + num_runtime_callbacks: component.num_runtime_callbacks.try_into().unwrap(), num_runtime_post_returns: component.num_runtime_post_returns.try_into().unwrap(), num_runtime_component_instances: component .num_runtime_component_instances @@ -103,9 +161,37 @@ impl VMComponentOffsets

{ lowerings: 0, memories: 0, reallocs: 0, + callbacks: 0, post_returns: 0, resource_destructors: 0, size: 0, + task_backpressure: 0, + task_return: 0, + task_wait: 0, + task_poll: 0, + task_yield: 0, + subtask_drop: 0, + async_enter: 0, + async_exit: 0, + future_new: 0, + future_write: 0, + future_read: 0, + future_cancel_write: 0, + future_cancel_read: 0, + future_close_writable: 0, + future_close_readable: 0, + stream_new: 0, + stream_write: 0, + stream_read: 0, + stream_cancel_write: 0, + stream_cancel_read: 0, + stream_close_writable: 0, + stream_close_readable: 0, + flat_stream_write: 0, + flat_stream_read: 0, + error_context_new: 0, + error_context_debug_message: 0, + error_context_drop: 0, }; // Convenience functions for checked addition and multiplication. @@ -138,6 +224,33 @@ impl VMComponentOffsets

{ size(builtins) = ret.ptr.size(), size(store) = cmul(2, ret.ptr.size()), size(limits) = ret.ptr.size(), + size(task_backpressure) = ret.ptr.size(), + size(task_return) = ret.ptr.size(), + size(task_wait) = ret.ptr.size(), + size(task_poll) = ret.ptr.size(), + size(task_yield) = ret.ptr.size(), + size(subtask_drop) = ret.ptr.size(), + size(async_enter) = ret.ptr.size(), + size(async_exit) = ret.ptr.size(), + size(future_new) = ret.ptr.size(), + size(future_write) = ret.ptr.size(), + size(future_read) = ret.ptr.size(), + size(future_cancel_write) = ret.ptr.size(), + size(future_cancel_read) = ret.ptr.size(), + size(future_close_writable) = ret.ptr.size(), + size(future_close_readable) = ret.ptr.size(), + size(stream_new) = ret.ptr.size(), + size(stream_write) = ret.ptr.size(), + size(stream_read) = ret.ptr.size(), + size(stream_cancel_write) = ret.ptr.size(), + size(stream_cancel_read) = ret.ptr.size(), + size(stream_close_writable) = ret.ptr.size(), + size(stream_close_readable) = ret.ptr.size(), + size(flat_stream_write) = ret.ptr.size(), + size(flat_stream_read) = ret.ptr.size(), + size(error_context_new) = ret.ptr.size(), + size(error_context_debug_message) = ret.ptr.size(), + size(error_context_drop) = ret.ptr.size(), align(16), size(flags) = cmul(ret.num_runtime_component_instances, ret.ptr.size_of_vmglobal_definition()), align(u32::from(ret.ptr.size())), @@ -145,6 +258,7 @@ impl VMComponentOffsets

{ size(lowerings) = cmul(ret.num_lowerings, ret.ptr.size() * 2), size(memories) = cmul(ret.num_runtime_memories, ret.ptr.size()), size(reallocs) = cmul(ret.num_runtime_reallocs, ret.ptr.size()), + size(callbacks) = cmul(ret.num_runtime_callbacks, ret.ptr.size()), size(post_returns) = cmul(ret.num_runtime_post_returns, ret.ptr.size()), size(resource_destructors) = cmul(ret.num_resources, ret.ptr.size()), } @@ -215,6 +329,141 @@ impl VMComponentOffsets

{ self.lowerings } + /// The offset of the `task_backpressure` field. + pub fn task_backpressure(&self) -> u32 { + self.task_backpressure + } + + /// The offset of the `task_return` field. + pub fn task_return(&self) -> u32 { + self.task_return + } + + /// The offset of the `task_wait` field. + pub fn task_wait(&self) -> u32 { + self.task_wait + } + + /// The offset of the `task_poll` field. + pub fn task_poll(&self) -> u32 { + self.task_poll + } + + /// The offset of the `task_yield` field. + pub fn task_yield(&self) -> u32 { + self.task_yield + } + + /// The offset of the `subtask_drop` field. + pub fn subtask_drop(&self) -> u32 { + self.subtask_drop + } + + /// The offset of the `async_enter` field. + pub fn async_enter(&self) -> u32 { + self.async_enter + } + + /// The offset of the `async_exit` field. + pub fn async_exit(&self) -> u32 { + self.async_exit + } + + /// The offset of the `future_new` field. + pub fn future_new(&self) -> u32 { + self.future_new + } + + /// The offset of the `future_write` field. + pub fn future_write(&self) -> u32 { + self.future_write + } + + /// The offset of the `future_read` field. + pub fn future_read(&self) -> u32 { + self.future_read + } + + /// The offset of the `future_cancel_write` field. + pub fn future_cancel_write(&self) -> u32 { + self.future_cancel_write + } + + /// The offset of the `future_cancel_read` field. + pub fn future_cancel_read(&self) -> u32 { + self.future_cancel_read + } + + /// The offset of the `future_close_writable` field. + pub fn future_close_writable(&self) -> u32 { + self.future_close_writable + } + + /// The offset of the `future_close_readable` field. + pub fn future_close_readable(&self) -> u32 { + self.future_close_readable + } + + /// The offset of the `stream_new` field. + pub fn stream_new(&self) -> u32 { + self.stream_new + } + + /// The offset of the `stream_write` field. + pub fn stream_write(&self) -> u32 { + self.stream_write + } + + /// The offset of the `stream_read` field. + pub fn stream_read(&self) -> u32 { + self.stream_read + } + + /// The offset of the `stream_cancel_write` field. + pub fn stream_cancel_write(&self) -> u32 { + self.stream_cancel_write + } + + /// The offset of the `stream_cancel_read` field. + pub fn stream_cancel_read(&self) -> u32 { + self.stream_cancel_read + } + + /// The offset of the `stream_close_writable` field. + pub fn stream_close_writable(&self) -> u32 { + self.stream_close_writable + } + + /// The offset of the `stream_close_readable` field. + pub fn stream_close_readable(&self) -> u32 { + self.stream_close_readable + } + + /// The offset of the `flat_stream_write` field. + pub fn flat_stream_write(&self) -> u32 { + self.flat_stream_write + } + + /// The offset of the `flat_stream_read` field. + pub fn flat_stream_read(&self) -> u32 { + self.flat_stream_read + } + + /// The offset of the `error_context_new` field. + pub fn error_context_new(&self) -> u32 { + self.error_context_new + } + + /// The offset of the `error_context_debug_message` field. + pub fn error_context_debug_message(&self) -> u32 { + self.error_context_debug_message + } + + /// The offset of the `error_context_drop` field. + pub fn error_context_drop(&self) -> u32 { + self.error_context_drop + } + /// The offset of the `VMLowering` for the `index` specified. #[inline] pub fn lowering(&self, index: LoweredIndex) -> u32 { @@ -280,6 +529,20 @@ impl VMComponentOffsets

{ self.runtime_reallocs() + index.as_u32() * u32::from(self.ptr.size()) } + /// The offset of the base of the `runtime_callbacks` field + #[inline] + pub fn runtime_callbacks(&self) -> u32 { + self.callbacks + } + + /// The offset of the `*mut VMFuncRef` for the runtime index + /// provided. + #[inline] + pub fn runtime_callback(&self, index: RuntimeCallbackIndex) -> u32 { + assert!(index.as_u32() < self.num_runtime_callbacks); + self.runtime_callbacks() + index.as_u32() * u32::from(self.ptr.size()) + } + /// The offset of the base of the `runtime_post_returns` field #[inline] pub fn runtime_post_returns(&self) -> u32 { diff --git a/crates/environ/src/fact.rs b/crates/environ/src/fact.rs index 4afdac971ff7..4dc3ec13902c 100644 --- a/crates/environ/src/fact.rs +++ b/crates/environ/src/fact.rs @@ -21,7 +21,7 @@ use crate::component::dfg::CoreDef; use crate::component::{ Adapter, AdapterOptions as AdapterOptionsDfg, ComponentTypesBuilder, FlatType, InterfaceType, - StringEncoding, Transcode, TypeFuncIndex, + RuntimeComponentInstanceIndex, StringEncoding, Transcode, TypeFuncIndex, }; use crate::fact::transcode::Transcoder; use crate::prelude::*; @@ -64,6 +64,11 @@ pub struct Module<'a> { imported_resource_transfer_borrow: Option, imported_resource_enter_call: Option, imported_resource_exit_call: Option, + imported_async_enter_call: Option, + imported_async_exit_call: Option, + imported_future_transfer: Option, + imported_stream_transfer: Option, + imported_error_context_transfer: Option, // Current status of index spaces from the imports generated so far. imported_funcs: PrimaryMap>, @@ -73,6 +78,11 @@ pub struct Module<'a> { funcs: PrimaryMap, helper_funcs: HashMap, helper_worklist: Vec<(FunctionId, Helper)>, + + globals_by_type: [Vec; 4], + globals: Vec, + + exports: Vec<(u32, String)>, } struct AdapterData { @@ -95,6 +105,7 @@ struct AdapterData { /// These options are typically unique per-adapter and generally aren't needed /// when translating recursive types within an adapter. struct AdapterOptions { + instance: RuntimeComponentInstanceIndex, /// The ascribed type of this adapter. ty: TypeFuncIndex, /// The global that represents the instance flags for where this adapter @@ -122,6 +133,8 @@ struct Options { /// An optionally-specified function to be used to allocate space for /// types such as strings as they go into a module. realloc: Option, + callback: Option, + async_: bool, } enum Context { @@ -187,6 +200,14 @@ impl<'a> Module<'a> { imported_resource_transfer_borrow: None, imported_resource_enter_call: None, imported_resource_exit_call: None, + imported_async_enter_call: None, + imported_async_exit_call: None, + imported_future_transfer: None, + imported_stream_transfer: None, + imported_error_context_transfer: None, + globals_by_type: Default::default(), + globals: Default::default(), + exports: Vec::new(), } } @@ -240,6 +261,28 @@ impl<'a> Module<'a> { } } + fn allocate(&mut self, counts: &mut [usize; 4], ty: ValType) -> u32 { + let which = match ty { + ValType::I32 => 0, + ValType::I64 => 1, + ValType::F32 => 2, + ValType::F64 => 3, + _ => unreachable!(), + }; + + let index = counts[which]; + counts[which] += 1; + + if let Some(offset) = self.globals_by_type[which].get(index) { + *offset + } else { + let offset = u32::try_from(self.globals.len()).unwrap(); + self.globals_by_type[which].push(offset); + self.globals.push(ty); + offset + } + } + fn import_options(&mut self, ty: TypeFuncIndex, options: &AdapterOptionsDfg) -> AdapterOptions { let AdapterOptionsDfg { instance, @@ -248,7 +291,10 @@ impl<'a> Module<'a> { memory64, realloc, post_return: _, // handled above + callback, + async_, } = options; + let flags = self.import_global( "flags", &format!("instance{}", instance.as_u32()), @@ -287,8 +333,26 @@ impl<'a> Module<'a> { func.clone(), ) }); + let callback = callback.as_ref().map(|func| { + let ptr = if *memory64 { + ValType::I64 + } else { + ValType::I32 + }; + let ty = self.core_types.function( + &[ptr, ValType::I32, ValType::I32, ValType::I32], + &[ValType::I32], + ); + self.import_func( + "callback", + &format!("f{}", self.imported_funcs.len()), + ty, + func.clone(), + ) + }); AdapterOptions { + instance: *instance, ty, flags, post_return: None, @@ -297,6 +361,8 @@ impl<'a> Module<'a> { memory64: *memory64, memory, realloc, + callback, + async_: *async_, }, } } @@ -397,6 +463,78 @@ impl<'a> Module<'a> { idx } + fn import_async_enter_call(&mut self) -> FuncIndex { + self.import_simple( + "async", + "enter-call", + &[ + ValType::FUNCREF, + ValType::FUNCREF, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + &[], + Import::AsyncEnterCall, + |me| &mut me.imported_async_enter_call, + ) + } + + fn import_async_exit_call(&mut self, callback: Option) -> FuncIndex { + self.import_simple( + "async", + "exit-call", + &[ + ValType::I32, + ValType::FUNCREF, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + &[ValType::I32], + Import::AsyncExitCall( + callback + .map(|callback| self.imported_funcs.get(callback).unwrap().clone().unwrap()), + ), + |me| &mut me.imported_async_exit_call, + ) + } + + fn import_future_transfer(&mut self) -> FuncIndex { + self.import_simple( + "future", + "transfer", + &[ValType::I32; 3], + &[ValType::I32], + Import::FutureTransfer, + |me| &mut me.imported_future_transfer, + ) + } + + fn import_stream_transfer(&mut self) -> FuncIndex { + self.import_simple( + "stream", + "transfer", + &[ValType::I32; 3], + &[ValType::I32], + Import::StreamTransfer, + |me| &mut me.imported_stream_transfer, + ) + } + + fn import_error_context_transfer(&mut self) -> FuncIndex { + self.import_simple( + "error-context", + "transfer", + &[ValType::I32; 3], + &[ValType::I32], + Import::ErrorContextTransfer, + |me| &mut me.imported_error_context_transfer, + ) + } + fn import_resource_transfer_own(&mut self) -> FuncIndex { self.import_simple( "resource", @@ -472,6 +610,11 @@ impl<'a> Module<'a> { exports.export(name, ExportKind::Func, idx.as_u32()); } } + for (idx, name) in &self.exports { + exports.export(name, ExportKind::Func, *idx); + } + + let imported_global_count = u32::try_from(self.imported_globals.len()).unwrap(); // With all functions numbered the fragments of the body of each // function can be assigned into one final adapter function. @@ -504,6 +647,15 @@ impl<'a> Module<'a> { Body::Call(id) => { Instruction::Call(id_to_index[*id].as_u32()).encode(&mut body); } + Body::RefFunc(id) => { + Instruction::RefFunc(id_to_index[*id].as_u32()).encode(&mut body); + } + Body::GlobalGet(offset) => { + Instruction::GlobalGet(offset + imported_global_count).encode(&mut body); + } + Body::GlobalSet(offset) => { + Instruction::GlobalSet(offset + imported_global_count).encode(&mut body); + } } } code.raw(&body); @@ -512,10 +664,29 @@ impl<'a> Module<'a> { let traps = traps.finish(); + let mut globals = GlobalSection::new(); + for ty in &self.globals { + globals.global( + GlobalType { + val_type: *ty, + mutable: true, + shared: false, + }, + &match ty { + ValType::I32 => ConstExpr::i32_const(0), + ValType::I64 => ConstExpr::i64_const(0), + ValType::F32 => ConstExpr::f32_const(0_f32), + ValType::F64 => ConstExpr::f64_const(0_f64), + _ => unreachable!(), + }, + ); + } + let mut result = wasm_encoder::Module::new(); result.section(&self.core_types.section); result.section(&self.core_imports); result.section(&funcs); + result.section(&globals); result.section(&exports); result.section(&code); if self.debug { @@ -561,6 +732,21 @@ pub enum Import { /// Tears down a previous entry and handles checking borrow-related /// metadata. ResourceExitCall, + /// An intrinsic used by FACT-generated modules to begin a call to an + /// async-lowered import function. + AsyncEnterCall, + /// An intrinsic used by FACT-generated modules to complete a call to an + /// async-lowered import function. + AsyncExitCall(Option), + /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer + /// ownership of a `future`. + FutureTransfer, + /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer + /// ownership of a `stream`. + StreamTransfer, + /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer + /// ownership of an `error-context`. + ErrorContextTransfer, } impl Options { @@ -659,6 +845,9 @@ struct Function { enum Body { Raw(Vec, Vec<(usize, traps::Trap)>), Call(FunctionId), + RefFunc(FunctionId), + GlobalGet(u32), + GlobalSet(u32), } impl Function { diff --git a/crates/environ/src/fact/signature.rs b/crates/environ/src/fact/signature.rs index 328ec085e359..899fc8e1b4a7 100644 --- a/crates/environ/src/fact/signature.rs +++ b/crates/environ/src/fact/signature.rs @@ -13,6 +13,14 @@ pub struct Signature { pub params: Vec, /// Core wasm results. pub results: Vec, + /// Indicator to whether parameters are indirect, meaning that the first + /// entry of `params` is a pointer type which all parameters are loaded + /// through. + pub params_indirect: bool, + /// Indicator whether results are passed indirectly. This may mean that + /// `results` is an `i32` or that `params` ends with an `i32` depending on + /// the `Context`. + pub results_indirect: bool, } impl ComponentTypesBuilder { @@ -26,6 +34,16 @@ impl ComponentTypesBuilder { let ty = &self[options.ty]; let ptr_ty = options.options.ptr(); + if let (Context::Lower, true) = (&context, options.options.async_) { + return Signature { + params: vec![ptr_ty; 2], + results: vec![ValType::I32], + params_indirect: true, + results_indirect: true, + }; + } + + let mut params_indirect = false; let mut params = match self.flatten_types( &options.options, MAX_FLAT_PARAMS, @@ -33,10 +51,25 @@ impl ComponentTypesBuilder { ) { Some(list) => list, None => { + params_indirect = true; vec![ptr_ty] } }; + if options.options.async_ { + return Signature { + params, + results: if options.options.callback.is_some() { + vec![ptr_ty] + } else { + Vec::new() + }, + params_indirect, + results_indirect: false, + }; + } + + let mut results_indirect = false; let results = match self.flatten_types( &options.options, MAX_FLAT_RESULTS, @@ -44,6 +77,7 @@ impl ComponentTypesBuilder { ) { Some(list) => list, None => { + results_indirect = true; match context { // For a lifted function too-many-results gets translated to a // returned pointer where results are read from. The callee @@ -59,7 +93,70 @@ impl ComponentTypesBuilder { } } }; - Signature { params, results } + Signature { + params, + results, + params_indirect, + results_indirect, + } + } + + pub(super) fn async_start_signature(&self, options: &AdapterOptions) -> Signature { + let ty = &self[options.ty]; + let ptr_ty = options.options.ptr(); + + let mut params = vec![ptr_ty]; + + let mut results_indirect = false; + let results = match self.flatten_types( + &options.options, + MAX_FLAT_PARAMS, + self[ty.params].types.iter().copied(), + ) { + Some(list) => list, + None => { + results_indirect = true; + params.push(ptr_ty); + Vec::new() + } + }; + Signature { + params, + results, + params_indirect: false, + results_indirect, + } + } + + pub(super) fn async_return_signature(&self, options: &AdapterOptions) -> Signature { + let ty = &self[options.ty]; + let ptr_ty = options.options.ptr(); + + let mut params_indirect = false; + let mut params = match self.flatten_types( + &options.options, + if options.options.async_ { + MAX_FLAT_PARAMS + } else { + MAX_FLAT_RESULTS + }, + self[ty.results].types.iter().copied(), + ) { + Some(list) => list, + None => { + params_indirect = true; + vec![ptr_ty] + } + }; + // Add return pointer + params.push(ptr_ty); + + Signature { + params, + results: Vec::new(), + params_indirect, + results_indirect: false, + } } /// Pushes the flat version of a list of component types into a final result diff --git a/crates/environ/src/fact/trampoline.rs b/crates/environ/src/fact/trampoline.rs index 8af700de421b..005aa7423709 100644 --- a/crates/environ/src/fact/trampoline.rs +++ b/crates/environ/src/fact/trampoline.rs @@ -17,9 +17,10 @@ use crate::component::{ CanonicalAbiInfo, ComponentTypesBuilder, FixedEncoding as FE, FlatType, InterfaceType, - StringEncoding, Transcode, TypeEnumIndex, TypeFlagsIndex, TypeListIndex, TypeOptionIndex, - TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeTupleIndex, TypeVariantIndex, - VariantInfo, FLAG_MAY_ENTER, FLAG_MAY_LEAVE, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, + StringEncoding, Transcode, TypeEnumIndex, TypeErrorContextTableIndex, TypeFlagsIndex, + TypeFutureTableIndex, TypeListIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, + TypeResultIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, VariantInfo, + FLAG_MAY_ENTER, FLAG_MAY_LEAVE, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, }; use crate::fact::signature::Signature; use crate::fact::transcode::Transcoder; @@ -39,6 +40,9 @@ use wasmtime_component_util::{DiscriminantSize, FlagsSize}; const MAX_STRING_BYTE_LENGTH: u32 = 1 << 31; const UTF16_TAG: u32 = 1 << 31; +const EXIT_FLAG_ASYNC_CALLER: i32 = 1 << 0; +const EXIT_FLAG_ASYNC_CALLEE: i32 = 1 << 1; + /// This value is arbitrarily chosen and should be fine to change at any time, /// it just seemed like a halfway reasonable starting point. const INITIAL_FUEL: usize = 1_000; @@ -80,37 +84,168 @@ struct Compiler<'a, 'b> { } pub(super) fn compile(module: &mut Module<'_>, adapter: &AdapterData) { - let lower_sig = module.types.signature(&adapter.lower, Context::Lower); - let lift_sig = module.types.signature(&adapter.lift, Context::Lift); - let ty = module - .core_types - .function(&lower_sig.params, &lower_sig.results); - let result = module - .funcs - .push(Function::new(Some(adapter.name.clone()), ty)); - - // If this type signature contains any borrowed resources then invocations - // of enter/exit call for resource-related metadata tracking must be used. - // It shouldn't matter whether the lower/lift signature is used here as both - // should return the same answer. - let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower); - assert_eq!( - emit_resource_call, - module.types.contains_borrow_resource(&adapter.lift) - ); - - Compiler { - types: module.types, - module, - code: Vec::new(), - nlocals: lower_sig.params.len() as u32, - free_locals: HashMap::new(), - traps: Vec::new(), - result, - fuel: INITIAL_FUEL, - emit_resource_call, + fn compiler<'a, 'b>( + module: &'b mut Module<'a>, + adapter: &AdapterData, + ) -> (Compiler<'a, 'b>, Signature, Signature) { + let lower_sig = module.types.signature(&adapter.lower, Context::Lower); + let lift_sig = module.types.signature(&adapter.lift, Context::Lift); + let ty = module + .core_types + .function(&lower_sig.params, &lower_sig.results); + let result = module + .funcs + .push(Function::new(Some(adapter.name.clone()), ty)); + + // If this type signature contains any borrowed resources then invocations + // of enter/exit call for resource-related metadata tracking must be used. + // It shouldn't matter whether the lower/lift signature is used here as both + // should return the same answer. + let emit_resource_call = module.types.contains_borrow_resource(&adapter.lower); + assert_eq!( + emit_resource_call, + module.types.contains_borrow_resource(&adapter.lift) + ); + + ( + Compiler { + types: module.types, + module, + code: Vec::new(), + nlocals: lower_sig.params.len() as u32, + free_locals: HashMap::new(), + traps: Vec::new(), + result, + fuel: INITIAL_FUEL, + emit_resource_call, + }, + lower_sig, + lift_sig, + ) + } + + let start_adapter = |module: &mut Module, param_globals| { + let sig = module.types.async_start_signature(&adapter.lift); + let ty = module.core_types.function(&sig.params, &sig.results); + let result = module.funcs.push(Function::new( + Some(format!("[async-start]{}", adapter.name)), + ty, + )); + + Compiler { + types: module.types, + module, + code: Vec::new(), + nlocals: sig.params.len() as u32, + free_locals: HashMap::new(), + traps: Vec::new(), + result, + fuel: INITIAL_FUEL, + emit_resource_call: false, + } + .compile_async_start_adapter(adapter, &sig, param_globals); + + result + }; + + let return_adapter = |module: &mut Module, result_globals| { + let sig = module.types.async_return_signature(&adapter.lift); + let ty = module.core_types.function(&sig.params, &sig.results); + let result = module.funcs.push(Function::new( + Some(format!("[async-return]{}", adapter.name)), + ty, + )); + + Compiler { + types: module.types, + module, + code: Vec::new(), + nlocals: sig.params.len() as u32, + free_locals: HashMap::new(), + traps: Vec::new(), + result, + fuel: INITIAL_FUEL, + emit_resource_call: false, + } + .compile_async_return_adapter(adapter, &sig, result_globals); + + result + }; + + match (adapter.lower.options.async_, adapter.lift.options.async_) { + (false, false) => { + let (compiler, lower_sig, lift_sig) = compiler(module, adapter); + compiler.compile_sync_to_sync_adapter(adapter, &lower_sig, &lift_sig) + } + (true, true) => { + let start = start_adapter(module, None); + let return_ = return_adapter(module, None); + let (compiler, _, lift_sig) = compiler(module, adapter); + compiler.compile_async_to_async_adapter( + adapter, + start, + return_, + i32::try_from(lift_sig.params.len()).unwrap(), + ); + } + (false, true) => { + let lower_sig = module.types.signature(&adapter.lower, Context::Lower); + let param_globals = if lower_sig.params_indirect { + None + } else { + let mut counts = [0; 4]; + Some( + lower_sig + .params + .iter() + .take(if lower_sig.results_indirect { + lower_sig.params.len() - 1 + } else { + lower_sig.params.len() + }) + .map(|ty| module.allocate(&mut counts, *ty)) + .collect::>(), + ) + }; + let result_globals = if lower_sig.results_indirect { + None + } else { + let mut counts = [0; 4]; + Some( + lower_sig + .results + .iter() + .map(|ty| module.allocate(&mut counts, *ty)) + .collect::>(), + ) + }; + + let start = start_adapter(module, param_globals.as_deref()); + let return_ = return_adapter(module, result_globals.as_deref()); + let (compiler, _, lift_sig) = compiler(module, adapter); + compiler.compile_sync_to_async_adapter( + adapter, + start, + return_, + i32::try_from(lift_sig.params.len()).unwrap(), + param_globals.as_deref(), + result_globals.as_deref(), + ); + } + (true, false) => { + let lift_sig = module.types.signature(&adapter.lift, Context::Lift); + let start = start_adapter(module, None); + let return_ = return_adapter(module, None); + let (compiler, ..) = compiler(module, adapter); + compiler.compile_async_to_sync_adapter( + adapter, + start, + return_, + i32::try_from(lift_sig.params.len()).unwrap(), + i32::try_from(lift_sig.results.len()).unwrap(), + ); + } } - .compile_adapter(adapter, &lower_sig, &lift_sig) } /// Compiles a helper function as specified by the `Helper` configuration. @@ -244,7 +379,292 @@ struct Memory<'a> { } impl Compiler<'_, '_> { - fn compile_adapter( + fn compile_async_to_async_adapter( + mut self, + adapter: &AdapterData, + start: FunctionId, + return_: FunctionId, + param_count: i32, + ) { + let enter = self.module.import_async_enter_call(); + let exit = self + .module + .import_async_exit_call(adapter.lift.options.callback); + + self.flush_code(); + self.module.funcs[self.result] + .body + .push(Body::RefFunc(start)); + self.module.funcs[self.result] + .body + .push(Body::RefFunc(return_)); + self.instruction(I32Const( + i32::try_from(adapter.lower.instance.as_u32()).unwrap(), + )); + self.instruction(I32Const( + i32::try_from({ + let ty = &self.types[adapter.lift.ty]; + if adapter.lift.options.memory64 { + ty.task_return_type64.as_u32() + } else { + ty.task_return_type32.as_u32() + } + }) + .unwrap(), + )); + self.instruction(LocalGet(0)); + self.instruction(LocalGet(1)); + self.instruction(Call(enter.as_u32())); + + // TODO: As an optimization, consider checking the backpressure flag on the callee instance and, if it's + // unset _and_ the callee uses a callback, translate the params and call the callee function directly here + // (and make sure `exit` knows _not_ to call it in that case). + + self.module.exports.push(( + adapter.callee.as_u32(), + format!("[adapter-callee]{}", adapter.name), + )); + + self.instruction(I32Const( + i32::try_from(adapter.lower.instance.as_u32()).unwrap(), + )); + self.instruction(RefFunc(adapter.callee.as_u32())); + self.instruction(I32Const( + i32::try_from(adapter.lift.instance.as_u32()).unwrap(), + )); + self.instruction(I32Const(param_count)); + self.instruction(I32Const(1)); // leave room for the guest context result + self.instruction(I32Const(EXIT_FLAG_ASYNC_CALLER | EXIT_FLAG_ASYNC_CALLEE)); + self.instruction(Call(exit.as_u32())); + + self.finish() + } + + fn compile_sync_to_async_adapter( + mut self, + adapter: &AdapterData, + start: FunctionId, + return_: FunctionId, + param_count: i32, + param_globals: Option<&[u32]>, + result_globals: Option<&[u32]>, + ) { + let enter = self.module.import_async_enter_call(); + let exit = self + .module + .import_async_exit_call(adapter.lift.options.callback); + + self.flush_code(); + self.module.funcs[self.result] + .body + .push(Body::RefFunc(start)); + self.module.funcs[self.result] + .body + .push(Body::RefFunc(return_)); + self.instruction(I32Const( + i32::try_from(adapter.lower.instance.as_u32()).unwrap(), + )); + self.instruction(I32Const( + i32::try_from({ + let ty = &self.types[adapter.lift.ty]; + if adapter.lift.options.memory64 { + ty.task_return_type64.as_u32() + } else { + ty.task_return_type32.as_u32() + } + }) + .unwrap(), + )); + + let results_local = if let Some(globals) = param_globals { + for (local, global) in globals.iter().enumerate() { + self.instruction(LocalGet(u32::try_from(local).unwrap())); + self.flush_code(); + self.module.funcs[self.result] + .body + .push(Body::GlobalSet(*global)); + } + self.instruction(I32Const(0)); // dummy params pointer + u32::try_from(globals.len()).unwrap() + } else { + self.instruction(LocalGet(0)); + 1 + }; + + if result_globals.is_some() { + self.instruction(I32Const(0)); // dummy results pointer + } else { + self.instruction(LocalGet(results_local)); + } + + self.instruction(Call(enter.as_u32())); + + // TODO: As an optimization, consider checking the backpressure flag on the callee instance and, if it's + // unset _and_ the callee uses a callback, translate the params and call the callee function directly here + // (and make sure `exit` knows _not_ to call it in that case). + + self.module.exports.push(( + adapter.callee.as_u32(), + format!("[adapter-callee]{}", adapter.name), + )); + self.instruction(I32Const( + i32::try_from(adapter.lower.instance.as_u32()).unwrap(), + )); + self.instruction(RefFunc(adapter.callee.as_u32())); + self.instruction(I32Const( + i32::try_from(adapter.lift.instance.as_u32()).unwrap(), + )); + self.instruction(I32Const(param_count)); + self.instruction(I32Const(1)); // leave room for the guest context result + self.instruction(I32Const(EXIT_FLAG_ASYNC_CALLEE)); + self.instruction(Call(exit.as_u32())); + self.instruction(Drop); + + if let Some(globals) = result_globals { + self.flush_code(); + for global in globals { + self.module.funcs[self.result] + .body + .push(Body::GlobalGet(*global)); + } + } + + self.finish() + } + + fn compile_async_to_sync_adapter( + mut self, + adapter: &AdapterData, + start: FunctionId, + return_: FunctionId, + param_count: i32, + result_count: i32, + ) { + let enter = self.module.import_async_enter_call(); + let exit = self.module.import_async_exit_call(None); + + self.flush_code(); + self.module.funcs[self.result] + .body + .push(Body::RefFunc(start)); + self.module.funcs[self.result] + .body + .push(Body::RefFunc(return_)); + self.instruction(I32Const( + i32::try_from(adapter.lower.instance.as_u32()).unwrap(), + )); + self.instruction(I32Const( + i32::try_from({ + let ty = &self.types[adapter.lift.ty]; + if adapter.lift.options.memory64 { + ty.task_return_type64.as_u32() + } else { + ty.task_return_type32.as_u32() + } + }) + .unwrap(), + )); + self.instruction(LocalGet(0)); + self.instruction(LocalGet(1)); + self.instruction(Call(enter.as_u32())); + self.module.exports.push(( + adapter.callee.as_u32(), + format!("[adapter-callee]{}", adapter.name), + )); + self.instruction(I32Const( + i32::try_from(adapter.lower.instance.as_u32()).unwrap(), + )); + self.instruction(RefFunc(adapter.callee.as_u32())); + self.instruction(I32Const( + i32::try_from(adapter.lift.instance.as_u32()).unwrap(), + )); + self.instruction(I32Const(param_count)); + self.instruction(I32Const(result_count)); + self.instruction(I32Const(EXIT_FLAG_ASYNC_CALLER)); + self.instruction(Call(exit.as_u32())); + + self.finish() + } + + fn compile_async_start_adapter( + mut self, + adapter: &AdapterData, + sig: &Signature, + param_globals: Option<&[u32]>, + ) { + let mut temps = Vec::new(); + let param_locals = if let Some(globals) = param_globals { + for global in globals { + let ty = self.module.globals[usize::try_from(*global).unwrap()]; + + self.flush_code(); + self.module.funcs[self.result] + .body + .push(Body::GlobalGet(*global)); + temps.push(self.local_set_new_tmp(ty)); + } + temps + .iter() + .map(|t| (t.idx, t.ty)) + .chain(if sig.results_indirect { + sig.params + .iter() + .enumerate() + .map(|(i, ty)| (i as u32, *ty)) + .last() + } else { + None + }) + .collect::>() + } else { + sig.params + .iter() + .enumerate() + .map(|(i, ty)| (i as u32, *ty)) + .collect::>() + }; + + self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, false); + self.translate_params(adapter, ¶m_locals); + self.set_flag(adapter.lift.flags, FLAG_MAY_LEAVE, true); + + for tmp in temps { + self.free_temp_local(tmp); + } + + self.finish(); + } + + fn compile_async_return_adapter( + mut self, + adapter: &AdapterData, + sig: &Signature, + result_globals: Option<&[u32]>, + ) { + let param_locals = sig + .params + .iter() + .enumerate() + .map(|(i, ty)| (i as u32, *ty)) + .collect::>(); + + self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, false); + self.translate_results(adapter, ¶m_locals, ¶m_locals); + self.set_flag(adapter.lower.flags, FLAG_MAY_LEAVE, true); + + if let Some(globals) = result_globals { + self.flush_code(); + for global in globals { + self.module.funcs[self.result] + .body + .push(Body::GlobalSet(*global)); + } + } + + self.finish() + } + + fn compile_sync_to_sync_adapter( mut self, adapter: &AdapterData, lower_sig: &Signature, @@ -362,9 +782,12 @@ impl Compiler<'_, '_> { // TODO: handle subtyping assert_eq!(src_tys.len(), dst_tys.len()); - let src_flat = + let src_flat = if adapter.lower.options.async_ { + None + } else { self.types - .flatten_types(lower_opts, MAX_FLAT_PARAMS, src_tys.iter().copied()); + .flatten_types(lower_opts, MAX_FLAT_PARAMS, src_tys.iter().copied()) + }; let dst_flat = self.types .flatten_types(lift_opts, MAX_FLAT_PARAMS, dst_tys.iter().copied()); @@ -391,16 +814,28 @@ impl Compiler<'_, '_> { let dst = if let Some(flat) = &dst_flat { Destination::Stack(flat, lift_opts) } else { - // If there are too many parameters then space is allocated in the - // destination module for the parameters via its `realloc` function. - let abi = CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t))); - let (size, align) = if lift_opts.memory64 { - (abi.size64, abi.align64) + if lift_opts.async_ { + let align = dst_tys + .iter() + .map(|t| self.types.align(lift_opts, t)) + .max() + .unwrap_or(1); + let (addr, ty) = *param_locals.last().expect("no retptr"); + assert_eq!(ty, lift_opts.ptr()); + Destination::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align)) } else { - (abi.size32, abi.align32) - }; - let size = MallocSize::Const(size); - Destination::Memory(self.malloc(lift_opts, size, align)) + // If there are too many parameters then space is allocated in the + // destination module for the parameters via its `realloc` function. + let abi = + CanonicalAbiInfo::record(dst_tys.iter().map(|t| self.types.canonical_abi(t))); + let (size, align) = if lift_opts.memory64 { + (abi.size64, abi.align64) + } else { + (abi.size32, abi.align32) + }; + let size = MallocSize::Const(size); + Destination::Memory(self.malloc(lift_opts, size, align)) + } }; let srcs = src @@ -416,7 +851,7 @@ impl Compiler<'_, '_> { // If the destination was linear memory instead of the stack then the // actual parameter that we're passing is the address of the values // stored, so ensure that's happening in the wasm body here. - if let Destination::Memory(mem) = dst { + if let (Destination::Memory(mem), false) = (dst, lift_opts.async_) { self.instruction(LocalGet(mem.addr.idx)); self.free_temp_local(mem.addr); } @@ -443,12 +878,21 @@ impl Compiler<'_, '_> { let lift_opts = &adapter.lift.options; let lower_opts = &adapter.lower.options; - let src_flat = - self.types - .flatten_types(lift_opts, MAX_FLAT_RESULTS, src_tys.iter().copied()); - let dst_flat = + let src_flat = self.types.flatten_types( + lift_opts, + if lift_opts.async_ { + MAX_FLAT_PARAMS + } else { + MAX_FLAT_RESULTS + }, + src_tys.iter().copied(), + ); + let dst_flat = if lower_opts.async_ { + None + } else { self.types - .flatten_types(lower_opts, MAX_FLAT_RESULTS, dst_tys.iter().copied()); + .flatten_types(lower_opts, MAX_FLAT_RESULTS, dst_tys.iter().copied()) + }; let src = if src_flat.is_some() { Source::Stack(Stack { @@ -465,7 +909,7 @@ impl Compiler<'_, '_> { .map(|t| self.types.align(lift_opts, t)) .max() .unwrap_or(1); - assert_eq!(result_locals.len(), 1); + assert_eq!(result_locals.len(), if lower_opts.async_ { 2 } else { 1 }); let (addr, ty) = result_locals[0]; assert_eq!(ty, lift_opts.ptr()); Source::Memory(self.memory_operand(lift_opts, TempLocal::new(addr, ty), align)) @@ -587,7 +1031,11 @@ impl Compiler<'_, '_> { InterfaceType::Option(_) | InterfaceType::Result(_) => 2, // TODO(#6696) - something nonzero, is 1 right? - InterfaceType::Own(_) | InterfaceType::Borrow(_) => 1, + InterfaceType::Own(_) + | InterfaceType::Borrow(_) + | InterfaceType::Future(_) + | InterfaceType::Stream(_) + | InterfaceType::ErrorContext(_) => 1, }; match self.fuel.checked_sub(cost) { @@ -622,6 +1070,11 @@ impl Compiler<'_, '_> { InterfaceType::Result(t) => self.translate_result(*t, src, dst_ty, dst), InterfaceType::Own(t) => self.translate_own(*t, src, dst_ty, dst), InterfaceType::Borrow(t) => self.translate_borrow(*t, src, dst_ty, dst), + InterfaceType::Future(t) => self.translate_future(*t, src, dst_ty, dst), + InterfaceType::Stream(t) => self.translate_stream(*t, src, dst_ty, dst), + InterfaceType::ErrorContext(t) => { + self.translate_error_context_context(*t, src, dst_ty, dst) + } } } @@ -2448,6 +2901,51 @@ impl Compiler<'_, '_> { } } + fn translate_future( + &mut self, + src_ty: TypeFutureTableIndex, + src: &Source<'_>, + dst_ty: &InterfaceType, + dst: &Destination, + ) { + let dst_ty = match dst_ty { + InterfaceType::Future(t) => *t, + _ => panic!("expected a `Future`"), + }; + let transfer = self.module.import_future_transfer(); + self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer); + } + + fn translate_stream( + &mut self, + src_ty: TypeStreamTableIndex, + src: &Source<'_>, + dst_ty: &InterfaceType, + dst: &Destination, + ) { + let dst_ty = match dst_ty { + InterfaceType::Stream(t) => *t, + _ => panic!("expected a `Stream`"), + }; + let transfer = self.module.import_stream_transfer(); + self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer); + } + + fn translate_error_context_context( + &mut self, + src_ty: TypeErrorContextTableIndex, + src: &Source<'_>, + dst_ty: &InterfaceType, + dst: &Destination, + ) { + let dst_ty = match dst_ty { + InterfaceType::ErrorContext(t) => *t, + _ => panic!("expected an `ErrorContext`"), + }; + let transfer = self.module.import_error_context_transfer(); + self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer); + } + fn translate_own( &mut self, src_ty: TypeResourceTableIndex, @@ -2460,7 +2958,7 @@ impl Compiler<'_, '_> { _ => panic!("expected an `Own`"), }; let transfer = self.module.import_resource_transfer_own(); - self.translate_resource(src_ty, src, dst_ty, dst, transfer); + self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer); } fn translate_borrow( @@ -2476,7 +2974,7 @@ impl Compiler<'_, '_> { }; let transfer = self.module.import_resource_transfer_borrow(); - self.translate_resource(src_ty, src, dst_ty, dst, transfer); + self.translate_handle(src_ty.as_u32(), src, dst_ty.as_u32(), dst, transfer); } /// Translates the index `src`, which resides in the table `src_ty`, into @@ -2486,11 +2984,11 @@ impl Compiler<'_, '_> { /// cranelift-generated trampoline to satisfy this import will call. The /// `transfer` function is an imported function which takes the src, src_ty, /// and dst_ty, and returns the dst index. - fn translate_resource( + fn translate_handle( &mut self, - src_ty: TypeResourceTableIndex, + src_ty: u32, src: &Source<'_>, - dst_ty: TypeResourceTableIndex, + dst_ty: u32, dst: &Destination, transfer: FuncIndex, ) { @@ -2499,8 +2997,8 @@ impl Compiler<'_, '_> { Source::Memory(mem) => self.i32_load(mem), Source::Stack(stack) => self.stack_get(stack, ValType::I32), } - self.instruction(I32Const(src_ty.as_u32() as i32)); - self.instruction(I32Const(dst_ty.as_u32() as i32)); + self.instruction(I32Const(src_ty as i32)); + self.instruction(I32Const(dst_ty as i32)); self.instruction(Call(transfer.as_u32())); match dst { Destination::Memory(mem) => self.i32_store(mem), diff --git a/crates/environ/src/trap_encoding.rs b/crates/environ/src/trap_encoding.rs index 0006d3e3ec9a..acb1f04db454 100644 --- a/crates/environ/src/trap_encoding.rs +++ b/crates/environ/src/trap_encoding.rs @@ -88,7 +88,10 @@ pub enum Trap { /// would have violated the reentrance rules of the component model, /// triggering a trap instead. CannotEnterComponent, - // if adding a variant here be sure to update the `check!` macro below + + /// Async-lifted export failed to produce a result by calling `task.return` + /// before returning `STATUS_DONE` and/or after all host tasks completed. + NoAsyncResult, // if adding a variant here be sure to update the `check!` macro below } impl Trap { @@ -124,6 +127,7 @@ impl Trap { AllocationTooLarge CastFailure CannotEnterComponent + NoAsyncResult } None @@ -154,6 +158,7 @@ impl fmt::Display for Trap { AllocationTooLarge => "allocation size too large", CastFailure => "cast failure", CannotEnterComponent => "cannot enter component instance", + NoAsyncResult => "async-lifted export failed to produce a result", }; write!(f, "wasm trap: {desc}") } diff --git a/crates/fuzzing/src/generators/component_types.rs b/crates/fuzzing/src/generators/component_types.rs index b184fa28e7a9..e3df7a2cceb9 100644 --- a/crates/fuzzing/src/generators/component_types.rs +++ b/crates/fuzzing/src/generators/component_types.rs @@ -108,8 +108,10 @@ pub fn arbitrary_val(ty: &component::Type, input: &mut Unstructured) -> arbitrar .collect::>()?, ), - // Resources aren't fuzzed at this time. - Type::Own(_) | Type::Borrow(_) => unreachable!(), + // Resources, futures, streams, and error contexts aren't fuzzed at this time. + Type::Own(_) | Type::Borrow(_) | Type::Future(_) | Type::Stream(_) | Type::ErrorContext => { + unreachable!() + } }) } @@ -120,8 +122,25 @@ pub fn static_api_test<'a, P, R>( declarations: &Declarations, ) -> arbitrary::Result<()> where - P: ComponentNamedList + Lift + Lower + Clone + PartialEq + Debug + Arbitrary<'a> + 'static, - R: ComponentNamedList + Lift + Lower + Clone + PartialEq + Debug + Arbitrary<'a> + 'static, + P: ComponentNamedList + + Lift + + Lower + + Clone + + PartialEq + + Debug + + Arbitrary<'a> + + Send + + 'static, + R: ComponentNamedList + + Lift + + Lower + + Clone + + PartialEq + + Debug + + Arbitrary<'a> + + Send + + Sync + + 'static, { crate::init_fuzzing(); @@ -139,7 +158,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; @@ -149,7 +168,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/misc/component-test-util/src/lib.rs b/crates/misc/component-test-util/src/lib.rs index 07d492b298df..d2804990b855 100644 --- a/crates/misc/component-test-util/src/lib.rs +++ b/crates/misc/component-test-util/src/lib.rs @@ -8,15 +8,23 @@ 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, + R: ComponentNamedList + Lift + Send + Sync + 'static, { - 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) @@ -24,18 +32,18 @@ where } pub trait FuncExt { - fn call_and_post_return( + fn call_and_post_return( &self, - store: impl AsContextMut, + store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()>; } impl FuncExt for Func { - fn call_and_post_return( + fn call_and_post_return( &self, - mut store: impl AsContextMut, + mut store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()> { diff --git a/crates/wasi-config/Cargo.toml b/crates/wasi-config/Cargo.toml index 81bd61ef7184..cadaf77bb7a2 100644 --- a/crates/wasi-config/Cargo.toml +++ b/crates/wasi-config/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] anyhow = { workspace = true } -wasmtime = { workspace = true, features = ["runtime", "component-model"] } +wasmtime = { workspace = true, features = ["runtime", "component-model", "async"] } [dev-dependencies] test-programs-artifacts = { workspace = true } diff --git a/crates/wasi-keyvalue/src/lib.rs b/crates/wasi-keyvalue/src/lib.rs index 4d53a9acf20b..d88b5220aeec 100644 --- a/crates/wasi-keyvalue/src/lib.rs +++ b/crates/wasi-keyvalue/src/lib.rs @@ -75,7 +75,7 @@ mod generated { }, trappable_error_type: { "wasi:keyvalue/store/error" => crate::Error, - }, + } }); } diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 53497575eac2..da38ef5d5feb 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -61,6 +61,7 @@ smallvec = { workspace = true, optional = true } hashbrown = { workspace = true, features = ["ahash"] } libm = "0.2.7" bitflags = { workspace = true } +futures = { workspace = true, features = ["alloc"] } [target.'cfg(target_os = "windows")'.dependencies.windows-sys] workspace = true @@ -364,3 +365,12 @@ wave = ["dep:wasm-wave"] signals-based-traps = [ "dep:wasmtime-jit-icache-coherence", ] + +# Enables support for the Component Model Async ABI, along with `future`, +# `stream`, and `error-context` types. +component-model-async = [ + "async", + "component-model", + "std", + 'wasmtime-component-macro?/component-model-async', +] diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index a99d422d1b4c..97b35ea6015c 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1053,6 +1053,17 @@ impl Config { self } + /// Configures whether components support the async ABI [proposal] for + /// lifting and lowering functions, as well as `stream`, `future`, and + /// `error-context` types. + /// + /// [proposal]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Async.md + #[cfg(feature = "component-model-async")] + pub fn wasm_component_model_async(&mut self, enable: bool) -> &mut Self { + self.wasm_feature(WasmFeatures::COMPONENT_MODEL_ASYNC, enable); + self + } + /// Configures which compilation strategy will be used for wasm modules. /// /// This method can be used to configure which compiler is used for wasm diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs index 84a1b36bb628..8051970917c6 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs @@ -202,6 +202,7 @@ struct WasmFeatures { custom_page_sizes: bool, component_model_more_flags: bool, component_model_multiple_returns: bool, + component_model_async: bool, gc_types: bool, wide_arithmetic: bool, } @@ -231,6 +232,7 @@ impl Metadata<'_> { component_model_nested_names, component_model_more_flags, component_model_multiple_returns, + component_model_async, legacy_exceptions, gc_types, stack_switching, @@ -276,6 +278,7 @@ impl Metadata<'_> { custom_page_sizes, component_model_more_flags, component_model_multiple_returns, + component_model_async, gc_types, wide_arithmetic, }, @@ -486,6 +489,7 @@ impl Metadata<'_> { custom_page_sizes, component_model_more_flags, component_model_multiple_returns, + component_model_async, gc_types, wide_arithmetic, } = self.features; @@ -572,6 +576,11 @@ impl Metadata<'_> { other.contains(F::COMPONENT_MODEL_MULTIPLE_RETURNS), "WebAssembly component model support for multiple returns", )?; + Self::check_bool( + component_model_async, + other.contains(F::COMPONENT_MODEL_ASYNC), + "WebAssembly component model support for async lifts/lowers, futures, streams, and errors", + )?; Self::check_cfg_bool( cfg!(feature = "gc"), "gc", diff --git a/crates/wasmtime/src/runtime/component/component.rs b/crates/wasmtime/src/runtime/component/component.rs index 10af60dc94ec..e0a7afb3a626 100644 --- a/crates/wasmtime/src/runtime/component/component.rs +++ b/crates/wasmtime/src/runtime/component/component.rs @@ -602,6 +602,7 @@ impl Component { GlobalInitializer::LowerImport { .. } | GlobalInitializer::ExtractMemory(_) | GlobalInitializer::ExtractRealloc(_) + | GlobalInitializer::ExtractCallback(_) | GlobalInitializer::ExtractPostReturn(_) | GlobalInitializer::Resource(_) => {} } diff --git a/crates/wasmtime/src/runtime/component/concurrent.rs b/crates/wasmtime/src/runtime/component/concurrent.rs new file mode 100644 index 000000000000..fca6dc6604ea --- /dev/null +++ b/crates/wasmtime/src/runtime/component/concurrent.rs @@ -0,0 +1,2075 @@ +use { + crate::{ + component::func::{self, Func, Lower as _, LowerContext, Options}, + vm::{ + component::{ComponentInstance, VMComponentContext, WaitableState}, + mpk::{self, ProtectionMask}, + AsyncWasmCallState, PreviousAsyncWasmCallState, SendSyncPtr, VMFuncRef, + VMMemoryDefinition, VMOpaqueContext, VMStore, + }, + AsContextMut, CallHook, Engine, StoreContextMut, ValRaw, + }, + anyhow::{anyhow, bail, Context as _, Result}, + futures::{ + channel::oneshot, + future::{self, Either, FutureExt}, + stream::{FuturesUnordered, StreamExt}, + }, + once_cell::sync::Lazy, + ready_chunks::ReadyChunks, + std::{ + any::Any, + borrow::ToOwned, + boxed::Box, + cell::UnsafeCell, + collections::{HashMap, HashSet, VecDeque}, + future::Future, + marker::PhantomData, + mem::{self, MaybeUninit}, + pin::{pin, Pin}, + ptr::{self, NonNull}, + sync::{Arc, Mutex}, + task::{Context, Poll, Wake, Waker}, + vec::Vec, + }, + table::{Table, TableId}, + wasmtime_environ::component::{ + InterfaceType, RuntimeComponentInstanceIndex, StringEncoding, TypeTaskReturnIndex, + MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, + }, + wasmtime_fiber::{Fiber, Suspend}, +}; + +use futures_and_streams::TransmitState; +pub(crate) use futures_and_streams::{ + error_context_debug_message, error_context_drop, error_context_new, flat_stream_read, + flat_stream_write, future_cancel_read, future_cancel_write, future_close_readable, + future_close_writable, future_new, future_read, future_write, stream_cancel_read, + stream_cancel_write, stream_close_readable, stream_close_writable, stream_new, stream_read, + stream_write, +}; +pub use futures_and_streams::{ + future, stream, ErrorContext, FutureReader, FutureWriter, StreamReader, StreamWriter, +}; + +mod futures_and_streams; +mod ready_chunks; +mod table; + +// TODO: The handling of `task.yield` and `task.backpressure` was bolted on late in the implementation and is +// currently haphazard. We need a refactor to manage yielding, backpressure, and event polling and delivery in a +// more unified and structured way. + +// TODO: move these into an enum: +const STATUS_STARTING: u32 = 0; +const STATUS_STARTED: u32 = 1; +const STATUS_RETURNED: u32 = 2; +const STATUS_DONE: u32 = 3; + +mod events { + // TODO: move these into an enum: + pub const _EVENT_CALL_STARTING: u32 = 0; + pub const EVENT_CALL_STARTED: u32 = 1; + pub const EVENT_CALL_RETURNED: u32 = 2; + pub const EVENT_CALL_DONE: u32 = 3; + pub const _EVENT_YIELDED: u32 = 4; + pub const EVENT_STREAM_READ: u32 = 5; + pub const EVENT_STREAM_WRITE: u32 = 6; + pub const EVENT_FUTURE_READ: u32 = 7; + pub const EVENT_FUTURE_WRITE: u32 = 8; +} + +const EXIT_FLAG_ASYNC_CALLER: u32 = 1 << 0; +const EXIT_FLAG_ASYNC_CALLEE: u32 = 1 << 1; + +/// 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>>); + +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))) + } + + /// 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, mut store: impl AsContextMut) -> Result { + Ok(poll_until(store.as_context_mut(), self.0).await?.1) + } + + /// 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 + } +} + +/// 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>>>, +); + +impl PromisesUnordered { + /// Create a new `PromisesUnordered` with no entries. + pub fn new() -> Self { + Self(FuturesUnordered::new()) + } + + /// Add the specified [`Promise`] to this collection. + pub fn push(&mut self, promise: Promise) { + self.0.push(promise.0) + } + + /// Get the next result from this collection, if any. + pub async fn next( + &mut self, + mut store: impl AsContextMut, + ) -> Result> { + Ok(poll_until(store.as_context_mut(), self.0.next()).await?.1) + } +} + +struct HostTaskResult { + event: u32, + param: u32, + caller: TableId, +} + +type HostTaskFuture = Pin< + Box< + dyn Future< + Output = ( + u32, + Box Result + Send + Sync>, + ), + > + Send + + Sync + + 'static, + >, +>; + +struct HostTask { + caller_instance: RuntimeComponentInstanceIndex, +} + +enum Deferred { + None, + Stackful(StoreFiber<'static>), + Stackless { + call: Box Result + Send + Sync + 'static>, + instance: RuntimeComponentInstanceIndex, + callback: SendSyncPtr, + }, +} + +impl Deferred { + fn take_fiber(&mut self) -> Option> { + if let Self::Stackful(_) = self { + let Self::Stackful(fiber) = mem::replace(self, Self::None) else { + unreachable!() + }; + Some(fiber) + } else { + None + } + } +} + +#[derive(Copy, Clone)] +struct Callback { + function: SendSyncPtr, + context: u32, + instance: RuntimeComponentInstanceIndex, +} + +enum Caller { + Host(Option>), + Guest { + task: TableId, + instance: RuntimeComponentInstanceIndex, + }, +} + +struct GuestTask { + lower_params: Option, + lift_result: Option<(RawLift, TypeTaskReturnIndex)>, + result: Option, + callback: Option, + events: VecDeque<(u32, AnyTask, u32)>, + caller: Caller, + deferred: Deferred, + should_yield: bool, +} + +impl Default for GuestTask { + fn default() -> Self { + Self { + lower_params: None, + lift_result: None, + result: None, + callback: None, + events: VecDeque::new(), + caller: Caller::Host(None), + deferred: Deferred::None, + should_yield: false, + } + } +} + +#[derive(Copy, Clone)] +enum AnyTask { + Host(TableId), + Guest(TableId), + Transmit(TableId), +} + +impl AnyTask { + fn rep(&self) -> u32 { + match self { + Self::Host(task) => task.rep(), + Self::Guest(task) => task.rep(), + Self::Transmit(task) => task.rep(), + } + } + + fn delete_all_from(&self, mut store: StoreContextMut) -> Result<()> { + match self { + Self::Host(task) => { + log::trace!("delete host task {}", task.rep()); + store.concurrent_state().table.delete(*task).map(drop) + } + Self::Guest(task) => { + let finished = store + .concurrent_state() + .table + .get(*task)? + .events + .iter() + .filter_map(|(event, call, _)| { + (*event == events::EVENT_CALL_DONE).then_some(*call) + }) + .collect::>(); + + for call in finished { + log::trace!("will delete call {}", call.rep()); + call.delete_all_from(store.as_context_mut())?; + } + + log::trace!("delete guest task {}", task.rep()); + store.concurrent_state().table.delete(*task).map(drop) + } + Self::Transmit(task) => store.concurrent_state().table.delete(*task).map(drop), + }?; + + Ok(()) + } +} + +pub(crate) struct LiftLowerContext { + pub(crate) pointer: *mut u8, + pub(crate) dropper: fn(*mut u8), +} + +unsafe impl Send for LiftLowerContext {} +unsafe impl Sync for LiftLowerContext {} + +impl Drop for LiftLowerContext { + fn drop(&mut self) { + (self.dropper)(self.pointer); + } +} + +type RawLower = + Box]) -> Result<()> + Send + Sync>; + +type LowerFn = fn(LiftLowerContext, *mut dyn VMStore, &mut [MaybeUninit]) -> Result<()>; + +type RawLift = Box< + dyn FnOnce(*mut dyn VMStore, &[ValRaw]) -> Result>> + + Send + + Sync, +>; + +type LiftFn = + fn(LiftLowerContext, *mut dyn VMStore, &[ValRaw]) -> Result>>; + +type LiftedResult = Box; + +struct Reset(*mut T, T); + +impl Drop for Reset { + fn drop(&mut self) { + unsafe { + *self.0 = self.1; + } + } +} + +struct AsyncState { + current_suspend: UnsafeCell< + *mut Suspend< + (Option<*mut dyn VMStore>, Result<()>), + Option<*mut dyn VMStore>, + (Option<*mut dyn VMStore>, Result<()>), + >, + >, + current_poll_cx: UnsafeCell<*mut Context<'static>>, +} + +unsafe impl Send for AsyncState {} +unsafe impl Sync for AsyncState {} + +pub(crate) struct AsyncCx { + current_suspend: *mut *mut wasmtime_fiber::Suspend< + (Option<*mut dyn VMStore>, Result<()>), + Option<*mut dyn VMStore>, + (Option<*mut dyn VMStore>, Result<()>), + >, + current_stack_limit: *mut usize, + current_poll_cx: *mut *mut Context<'static>, + track_pkey_context_switch: bool, +} + +impl AsyncCx { + pub(crate) fn new(store: &mut StoreContextMut) -> Self { + Self { + current_suspend: store.concurrent_state().async_state.current_suspend.get(), + current_stack_limit: store.0.runtime_limits().stack_limit.get(), + current_poll_cx: store.concurrent_state().async_state.current_poll_cx.get(), + track_pkey_context_switch: store.has_pkey(), + } + } + + unsafe fn poll(&self, mut future: Pin<&mut (dyn Future + Send)>) -> Poll { + let poll_cx = *self.current_poll_cx; + let _reset = Reset(self.current_poll_cx, poll_cx); + *self.current_poll_cx = ptr::null_mut(); + assert!(!poll_cx.is_null()); + future.as_mut().poll(&mut *poll_cx) + } + + pub(crate) unsafe fn block_on<'a, T, U>( + &self, + mut future: Pin<&mut (dyn Future + Send)>, + mut store: Option>, + ) -> Result<(U, Option>)> { + loop { + match self.poll(future.as_mut()) { + Poll::Ready(v) => break Ok((v, store)), + Poll::Pending => {} + } + + store = self.suspend(store)?; + } + } + + unsafe fn suspend<'a, T>( + &self, + store: Option>, + ) -> Result>> { + let previous_mask = if self.track_pkey_context_switch { + let previous_mask = mpk::current_mask(); + mpk::allow(ProtectionMask::all()); + previous_mask + } else { + ProtectionMask::all() + }; + let store = suspend_fiber(self.current_suspend, self.current_stack_limit, store); + if self.track_pkey_context_switch { + mpk::allow(previous_mask); + } + store + } +} + +#[derive(Default)] +struct InstanceState { + backpressure: bool, + in_sync_call: bool, + task_queue: VecDeque>, +} + +pub struct ConcurrentState { + guest_task: Option>, + futures: ReadyChunks>, + table: Table, + async_state: AsyncState, + // TODO: this can and should be a `PrimaryMap` + instance_states: HashMap, + yielding: HashSet, + unblocked: HashSet, + component_instance: Option>, + _phantom: PhantomData, +} + +impl Default for ConcurrentState { + fn default() -> Self { + Self { + guest_task: None, + table: Table::new(), + futures: ReadyChunks::new(FuturesUnordered::new(), 1024), + async_state: AsyncState { + current_suspend: UnsafeCell::new(ptr::null_mut()), + current_poll_cx: UnsafeCell::new(ptr::null_mut()), + }, + instance_states: HashMap::new(), + yielding: HashSet::new(), + unblocked: HashSet::new(), + component_instance: None, + _phantom: PhantomData, + } + } +} + +fn dummy_waker() -> Waker { + struct DummyWaker; + + impl Wake for DummyWaker { + fn wake(self: Arc) {} + } + + static WAKER: Lazy> = Lazy::new(|| Arc::new(DummyWaker)); + + WAKER.clone().into() +} + +/// Provide a hint to Rust type inferencer that we're returning a compatible +/// closure from a `LinkerInstance::func_wrap_concurrent` future. +pub fn for_any(fun: F) -> F +where + F: FnOnce(StoreContextMut) -> R + 'static, + R: 'static, +{ + fun +} + +fn for_any_lower< + F: FnOnce(*mut dyn VMStore, &mut [MaybeUninit]) -> Result<()> + Send + Sync, +>( + fun: F, +) -> F { + fun +} + +fn for_any_lift< + F: FnOnce(*mut dyn VMStore, &[ValRaw]) -> Result>> + Send + Sync, +>( + fun: F, +) -> F { + fun +} + +pub(crate) fn first_poll( + instance: *mut ComponentInstance, + mut store: StoreContextMut, + future: impl Future) -> Result + Send + Sync + 'static> + + Send + + Sync + + 'static, + caller_instance: RuntimeComponentInstanceIndex, + lower: impl FnOnce(StoreContextMut, R) -> Result<()> + Send + Sync + 'static, +) -> Result> { + let caller = store.concurrent_state().guest_task.unwrap(); + let task = store + .concurrent_state() + .table + .push_child(HostTask { caller_instance }, caller)?; + log::trace!("new child of {}: {}", caller.rep(), task.rep()); + let mut future = Box::pin(future.map(move |fun| { + ( + task.rep(), + Box::new(move |store: *mut dyn VMStore| { + let mut store = unsafe { StoreContextMut(&mut *store.cast()) }; + let result = fun(store.as_context_mut())?; + lower(store, result)?; + Ok(HostTaskResult { + event: events::EVENT_CALL_DONE, + param: 0u32, + caller, + }) + }) + as Box Result + Send + Sync>, + ) + })) as HostTaskFuture; + + Ok( + match future + .as_mut() + .poll(&mut Context::from_waker(&dummy_waker())) + { + Poll::Ready((_, fun)) => { + log::trace!("delete host task {} (already ready)", task.rep()); + store.concurrent_state().table.delete(task)?; + fun(store.0.traitobj())?; + None + } + Poll::Pending => { + store.concurrent_state().futures.get_mut().push(future); + Some( + unsafe { &mut *instance }.component_waitable_tables()[caller_instance] + .insert(task.rep(), WaitableState::Task)?, + ) + } + }, + ) +} + +pub(crate) fn poll_and_block<'a, T, R: Send + Sync + 'static>( + mut store: StoreContextMut<'a, T>, + future: impl Future) -> Result + Send + Sync + 'static> + + Send + + Sync + + 'static, + caller_instance: RuntimeComponentInstanceIndex, +) -> Result<(R, StoreContextMut<'a, T>)> { + let caller = store.concurrent_state().guest_task.unwrap(); + let old_result = store + .concurrent_state() + .table + .get_mut(caller) + .with_context(|| format!("bad handle: {}", caller.rep()))? + .result + .take(); + let task = store + .concurrent_state() + .table + .push_child(HostTask { caller_instance }, caller)?; + log::trace!("new child of {}: {}", caller.rep(), task.rep()); + let mut future = Box::pin(future.map(move |fun| { + ( + task.rep(), + Box::new(move |store: *mut dyn VMStore| { + let mut store = unsafe { StoreContextMut(&mut *store.cast()) }; + let result = fun(store.as_context_mut())?; + store.concurrent_state().table.get_mut(caller)?.result = + Some(Box::new(result) as _); + Ok(HostTaskResult { + event: events::EVENT_CALL_DONE, + param: 0u32, + caller, + }) + }) + as Box Result + Send + Sync>, + ) + })) as HostTaskFuture; + + Ok( + match unsafe { AsyncCx::new(&mut store).poll(future.as_mut()) } { + Poll::Ready((_, fun)) => { + log::trace!("delete host task {} (already ready)", task.rep()); + store.concurrent_state().table.delete(task)?; + let store = store.0.traitobj(); + fun(store)?; + let mut store = unsafe { StoreContextMut(&mut *store.cast()) }; + let result = *mem::replace( + &mut store.concurrent_state().table.get_mut(caller)?.result, + old_result, + ) + .unwrap() + .downcast() + .unwrap(); + (result, store) + } + Poll::Pending => { + store.concurrent_state().futures.get_mut().push(future); + loop { + if let Some(result) = store + .concurrent_state() + .table + .get_mut(caller)? + .result + .take() + { + store.concurrent_state().table.get_mut(caller)?.result = old_result; + break (*result.downcast().unwrap(), store); + } else { + let async_cx = AsyncCx::new(&mut store); + store = unsafe { async_cx.suspend(Some(store)) }?.unwrap(); + } + } + } + }, + ) +} + +pub(crate) async fn on_fiber<'a, R: Send + Sync + 'static, T: Send>( + mut store: StoreContextMut<'a, T>, + instance: RuntimeComponentInstanceIndex, + func: impl FnOnce(&mut StoreContextMut) -> R + Send, +) -> Result<(R, StoreContextMut<'a, T>)> { + let result = Arc::new(Mutex::new(None)); + let mut fiber = make_fiber(&mut store, instance, { + let result = result.clone(); + move |mut store| { + *result.lock().unwrap() = Some(func(&mut store)); + Ok(()) + } + })?; + + store = poll_fn(store, move |_, mut store| { + match resume_fiber(&mut fiber, store.take(), Ok(())) { + Ok(Ok((store, result))) => Ok(result.map(|()| store)), + Ok(Err(s)) => Err(s), + Err(e) => Ok(Err(e)), + } + }) + .await?; + + let result = result.lock().unwrap().take().unwrap(); + Ok((result, store)) +} + +fn maybe_send_event<'a, T>( + mut store: StoreContextMut<'a, T>, + guest_task: TableId, + event: u32, + call: AnyTask, + result: u32, +) -> Result> { + assert_ne!(guest_task.rep(), call.rep()); + if let Some(callback) = store.concurrent_state().table.get(guest_task)?.callback { + let old_task = store.concurrent_state().guest_task.replace(guest_task); + let Some((handle, _)) = unsafe { + &mut *store + .concurrent_state() + .component_instance + .unwrap() + .as_ptr() + } + .component_waitable_tables()[callback.instance] + .get_mut_by_rep(call.rep()) + else { + bail!("handle not found for waitable rep {}", call.rep()); + }; + log::trace!( + "use callback to deliver event {event} to {} for {} (handle {handle}): {:?} {}", + guest_task.rep(), + call.rep(), + callback.function, + callback.context + ); + let params = &mut [ + ValRaw::u32(callback.context), + ValRaw::u32(event), + ValRaw::u32(handle), + ValRaw::u32(result), + ]; + unsafe { + crate::Func::call_unchecked_raw(&mut store, callback.function.as_non_null(), params)?; + } + let done = params[0].get_u32() != 0; + log::trace!("{} done? {done}", guest_task.rep()); + if done { + store.concurrent_state().table.get_mut(guest_task)?.callback = None; + + match &store.concurrent_state().table.get(guest_task)?.caller { + Caller::Guest { task, .. } => { + let task = *task; + store = maybe_send_event( + store, + task, + events::EVENT_CALL_DONE, + AnyTask::Guest(guest_task), + 0, + )?; + } + Caller::Host(_) => { + log::trace!("maybe_send_event will delete {}", call.rep()); + AnyTask::Guest(guest_task).delete_all_from(store.as_context_mut())?; + } + } + } + store.concurrent_state().guest_task = old_task; + Ok(store) + } else { + store + .concurrent_state() + .table + .get_mut(guest_task)? + .events + .push_back((event, call, result)); + + let resumed = if event == events::EVENT_CALL_DONE { + if let Some(fiber) = store + .concurrent_state() + .table + .get_mut(guest_task)? + .deferred + .take_fiber() + { + log::trace!( + "use fiber to deliver event {event} to {} for {}", + guest_task.rep(), + call.rep() + ); + let old_task = store.concurrent_state().guest_task.replace(guest_task); + store = resume_stackful(store, guest_task, fiber)?; + store.concurrent_state().guest_task = old_task; + true + } else { + false + } + } else { + false + }; + + if !resumed { + log::trace!( + "queue event {event} to {} for {}", + guest_task.rep(), + call.rep() + ); + } + + Ok(store) + } +} + +fn resume_stackful<'a, T>( + mut store: StoreContextMut<'a, T>, + guest_task: TableId, + mut fiber: StoreFiber<'static>, +) -> Result> { + match resume_fiber(&mut fiber, Some(store), Ok(()))? { + Ok((mut store, result)) => { + result?; + store = maybe_resume_next_task(store, fiber.instance)?; + for (event, call, _) in mem::take( + &mut store + .concurrent_state() + .table + .get_mut(guest_task) + .with_context(|| format!("bad handle: {}", guest_task.rep()))? + .events, + ) { + if event == events::EVENT_CALL_DONE { + log::trace!("resume_stackful will delete call {}", call.rep()); + call.delete_all_from(store.as_context_mut())?; + } + } + match &store.concurrent_state().table.get(guest_task)?.caller { + Caller::Host(_) => { + log::trace!("resume_stackful will delete task {}", guest_task.rep()); + AnyTask::Guest(guest_task).delete_all_from(store.as_context_mut())?; + Ok(store) + } + Caller::Guest { task, .. } => { + let task = *task; + maybe_send_event( + store, + task, + events::EVENT_CALL_DONE, + AnyTask::Guest(guest_task), + 0, + ) + } + } + } + Err(new_store) => { + store = new_store.unwrap(); + store.concurrent_state().table.get_mut(guest_task)?.deferred = + Deferred::Stackful(fiber); + Ok(store) + } + } +} + +fn resume_stackless<'a, T>( + store: StoreContextMut<'a, T>, + guest_task: TableId, + call: Box Result>, + instance: RuntimeComponentInstanceIndex, + callback: SendSyncPtr, +) -> Result> { + let store = store.0.traitobj(); + let guest_context = call(store)?; + let mut store = unsafe { StoreContextMut(&mut *store.cast()) }; + + let task = store.concurrent_state().table.get_mut(guest_task)?; + let event = if task.lift_result.is_some() { + events::EVENT_CALL_STARTED + } else if guest_context != 0 { + events::EVENT_CALL_RETURNED + } else { + events::EVENT_CALL_DONE + }; + if guest_context != 0 { + log::trace!("set callback for {}", guest_task.rep()); + task.callback = Some(Callback { + function: callback, + instance, + context: guest_context, + }); + for (event, call, result) in mem::take(&mut task.events) { + store = maybe_send_event(store, guest_task, event, call, result)?; + } + } + store = maybe_resume_next_task(store, instance)?; + if let Caller::Guest { task, .. } = &store.concurrent_state().table.get(guest_task)?.caller { + let task = *task; + maybe_send_event(store, task, event, AnyTask::Guest(guest_task), 0) + } else { + Ok(store) + } +} + +fn poll_for_result<'a, T>(mut store: StoreContextMut<'a, T>) -> Result> { + let task = store.concurrent_state().guest_task; + poll_loop(store, move |store| { + task.map(|task| { + Ok::<_, anyhow::Error>(store.concurrent_state().table.get(task)?.result.is_none()) + }) + .unwrap_or(Ok(true)) + }) +} + +fn handle_ready<'a, T>( + mut store: StoreContextMut<'a, T>, + ready: Vec<( + u32, + Box Result + Send + Sync>, + )>, +) -> Result> { + for (task, fun) in ready { + let vm_store = store.0.traitobj(); + let result = fun(vm_store)?; + store = unsafe { StoreContextMut::(&mut *vm_store.cast()) }; + let task = match result.event { + events::EVENT_CALL_DONE => AnyTask::Host(TableId::::new(task)), + events::EVENT_STREAM_READ + | events::EVENT_FUTURE_READ + | events::EVENT_STREAM_WRITE + | events::EVENT_FUTURE_WRITE => AnyTask::Transmit(TableId::::new(task)), + _ => unreachable!(), + }; + store = maybe_send_event(store, result.caller, result.event, task, result.param)?; + } + Ok(store) +} + +fn maybe_yield<'a, T>(mut store: StoreContextMut<'a, T>) -> Result> { + let guest_task = store.concurrent_state().guest_task.unwrap(); + + if store.concurrent_state().table.get(guest_task)?.should_yield { + log::trace!("maybe_yield suspend {}", guest_task.rep()); + + store.concurrent_state().yielding.insert(guest_task.rep()); + let cx = AsyncCx::new(&mut store); + store = unsafe { cx.suspend(Some(store)) }?.unwrap(); + + log::trace!("maybe_yield resume {}", guest_task.rep()); + } else { + log::trace!("maybe_yield skip {}", guest_task.rep()); + } + + Ok(store) +} + +fn unyield<'a, T>(mut store: StoreContextMut<'a, T>) -> Result<(StoreContextMut<'a, T>, bool)> { + let mut resumed = false; + for task in mem::take(&mut store.concurrent_state().yielding) { + let guest_task = TableId::::new(task); + if let Some(fiber) = store + .concurrent_state() + .table + .get_mut(guest_task)? + .deferred + .take_fiber() + { + resumed = true; + let old_task = store.concurrent_state().guest_task.replace(guest_task); + store = resume_stackful(store, guest_task, fiber)?; + store.concurrent_state().guest_task = old_task; + } + } + + for instance in mem::take(&mut store.concurrent_state().unblocked) { + let entry = store + .concurrent_state() + .instance_states + .entry(instance) + .or_default(); + + if !(entry.backpressure || entry.in_sync_call) { + if let Some(task) = entry.task_queue.pop_front() { + resumed = true; + store = resume(store, task)?; + } + } + } + + Ok((store, resumed)) +} + +fn poll_loop<'a, T>( + mut store: StoreContextMut<'a, T>, + mut continue_: impl FnMut(&mut StoreContextMut<'a, T>) -> Result, +) -> Result> { + loop { + let cx = AsyncCx::new(&mut store); + let mut future = pin!(store.concurrent_state().futures.next()); + let ready = unsafe { cx.poll(future.as_mut()) }; + + match ready { + Poll::Ready(Some(ready)) => { + store = handle_ready(store, ready)?; + } + Poll::Ready(None) => { + let (s, resumed) = unyield(store)?; + store = s; + if !resumed { + log::trace!("exhausted future queue; exiting poll_loop"); + break; + } + } + Poll::Pending => { + let (s, resumed) = unyield(store)?; + store = s; + if continue_(&mut store)? { + let cx = AsyncCx::new(&mut store); + store = unsafe { cx.suspend(Some(store)) }?.unwrap(); + } else if !resumed { + break; + } + } + } + } + + Ok(store) +} + +fn resume<'a, T>( + mut store: StoreContextMut<'a, T>, + task: TableId, +) -> Result> { + log::trace!("resume {}", task.rep()); + + // TODO: Avoid calling `resume_stackful` or `resume_stackless` here, because it may call us, leading to + // recursion limited only by the number of waiters. Flatten this into an iteration instead. + let old_task = store.concurrent_state().guest_task.replace(task); + store = match mem::replace( + &mut store.concurrent_state().table.get_mut(task)?.deferred, + Deferred::None, + ) { + Deferred::None => unreachable!(), + Deferred::Stackful(fiber) => resume_stackful(store, task, fiber), + Deferred::Stackless { + call, + instance, + callback, + } => resume_stackless(store, task, call, instance, callback), + }?; + store.concurrent_state().guest_task = old_task; + Ok(store) +} + +fn maybe_resume_next_task<'a, T>( + mut store: StoreContextMut<'a, T>, + instance: RuntimeComponentInstanceIndex, +) -> Result> { + let state = store + .concurrent_state() + .instance_states + .get_mut(&instance) + .unwrap(); + + if state.backpressure || state.in_sync_call { + Ok(store) + } else { + if let Some(next) = state.task_queue.pop_front() { + resume(store, next) + } else { + Ok(store) + } + } +} + +struct StoreFiber<'a> { + fiber: Option< + Fiber< + 'a, + (Option<*mut dyn VMStore>, Result<()>), + Option<*mut dyn VMStore>, + (Option<*mut dyn VMStore>, Result<()>), + >, + >, + state: Option, + engine: Engine, + suspend: *mut *mut Suspend< + (Option<*mut dyn VMStore>, Result<()>), + Option<*mut dyn VMStore>, + (Option<*mut dyn VMStore>, Result<()>), + >, + stack_limit: *mut usize, + instance: RuntimeComponentInstanceIndex, +} + +impl<'a> Drop for StoreFiber<'a> { + fn drop(&mut self) { + if !self.fiber.as_ref().unwrap().done() { + let result = unsafe { resume_fiber_raw(self, None, Err(anyhow!("future dropped"))) }; + debug_assert!(result.is_ok()); + } + + self.state.take().unwrap().assert_null(); + + unsafe { + self.engine + .allocator() + .deallocate_fiber_stack(self.fiber.take().unwrap().into_stack()); + } + } +} + +unsafe impl<'a> Send for StoreFiber<'a> {} +unsafe impl<'a> Sync for StoreFiber<'a> {} + +fn make_fiber<'a, T>( + store: &mut StoreContextMut, + instance: RuntimeComponentInstanceIndex, + fun: impl FnOnce(StoreContextMut) -> Result<()> + 'a, +) -> Result> { + let engine = store.engine().clone(); + let stack = engine.allocator().allocate_fiber_stack()?; + Ok(StoreFiber { + fiber: Some(Fiber::new( + stack, + move |(store_ptr, result): (Option<*mut dyn VMStore>, Result<()>), suspend| { + if result.is_err() { + (store_ptr, result) + } else { + unsafe { + let store_ptr = store_ptr.unwrap(); + let mut store = StoreContextMut(&mut *store_ptr.cast()); + let suspend_ptr = + store.concurrent_state().async_state.current_suspend.get(); + let _reset = Reset(suspend_ptr, *suspend_ptr); + *suspend_ptr = suspend; + (Some(store_ptr), fun(store.as_context_mut())) + } + } + }, + )?), + state: Some(AsyncWasmCallState::new()), + engine, + suspend: store.concurrent_state().async_state.current_suspend.get(), + stack_limit: store.0.runtime_limits().stack_limit.get(), + instance, + }) +} + +unsafe fn resume_fiber_raw<'a>( + fiber: *mut StoreFiber<'a>, + store: Option<*mut dyn VMStore>, + result: Result<()>, +) -> Result<(Option<*mut dyn VMStore>, Result<()>), Option<*mut dyn VMStore>> { + struct Restore<'a> { + fiber: *mut StoreFiber<'a>, + state: Option, + } + + impl Drop for Restore<'_> { + fn drop(&mut self) { + unsafe { + (*self.fiber).state = Some(self.state.take().unwrap().restore()); + } + } + } + + let _reset_suspend = Reset((*fiber).suspend, *(*fiber).suspend); + let _reset_stack_limit = Reset((*fiber).stack_limit, *(*fiber).stack_limit); + let state = Some((*fiber).state.take().unwrap().push()); + let restore = Restore { fiber, state }; + (*restore.fiber) + .fiber + .as_ref() + .unwrap() + .resume((store, result)) +} + +fn poll_ready<'a, T>(mut store: StoreContextMut<'a, T>) -> Result> { + unsafe { + let cx = *store.concurrent_state().async_state.current_poll_cx.get(); + assert!(!cx.is_null()); + while let Poll::Ready(Some(ready)) = + store.concurrent_state().futures.poll_next_unpin(&mut *cx) + { + match handle_ready(store, ready) { + Ok(s) => { + store = s; + } + Err(e) => { + return Err(e); + } + } + } + } + Ok(store) +} + +fn resume_fiber<'a, T>( + fiber: &mut StoreFiber, + mut store: Option>, + result: Result<()>, +) -> Result, Result<()>), Option>>> { + if let Some(s) = store.take() { + store = Some(poll_ready(s)?); + } + + unsafe { + match resume_fiber_raw(fiber, store.map(|s| s.0.traitobj()), result) + .map(|(store, result)| (StoreContextMut(&mut *store.unwrap().cast()), result)) + .map_err(|v| v.map(|v| StoreContextMut(&mut *v.cast()))) + { + Ok(pair) => Ok(Ok(pair)), + Err(s) => { + if let Some(range) = fiber.fiber.as_ref().unwrap().stack().range() { + AsyncWasmCallState::assert_current_state_not_in_range(range); + } + + Ok(Err(s)) + } + } + } +} + +unsafe fn suspend_fiber<'a, T>( + suspend: *mut *mut Suspend< + (Option<*mut dyn VMStore>, Result<()>), + Option<*mut dyn VMStore>, + (Option<*mut dyn VMStore>, Result<()>), + >, + stack_limit: *mut usize, + store: Option>, +) -> Result>> { + let _reset_suspend = Reset(suspend, *suspend); + let _reset_stack_limit = Reset(stack_limit, *stack_limit); + let (store, result) = (**suspend).suspend(store.map(|s| s.0.traitobj())); + result?; + Ok(store.map(|v| StoreContextMut(&mut *v.cast()))) +} + +enum TaskCheck { + Wait(*mut VMMemoryDefinition, u32, RuntimeComponentInstanceIndex), + Poll(*mut VMMemoryDefinition, u32, RuntimeComponentInstanceIndex), + Yield, +} + +unsafe fn task_check(cx: *mut VMOpaqueContext, async_: bool, check: TaskCheck) -> Result { + if async_ { + bail!("todo: async `task.wait`, `task.poll`, and `task.yield` not yet implemented"); + } + + let cx = VMComponentContext::from_opaque(cx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + + let guest_task = cx.concurrent_state().guest_task.unwrap(); + + log::trace!("task check for {}", guest_task.rep()); + + let wait = matches!(check, TaskCheck::Wait(..)); + + if wait + && cx + .concurrent_state() + .table + .get(guest_task)? + .callback + .is_some() + { + bail!("cannot call `task.wait` from async-lifted export with callback"); + } + + if matches!(check, TaskCheck::Yield) + || cx + .concurrent_state() + .table + .get(guest_task)? + .events + .is_empty() + { + cx = maybe_yield(cx)?; + + if cx + .concurrent_state() + .table + .get(guest_task)? + .events + .is_empty() + { + cx = poll_loop(cx, move |cx| { + Ok::<_, anyhow::Error>( + wait && cx + .concurrent_state() + .table + .get(guest_task)? + .events + .is_empty(), + ) + })?; + } + } + + log::trace!("task check for {}, part two", guest_task.rep()); + + let result = match check { + TaskCheck::Wait(memory, payload, caller_instance) => { + let (event, call, result) = cx + .concurrent_state() + .table + .get_mut(guest_task)? + .events + .pop_front() + .ok_or_else(|| anyhow!("no tasks to wait for"))?; + + log::trace!( + "deliver event {event} via task.wait to {} for {}", + guest_task.rep(), + call.rep() + ); + + let Some((handle, _)) = + (*instance).component_waitable_tables()[caller_instance].get_mut_by_rep(call.rep()) + else { + bail!("handle not found for waitable rep {}", call.rep()); + }; + + let options = Options::new( + cx.0.id(), + NonNull::new(memory), + None, + StringEncoding::Utf8, + true, + None, + ); + let types = (*instance).component_types(); + let ptr = + func::validate_inbounds::(options.memory_mut(cx.0), &ValRaw::u32(payload))?; + let mut lower = LowerContext::new(cx, &options, types, instance); + handle.store(&mut lower, InterfaceType::U32, ptr)?; + result.store(&mut lower, InterfaceType::U32, ptr + 4)?; + + Ok(event) + } + TaskCheck::Poll(memory, payload, caller_instance) => { + if let Some((event, call, result)) = cx + .concurrent_state() + .table + .get_mut(guest_task)? + .events + .pop_front() + { + log::trace!( + "deliver event {event} via task.poll to {} for {}", + guest_task.rep(), + call.rep() + ); + + let Some((handle, _)) = (*instance).component_waitable_tables()[caller_instance] + .get_mut_by_rep(call.rep()) + else { + bail!("handle not found for waitable rep {}", call.rep()); + }; + + let options = Options::new( + cx.0.id(), + NonNull::new(memory), + None, + StringEncoding::Utf8, + true, + None, + ); + let types = (*instance).component_types(); + let ptr = func::validate_inbounds::<(u32, u32)>( + options.memory_mut(cx.0), + &ValRaw::u32(payload), + )?; + let mut lower = LowerContext::new(cx, &options, types, instance); + event.store(&mut lower, InterfaceType::U32, ptr)?; + handle.store(&mut lower, InterfaceType::U32, ptr + 4)?; + result.store(&mut lower, InterfaceType::U32, ptr + 8)?; + + Ok(1) + } else { + log::trace!( + "no events ready to deliver via task.poll to {}", + guest_task.rep() + ); + + Ok(0) + } + } + TaskCheck::Yield => Ok(0), + }; + + result +} + +unsafe fn call_host_and_handle_result( + cx: *mut VMOpaqueContext, + func: impl FnOnce() -> Result, +) -> R::Abi { + let cx = VMComponentContext::from_opaque(cx); + let instance = (*cx).instance(); + let raw_store = (*instance).store(); + let store = StoreContextMut::(&mut *raw_store.cast()); + + crate::runtime::vm::catch_unwind_and_record_trap(|| { + store.0.call_hook(CallHook::CallingHost)?; + let res = func(); + store.0.call_hook(CallHook::ReturningFromHost)?; + res + }) +} + +pub(crate) extern "C" fn task_backpressure( + cx: *mut VMOpaqueContext, + caller_instance: RuntimeComponentInstanceIndex, + enabled: u32, +) -> bool { + unsafe { + call_host_and_handle_result::(cx, || { + let cx = VMComponentContext::from_opaque(cx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + let entry = cx + .concurrent_state() + .instance_states + .entry(caller_instance) + .or_default(); + let old = entry.backpressure; + let new = enabled != 0; + entry.backpressure = new; + + if old && !new && !entry.task_queue.is_empty() { + cx.concurrent_state().unblocked.insert(caller_instance); + } + + Ok(()) + }) + } +} + +pub(crate) extern "C" fn task_return( + cx: *mut VMOpaqueContext, + ty: TypeTaskReturnIndex, + storage: *mut MaybeUninit, + storage_len: usize, +) -> bool { + unsafe { + call_host_and_handle_result::(cx, || { + let storage = std::slice::from_raw_parts(storage, storage_len); + let cx = VMComponentContext::from_opaque(cx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + let guest_task = cx.concurrent_state().guest_task.unwrap(); + let (lift, lift_ty) = cx + .concurrent_state() + .table + .get_mut(guest_task)? + .lift_result + .take() + .ok_or_else(|| anyhow!("`task.return` called more than once"))?; + + if ty != lift_ty { + bail!("invalid `task.return` signature for current task"); + } + + assert!(cx + .concurrent_state() + .table + .get(guest_task)? + .result + .is_none()); + + let cx = cx.0.traitobj(); + let result = lift( + cx, + mem::transmute::<&[MaybeUninit], &[ValRaw]>(storage), + )?; + + let mut cx = StoreContextMut::(&mut *cx.cast()); + if let Caller::Host(tx) = &mut cx.concurrent_state().table.get_mut(guest_task)?.caller { + _ = tx.take().unwrap().send(result.unwrap()); + } else { + cx.concurrent_state().table.get_mut(guest_task)?.result = result; + } + + Ok(()) + }) + } +} + +pub(crate) extern "C" fn task_wait( + cx: *mut VMOpaqueContext, + caller_instance: RuntimeComponentInstanceIndex, + async_: bool, + memory: *mut VMMemoryDefinition, + payload: u32, +) -> u64 { + unsafe { + call_host_and_handle_result::(cx, || { + task_check::( + cx, + async_, + TaskCheck::Wait(memory, payload, caller_instance), + ) + }) + } +} + +pub(crate) extern "C" fn task_poll( + cx: *mut VMOpaqueContext, + caller_instance: RuntimeComponentInstanceIndex, + async_: bool, + memory: *mut VMMemoryDefinition, + payload: u32, +) -> u64 { + unsafe { + call_host_and_handle_result::(cx, || { + task_check::( + cx, + async_, + TaskCheck::Poll(memory, payload, caller_instance), + ) + }) + } +} + +pub(crate) extern "C" fn task_yield(cx: *mut VMOpaqueContext, async_: bool) -> bool { + unsafe { + call_host_and_handle_result::(cx, || { + task_check::(cx, async_, TaskCheck::Yield)?; + Ok(()) + }) + } +} + +pub(crate) extern "C" fn subtask_drop( + cx: *mut VMOpaqueContext, + caller_instance: RuntimeComponentInstanceIndex, + task_id: u32, +) -> bool { + unsafe { + call_host_and_handle_result::(cx, || { + let cx = VMComponentContext::from_opaque(cx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + let (rep, WaitableState::Task) = (*instance).component_waitable_tables() + [caller_instance] + .remove_by_index(task_id)? + else { + bail!("invalid task handle: {task_id}"); + }; + let table = &mut cx.concurrent_state().table; + log::trace!("subtask_drop delete {rep}"); + let task = table.delete_any(rep)?; + let expected_caller_instance = match task.downcast::() { + Ok(task) => task.caller_instance, + Err(task) => match task.downcast::() { + Ok(task) => { + if let Caller::Guest { instance, .. } = task.caller { + instance + } else { + unreachable!() + } + } + Err(_) => unreachable!(), + }, + }; + assert_eq!(expected_caller_instance, caller_instance); + Ok(()) + }) + } +} + +pub(crate) extern "C" fn async_enter( + cx: *mut VMOpaqueContext, + start: *mut VMFuncRef, + return_: *mut VMFuncRef, + caller_instance: RuntimeComponentInstanceIndex, + task_return_type: TypeTaskReturnIndex, + params: u32, + results: u32, +) -> bool { + unsafe { + call_host_and_handle_result::(cx, || { + let cx = VMComponentContext::from_opaque(cx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + let start = SendSyncPtr::new(NonNull::new(start).unwrap()); + let return_ = SendSyncPtr::new(NonNull::new(return_).unwrap()); + let old_task = cx.concurrent_state().guest_task.take(); + let old_task_rep = old_task.map(|v| v.rep()); + let new_task = GuestTask { + lower_params: Some(Box::new(move |cx, dst| { + let mut cx = StoreContextMut::(&mut *cx.cast()); + assert!(dst.len() <= MAX_FLAT_PARAMS); + let mut src = [MaybeUninit::uninit(); MAX_FLAT_PARAMS]; + src[0] = MaybeUninit::new(ValRaw::u32(params)); + crate::Func::call_unchecked_raw( + &mut cx, + start.as_non_null(), + &mut src[..1.max(dst.len())] as *mut [MaybeUninit] as _, + )?; + dst.copy_from_slice(&src[..dst.len()]); + let task = cx.concurrent_state().guest_task.unwrap(); + if let Some(rep) = old_task_rep { + maybe_send_event( + cx, + TableId::new(rep), + events::EVENT_CALL_STARTED, + AnyTask::Guest(task), + 0, + )?; + } + Ok(()) + })), + lift_result: Some(( + Box::new(move |cx, src| { + let mut cx = StoreContextMut::(&mut *cx.cast()); + let mut my_src = src.to_owned(); // TODO: use stack to avoid allocation? + my_src.push(ValRaw::u32(results)); + crate::Func::call_unchecked_raw( + &mut cx, + return_.as_non_null(), + my_src.as_mut_slice(), + )?; + let task = cx.concurrent_state().guest_task.unwrap(); + if let Some(rep) = old_task_rep { + maybe_send_event( + cx, + TableId::new(rep), + events::EVENT_CALL_RETURNED, + AnyTask::Guest(task), + 0, + )?; + } + Ok(None) + }), + task_return_type, + )), + result: None, + callback: None, + caller: Caller::Guest { + task: old_task.unwrap(), + instance: caller_instance, + }, + deferred: Deferred::None, + events: VecDeque::new(), + should_yield: false, + }; + let guest_task = if let Some(old_task) = old_task { + let child = cx.concurrent_state().table.push_child(new_task, old_task)?; + log::trace!("new child of {}: {}", old_task.rep(), child.rep()); + child + } else { + cx.concurrent_state().table.push(new_task)? + }; + + cx.concurrent_state().guest_task = Some(guest_task); + + Ok(()) + }) + } +} + +fn make_call( + guest_task: TableId, + callee: SendSyncPtr, + param_count: usize, + result_count: usize, +) -> impl FnOnce( + StoreContextMut, +) -> Result<([MaybeUninit; MAX_FLAT_PARAMS], StoreContextMut)> + + Send + + Sync + + 'static { + move |mut cx: StoreContextMut| { + let mut storage = [MaybeUninit::uninit(); MAX_FLAT_PARAMS]; + let lower = cx + .concurrent_state() + .table + .get_mut(guest_task)? + .lower_params + .take() + .unwrap(); + let cx = cx.0.traitobj(); + lower(cx, &mut storage[..param_count])?; + let mut cx = unsafe { StoreContextMut::(&mut *cx.cast()) }; + + unsafe { + crate::Func::call_unchecked_raw( + &mut cx, + callee.as_non_null(), + &mut storage[..param_count.max(result_count)] as *mut [MaybeUninit] as _, + )?; + } + + Ok((storage, cx)) + } +} + +fn do_start_call<'a, T>( + mut cx: StoreContextMut<'a, T>, + guest_task: TableId, + async_: bool, + call: impl FnOnce( + StoreContextMut, + ) -> Result<([MaybeUninit; MAX_FLAT_PARAMS], StoreContextMut)> + + Send + + Sync + + 'static, + callback: Option>, + callee_instance: RuntimeComponentInstanceIndex, + result_count: usize, +) -> Result<(u32, StoreContextMut<'a, T>)> { + let state = &mut cx + .concurrent_state() + .instance_states + .entry(callee_instance) + .or_default(); + let ready = state.task_queue.is_empty() && !(state.backpressure || state.in_sync_call); + + let mut guest_context = 0; + + let mut cx = if let Some(callback) = callback { + assert!(async_); + + if ready { + let (storage, cx) = call(cx)?; + guest_context = unsafe { storage[0].assume_init() }.get_i32() as u32; + cx + } else { + cx.concurrent_state() + .instance_states + .get_mut(&callee_instance) + .unwrap() + .task_queue + .push_back(guest_task); + + cx.concurrent_state().table.get_mut(guest_task)?.deferred = Deferred::Stackless { + call: Box::new(move |cx| { + let mut cx = unsafe { StoreContextMut(&mut *cx.cast()) }; + let old_task = cx.concurrent_state().guest_task.replace(guest_task); + let (storage, mut cx) = call(cx)?; + cx.concurrent_state().guest_task = old_task; + Ok(unsafe { storage[0].assume_init() }.get_i32() as u32) + }), + instance: callee_instance, + callback, + }; + cx + } + } else { + let mut fiber = make_fiber(&mut cx, callee_instance, move |mut cx| { + if !async_ { + cx.concurrent_state() + .instance_states + .get_mut(&callee_instance) + .unwrap() + .in_sync_call = true; + } + + let (storage, mut cx) = call(cx)?; + + if !async_ { + cx.concurrent_state() + .instance_states + .get_mut(&callee_instance) + .unwrap() + .in_sync_call = false; + + let (lift, _) = cx + .concurrent_state() + .table + .get_mut(guest_task)? + .lift_result + .take() + .unwrap(); + + assert!(cx + .concurrent_state() + .table + .get(guest_task)? + .result + .is_none()); + + let cx = cx.0.traitobj(); + let result = lift(cx, unsafe { + mem::transmute::<&[MaybeUninit], &[ValRaw]>(&storage[..result_count]) + })?; + let mut cx = unsafe { StoreContextMut::(&mut *cx.cast()) }; + + // TODO: call post_return if necessary + + if let Caller::Host(tx) = + &mut cx.concurrent_state().table.get_mut(guest_task)?.caller + { + _ = tx.take().unwrap().send(result.unwrap()); + } else { + cx.concurrent_state().table.get_mut(guest_task)?.result = result; + } + } + + Ok(()) + })?; + + cx.concurrent_state() + .table + .get_mut(guest_task)? + .should_yield = true; + + if ready { + let mut cx = Some(cx); + loop { + match resume_fiber(&mut fiber, cx.take(), Ok(()))? { + Ok((cx, result)) => { + result?; + break maybe_resume_next_task(cx, callee_instance)?; + } + Err(cx) => { + if let Some(mut cx) = cx { + cx.concurrent_state().table.get_mut(guest_task)?.deferred = + Deferred::Stackful(fiber); + break cx; + } else { + unsafe { suspend_fiber::(fiber.suspend, fiber.stack_limit, None)? }; + } + } + } + } + } else { + cx.concurrent_state() + .instance_states + .get_mut(&callee_instance) + .unwrap() + .task_queue + .push_back(guest_task); + + cx.concurrent_state().table.get_mut(guest_task)?.deferred = Deferred::Stackful(fiber); + cx + } + }; + + let guest_task = cx.concurrent_state().guest_task.take().unwrap(); + + let caller = + if let Caller::Guest { task, .. } = &cx.concurrent_state().table.get(guest_task)?.caller { + Some(*task) + } else { + None + }; + cx.concurrent_state().guest_task = caller; + + let task = cx.concurrent_state().table.get_mut(guest_task)?; + + if guest_context != 0 { + log::trace!("set callback for {}", guest_task.rep()); + task.callback = Some(Callback { + function: callback.unwrap(), + instance: callee_instance, + context: guest_context, + }); + for (event, call, result) in mem::take(&mut task.events) { + cx = maybe_send_event(cx, guest_task, event, call, result)?; + } + } + + Ok((guest_context, cx)) +} + +pub(crate) extern "C" fn async_exit( + cx: *mut VMOpaqueContext, + callback: *mut VMFuncRef, + caller_instance: RuntimeComponentInstanceIndex, + callee: *mut VMFuncRef, + callee_instance: RuntimeComponentInstanceIndex, + param_count: u32, + result_count: u32, + flags: u32, +) -> u64 { + unsafe { + call_host_and_handle_result::(cx, || { + let cx = VMComponentContext::from_opaque(cx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + + let guest_task = cx.concurrent_state().guest_task.unwrap(); + let callee = SendSyncPtr::new(NonNull::new(callee).unwrap()); + let param_count = usize::try_from(param_count).unwrap(); + assert!(param_count <= MAX_FLAT_PARAMS); + let result_count = usize::try_from(result_count).unwrap(); + assert!(result_count <= MAX_FLAT_RESULTS); + + let call = make_call(guest_task, callee, param_count, result_count); + + let (guest_context, new_cx) = do_start_call( + cx, + guest_task, + (flags & EXIT_FLAG_ASYNC_CALLEE) != 0, + call, + NonNull::new(callback).map(SendSyncPtr::new), + callee_instance, + result_count, + )?; + + cx = new_cx; + + let task = cx.concurrent_state().table.get(guest_task)?; + + let mut status = if task.lower_params.is_some() { + STATUS_STARTING + } else if task.lift_result.is_some() { + STATUS_STARTED + } else if guest_context != 0 || callback.is_null() { + STATUS_RETURNED + } else { + STATUS_DONE + }; + + let call = if status != STATUS_DONE { + if (flags & EXIT_FLAG_ASYNC_CALLER) != 0 { + (*instance).component_waitable_tables()[caller_instance] + .insert(guest_task.rep(), WaitableState::Task)? + } else { + poll_for_result(cx)?; + status = STATUS_DONE; + 0 + } + } else { + 0 + }; + + Ok((status << 30) | call) + }) + } +} + +pub(crate) fn start_call<'a, T: Send, LowerParams: Copy, R: 'static>( + mut store: StoreContextMut<'a, T>, + lower_params: LowerFn, + lower_context: LiftLowerContext, + lift_result: LiftFn, + lift_context: LiftLowerContext, + handle: Func, +) -> Result<(Promise, StoreContextMut<'a, T>)> { + // TODO: Check to see if the callee is using the memory64 ABI, in which case we must use task_return_type64. + // How do we check that? + let func_data = &store.0[handle.0]; + let task_return_type = func_data.types[func_data.ty].task_return_type32; + let is_concurrent = func_data.options.async_(); + let instance = func_data.component_instance; + let callee = func_data.export.func_ref; + let callback = func_data.options.callback; + + assert!(store.concurrent_state().guest_task.is_none()); + + // TODO: Can we safely leave this set? Can the same store be used with more than one ComponentInstance? Could + // we instead set this when the ConcurrentState is created so we don't have to set/unset it on the fly? + store.concurrent_state().component_instance = Some( + store.0[store.0[handle.0].instance.0] + .as_ref() + .unwrap() + .state + .ptr, + ); + + let (tx, rx) = oneshot::channel(); + + let guest_task = store.concurrent_state().table.push(GuestTask { + lower_params: Some(Box::new(for_any_lower(move |store, params| { + lower_params(lower_context, store, params) + })) as RawLower), + lift_result: Some(( + Box::new(for_any_lift(move |store, result| { + lift_result(lift_context, store, result) + })) as RawLift, + task_return_type, + )), + caller: Caller::Host(Some(tx)), + ..GuestTask::default() + })?; + + log::trace!("starting call {}", guest_task.rep()); + + let call = make_call( + guest_task, + SendSyncPtr::new(callee), + mem::size_of::() / mem::size_of::(), + 1, + ); + + store.concurrent_state().guest_task = Some(guest_task); + + store = do_start_call( + store, + guest_task, + is_concurrent, + call, + callback.map(SendSyncPtr::new), + instance, + 1, + )? + .1; + + store.concurrent_state().guest_task = None; + + log::trace!("started call {}", guest_task.rep()); + + Ok(( + Promise(Box::pin( + rx.map(|result| *result.unwrap().downcast().unwrap()), + )), + store, + )) +} + +pub(crate) fn call<'a, T: Send, LowerParams: Copy, R: 'static>( + store: StoreContextMut<'a, T>, + lower_params: LowerFn, + lower_context: LiftLowerContext, + lift_result: LiftFn, + lift_context: LiftLowerContext, + handle: Func, +) -> Result<(R, StoreContextMut<'a, T>)> { + let (promise, mut store) = start_call::<_, LowerParams, R>( + store, + lower_params, + lower_context, + lift_result, + lift_context, + handle, + )?; + + let mut future = promise.into_future(); + let result = Arc::new(Mutex::new(None)); + store = poll_loop(store, { + let result = result.clone(); + move |store| { + let cx = AsyncCx::new(store); + let ready = unsafe { cx.poll(future.as_mut()) }; + Ok(match ready { + Poll::Ready(value) => { + *result.lock().unwrap() = Some(value); + false + } + Poll::Pending => true, + }) + } + })?; + + let result = result.lock().unwrap().take(); + if let Some(result) = result { + Ok((result, store)) + } else { + // All outstanding host tasks completed, but the guest never yielded a result. + Err(anyhow!(crate::Trap::NoAsyncResult)) + } +} + +pub(crate) async fn poll_until<'a, T: Send, U>( + mut store: StoreContextMut<'a, T>, + future: impl Future, +) -> Result<(StoreContextMut<'a, T>, U)> { + let mut future = Box::pin(future); + loop { + loop { + let mut ready = pin!(store.concurrent_state().futures.next()); + + let mut ready = future::poll_fn({ + move |cx| { + Poll::Ready(match ready.as_mut().poll(cx) { + Poll::Ready(Some(value)) => Some(value), + Poll::Ready(None) | Poll::Pending => None, + }) + } + }) + .await; + + if ready.is_some() { + store = poll_fn(store, move |_, mut store| { + Ok(handle_ready(store.take().unwrap(), ready.take().unwrap())) + }) + .await?; + } else { + let (s, resumed) = poll_fn(store, move |_, mut store| { + Ok(unyield(store.take().unwrap())) + }) + .await?; + store = s; + if !resumed { + break; + } + } + } + + let ready = pin!(store.concurrent_state().futures.next()); + + match future::select(ready, future).await { + Either::Left((None, future_again)) => break Ok((store, future_again.await)), + Either::Left((Some(ready), future_again)) => { + let mut ready = Some(ready); + store = poll_fn(store, move |_, mut store| { + Ok(handle_ready(store.take().unwrap(), ready.take().unwrap())) + }) + .await?; + future = future_again; + } + Either::Right((result, _)) => break Ok((store, result)), + } + } +} + +async fn poll_fn<'a, T, R>( + mut store: StoreContextMut<'a, T>, + mut fun: impl FnMut( + &mut Context, + Option>, + ) -> Result>>, +) -> R { + #[derive(Clone, Copy)] + struct PollCx(*mut *mut Context<'static>); + + unsafe impl Send for PollCx {} + + let poll_cx = PollCx(store.concurrent_state().async_state.current_poll_cx.get()); + future::poll_fn({ + let mut store = Some(store); + + move |cx| unsafe { + let _reset = Reset(poll_cx.0, *poll_cx.0); + *poll_cx.0 = mem::transmute::<&mut Context<'_>, *mut Context<'static>>(cx); + #[allow(dropping_copy_types)] + drop(poll_cx); + + match fun(cx, store.take()) { + Ok(v) => Poll::Ready(v), + Err(s) => { + store = s; + Poll::Pending + } + } + } + }) + .await +} diff --git a/crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs b/crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs new file mode 100644 index 000000000000..e57e257b9027 --- /dev/null +++ b/crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs @@ -0,0 +1,2007 @@ +use { + super::{ + call_host_and_handle_result, events, table::TableId, GuestTask, HostTaskFuture, + HostTaskResult, Promise, + }, + crate::{ + component::{ + func::{self, LiftContext, LowerContext, Options}, + matching::InstanceType, + values::{ErrorContextAny, FutureAny, StreamAny}, + Val, WasmList, + }, + vm::{ + component::{ + ComponentInstance, StateTable, StreamFutureState, VMComponentContext, WaitableState, + }, + SendSyncPtr, VMFuncRef, VMMemoryDefinition, VMOpaqueContext, VMStore, + }, + AsContextMut, StoreContextMut, + }, + anyhow::{anyhow, bail, Context, Result}, + futures::{ + channel::oneshot, + future::{self, FutureExt}, + }, + std::{ + any::Any, + boxed::Box, + marker::PhantomData, + mem::{self, MaybeUninit}, + ptr::NonNull, + string::ToString, + sync::Arc, + vec::Vec, + }, + wasmtime_environ::component::{ + CanonicalAbiInfo, ComponentTypes, InterfaceType, StringEncoding, + TypeErrorContextTableIndex, TypeFutureTableIndex, TypeStreamTableIndex, + }, +}; + +// TODO: add `validate_inbounds` calls where appropriate + +const BLOCKED: usize = 0xffff_ffff; +const CLOSED: usize = 0x8000_0000; + +#[derive(Copy, Clone, Debug)] +enum TableIndex { + Stream(TypeStreamTableIndex), + Future(TypeFutureTableIndex), +} + +fn payload(ty: TableIndex, types: &Arc) -> Option { + match ty { + TableIndex::Future(ty) => types[types[ty].ty].payload, + TableIndex::Stream(ty) => Some(types[types[ty].ty].payload), + } +} + +fn state_table(instance: &mut ComponentInstance, ty: TableIndex) -> &mut StateTable { + let runtime_instance = match ty { + TableIndex::Stream(ty) => instance.component_types()[ty].instance, + TableIndex::Future(ty) => instance.component_types()[ty].instance, + }; + &mut instance.component_waitable_tables()[runtime_instance] +} + +fn push_event( + mut store: StoreContextMut, + rep: u32, + event: u32, + param: usize, + caller: TableId, +) { + store + .concurrent_state() + .futures + .get_mut() + .push(Box::pin(future::ready(( + rep, + Box::new(move |_| { + Ok(HostTaskResult { + event, + param: u32::try_from(param).unwrap(), + caller, + }) + }) + as Box Result + Send + Sync>, + ))) as HostTaskFuture); +} + +fn get_mut_by_index( + instance: &mut ComponentInstance, + ty: TableIndex, + index: u32, +) -> Result<(u32, &mut StreamFutureState)> { + get_mut_by_index_from(state_table(instance, ty), ty, index) +} + +fn get_mut_by_index_from( + state_table: &mut StateTable, + ty: TableIndex, + index: u32, +) -> Result<(u32, &mut StreamFutureState)> { + Ok(match ty { + TableIndex::Stream(ty) => { + let (rep, WaitableState::Stream(actual_ty, state)) = + state_table.get_mut_by_index(index)? + else { + bail!("invalid stream handle"); + }; + if *actual_ty != ty { + bail!("invalid stream handle"); + } + (rep, state) + } + TableIndex::Future(ty) => { + let (rep, WaitableState::Future(actual_ty, state)) = + state_table.get_mut_by_index(index)? + else { + bail!("invalid future handle"); + }; + if *actual_ty != ty { + bail!("invalid future handle"); + } + (rep, state) + } + }) +} + +fn waitable_state(ty: TableIndex, state: StreamFutureState) -> WaitableState { + match ty { + TableIndex::Stream(ty) => WaitableState::Stream(ty, state), + TableIndex::Future(ty) => WaitableState::Future(ty, state), + } +} + +fn accept( + values: Vec, + mut offset: usize, + transmit_id: TableId, + tx: oneshot::Sender<()>, +) -> impl FnOnce(Reader) -> Result + Send + Sync + 'static { + move |reader| { + let count = match reader { + Reader::Guest { + lower: + RawLowerContext { + store, + options, + types, + instance, + }, + ty, + address, + count, + } => { + let mut store = unsafe { StoreContextMut::(&mut *store.cast()) }; + let lower = &mut unsafe { + LowerContext::new(store.as_context_mut(), options, types, instance) + }; + let count = values.len().min(usize::try_from(count).unwrap()); + if let Some(ty) = payload(ty, types) { + T::store_list(lower, ty, address, &values[offset..][..count])?; + } + offset += count; + + if offset < values.len() { + let transmit = store.concurrent_state().table.get_mut(transmit_id)?; + assert!(matches!(&transmit.write, WriteState::Open)); + + transmit.write = WriteState::HostReady { + accept: Box::new(accept::(values, offset, transmit_id, tx)), + close: false, + }; + } + + count + } + Reader::Host { accept } => { + assert!(offset == 0); // todo: do we need to handle offset != 0? + let count = values.len(); + accept(Box::new(values))?; + + count + } + Reader::None => 0, + }; + + Ok(count) + } +} + +fn host_write>( + mut store: S, + rep: u32, + values: Vec, + mut close: bool, +) -> Result> { + let mut store = store.as_context_mut(); + let (tx, rx) = oneshot::channel(); + let transmit_id = TableId::::new(rep); + let mut offset = 0; + + loop { + let transmit = store + .concurrent_state() + .table + .get_mut(transmit_id) + .with_context(|| rep.to_string())?; + let new_state = if let ReadState::Closed = &transmit.read { + ReadState::Closed + } else { + ReadState::Open + }; + + match mem::replace(&mut transmit.read, new_state) { + ReadState::Open => { + assert!(matches!(&transmit.write, WriteState::Open)); + + transmit.write = WriteState::HostReady { + accept: Box::new(accept::(values, offset, transmit_id, tx)), + close, + }; + close = false; + } + + ReadState::GuestReady { + ty, + flat_abi: _, + options, + address, + count, + instance, + handle, + caller, + } => unsafe { + let types = (*instance.as_ptr()).component_types(); + let lower = &mut LowerContext::new( + store.as_context_mut(), + &options, + types, + instance.as_ptr(), + ); + let count = values.len().min(count); + if let Some(ty) = payload(ty, types) { + T::store_list(lower, ty, address, &values[offset..][..count])?; + } + offset += count; + + log::trace!( + "remove read child of {}: {}", + caller.rep(), + transmit_id.rep() + ); + store + .concurrent_state() + .table + .remove_child(transmit_id, caller)?; + + *get_mut_by_index(&mut *instance.as_ptr(), ty, handle)?.1 = StreamFutureState::Read; + + push_event( + store.as_context_mut(), + transmit_id.rep(), + match ty { + TableIndex::Future(_) => events::EVENT_FUTURE_READ, + TableIndex::Stream(_) => events::EVENT_STREAM_READ, + }, + count, + caller, + ); + + if offset < values.len() { + continue; + } + }, + + ReadState::HostReady { accept } => { + accept(Writer::Host { + values: Box::new(values), + })?; + } + + ReadState::Closed => {} + } + + if close { + host_close_writer(store, rep)?; + } + + break Ok(rx); + } +} + +pub fn host_read>( + mut store: S, + rep: u32, +) -> Result>>> { + let mut store = store.as_context_mut(); + let (tx, rx) = oneshot::channel(); + let transmit_id = TableId::::new(rep); + let transmit = store + .concurrent_state() + .table + .get_mut(transmit_id) + .with_context(|| rep.to_string())?; + let new_state = if let WriteState::Closed = &transmit.write { + WriteState::Closed + } else { + WriteState::Open + }; + + match mem::replace(&mut transmit.write, new_state) { + WriteState::Open => { + assert!(matches!(&transmit.read, ReadState::Open)); + + transmit.read = ReadState::HostReady { + accept: Box::new(move |writer| { + Ok(match writer { + Writer::Guest { + lift, + ty, + address, + count, + } => { + _ = tx.send( + ty.map(|ty| { + let list = &WasmList::new(address, count, lift, ty)?; + T::load_list(lift, list) + }) + .transpose()?, + ); + count + } + Writer::Host { values } => { + let values = *values + .downcast::>() + .map_err(|_| anyhow!("transmit type mismatch"))?; + let count = values.len(); + _ = tx.send(Some(values)); + count + } + Writer::None => 0, + }) + }), + }; + } + + WriteState::GuestReady { + ty, + flat_abi: _, + options, + address, + count, + instance, + handle, + caller, + close, + } => unsafe { + let types = (*instance.as_ptr()).component_types(); + let lift = &mut LiftContext::new(store.0, &options, types, instance.as_ptr()); + _ = tx.send( + payload(ty, types) + .map(|ty| { + let list = &WasmList::new(address, count, lift, ty)?; + T::load_list(lift, list) + }) + .transpose()?, + ); + + log::trace!( + "remove write child of {}: {}", + caller.rep(), + transmit_id.rep() + ); + store + .concurrent_state() + .table + .remove_child(transmit_id, caller)?; + + if close { + store.concurrent_state().table.get_mut(transmit_id)?.write = WriteState::Closed; + } else { + *get_mut_by_index(&mut *instance.as_ptr(), ty, handle)?.1 = + StreamFutureState::Write; + } + + push_event( + store, + transmit_id.rep(), + match ty { + TableIndex::Future(_) => events::EVENT_FUTURE_WRITE, + TableIndex::Stream(_) => events::EVENT_STREAM_WRITE, + }, + count, + caller, + ); + }, + + WriteState::HostReady { accept, close } => { + accept(Reader::Host { + accept: Box::new(move |any| { + _ = tx.send(Some( + *any.downcast() + .map_err(|_| anyhow!("transmit type mismatch"))?, + )); + Ok(()) + }), + })?; + + if close { + store.concurrent_state().table.get_mut(transmit_id)?.write = WriteState::Closed; + } + } + + WriteState::Closed => { + host_close_reader(store, rep)?; + } + } + + Ok(rx) +} + +fn host_cancel_write>(mut store: S, rep: u32) -> Result { + let mut store = store.as_context_mut(); + let transmit_id = TableId::::new(rep); + let transmit = store.concurrent_state().table.get_mut(transmit_id)?; + + match &transmit.write { + WriteState::GuestReady { caller, .. } => { + let caller = *caller; + transmit.write = WriteState::Open; + store + .concurrent_state() + .table + .remove_child(transmit_id, caller)?; + } + + WriteState::HostReady { .. } => { + transmit.write = WriteState::Open; + } + + WriteState::Open | WriteState::Closed => { + bail!("stream or future write canceled when no write is pending") + } + } + + log::trace!("canceled write {rep}"); + + Ok(0) +} + +fn host_cancel_read>(mut store: S, rep: u32) -> Result { + let mut store = store.as_context_mut(); + let transmit_id = TableId::::new(rep); + let transmit = store.concurrent_state().table.get_mut(transmit_id)?; + + match &transmit.read { + ReadState::GuestReady { caller, .. } => { + let caller = *caller; + transmit.read = ReadState::Open; + store + .concurrent_state() + .table + .remove_child(transmit_id, caller)?; + } + + ReadState::HostReady { .. } => { + transmit.read = ReadState::Open; + } + + ReadState::Open | ReadState::Closed => { + bail!("stream or future read canceled when no read is pending") + } + } + + log::trace!("canceled read {rep}"); + + Ok(0) +} + +fn host_close_writer>(mut store: S, rep: u32) -> Result<()> { + let mut store = store.as_context_mut(); + let transmit_id = TableId::::new(rep); + let transmit = store.concurrent_state().table.get_mut(transmit_id)?; + + match &mut transmit.write { + WriteState::GuestReady { close, .. } => { + *close = true; + } + + WriteState::HostReady { close, .. } => { + *close = true; + } + + v @ WriteState::Open => { + *v = WriteState::Closed; + } + + WriteState::Closed => unreachable!(), + } + + let new_state = if let ReadState::Closed = &transmit.read { + ReadState::Closed + } else { + ReadState::Open + }; + + match mem::replace(&mut transmit.read, new_state) { + ReadState::GuestReady { + ty, + instance, + handle, + caller, + .. + } => unsafe { + push_event( + store, + transmit_id.rep(), + match ty { + TableIndex::Future(_) => events::EVENT_FUTURE_READ, + TableIndex::Stream(_) => events::EVENT_STREAM_READ, + }, + CLOSED, + caller, + ); + + *get_mut_by_index(&mut *instance.as_ptr(), ty, handle)?.1 = StreamFutureState::Read; + }, + + ReadState::HostReady { accept } => { + accept(Writer::None)?; + + host_close_reader(store, rep)?; + } + + ReadState::Open => {} + + ReadState::Closed => { + log::trace!("host_close_writer delete {}", transmit_id.rep()); + store.concurrent_state().table.delete(transmit_id)?; + } + } + Ok(()) +} + +fn host_close_reader>(mut store: S, rep: u32) -> Result<()> { + let mut store = store.as_context_mut(); + let transmit_id = TableId::::new(rep); + let transmit = store.concurrent_state().table.get_mut(transmit_id)?; + + transmit.read = ReadState::Closed; + + let new_state = if let WriteState::Closed = &transmit.write { + WriteState::Closed + } else { + WriteState::Open + }; + + match mem::replace(&mut transmit.write, new_state) { + WriteState::GuestReady { + ty, + instance, + handle, + close, + caller, + .. + } => unsafe { + push_event( + store.as_context_mut(), + transmit_id.rep(), + match ty { + TableIndex::Future(_) => events::EVENT_FUTURE_WRITE, + TableIndex::Stream(_) => events::EVENT_STREAM_WRITE, + }, + CLOSED, + caller, + ); + + if close { + store.concurrent_state().table.delete(transmit_id)?; + } else { + *get_mut_by_index(&mut *instance.as_ptr(), ty, handle)?.1 = + StreamFutureState::Write; + } + }, + + WriteState::HostReady { accept, close } => { + accept(Reader::None)?; + + if close { + store.concurrent_state().table.delete(transmit_id)?; + } + } + + WriteState::Open => {} + + WriteState::Closed => { + log::trace!("host_close_reader delete {}", transmit_id.rep()); + store.concurrent_state().table.delete(transmit_id)?; + } + } + Ok(()) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct FlatAbi { + size: u32, + align: u32, +} + +/// Represents the writable end of a Component Model `future`. +pub struct FutureWriter { + rep: u32, + _phantom: PhantomData, +} + +impl FutureWriter { + /// Write the specified value to this `future`. + pub fn write>(self, store: S, value: T) -> Result> + where + T: func::Lower + Send + Sync + 'static, + { + Ok(Promise(Box::pin( + host_write(store, self.rep, vec![value], true)?.map(drop), + ))) + } + + /// Close this object without writing a value. + /// + /// If this object is dropped without calling either this method or `write`, + /// any read on the readable end will remain pending forever. + pub fn close>(self, store: S) -> Result<()> { + host_close_writer(store, self.rep) + } +} + +/// Represents the readable end of a Component Model `future`. +pub struct FutureReader { + rep: u32, + _phantom: PhantomData, +} + +impl FutureReader { + pub(crate) fn new(rep: u32) -> Self { + Self { + rep, + _phantom: PhantomData, + } + } + + /// Read the value from this `future`. + pub fn read>(self, store: S) -> Result>> + where + T: func::Lift + Sync + Send + 'static, + { + Ok(Promise(Box::pin(host_read(store, self.rep)?.map(|v| { + v.ok() + .and_then(|v| v.map(|v| v.into_iter().next().unwrap())) + })))) + } + + /// Convert this `FutureReader` into a [`Val`]. + pub fn into_val(self) -> Val { + Val::Future(FutureAny(self.rep)) + } + + /// Attempt to convert the specified [`Val`] to a `FutureReader`. + pub fn from_val>(mut store: S, value: &Val) -> Result { + let Val::Future(FutureAny(rep)) = value else { + bail!("expected `future`; got `{}`", value.desc()); + }; + store + .as_context_mut() + .concurrent_state() + .table + .get(TableId::::new(*rep))?; + Ok(Self::new(*rep)) + } + + fn lower_to_index(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType) -> Result { + match ty { + InterfaceType::Future(dst) => { + state_table(unsafe { &mut *cx.instance }, TableIndex::Future(dst)).insert( + self.rep, + WaitableState::Future(dst, StreamFutureState::Read), + ) + } + _ => func::bad_type_info(), + } + } + + fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result { + match ty { + InterfaceType::Future(src) => { + let state_table = + state_table(unsafe { &mut *cx.instance }, TableIndex::Future(src)); + let (rep, state) = + get_mut_by_index_from(state_table, TableIndex::Future(src), index)?; + + match state { + StreamFutureState::Local => { + *state = StreamFutureState::Write; + } + StreamFutureState::Read => { + state_table.remove_by_index(index)?; + } + StreamFutureState::Write => bail!("cannot transfer write end of future"), + StreamFutureState::Busy => bail!("cannot transfer busy future"), + } + + Ok(Self { + rep, + _phantom: PhantomData, + }) + } + _ => func::bad_type_info(), + } + } + + /// Close this object without reading the value. + /// + /// If this object is dropped without calling either this method or `read`, + /// any write on the writable end will remain pending forever. + pub fn close>(self, store: S) -> Result<()> { + host_close_reader(store, self.rep) + } +} + +unsafe impl func::ComponentType for FutureReader { + const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4; + + type Lower = ::Lower; + + fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> { + match ty { + InterfaceType::Future(_) => Ok(()), + other => bail!("expected `future`, found `{}`", func::desc(other)), + } + } +} + +unsafe impl func::Lower for FutureReader { + fn lower( + &self, + cx: &mut LowerContext<'_, U>, + ty: InterfaceType, + dst: &mut MaybeUninit, + ) -> Result<()> { + self.lower_to_index(cx, ty)? + .lower(cx, InterfaceType::U32, dst) + } + + fn store( + &self, + cx: &mut LowerContext<'_, U>, + ty: InterfaceType, + offset: usize, + ) -> Result<()> { + self.lower_to_index(cx, ty)? + .store(cx, InterfaceType::U32, offset) + } +} + +unsafe impl func::Lift for FutureReader { + fn lift(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result { + let index = u32::lift(cx, InterfaceType::U32, src)?; + Self::lift_from_index(cx, ty, index) + } + + fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result { + let index = u32::load(cx, InterfaceType::U32, bytes)?; + Self::lift_from_index(cx, ty, index) + } +} + +/// Create a new Component Model `future` as pair of writable and readable ends, +/// the latter of which may be passed to guest code. +pub fn future>( + mut store: S, +) -> Result<(FutureWriter, FutureReader)> { + let mut store = store.as_context_mut(); + let transmit = store.concurrent_state().table.push(TransmitState { + read: ReadState::Open, + write: WriteState::Open, + })?; + + Ok(( + FutureWriter { + rep: transmit.rep(), + _phantom: PhantomData, + }, + FutureReader { + rep: transmit.rep(), + _phantom: PhantomData, + }, + )) +} + +/// Represents the writable end of a Component Model `stream`. +pub struct StreamWriter { + rep: u32, + _phantom: PhantomData, +} + +impl StreamWriter { + /// Write the specified values to the `stream`. + pub fn write>( + self, + store: S, + values: Vec, + ) -> Result>> + where + T: func::Lower + Send + Sync + 'static, + { + Ok(Promise(Box::pin( + host_write(store, self.rep, values, false)?.map(move |_| self), + ))) + } + + /// Close this object without writing any more values. + /// + /// If this object is dropped without calling this method, any read on the + /// readable end will remain pending forever. + pub fn close>(self, store: S) -> Result<()> { + host_close_writer(store, self.rep) + } +} + +/// Represents the readable end of a Component Model `stream`. +pub struct StreamReader { + rep: u32, + _phantom: PhantomData, +} + +impl StreamReader { + pub(crate) fn new(rep: u32) -> Self { + Self { + rep, + _phantom: PhantomData, + } + } + + /// Read the next values (if any) from this `stream`. + pub fn read>( + self, + store: S, + ) -> Result, Vec)>>> + where + T: func::Lift + Sync + Send + 'static, + { + Ok(Promise(Box::pin( + host_read(store, self.rep)?.map(move |v| v.ok().and_then(|v| v.map(|v| (self, v)))), + ))) + } + + /// Convert this `StreamReader` into a [`Val`]. + pub fn into_val(self) -> Val { + Val::Stream(StreamAny(self.rep)) + } + + /// Attempt to convert the specified [`Val`] to a `StreamReader`. + pub fn from_val>(mut store: S, value: &Val) -> Result { + let Val::Stream(StreamAny(rep)) = value else { + bail!("expected `stream`; got `{}`", value.desc()); + }; + store + .as_context_mut() + .concurrent_state() + .table + .get(TableId::::new(*rep))?; + Ok(Self::new(*rep)) + } + + fn lower_to_index(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType) -> Result { + match ty { + InterfaceType::Stream(dst) => { + state_table(unsafe { &mut *cx.instance }, TableIndex::Stream(dst)).insert( + self.rep, + WaitableState::Stream(dst, StreamFutureState::Read), + ) + } + _ => func::bad_type_info(), + } + } + + fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result { + match ty { + InterfaceType::Stream(src) => { + let state_table = + state_table(unsafe { &mut *cx.instance }, TableIndex::Stream(src)); + let (rep, state) = + get_mut_by_index_from(state_table, TableIndex::Stream(src), index)?; + + match state { + StreamFutureState::Local => { + *state = StreamFutureState::Write; + } + StreamFutureState::Read => { + state_table.remove_by_index(index)?; + } + StreamFutureState::Write => bail!("cannot transfer write end of stream"), + StreamFutureState::Busy => bail!("cannot transfer busy stream"), + } + + Ok(Self { + rep, + _phantom: PhantomData, + }) + } + _ => func::bad_type_info(), + } + } + + /// Close this object without reading any more values. + /// + /// If the object is dropped without either calling this method or reading + /// until the end of the stream, any write on the writable end will remain + /// pending forever. + pub fn close>(self, store: S) -> Result<()> { + host_close_reader(store, self.rep) + } +} + +unsafe impl func::ComponentType for StreamReader { + const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4; + + type Lower = ::Lower; + + fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> { + match ty { + InterfaceType::Stream(_) => Ok(()), + other => bail!("expected `stream`, found `{}`", func::desc(other)), + } + } +} + +unsafe impl func::Lower for StreamReader { + fn lower( + &self, + cx: &mut LowerContext<'_, U>, + ty: InterfaceType, + dst: &mut MaybeUninit, + ) -> Result<()> { + self.lower_to_index(cx, ty)? + .lower(cx, InterfaceType::U32, dst) + } + + fn store( + &self, + cx: &mut LowerContext<'_, U>, + ty: InterfaceType, + offset: usize, + ) -> Result<()> { + self.lower_to_index(cx, ty)? + .store(cx, InterfaceType::U32, offset) + } +} + +unsafe impl func::Lift for StreamReader { + fn lift(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result { + let index = u32::lift(cx, InterfaceType::U32, src)?; + Self::lift_from_index(cx, ty, index) + } + + fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result { + let index = u32::load(cx, InterfaceType::U32, bytes)?; + Self::lift_from_index(cx, ty, index) + } +} + +/// Create a new Component Model `stream` as pair of writable and readable ends, +/// the latter of which may be passed to guest code. +pub fn stream>( + mut store: S, +) -> Result<(StreamWriter, StreamReader)> { + let mut store = store.as_context_mut(); + let transmit = store.concurrent_state().table.push(TransmitState { + read: ReadState::Open, + write: WriteState::Open, + })?; + + Ok(( + StreamWriter { + rep: transmit.rep(), + _phantom: PhantomData, + }, + StreamReader { + rep: transmit.rep(), + _phantom: PhantomData, + }, + )) +} + +/// Represents a Component Model `error-context`. +pub struct ErrorContext { + rep: u32, +} + +impl ErrorContext { + pub(crate) fn new(rep: u32) -> Self { + Self { rep } + } + + /// Convert this `ErrorContext` into a [`Val`]. + pub fn into_val(self) -> Val { + Val::ErrorContext(ErrorContextAny(self.rep)) + } + + /// Attempt to convert the specified [`Val`] to a `ErrorContext`. + pub fn from_val>(_: S, value: &Val) -> Result { + let Val::ErrorContext(ErrorContextAny(rep)) = value else { + bail!("expected `error-context`; got `{}`", value.desc()); + }; + Ok(Self::new(*rep)) + } + + fn lower_to_index(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType) -> Result { + match ty { + InterfaceType::ErrorContext(dst) => { + let dst = unsafe { &mut (*cx.instance).component_error_context_tables()[dst] }; + + if let Some((dst_idx, dst_state)) = dst.get_mut_by_rep(self.rep) { + *dst_state += 1; + Ok(dst_idx) + } else { + dst.insert(self.rep, 1) + } + } + _ => func::bad_type_info(), + } + } + + fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result { + match ty { + InterfaceType::ErrorContext(src) => { + let (rep, _) = unsafe { + (*cx.instance).component_error_context_tables()[src].get_mut_by_index(index)? + }; + + Ok(Self { rep }) + } + _ => func::bad_type_info(), + } + } +} + +unsafe impl func::ComponentType for ErrorContext { + const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4; + + type Lower = ::Lower; + + fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> { + match ty { + InterfaceType::ErrorContext(_) => Ok(()), + other => bail!("expected `error`, found `{}`", func::desc(other)), + } + } +} + +unsafe impl func::Lower for ErrorContext { + fn lower( + &self, + cx: &mut LowerContext<'_, T>, + ty: InterfaceType, + dst: &mut MaybeUninit, + ) -> Result<()> { + self.lower_to_index(cx, ty)? + .lower(cx, InterfaceType::U32, dst) + } + + fn store( + &self, + cx: &mut LowerContext<'_, T>, + ty: InterfaceType, + offset: usize, + ) -> Result<()> { + self.lower_to_index(cx, ty)? + .store(cx, InterfaceType::U32, offset) + } +} + +unsafe impl func::Lift for ErrorContext { + fn lift(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result { + let index = u32::lift(cx, InterfaceType::U32, src)?; + Self::lift_from_index(cx, ty, index) + } + + fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result { + let index = u32::load(cx, InterfaceType::U32, bytes)?; + Self::lift_from_index(cx, ty, index) + } +} + +pub(super) struct TransmitState { + write: WriteState, + read: ReadState, +} + +enum WriteState { + Open, + GuestReady { + ty: TableIndex, + flat_abi: Option, + options: Options, + address: usize, + count: usize, + instance: SendSyncPtr, + handle: u32, + caller: TableId, + close: bool, + }, + HostReady { + accept: Box Result + Send + Sync>, + close: bool, + }, + Closed, +} + +enum ReadState { + Open, + GuestReady { + ty: TableIndex, + flat_abi: Option, + options: Options, + address: usize, + count: usize, + instance: SendSyncPtr, + handle: u32, + caller: TableId, + }, + HostReady { + accept: Box Result + Send + Sync>, + }, + Closed, +} + +enum Writer<'a> { + Guest { + lift: &'a mut LiftContext<'a>, + ty: Option, + address: usize, + count: usize, + }, + Host { + values: Box, + }, + None, +} + +struct RawLowerContext<'a> { + store: *mut dyn VMStore, + options: &'a Options, + types: &'a Arc, + instance: *mut ComponentInstance, +} + +enum Reader<'a> { + Guest { + lower: RawLowerContext<'a>, + ty: TableIndex, + address: usize, + count: usize, + }, + Host { + accept: Box) -> Result<()>>, + }, + None, +} + +fn guest_new(vmctx: *mut VMOpaqueContext, ty: TableIndex) -> u64 { + unsafe { + call_host_and_handle_result::(vmctx, || { + let cx = VMComponentContext::from_opaque(vmctx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + let transmit = cx.concurrent_state().table.push(TransmitState { + read: ReadState::Open, + write: WriteState::Open, + })?; + state_table(&mut *instance, ty) + .insert(transmit.rep(), waitable_state(ty, StreamFutureState::Local)) + }) + } +} + +unsafe fn copy( + mut cx: StoreContextMut<'_, T>, + types: &Arc, + instance: *mut ComponentInstance, + flat_abi: Option, + write_ty: TableIndex, + write_options: &Options, + write_address: usize, + read_ty: TableIndex, + read_options: &Options, + read_address: usize, + count: usize, + rep: u32, +) -> Result<()> { + match (write_ty, read_ty) { + (TableIndex::Future(write_ty), TableIndex::Future(read_ty)) => { + assert_eq!(count, 1); + + let val = types[types[write_ty].ty] + .payload + .map(|ty| { + let lift = &mut LiftContext::new(cx.0, write_options, types, instance); + Val::load( + lift, + ty, + &lift.memory()[usize::try_from(write_address).unwrap()..] + [..usize::try_from(types.canonical_abi(&ty).size32).unwrap()], + ) + }) + .transpose()?; + + let mut lower = LowerContext::new(cx.as_context_mut(), read_options, types, instance); + if let Some(val) = val { + val.store( + &mut lower, + types[types[read_ty].ty].payload.unwrap(), + usize::try_from(read_address).unwrap(), + )?; + } + } + (TableIndex::Stream(write_ty), TableIndex::Stream(read_ty)) => { + let lift = &mut LiftContext::new(cx.0, write_options, types, instance); + if let Some(flat_abi) = flat_abi { + // Fast path memcpy for "flat" (i.e. no pointers or handles) payloads: + let length_in_bytes = usize::try_from(flat_abi.size).unwrap() * count; + + { + let src = + write_options.memory(cx.0)[write_address..][..length_in_bytes].as_ptr(); + let dst = read_options.memory_mut(cx.0)[read_address..][..length_in_bytes] + .as_mut_ptr(); + src.copy_to(dst, length_in_bytes); + } + } else { + let ty = types[types[write_ty].ty].payload; + let abi = lift.types.canonical_abi(&ty); + let size = usize::try_from(abi.size32).unwrap(); + let values = (0..count) + .map(|index| { + Val::load( + lift, + ty, + &lift.memory()[write_address + (index * size)..][..size], + ) + }) + .collect::>>()?; + + log::trace!("copy values {values:?} for {rep}"); + + let lower = + &mut LowerContext::new(cx.as_context_mut(), read_options, types, instance); + let mut ptr = read_address; + let ty = types[types[read_ty].ty].payload; + let abi = lower.types.canonical_abi(&ty); + let size = usize::try_from(abi.size32).unwrap(); + for value in values { + value.store(lower, ty, ptr)?; + ptr += size + } + } + } + _ => unreachable!(), + } + + Ok(()) +} + +fn guest_write( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TableIndex, + flat_abi: Option, + handle: u32, + address: u32, + count: u32, +) -> u64 { + unsafe { + call_host_and_handle_result::(vmctx, || { + let address = usize::try_from(address).unwrap(); + let count = usize::try_from(count).unwrap(); + let cx = VMComponentContext::from_opaque(vmctx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + let options = Options::new( + cx.0.id(), + NonNull::new(memory), + NonNull::new(realloc), + StringEncoding::from_u8(string_encoding).unwrap(), + true, + None, + ); + let types = (*instance).component_types(); + let (rep, state) = get_mut_by_index(&mut *instance, ty, handle)?; + let StreamFutureState::Write = *state else { + bail!("invalid handle"); + }; + *state = StreamFutureState::Busy; + let transmit_id = TableId::::new(rep); + let transmit = cx.concurrent_state().table.get_mut(transmit_id)?; + let new_state = if let ReadState::Closed = &transmit.read { + ReadState::Closed + } else { + ReadState::Open + }; + + let result = match mem::replace(&mut transmit.read, new_state) { + ReadState::GuestReady { + ty: read_ty, + flat_abi: read_flat_abi, + options: read_options, + address: read_address, + count: read_count, + instance: _, + handle: read_handle, + caller: read_caller, + } => { + assert_eq!(flat_abi, read_flat_abi); + + let count = count.min(read_count); + + copy( + cx.as_context_mut(), + types, + instance, + flat_abi, + ty, + &options, + address, + read_ty, + &read_options, + read_address, + count, + rep, + )?; + + log::trace!( + "remove read child of {}: {}", + read_caller.rep(), + transmit_id.rep() + ); + cx.concurrent_state() + .table + .remove_child(transmit_id, read_caller)?; + + *get_mut_by_index(&mut *instance, read_ty, read_handle)?.1 = + StreamFutureState::Read; + + push_event( + cx, + transmit_id.rep(), + match read_ty { + TableIndex::Future(_) => events::EVENT_FUTURE_READ, + TableIndex::Stream(_) => events::EVENT_STREAM_READ, + }, + count, + read_caller, + ); + + count + } + + ReadState::HostReady { accept } => { + let lift = &mut LiftContext::new(cx.0, &options, types, instance); + accept(Writer::Guest { + lift, + ty: payload(ty, types), + address, + count, + })? + } + + ReadState::Open => { + assert!(matches!(&transmit.write, WriteState::Open)); + + let caller = cx.concurrent_state().guest_task.unwrap(); + log::trace!( + "add write {} child of {}: {}", + match ty { + TableIndex::Future(_) => "future", + TableIndex::Stream(_) => "stream", + }, + caller.rep(), + transmit_id.rep() + ); + cx.concurrent_state().table.add_child(transmit_id, caller)?; + + let transmit = cx.concurrent_state().table.get_mut(transmit_id)?; + transmit.write = WriteState::GuestReady { + ty, + flat_abi, + options, + address: usize::try_from(address).unwrap(), + count: usize::try_from(count).unwrap(), + instance: SendSyncPtr::new(NonNull::new(instance).unwrap()), + handle, + caller, + close: false, + }; + + BLOCKED + } + + ReadState::Closed => CLOSED, + }; + + if result != BLOCKED { + *get_mut_by_index(&mut *instance, ty, handle)?.1 = StreamFutureState::Write; + } + + Ok(u32::try_from(result).unwrap()) + }) + } +} + +fn guest_read( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TableIndex, + flat_abi: Option, + handle: u32, + address: u32, + count: u32, +) -> u64 { + unsafe { + call_host_and_handle_result::(vmctx, || { + let address = usize::try_from(address).unwrap(); + let count = usize::try_from(count).unwrap(); + let cx = VMComponentContext::from_opaque(vmctx); + let instance = (*cx).instance(); + let mut cx = StoreContextMut::(&mut *(*instance).store().cast()); + let options = Options::new( + cx.0.id(), + NonNull::new(memory), + NonNull::new(realloc), + StringEncoding::from_u8(string_encoding).unwrap(), + true, + None, + ); + let types = (*instance).component_types(); + let (rep, state) = get_mut_by_index(&mut *instance, ty, handle)?; + let StreamFutureState::Read = *state else { + bail!("invalid handle"); + }; + *state = StreamFutureState::Busy; + let transmit_id = TableId::::new(rep); + let transmit = cx.concurrent_state().table.get_mut(transmit_id)?; + let new_state = if let WriteState::Closed = &transmit.write { + WriteState::Closed + } else { + WriteState::Open + }; + + let result = match mem::replace(&mut transmit.write, new_state) { + WriteState::GuestReady { + ty: write_ty, + flat_abi: write_flat_abi, + options: write_options, + address: write_address, + count: write_count, + instance: _, + handle: write_handle, + caller: write_caller, + close, + } => { + assert_eq!(flat_abi, write_flat_abi); + + let count = count.min(write_count); + + copy( + cx.as_context_mut(), + types, + instance, + flat_abi, + write_ty, + &write_options, + write_address, + ty, + &options, + address, + count, + rep, + )?; + + log::trace!( + "remove write child of {}: {}", + write_caller.rep(), + transmit_id.rep() + ); + cx.concurrent_state() + .table + .remove_child(transmit_id, write_caller)?; + + if close { + cx.concurrent_state().table.get_mut(transmit_id)?.write = + WriteState::Closed; + } else { + *get_mut_by_index(&mut *instance, write_ty, write_handle)?.1 = + StreamFutureState::Write; + } + + push_event( + cx, + transmit_id.rep(), + match write_ty { + TableIndex::Future(_) => events::EVENT_FUTURE_WRITE, + TableIndex::Stream(_) => events::EVENT_STREAM_WRITE, + }, + count, + write_caller, + ); + + count + } + + WriteState::HostReady { accept, close } => { + let count = accept(Reader::Guest { + lower: RawLowerContext { + store: cx.0.traitobj(), + options: &options, + types, + instance, + }, + ty, + address: usize::try_from(address).unwrap(), + count, + })?; + + if close { + cx.concurrent_state().table.get_mut(transmit_id)?.write = + WriteState::Closed; + } + + count + } + + WriteState::Open => { + assert!(matches!(&transmit.read, ReadState::Open)); + + let caller = cx.concurrent_state().guest_task.unwrap(); + log::trace!( + "add read {} child of {}: {}", + match ty { + TableIndex::Future(_) => "future", + TableIndex::Stream(_) => "stream", + }, + caller.rep(), + transmit_id.rep() + ); + cx.concurrent_state().table.add_child(transmit_id, caller)?; + + let transmit = cx.concurrent_state().table.get_mut(transmit_id)?; + transmit.read = ReadState::GuestReady { + ty, + flat_abi, + options, + address: usize::try_from(address).unwrap(), + count: usize::try_from(count).unwrap(), + instance: SendSyncPtr::new(NonNull::new(instance).unwrap()), + handle, + caller, + }; + + BLOCKED + } + + WriteState::Closed => CLOSED, + }; + + if result != BLOCKED { + *get_mut_by_index(&mut *instance, ty, handle)?.1 = StreamFutureState::Read; + } + + Ok(u32::try_from(result).unwrap()) + }) + } +} + +fn guest_cancel_write( + vmctx: *mut VMOpaqueContext, + ty: TableIndex, + writer: u32, + _async_: bool, +) -> u64 { + unsafe { + call_host_and_handle_result::(vmctx, || { + let cx = VMComponentContext::from_opaque(vmctx); + let instance = (*cx).instance(); + let cx = StoreContextMut::(&mut *(*instance).store().cast()); + let (rep, WaitableState::Stream(_, state) | WaitableState::Future(_, state)) = + state_table(&mut *instance, ty).get_mut_by_index(writer)? + else { + bail!("invalid stream or future handle"); + }; + match state { + StreamFutureState::Local | StreamFutureState::Write => { + bail!("stream or future write canceled when no write is pending") + } + StreamFutureState::Read => { + bail!("passed read end to `{{stream|future}}.cancel-write`") + } + StreamFutureState::Busy => { + *state = StreamFutureState::Write; + } + } + host_cancel_write(cx, rep) + }) + } +} + +fn guest_cancel_read( + vmctx: *mut VMOpaqueContext, + ty: TableIndex, + reader: u32, + _async_: bool, +) -> u64 { + unsafe { + call_host_and_handle_result::(vmctx, || { + let cx = VMComponentContext::from_opaque(vmctx); + let instance = (*cx).instance(); + let cx = StoreContextMut::(&mut *(*instance).store().cast()); + let (rep, WaitableState::Stream(_, state) | WaitableState::Future(_, state)) = + state_table(&mut *instance, ty).get_mut_by_index(reader)? + else { + bail!("invalid stream or future handle"); + }; + match state { + StreamFutureState::Local | StreamFutureState::Read => { + bail!("stream or future read canceled when no read is pending") + } + StreamFutureState::Write => { + bail!("passed write end to `{{stream|future}}.cancel-read`") + } + StreamFutureState::Busy => { + *state = StreamFutureState::Read; + } + } + host_cancel_read(cx, rep) + }) + } +} + +fn guest_close_writable( + vmctx: *mut VMOpaqueContext, + ty: TableIndex, + writer: u32, + error: u32, +) -> bool { + unsafe { + call_host_and_handle_result::(vmctx, || { + if error != 0 { + bail!("todo: closing writable streams and futures with errors not yet implemented"); + } + + let cx = VMComponentContext::from_opaque(vmctx); + let instance = (*cx).instance(); + let cx = StoreContextMut::(&mut *(*instance).store().cast()); + let (rep, WaitableState::Stream(_, state) | WaitableState::Future(_, state)) = + state_table(&mut *instance, ty).remove_by_index(writer)? + else { + bail!("invalid stream or future handle"); + }; + match state { + StreamFutureState::Local | StreamFutureState::Write => {} + StreamFutureState::Read => { + bail!("passed read end to `{{stream|future}}.close-writable`") + } + StreamFutureState::Busy => bail!("cannot drop busy stream or future"), + } + host_close_writer(cx, rep) + }) + } +} + +fn guest_close_readable(vmctx: *mut VMOpaqueContext, ty: TableIndex, reader: u32) -> bool { + unsafe { + call_host_and_handle_result::(vmctx, || { + let cx = VMComponentContext::from_opaque(vmctx); + let instance = (*cx).instance(); + let cx = StoreContextMut::(&mut *(*instance).store().cast()); + let (rep, WaitableState::Stream(_, state) | WaitableState::Future(_, state)) = + state_table(&mut *instance, ty).remove_by_index(reader)? + else { + bail!("invalid stream or future handle"); + }; + match state { + StreamFutureState::Local | StreamFutureState::Read => {} + StreamFutureState::Write => { + bail!("passed write end to `{{stream|future}}.close-readable`") + } + StreamFutureState::Busy => bail!("cannot drop busy stream or future"), + } + host_close_reader(cx, rep) + }) + } +} + +pub(crate) extern "C" fn future_new( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, +) -> u64 { + guest_new::(vmctx, TableIndex::Future(ty)) +} + +pub(crate) extern "C" fn future_write( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeFutureTableIndex, + future: u32, + address: u32, +) -> u64 { + guest_write::( + vmctx, + memory, + realloc, + string_encoding, + TableIndex::Future(ty), + None, + future, + address, + 1, + ) +} + +pub(crate) extern "C" fn future_read( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeFutureTableIndex, + future: u32, + address: u32, +) -> u64 { + guest_read::( + vmctx, + memory, + realloc, + string_encoding, + TableIndex::Future(ty), + None, + future, + address, + 1, + ) +} + +pub(crate) extern "C" fn future_cancel_write( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, + async_: bool, + writer: u32, +) -> u64 { + guest_cancel_write::(vmctx, TableIndex::Future(ty), writer, async_) +} + +pub(crate) extern "C" fn future_cancel_read( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, + async_: bool, + reader: u32, +) -> u64 { + guest_cancel_read::(vmctx, TableIndex::Future(ty), reader, async_) +} + +pub(crate) extern "C" fn future_close_writable( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, + writer: u32, + error: u32, +) -> bool { + guest_close_writable::(vmctx, TableIndex::Future(ty), writer, error) +} + +pub(crate) extern "C" fn future_close_readable( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, + reader: u32, +) -> bool { + guest_close_readable::(vmctx, TableIndex::Future(ty), reader) +} + +pub(crate) extern "C" fn stream_new( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, +) -> u64 { + guest_new::(vmctx, TableIndex::Stream(ty)) +} + +pub(crate) extern "C" fn stream_write( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeStreamTableIndex, + stream: u32, + address: u32, + count: u32, +) -> u64 { + guest_write::( + vmctx, + memory, + realloc, + string_encoding, + TableIndex::Stream(ty), + None, + stream, + address, + count, + ) +} + +pub(crate) extern "C" fn stream_read( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeStreamTableIndex, + stream: u32, + address: u32, + count: u32, +) -> u64 { + guest_read::( + vmctx, + memory, + realloc, + string_encoding, + TableIndex::Stream(ty), + None, + stream, + address, + count, + ) +} + +pub(crate) extern "C" fn stream_cancel_write( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, + async_: bool, + writer: u32, +) -> u64 { + guest_cancel_write::(vmctx, TableIndex::Stream(ty), writer, async_) +} + +pub(crate) extern "C" fn stream_cancel_read( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, + async_: bool, + reader: u32, +) -> u64 { + guest_cancel_read::(vmctx, TableIndex::Stream(ty), reader, async_) +} + +pub(crate) extern "C" fn stream_close_writable( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, + writer: u32, + error: u32, +) -> bool { + guest_close_writable::(vmctx, TableIndex::Stream(ty), writer, error) +} + +pub(crate) extern "C" fn stream_close_readable( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, + reader: u32, +) -> bool { + guest_close_readable::(vmctx, TableIndex::Stream(ty), reader) +} + +pub(crate) extern "C" fn flat_stream_write( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + ty: TypeStreamTableIndex, + payload_size: u32, + payload_align: u32, + stream: u32, + address: u32, + count: u32, +) -> u64 { + guest_write::( + vmctx, + memory, + realloc, + StringEncoding::Utf8 as u8, + TableIndex::Stream(ty), + Some(FlatAbi { + size: payload_size, + align: payload_align, + }), + stream, + address, + count, + ) +} + +pub(crate) extern "C" fn flat_stream_read( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + ty: TypeStreamTableIndex, + payload_size: u32, + payload_align: u32, + stream: u32, + address: u32, + count: u32, +) -> u64 { + guest_read::( + vmctx, + memory, + realloc, + StringEncoding::Utf8 as u8, + TableIndex::Stream(ty), + Some(FlatAbi { + size: payload_size, + align: payload_align, + }), + stream, + address, + count, + ) +} + +pub(crate) extern "C" fn error_context_new( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeErrorContextTableIndex, + address: u32, + count: u32, +) -> u64 { + unsafe { + call_host_and_handle_result::(vmctx, || { + _ = ( + vmctx, + memory, + realloc, + StringEncoding::from_u8(string_encoding).unwrap(), + ty, + address, + count, + ); + bail!("todo: `error.new` not yet implemented"); + }) + } +} + +pub(crate) extern "C" fn error_context_debug_message( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeErrorContextTableIndex, + handle: u32, + address: u32, +) -> bool { + unsafe { + call_host_and_handle_result::(vmctx, || { + _ = ( + vmctx, + memory, + realloc, + StringEncoding::from_u8(string_encoding).unwrap(), + ty, + handle, + address, + ); + bail!("todo: `error.debug-message` not yet implemented"); + }) + } +} + +pub(crate) extern "C" fn error_context_drop( + vmctx: *mut VMOpaqueContext, + ty: TypeErrorContextTableIndex, + error_context: u32, +) -> bool { + unsafe { + call_host_and_handle_result::(vmctx, || { + let cx = VMComponentContext::from_opaque(vmctx); + let instance = (*cx).instance(); + let (_, count) = + (*instance).component_error_context_tables()[ty].get_mut_by_index(error_context)?; + assert!(*count > 0); + *count -= 1; + + if *count == 0 { + (*instance).component_error_context_tables()[ty].remove_by_index(error_context)?; + } + + Ok(()) + }) + } +} diff --git a/crates/wasmtime/src/runtime/component/concurrent/ready_chunks.rs b/crates/wasmtime/src/runtime/component/concurrent/ready_chunks.rs new file mode 100644 index 000000000000..f82bddcee4c7 --- /dev/null +++ b/crates/wasmtime/src/runtime/component/concurrent/ready_chunks.rs @@ -0,0 +1,59 @@ +//! Like `futures::stream::ReadyChunks` but without fusing the inner stream. +//! +//! We use this with `FuturesUnordered` which may produce `Poll::Ready(None)` but later produce more elements due +//! to additional futures having been added, so fusing is not appropriate. + +use { + futures::{Stream, StreamExt}, + std::{ + pin::Pin, + task::{Context, Poll}, + vec::Vec, + }, +}; + +pub struct ReadyChunks { + stream: S, + capacity: usize, +} + +impl ReadyChunks { + pub fn new(stream: S, capacity: usize) -> Self { + Self { stream, capacity } + } + + pub fn get_mut(&mut self) -> &mut S { + &mut self.stream + } +} + +impl Stream for ReadyChunks { + type Item = Vec; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let mut items = Vec::new(); + + loop { + match self.stream.poll_next_unpin(cx) { + Poll::Pending => { + break if items.is_empty() { + Poll::Pending + } else { + Poll::Ready(Some(items)) + } + } + + Poll::Ready(Some(item)) => { + items.push(item); + if items.len() >= self.capacity { + break Poll::Ready(Some(items)); + } + } + + Poll::Ready(None) => { + break Poll::Ready(if items.is_empty() { None } else { Some(items) }); + } + } + } + } +} diff --git a/crates/wasmtime/src/runtime/component/concurrent/table.rs b/crates/wasmtime/src/runtime/component/concurrent/table.rs new file mode 100644 index 000000000000..7056f68bdb9a --- /dev/null +++ b/crates/wasmtime/src/runtime/component/concurrent/table.rs @@ -0,0 +1,316 @@ +// TODO: This duplicates a lot of resource_table.rs; consider reducing that +// duplication. +// +// The main difference between this and resource_table.rs is that the key type, +// `TableId` implements `Copy`, making them much easier to work with than +// `Resource`. I've also added a `Table::delete_any` function, useful for +// implementing `subtask.drop`. + +use std::{any::Any, boxed::Box, collections::BTreeSet, marker::PhantomData, vec::Vec}; + +pub struct TableId { + rep: u32, + _marker: PhantomData T>, +} + +impl TableId { + pub fn new(rep: u32) -> Self { + Self { + rep, + _marker: PhantomData, + } + } +} + +impl Clone for TableId { + fn clone(&self) -> Self { + Self::new(self.rep) + } +} + +impl Copy for TableId {} + +impl TableId { + pub fn rep(&self) -> u32 { + self.rep + } +} + +#[derive(Debug)] +/// Errors returned by operations on `Table` +pub enum TableError { + /// Table has no free keys + Full, + /// Entry not present in table + NotPresent, + /// Resource present in table, but with a different type + WrongType, + /// Entry cannot be deleted because child entrys exist in the table. + HasChildren, +} + +impl std::fmt::Display for TableError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Full => write!(f, "table has no free keys"), + Self::NotPresent => write!(f, "entry not present"), + Self::WrongType => write!(f, "entry is of another type"), + Self::HasChildren => write!(f, "entry has children"), + } + } +} +impl std::error::Error for TableError {} + +/// The `Table` type maps a `TableId` to its entry. +#[derive(Default)] +pub struct Table { + entries: Vec, + free_head: Option, +} + +enum Entry { + Free { next: Option }, + Occupied { entry: TableEntry }, +} + +impl Entry { + pub fn occupied(&self) -> Option<&TableEntry> { + match self { + Self::Occupied { entry } => Some(entry), + Self::Free { .. } => None, + } + } + + pub fn occupied_mut(&mut self) -> Option<&mut TableEntry> { + match self { + Self::Occupied { entry } => Some(entry), + Self::Free { .. } => None, + } + } +} + +/// This structure tracks parent and child relationships for a given table entry. +/// +/// Parents and children are referred to by table index. We maintain the +/// following invariants to prevent orphans and cycles: +/// * parent can only be assigned on creating the entry. +/// * parent, if some, must exist when creating the entry. +/// * whenever a child is created, its index is added to children. +/// * whenever a child is deleted, its index is removed from children. +/// * an entry with children may not be deleted. +struct TableEntry { + /// The entry in the table + entry: Box, + /// The index of the parent of this entry, if it has one. + parent: Option, + /// The indicies of any children of this entry. + children: BTreeSet, +} + +impl TableEntry { + fn new(entry: Box, parent: Option) -> Self { + Self { + entry, + parent, + children: BTreeSet::new(), + } + } + fn add_child(&mut self, child: u32) { + assert!(self.children.insert(child)); + } + fn remove_child(&mut self, child: u32) { + assert!(self.children.remove(&child)); + } +} + +impl Table { + /// Create an empty table + pub fn new() -> Self { + let mut me = Self { + entries: Vec::new(), + free_head: None, + }; + + // TODO: remove this once we've stopped exposing these indexes to guest code: + me.push(()).unwrap(); + + me + } + + /// Inserts a new entry into this table, returning a corresponding + /// `TableId` which can be used to refer to it after it was inserted. + pub fn push(&mut self, entry: T) -> Result, TableError> { + let idx = self.push_(TableEntry::new(Box::new(entry), None))?; + Ok(TableId::new(idx)) + } + + /// Pop an index off of the free list, if it's not empty. + fn pop_free_list(&mut self) -> Option { + if let Some(ix) = self.free_head { + // Advance free_head to the next entry if one is available. + match &self.entries[ix] { + Entry::Free { next } => self.free_head = *next, + Entry::Occupied { .. } => unreachable!(), + } + Some(ix) + } else { + None + } + } + + /// Free an entry in the table, returning its [`TableEntry`]. Add the index to the free list. + fn free_entry(&mut self, ix: usize) -> TableEntry { + let entry = match std::mem::replace( + &mut self.entries[ix], + Entry::Free { + next: self.free_head, + }, + ) { + Entry::Occupied { entry } => entry, + Entry::Free { .. } => unreachable!(), + }; + + self.free_head = Some(ix); + + entry + } + + /// Push a new entry into the table, returning its handle. This will prefer to use free entries + /// if they exist, falling back on pushing new entries onto the end of the table. + fn push_(&mut self, e: TableEntry) -> Result { + if let Some(free) = self.pop_free_list() { + self.entries[free] = Entry::Occupied { entry: e }; + Ok(free as u32) + } else { + let ix = self + .entries + .len() + .try_into() + .map_err(|_| TableError::Full)?; + self.entries.push(Entry::Occupied { entry: e }); + Ok(ix) + } + } + + fn occupied(&self, key: u32) -> Result<&TableEntry, TableError> { + self.entries + .get(key as usize) + .and_then(Entry::occupied) + .ok_or(TableError::NotPresent) + } + + fn occupied_mut(&mut self, key: u32) -> Result<&mut TableEntry, TableError> { + self.entries + .get_mut(key as usize) + .and_then(Entry::occupied_mut) + .ok_or(TableError::NotPresent) + } + + /// Insert a entry at the next available index, and track that it has a + /// parent entry. + /// + /// The parent must exist to create a child. All child entrys must be + /// destroyed before a parent can be destroyed - otherwise [`Table::delete`] + /// will fail with [`TableError::HasChildren`]. + /// + /// Parent-child relationships are tracked inside the table to ensure that a + /// parent is not deleted while it has live children. This allows children + /// to hold "references" to a parent by table index, to avoid needing + /// e.g. an `Arc>` and the associated locking overhead and + /// design issues, such as child existence extending lifetime of parent + /// referent even after parent is destroyed, possibility for deadlocks. + /// + /// Parent-child relationships may not be modified once created. There is no + /// way to observe these relationships through the [`Table`] methods except + /// for erroring on deletion, or the [`std::fmt::Debug`] impl. + pub fn push_child( + &mut self, + entry: T, + parent: TableId, + ) -> Result, TableError> { + let parent = parent.rep(); + self.occupied(parent)?; + let child = self.push_(TableEntry::new(Box::new(entry), Some(parent)))?; + self.occupied_mut(parent)?.add_child(child); + Ok(TableId::new(child)) + } + + pub fn add_child( + &mut self, + child: TableId, + parent: TableId, + ) -> Result<(), TableError> { + let entry = self.occupied_mut(child.rep())?; + assert!(entry.parent.is_none()); + entry.parent = Some(parent.rep()); + self.occupied_mut(parent.rep())?.add_child(child.rep()); + Ok(()) + } + + pub fn remove_child( + &mut self, + child: TableId, + parent: TableId, + ) -> Result<(), TableError> { + let entry = self.occupied_mut(child.rep())?; + assert_eq!(entry.parent, Some(parent.rep())); + entry.parent = None; + self.occupied_mut(parent.rep())?.remove_child(child.rep()); + Ok(()) + } + + /// Get an immutable reference to a task of a given type at a given index. + /// + /// Multiple shared references can be borrowed at any given time. + pub fn get(&self, key: TableId) -> Result<&T, TableError> { + self.get_(key.rep())? + .downcast_ref() + .ok_or(TableError::WrongType) + } + + fn get_(&self, key: u32) -> Result<&dyn Any, TableError> { + let r = self.occupied(key)?; + Ok(&*r.entry) + } + + /// Get an mutable reference to a task of a given type at a given index. + pub fn get_mut(&mut self, key: TableId) -> Result<&mut T, TableError> { + self.get_mut_(key.rep())? + .downcast_mut() + .ok_or(TableError::WrongType) + } + + pub fn get_mut_(&mut self, key: u32) -> Result<&mut dyn Any, TableError> { + let r = self.occupied_mut(key)?; + Ok(&mut *r.entry) + } + + /// Delete the specified task + pub fn delete(&mut self, key: TableId) -> Result { + self.delete_entry(key.rep())? + .entry + .downcast() + .map(|v| *v) + .map_err(|_| TableError::WrongType) + } + + pub fn delete_any(&mut self, key: u32) -> Result, TableError> { + Ok(self.delete_entry(key)?.entry) + } + + fn delete_entry(&mut self, key: u32) -> Result { + if !self.occupied(key)?.children.is_empty() { + return Err(TableError::HasChildren); + } + let e = self.free_entry(key as usize); + if let Some(parent) = e.parent { + // Remove deleted task from parent's child list. Parent must still + // be present because it cant be deleted while still having + // children: + self.occupied_mut(parent) + .expect("missing parent") + .remove_child(key); + } + Ok(e) + } +} diff --git a/crates/wasmtime/src/runtime/component/func.rs b/crates/wasmtime/src/runtime/component/func.rs index 9ac5329af7ce..4d6ce6429cab 100644 --- a/crates/wasmtime/src/runtime/component/func.rs +++ b/crates/wasmtime/src/runtime/component/func.rs @@ -15,6 +15,9 @@ use wasmtime_environ::component::{ TypeFuncIndex, TypeTuple, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, }; +#[cfg(feature = "component-model-async")] +use crate::component::concurrent::{self, LiftLowerContext, Promise}; + mod host; mod options; mod typed; @@ -22,6 +25,13 @@ pub use self::host::*; pub use self::options::*; pub use self::typed::*; +#[cfg(feature = "component-model-async")] +type LowerFn = + fn(&mut LowerContext, &Params, InterfaceType, &mut MaybeUninit) -> Result<()>; + +#[cfg(feature = "component-model-async")] +type LiftFn = fn(&mut LiftContext, InterfaceType, &[ValRaw]) -> Result; + #[repr(C)] union ParamsAndResults { params: Params, @@ -36,16 +46,16 @@ union ParamsAndResults { /// [`wasmtime::Func`](crate::Func) it's possible to call functions either /// synchronously or asynchronously and either typed or untyped. #[derive(Copy, Clone, Debug)] -pub struct Func(Stored); +pub struct Func(pub(crate) Stored); #[doc(hidden)] pub struct FuncData { - export: ExportFunction, - ty: TypeFuncIndex, - types: Arc, - options: Options, - instance: Instance, - component_instance: RuntimeComponentInstanceIndex, + pub(crate) export: ExportFunction, + pub(crate) ty: TypeFuncIndex, + pub(crate) types: Arc, + pub(crate) options: Options, + pub(crate) instance: Instance, + pub(crate) component_instance: RuntimeComponentInstanceIndex, post_return: Option, post_return_arg: Option, } @@ -72,7 +82,19 @@ impl Func { ExportFunction { func_ref } }); let component_instance = options.instance; - let options = unsafe { Options::new(store.id(), memory, realloc, options.string_encoding) }; + let callback = options + .callback + .map(|i| data.instance().runtime_callback(i)); + let options = unsafe { + Options::new( + store.id(), + memory, + realloc, + options.string_encoding, + options.async_, + callback, + ) + }; Func(store.store_data_mut().insert(FuncData { export, options, @@ -269,9 +291,9 @@ impl Func { /// Panics if this is called on a function in an asynchronous store. This /// only works with functions defined within a synchronous store. Also /// panics if `store` does not own this function. - pub fn call( + pub fn call( &self, - mut store: impl AsContextMut, + mut store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()> { @@ -294,32 +316,103 @@ impl Func { /// only works with functions defined within an asynchronous store. Also /// panics if `store` does not own this function. #[cfg(feature = "async")] - pub async fn call_async( + pub async fn call_async( &self, mut store: impl AsContextMut, params: &[Val], results: &mut [Val], - ) -> Result<()> - where - T: Send, - { - let mut store = store.as_context_mut(); + ) -> Result<()> { + let store = store.as_context_mut(); assert!( store.0.async_support(), "cannot use `call_async` without enabling async support in the config" ); - store - .on_fiber(|store| self.call_impl(store, params, results)) + #[cfg(feature = "component-model-async")] + { + let instance = store.0[self.0].component_instance; + // TODO: do we need to return the store here due to the possible + // invalidation of the reference we were passed? + concurrent::on_fiber(store, instance, move |store| { + self.call_impl(store, params, results) + }) .await? + .0 + } + #[cfg(not(feature = "component-model-async"))] + { + let mut store = store; + store + .on_fiber(|store| self.call_impl(store, params, results)) + .await? + } + } + + /// Start 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. + #[cfg(feature = "component-model-async")] + pub async fn call_concurrent( + self, + mut store: impl AsContextMut, + params: Vec, + ) -> Result>> { + let store = store.as_context_mut(); + assert!( + store.0.async_support(), + "cannot use `call_concurrent` when async support is not enabled on the config" + ); + let instance = store.0[self.0].component_instance; + // TODO: do we need to return the store here due to the possible + // invalidation of the reference we were passed? + concurrent::on_fiber(store, instance, move |store| { + self.start_call(store.as_context_mut(), params) + }) + .await? + .0 + } + + #[cfg(feature = "component-model-async")] + fn start_call<'a, T: Send>( + self, + mut store: StoreContextMut<'a, T>, + params: Vec, + ) -> Result>> { + let store = store.as_context_mut(); + + let param_tys = self.params(&store); + if param_tys.len() != params.len() { + bail!( + "expected {} argument(s), got {}", + param_tys.len(), + params.len() + ); + } + + let (lower, lift) = if store.0[self.0].options.async_() { + ( + Self::lower_args_async as LowerFn<_, _, _>, + Self::lift_results_async as LiftFn<_>, + ) + } else { + ( + Self::lower_args_sync as LowerFn<_, _, _>, + Self::lift_results_sync as LiftFn<_>, + ) + }; + + Ok(self.start_call_raw_async(store, params, lower, lift)?.0) } - fn call_impl( + fn call_impl( &self, - mut store: impl AsContextMut, + mut store: impl AsContextMut, params: &[Val], results: &mut [Val], ) -> Result<()> { - let store = &mut store.as_context_mut(); + let store = store.as_context_mut(); let param_tys = self.params(&store); let result_tys = self.results(&store); @@ -333,49 +426,122 @@ impl Func { } if result_tys.len() != results.len() { bail!( - "expected {} results(s), got {}", + "expected {} result(s), got {}", result_tys.len(), results.len() ); } - 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(); - - 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) + if store.0[self.0].options.async_() { + #[cfg(feature = "component-model-async")] + { + for (result, slot) in self + .call_raw_async( + store, + params.iter().cloned().collect(), + Self::lower_args_async, + Self::lift_results_async, + )? + .0 + .into_iter() + .zip(results) + { + *slot = result; } - }, - |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(()) + } + #[cfg(not(feature = "component-model-async"))] + { + unreachable!( + "async-lifted exports should have failed validation \ + when `component-model-async` feature disabled" + ); + } + } else { + self.call_raw( + store, + ¶ms.iter().cloned().collect::>(), + Self::lower_args_sync, + |cx, results_ty, src: &[ValRaw; MAX_FLAT_RESULTS]| { + for (result, slot) in Self::lift_results_sync(cx, results_ty, src)? + .into_iter() + .zip(results) + { + *slot = result; } Ok(()) - } else { - Self::load_results(cx, results_ty, results, &mut src.iter()) - } + }, + ) + } + } + + #[cfg(feature = "component-model-async")] + fn call_raw_async<'a, T: Send, Params, Return: Send + Sync + 'static, LowerParams>( + &self, + store: StoreContextMut<'a, T>, + params: Params, + lower: LowerFn, + lift: LiftFn, + ) -> Result<(Return, StoreContextMut<'a, T>)> + where + LowerParams: Copy, + { + let me = self.0; + // Note that we smuggle the params through as raw pointers to avoid + // requiring `Params: Send + Sync + 'static` bounds on this function, + // which would prevent passing references as parameters. Technically, + // we don't need to do that for the return type, but we do it anyway for + // symmetry. + // + // This is only safe because `concurrent::call` will either consume or + // drop the contexts before returning. + concurrent::call::<_, LowerParams, _>( + store, + lower_params_with_context::>, + concurrent::LiftLowerContext { + pointer: Box::into_raw(Box::new((me, params, lower))) as _, + dropper: drop_context::<(Stored, Params, LowerFn)>, }, + lift_results_with_context::>, + concurrent::LiftLowerContext { + pointer: Box::into_raw(Box::new((me, lift))) as _, + dropper: drop_context::<(Stored, LiftFn)>, + }, + *self, + ) + } + + #[cfg(feature = "component-model-async")] + fn start_call_raw_async< + 'a, + T: Send, + Params: Send + Sync + 'static, + Return: Send + Sync + 'static, + LowerParams, + >( + &self, + store: StoreContextMut<'a, T>, + params: Params, + lower: LowerFn, + lift: LiftFn, + ) -> Result<(Promise, StoreContextMut<'a, T>)> + where + LowerParams: Copy, + { + let me = self.0; + concurrent::start_call::<_, LowerParams, _>( + store, + lower_params_with_context::>, + concurrent::LiftLowerContext { + pointer: Box::into_raw(Box::new((me, params, lower))) as _, + dropper: drop_context::<(Stored, Params, LowerFn)>, + }, + lift_results_with_context::>, + concurrent::LiftLowerContext { + pointer: Box::into_raw(Box::new((me, lift))) as _, + dropper: drop_context::<(Stored, LiftFn)>, + }, + *self, ) } @@ -389,7 +555,7 @@ impl Func { /// happening. fn call_raw( &self, - store: &mut StoreContextMut<'_, T>, + mut store: StoreContextMut<'_, T>, params: &Params, lower: impl FnOnce( &mut LowerContext<'_, T>, @@ -468,7 +634,7 @@ impl Func { // on the correctness of this module and `ComponentType` // implementations, hence `ComponentType` being an `unsafe` trait. crate::Func::call_unchecked_raw( - store, + &mut store, export.func_ref, core::ptr::slice_from_raw_parts_mut( space.as_mut_ptr().cast(), @@ -642,8 +808,56 @@ impl Func { Ok(()) } + fn lower_args_sync( + cx: &mut LowerContext<'_, T>, + params: &Vec, + params_ty: InterfaceType, + dst: &mut MaybeUninit<[ValRaw; MAX_FLAT_PARAMS]>, + ) -> Result<()> { + Self::lower_args(cx, params, params_ty, dst, false) + } + + #[cfg(feature = "component-model-async")] + fn lower_args_async( + cx: &mut LowerContext<'_, T>, + params: &Vec, + params_ty: InterfaceType, + dst: &mut MaybeUninit<[ValRaw; MAX_FLAT_PARAMS]>, + ) -> Result<()> { + Self::lower_args(cx, params, params_ty, dst, true) + } + + fn lower_args( + cx: &mut LowerContext<'_, T>, + params: &[Val], + params_ty: InterfaceType, + dst: &mut MaybeUninit<[ValRaw; MAX_FLAT_PARAMS]>, + async_: bool, + ) -> 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 unsafe { + mem::transmute::<_, &mut [MaybeUninit; MAX_FLAT_PARAMS]>(dst) + } + .iter_mut(); + + params + .iter() + .zip(params_ty.types.iter()) + .try_for_each(|(param, ty)| param.lower(cx, *ty, dst)) + } else { + if async_ { + todo!() + } else { + Self::store_args(cx, ¶ms_ty, params, dst) + } + } + } + fn store_args( - &self, cx: &mut LowerContext<'_, T>, params_ty: &TypeTuple, args: &[Val], @@ -662,12 +876,59 @@ impl Func { Ok(()) } + fn lift_results_sync( + cx: &mut LiftContext<'_>, + results_ty: InterfaceType, + src: &[ValRaw], + ) -> Result> { + Self::lift_results(cx, results_ty, src, false) + } + + #[cfg(feature = "component-model-async")] + fn lift_results_async( + cx: &mut LiftContext<'_>, + results_ty: InterfaceType, + src: &[ValRaw], + ) -> Result> { + Self::lift_results(cx, results_ty, src, true) + } + + fn lift_results( + cx: &mut LiftContext<'_>, + results_ty: InterfaceType, + src: &[ValRaw], + async_: bool, + ) -> Result> { + let results_ty = match results_ty { + InterfaceType::Tuple(i) => &cx.types[i], + _ => unreachable!(), + }; + let limit = if async_ { + MAX_FLAT_PARAMS + } else { + MAX_FLAT_RESULTS + }; + if results_ty.abi.flat_count(limit).is_some() { + let mut flat = src.iter(); + results_ty + .types + .iter() + .map(|ty| Val::lift(cx, *ty, &mut flat)) + .collect() + } else { + if async_ { + todo!() + } else { + Self::load_results(cx, results_ty, &mut src.iter()) + } + } + } + fn load_results( cx: &mut LiftContext<'_>, results_ty: &TypeTuple, - results: &mut [Val], src: &mut core::slice::Iter<'_, ValRaw>, - ) -> Result<()> { + ) -> Result> { // FIXME: 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 { @@ -681,11 +942,156 @@ impl Func { .ok_or_else(|| anyhow::anyhow!("pointer out of bounds of memory"))?; let mut offset = 0; - 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); - *slot = Val::load(cx, *ty, &bytes[offset..][..abi.size32 as usize])?; + results_ty + .types + .iter() + .map(|ty| { + 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]) + }) + .collect() + } +} + +#[cfg(feature = "component-model-async")] +fn drop_context(pointer: *mut u8) { + drop(unsafe { Box::from_raw(pointer as *mut T) }) +} + +#[cfg(feature = "component-model-async")] +fn lower_params_with_context< + Params, + LowerParams, + T, + F: FnOnce( + &mut LowerContext, + &Params, + InterfaceType, + &mut MaybeUninit, + ) -> Result<()> + + Send + + Sync, +>( + context: LiftLowerContext, + store: *mut dyn crate::vm::VMStore, + lowered: &mut [MaybeUninit], +) -> Result<()> { + let (me, params, lower) = unsafe { + *Box::from_raw( + std::mem::ManuallyDrop::new(context).pointer as *mut (Stored, Params, F), + ) + }; + + lower_params(store, lowered, me, params, lower) +} + +#[cfg(feature = "component-model-async")] +fn lower_params< + Params, + LowerParams, + T, + F: FnOnce( + &mut LowerContext, + &Params, + InterfaceType, + &mut MaybeUninit, + ) -> Result<()> + + Send + + Sync, +>( + store: *mut dyn crate::vm::VMStore, + lowered: &mut [MaybeUninit], + me: Stored, + params: Params, + lower: F, +) -> Result<()> { + use crate::component::storage::slice_to_storage_mut; + + let mut store = unsafe { StoreContextMut(&mut *store.cast()) }; + let FuncData { + options, + instance, + component_instance, + ty, + .. + } = store.0[me]; + + let instance = store.0[instance.0].as_ref().unwrap(); + let types = instance.component_types().clone(); + let instance_ptr = instance.instance_ptr(); + let mut flags = instance.instance().instance_flags(component_instance); + + unsafe { + if !flags.may_enter() { + bail!(crate::Trap::CannotEnterComponent); } + + flags.set_may_leave(false); + let mut cx = LowerContext::new(store.as_context_mut(), &options, &types, instance_ptr); + cx.enter_call(); + let result = lower( + &mut cx, + ¶ms, + InterfaceType::Tuple(types[ty].params), + slice_to_storage_mut(lowered), + ); + flags.set_may_leave(true); + result?; Ok(()) } } + +#[cfg(feature = "component-model-async")] +fn lift_results_with_context< + Return: Send + Sync + 'static, + T, + F: FnOnce(&mut LiftContext, InterfaceType, &[ValRaw]) -> Result + Send + Sync, +>( + context: LiftLowerContext, + store: *mut dyn crate::vm::VMStore, + lowered: &[ValRaw], +) -> Result>> { + let (me, lift) = unsafe { + *Box::from_raw(std::mem::ManuallyDrop::new(context).pointer as *mut (Stored, F)) + }; + + lift_results::<_, T, _>(store, lowered, me, lift) +} + +#[cfg(feature = "component-model-async")] +fn lift_results< + Return: Send + Sync + 'static, + T, + F: FnOnce(&mut LiftContext, InterfaceType, &[ValRaw]) -> Result + Send + Sync, +>( + store: *mut dyn crate::vm::VMStore, + lowered: &[ValRaw], + me: Stored, + lift: F, +) -> Result>> { + let store = unsafe { StoreContextMut::(&mut *store.cast()) }; + let FuncData { + options, + instance, + component_instance, + ty, + .. + } = store.0[me]; + + let instance = store.0[instance.0].as_ref().unwrap(); + let types = instance.component_types().clone(); + let instance_ptr = instance.instance_ptr(); + let mut flags = instance.instance().instance_flags(component_instance); + + store.0[me].post_return_arg = Some(ValRaw::i32(0)); + + unsafe { + flags.set_needs_post_return(true); + Ok(Some(Box::new(lift( + &mut LiftContext::new(store.0, &options, &types, instance_ptr), + InterfaceType::Tuple(types[ty].results), + lowered, + )?) as Box)) + } +} diff --git a/crates/wasmtime/src/runtime/component/func/host.rs b/crates/wasmtime/src/runtime/component/func/host.rs index 1461554ad8a9..45e34c48d4bd 100644 --- a/crates/wasmtime/src/runtime/component/func/host.rs +++ b/crates/wasmtime/src/runtime/component/func/host.rs @@ -1,3 +1,4 @@ +use crate::component::concurrent; use crate::component::func::{LiftContext, LowerContext, Options}; use crate::component::matching::InstanceType; use crate::component::storage::slice_to_storage_mut; @@ -10,13 +11,28 @@ use crate::runtime::vm::{VMFuncRef, VMMemoryDefinition, VMOpaqueContext}; use crate::{AsContextMut, CallHook, StoreContextMut, ValRaw}; use alloc::sync::Arc; use core::any::Any; +use core::future::Future; +use core::iter; use core::mem::{self, MaybeUninit}; use core::ptr::NonNull; use wasmtime_environ::component::{ - CanonicalAbiInfo, ComponentTypes, InterfaceType, StringEncoding, TypeFuncIndex, - MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, + CanonicalAbiInfo, ComponentTypes, InterfaceType, RuntimeComponentInstanceIndex, StringEncoding, + TypeFuncIndex, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, }; +#[cfg(feature = "component-model-async")] +use crate::runtime::vm::SendSyncPtr; + +#[cfg(feature = "component-model-async")] +const STATUS_PARAMS_READ: u32 = 1; +#[cfg(feature = "component-model-async")] +const STATUS_DONE: u32 = 3; + +struct Ptr(*const F); + +unsafe impl Sync for Ptr {} +unsafe impl Send for Ptr {} + pub struct HostFunc { entrypoint: VMLoweringCallee, typecheck: Box) -> Result<()>) + Send + Sync>, @@ -28,9 +44,23 @@ impl HostFunc { where F: Fn(StoreContextMut, P) -> Result + Send + Sync + 'static, P: ComponentNamedList + Lift + 'static, - R: ComponentNamedList + Lower + 'static, + R: ComponentNamedList + Lower + Send + Sync + 'static, + { + Self::from_concurrent(move |store, params| { + let result = func(store, params); + async move { concurrent::for_any(move |_| result) } + }) + } + + pub(crate) fn from_concurrent(func: F) -> Arc + where + N: FnOnce(StoreContextMut) -> Result + Send + Sync + 'static, + FN: Future + Send + Sync + 'static, + F: Fn(StoreContextMut, P) -> FN + Send + Sync + 'static, + P: ComponentNamedList + Lift + 'static, + R: ComponentNamedList + Lower + Send + Sync + 'static, { - let entrypoint = Self::entrypoint::; + let entrypoint = Self::entrypoint::; Arc::new(HostFunc { entrypoint, typecheck: Box::new(typecheck::), @@ -38,36 +68,42 @@ impl HostFunc { }) } - extern "C" fn entrypoint( + extern "C" fn entrypoint( cx: *mut VMOpaqueContext, data: *mut u8, ty: u32, + caller_instance: u32, flags: *mut u8, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, + async_: u8, storage: *mut MaybeUninit, storage_len: usize, ) -> bool where - F: Fn(StoreContextMut, P) -> Result, + N: FnOnce(StoreContextMut) -> Result + Send + Sync + 'static, + FN: Future + Send + Sync + 'static, + F: Fn(StoreContextMut, P) -> FN + Send + Sync + 'static, P: ComponentNamedList + Lift + 'static, - R: ComponentNamedList + Lower + 'static, + R: ComponentNamedList + Lower + Send + Sync + 'static, { - let data = data as *const F; + let data = Ptr(data as *const F); unsafe { call_host_and_handle_result::(cx, |instance, types, store| { - call_host::<_, _, _, _>( + call_host( instance, types, store, TypeFuncIndex::from_u32(ty), + RuntimeComponentInstanceIndex::from_u32(caller_instance), InstanceFlags::from_raw(flags), memory, realloc, StringEncoding::from_u8(string_encoding).unwrap(), + async_ != 0, core::slice::from_raw_parts_mut(storage, storage_len), - |store, args| (*data)(store, args), + move |store, args| (*data.0)(store, args), ) }) } @@ -76,14 +112,30 @@ 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_concurrent(move |store, params: Vec, result_count| { + let mut results = iter::repeat(Val::Bool(false)) + .take(result_count) + .collect::>(); + let result = func(store, ¶ms, &mut results); + let result = result.map(move |()| results); + async move { concurrent::for_any(move |_| result) } + }) + } + + pub(crate) fn new_dynamic_concurrent(f: F) -> Arc + where + N: FnOnce(StoreContextMut) -> Result> + Send + Sync + 'static, + FN: Future + Send + Sync + 'static, + F: Fn(StoreContextMut, Vec, usize) -> FN + Send + Sync + 'static, { Arc::new(HostFunc { - entrypoint: dynamic_entrypoint::, + entrypoint: dynamic_entrypoint::, // This function performs dynamic type checks and subsequently does // not need to perform up-front type checks. Instead everything is // dynamically managed at runtime. typecheck: Box::new(move |_expected_index, _expected_types| Ok(())), - func: Box::new(func), + func: Box::new(f), }) } @@ -133,22 +185,26 @@ where /// This function is in general `unsafe` as the validity of all the parameters /// must be upheld. Generally that's done by ensuring this is only called from /// the select few places it's intended to be called from. -unsafe fn call_host( +unsafe fn call_host( instance: *mut ComponentInstance, types: &Arc, mut cx: StoreContextMut<'_, T>, ty: TypeFuncIndex, + caller_instance: RuntimeComponentInstanceIndex, mut flags: InstanceFlags, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: StringEncoding, + async_: bool, storage: &mut [MaybeUninit], closure: F, ) -> Result<()> where + N: FnOnce(StoreContextMut) -> Result + Send + Sync + 'static, + FN: Future + Send + Sync + 'static, + F: Fn(StoreContextMut, Params) -> FN + 'static, Params: Lift, - Return: Lower, - F: FnOnce(StoreContextMut<'_, T>, Params) -> Result, + Return: Lower + Send + Sync + 'static, { /// Representation of arguments to this function when a return pointer is in /// use, namely the argument list is followed by a single value which is the @@ -173,6 +229,8 @@ where NonNull::new(memory), NonNull::new(realloc), string_encoding, + async_, + None, ); // Perform a dynamic check that this instance can indeed be left. Exiting @@ -186,39 +244,85 @@ where let param_tys = InterfaceType::Tuple(ty.params); let result_tys = InterfaceType::Tuple(ty.results); - // There's a 2x2 matrix of whether parameters and results are stored on the - // stack or on the heap. Each of the 4 branches here have a different - // representation of the storage of arguments/returns. - // - // Also note that while four branches are listed here only one is taken for - // any particular `Params` and `Return` combination. This should be - // trivially DCE'd by LLVM. Perhaps one day with enough const programming in - // Rust we can make monomorphizations of this function codegen only one - // branch, but today is not that day. - let mut storage: Storage<'_, Params, Return> = if Params::flatten_count() <= MAX_FLAT_PARAMS { - if Return::flatten_count() <= MAX_FLAT_RESULTS { - Storage::Direct(slice_to_storage_mut(storage)) - } else { - Storage::ResultsIndirect(slice_to_storage_mut(storage).assume_init_ref()) + if async_ { + #[cfg(feature = "component-model-async")] + { + let paramptr = storage[0].assume_init(); + let retptr = storage[1].assume_init(); + + let params = { + let lift = &mut LiftContext::new(cx.0, &options, types, instance); + lift.enter_call(); + let ptr = validate_inbounds::(lift.memory(), ¶mptr)?; + Params::load(lift, param_tys, &lift.memory()[ptr..][..Params::SIZE32])? + }; + + let future = closure(cx.as_context_mut(), params); + + let task = + concurrent::first_poll(instance, cx.as_context_mut(), future, caller_instance, { + let types = types.clone(); + let instance = SendSyncPtr::new(NonNull::new(instance).unwrap()); + move |cx, ret: Return| { + let mut lower = LowerContext::new(cx, &options, &types, instance.as_ptr()); + let ptr = validate_inbounds::(lower.as_slice_mut(), &retptr)?; + ret.store(&mut lower, result_tys, ptr) + } + })?; + + let status = if let Some(task) = task { + (STATUS_PARAMS_READ << 30) | task + } else { + STATUS_DONE << 30 + }; + + 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" + ); } } else { - if Return::flatten_count() <= MAX_FLAT_RESULTS { - Storage::ParamsIndirect(slice_to_storage_mut(storage)) + // There's a 2x2 matrix of whether parameters and results are stored on the + // stack or on the heap. Each of the 4 branches here have a different + // representation of the storage of arguments/returns. + // + // Also note that while four branches are listed here only one is taken for + // any particular `Params` and `Return` combination. This should be + // trivially DCE'd by LLVM. Perhaps one day with enough const programming in + // Rust we can make monomorphizations of this function codegen only one + // branch, but today is not that day. + let mut storage: Storage<'_, Params, Return> = if Params::flatten_count() <= MAX_FLAT_PARAMS + { + if Return::flatten_count() <= MAX_FLAT_RESULTS { + Storage::Direct(slice_to_storage_mut(storage)) + } else { + Storage::ResultsIndirect(slice_to_storage_mut(storage).assume_init_ref()) + } } else { - Storage::Indirect(slice_to_storage_mut(storage).assume_init_ref()) - } - }; - let mut lift = LiftContext::new(cx.0, &options, types, instance); - lift.enter_call(); - let params = storage.lift_params(&mut lift, param_tys)?; + if Return::flatten_count() <= MAX_FLAT_RESULTS { + Storage::ParamsIndirect(slice_to_storage_mut(storage)) + } else { + Storage::Indirect(slice_to_storage_mut(storage).assume_init_ref()) + } + }; + let mut lift = LiftContext::new(cx.0, &options, types, instance); + lift.enter_call(); + let params = storage.lift_params(&mut lift, param_tys)?; - let ret = closure(cx.as_context_mut(), params)?; - flags.set_may_leave(false); - let mut lower = LowerContext::new(cx, &options, types, instance); - storage.lower_results(&mut lower, result_tys, ret)?; - flags.set_may_leave(true); + let future = closure(cx.as_context_mut(), params); - lower.exit_call()?; + let (ret, cx) = concurrent::poll_and_block(cx, future, caller_instance)?; + + flags.set_may_leave(false); + let mut lower = LowerContext::new(cx, &options, types, instance); + storage.lower_results(&mut lower, result_tys, ret)?; + flags.set_may_leave(true); + lower.exit_call()?; + } return Ok(()); @@ -273,7 +377,7 @@ where } } -fn validate_inbounds(memory: &[u8], ptr: &ValRaw) -> Result { +pub(crate) fn validate_inbounds(memory: &[u8], ptr: &ValRaw) -> Result { // FIXME: needs memory64 support let ptr = usize::try_from(ptr.get_u32())?; if ptr % usize::try_from(T::ALIGN32)? != 0 { @@ -311,26 +415,32 @@ unsafe fn call_host_and_handle_result( }) } -unsafe fn call_host_dynamic( +unsafe fn call_host_dynamic( instance: *mut ComponentInstance, types: &Arc, mut store: StoreContextMut<'_, T>, ty: TypeFuncIndex, + caller_instance: RuntimeComponentInstanceIndex, mut flags: InstanceFlags, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: StringEncoding, + async_: bool, storage: &mut [MaybeUninit], closure: F, ) -> Result<()> where - F: FnOnce(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()>, + N: FnOnce(StoreContextMut) -> Result> + Send + Sync + 'static, + FN: Future + Send + Sync + 'static, + F: Fn(StoreContextMut, Vec, usize) -> FN + 'static, { let options = Options::new( 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 @@ -346,61 +456,136 @@ where let func_ty = &types[ty]; let param_tys = &types[func_ty.params]; let result_tys = &types[func_ty.results]; - 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 { - 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 mut result_vals = Vec::with_capacity(result_tys.types.len()); - for _ in result_tys.types.iter() { - result_vals.push(Val::Bool(false)); - } - 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)?; + if async_ { + #[cfg(feature = "component-model-async")] + { + let paramptr = storage[0].assume_init(); + let retptr = storage[1].assume_init(); + + let params = { + let mut lift = &mut LiftContext::new(store.0, &options, types, instance); + lift.enter_call(); + let mut offset = + validate_inbounds_dynamic(¶m_tys.abi, lift.memory(), ¶mptr)?; + param_tys + .types + .iter() + .map(|ty| { + let abi = types.canonical_abi(ty); + let size = usize::try_from(abi.size32).unwrap(); + let memory = &lift.memory()[abi.next_field32_size(&mut offset)..][..size]; + Val::load(&mut lift, *ty, memory) + }) + .collect::>>()? + }; + + let future = closure(store.as_context_mut(), params, result_tys.types.len()); + + let task = concurrent::first_poll( + instance, + store.as_context_mut(), + future, + caller_instance, + { + let types = types.clone(); + let instance = SendSyncPtr::new(NonNull::new(instance).unwrap()); + let result_tys = func_ty.results; + move |store, result_vals: Vec| { + let result_tys = &types[result_tys]; + if result_vals.len() != result_tys.types.len() { + bail!("result length mismatch"); + } + + let mut lower = + LowerContext::new(store, &options, &types, instance.as_ptr()); + let mut ptr = validate_inbounds_dynamic( + &result_tys.abi, + lower.as_slice_mut(), + &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)?; + } + Ok(()) + } + }, + )?; + + let status = if let Some(task) = task { + (STATUS_PARAMS_READ << 30) | task + } else { + STATUS_DONE << 30 + }; + + 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" + ); } - 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 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 { + 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 future = closure(store.as_context_mut(), args, result_tys.types.len()); + let (result_vals, store) = concurrent::poll_and_block(store, future, caller_instance)?; + + 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)?; + } } - } - flags.set_may_leave(true); + flags.set_may_leave(true); - cx.exit_call()?; + cx.exit_call()?; + } return Ok(()); } @@ -421,34 +606,40 @@ fn validate_inbounds_dynamic(abi: &CanonicalAbiInfo, memory: &[u8], ptr: &ValRaw Ok(ptr) } -extern "C" fn dynamic_entrypoint( +extern "C" fn dynamic_entrypoint( cx: *mut VMOpaqueContext, data: *mut u8, ty: u32, + caller_instance: u32, flags: *mut u8, memory: *mut VMMemoryDefinition, realloc: *mut VMFuncRef, string_encoding: u8, + async_: u8, storage: *mut MaybeUninit, storage_len: usize, ) -> bool where - F: Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static, + N: FnOnce(StoreContextMut) -> Result> + Send + Sync + 'static, + FN: Future + Send + Sync + 'static, + F: Fn(StoreContextMut, Vec, usize) -> FN + Send + Sync + 'static, { - let data = data as *const F; + let data = Ptr(data as *const F); unsafe { call_host_and_handle_result(cx, |instance, types, store| { - call_host_dynamic::( + call_host_dynamic( instance, types, store, TypeFuncIndex::from_u32(ty), + RuntimeComponentInstanceIndex::from_u32(caller_instance), InstanceFlags::from_raw(flags), memory, realloc, StringEncoding::from_u8(string_encoding).unwrap(), + async_ != 0, core::slice::from_raw_parts_mut(storage, storage_len), - |store, params, results| (*data)(store, params, results), + move |store, params, results| (*data.0)(store, params, results), ) }) } diff --git a/crates/wasmtime/src/runtime/component/func/options.rs b/crates/wasmtime/src/runtime/component/func/options.rs index cd0482965e21..0458735b4368 100644 --- a/crates/wasmtime/src/runtime/component/func/options.rs +++ b/crates/wasmtime/src/runtime/component/func/options.rs @@ -43,6 +43,11 @@ pub struct Options { /// /// This defaults to utf-8 but can be changed if necessary. string_encoding: StringEncoding, + + async_: bool, + + #[cfg_attr(not(feature = "component-model-async"), allow(unused))] + pub(crate) callback: Option>, } // The `Options` structure stores raw pointers but they're never used unless a @@ -66,12 +71,16 @@ impl Options { memory: Option>, realloc: Option>, string_encoding: StringEncoding, + async_: bool, + callback: Option>, ) -> Options { Options { store_id, memory, realloc, string_encoding, + async_, + callback, } } @@ -163,6 +172,11 @@ 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_ + } } /// A helper structure which is a "package" of the context used during lowering @@ -196,7 +210,7 @@ pub struct LowerContext<'a, T> { /// into. /// /// This pointer is required to be owned by the `store` provided. - instance: *mut ComponentInstance, + pub(crate) instance: *mut ComponentInstance, } #[doc(hidden)] @@ -402,7 +416,7 @@ pub struct LiftContext<'a> { memory: Option<&'a [u8]>, - instance: *mut ComponentInstance, + pub(crate) instance: *mut ComponentInstance, host_table: &'a mut ResourceTable, host_resource_data: &'a mut HostResourceData, diff --git a/crates/wasmtime/src/runtime/component/func/typed.rs b/crates/wasmtime/src/runtime/component/func/typed.rs index 4dd5050e000d..fef3cf3c96b6 100644 --- a/crates/wasmtime/src/runtime/component/func/typed.rs +++ b/crates/wasmtime/src/runtime/component/func/typed.rs @@ -17,6 +17,9 @@ use wasmtime_environ::component::{ MAX_FLAT_RESULTS, }; +#[cfg(feature = "component-model-async")] +use crate::component::concurrent::{self, Promise}; + /// A statically-typed version of [`Func`] which takes `Params` as input and /// returns `Return`. /// @@ -154,7 +157,14 @@ where /// Panics if this is called on a function in an asynchronous store. This /// only works with functions defined within a synchronous store. Also /// panics if `store` does not own this function. - pub fn call(&self, store: impl AsContextMut, params: Params) -> Result { + pub fn call( + &self, + store: impl AsContextMut, + params: Params, + ) -> Result + where + Return: Send + Sync + 'static, + { assert!( !store.as_context().async_support(), "must use `call_async` when async support is enabled on the config" @@ -170,28 +180,215 @@ where /// only works with functions defined within an asynchronous store. Also /// panics if `store` does not own this function. #[cfg(feature = "async")] - pub async fn call_async( - &self, + pub async fn call_async( + self, mut store: impl AsContextMut, params: Params, ) -> Result where - T: Send, Params: Send + Sync, - Return: Send + Sync, + Return: Send + Sync + 'static, { - let mut store = store.as_context_mut(); + let store = store.as_context_mut(); assert!( store.0.async_support(), "cannot use `call_async` when async support is not enabled on the config" ); - store - .on_fiber(|store| self.call_impl(store, params)) - .await? + #[cfg(feature = "component-model-async")] + { + let instance = store.0[self.func.0].component_instance; + // TODO: do we need to return the store here due to the possible + // invalidation of the reference we were passed? + concurrent::on_fiber(store, instance, move |store| self.call_impl(store, params)) + .await? + .0 + } + #[cfg(not(feature = "component-model-async"))] + { + let mut store = store; + store + .on_fiber(|store| self.call_impl(store, params)) + .await? + } + } + + /// Start 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. + #[cfg(feature = "component-model-async")] + pub async fn call_concurrent( + self, + mut store: impl AsContextMut, + params: Params, + ) -> Result> + where + Params: Send + Sync + 'static, + Return: Send + Sync + 'static, + { + let store = store.as_context_mut(); + assert!( + store.0.async_support(), + "cannot use `call_concurrent` when async support is not enabled on the config" + ); + let instance = store.0[self.func.0].component_instance; + // TODO: do we need to return the store here due to the possible + // invalidation of the reference we were passed? + concurrent::on_fiber(store, instance, move |store| { + self.start_call(store.as_context_mut(), params) + }) + .await? + .0 } - fn call_impl(&self, mut store: impl AsContextMut, params: Params) -> Result { - let store = &mut store.as_context_mut(); + #[cfg(feature = "component-model-async")] + fn start_call<'a, T: Send>( + self, + store: StoreContextMut<'a, T>, + params: Params, + ) -> Result> + where + Params: Send + Sync + 'static, + Return: Send + Sync + 'static, + { + Ok(if store.0[self.func.0].options.async_() { + #[cfg(feature = "component-model-async")] + { + if Params::flatten_count() <= MAX_FLAT_PARAMS { + if Return::flatten_count() <= MAX_FLAT_PARAMS { + self.func.start_call_raw_async( + store, + params, + Self::lower_stack_args, + Self::lift_stack_result_raw, + ) + } else { + self.func.start_call_raw_async( + store, + params, + Self::lower_stack_args, + Self::lift_heap_result_guest, + ) + } + } else { + if Return::flatten_count() <= MAX_FLAT_PARAMS { + self.func.start_call_raw_async( + store, + params, + Self::lower_heap_args_guest, + Self::lift_stack_result_raw, + ) + } else { + self.func.start_call_raw_async( + store, + params, + Self::lower_heap_args_guest, + Self::lift_heap_result_guest, + ) + } + } + } + #[cfg(not(feature = "component-model-async"))] + { + unreachable!( + "async-lifted exports should have failed validation \ + when `component-model-async` feature disabled" + ); + } + } else if Params::flatten_count() <= MAX_FLAT_PARAMS { + if Return::flatten_count() <= MAX_FLAT_RESULTS { + self.func.start_call_raw_async( + store, + params, + Self::lower_stack_args, + Self::lift_stack_result_raw, + ) + } else { + self.func.start_call_raw_async( + store, + params, + Self::lower_stack_args, + Self::lift_heap_result_raw, + ) + } + } else { + if Return::flatten_count() <= MAX_FLAT_RESULTS { + self.func.start_call_raw_async( + store, + params, + Self::lower_heap_args, + Self::lift_stack_result_raw, + ) + } else { + self.func.start_call_raw_async( + store, + params, + Self::lower_heap_args, + Self::lift_heap_result_raw, + ) + } + }? + .0) + } + + fn call_impl( + &self, + mut store: impl AsContextMut, + params: Params, + ) -> Result + where + Return: Send + Sync + 'static, + { + let store = store.as_context_mut(); + + if store.0[self.func.0].options.async_() { + #[cfg(feature = "component-model-async")] + { + return Ok(if Params::flatten_count() <= MAX_FLAT_PARAMS { + if Return::flatten_count() <= MAX_FLAT_PARAMS { + self.func.call_raw_async( + store, + params, + Self::lower_stack_args, + Self::lift_stack_result_raw, + ) + } else { + self.func.call_raw_async( + store, + params, + Self::lower_stack_args, + Self::lift_heap_result_guest, + ) + } + } else { + if Return::flatten_count() <= MAX_FLAT_PARAMS { + self.func.call_raw_async( + store, + params, + Self::lower_heap_args_guest, + Self::lift_stack_result_raw, + ) + } else { + self.func.call_raw_async( + store, + params, + Self::lower_heap_args_guest, + Self::lift_heap_result_guest, + ) + } + }? + .0); + } + #[cfg(not(feature = "component-model-async"))] + { + bail!( + "must enable the `component-model-async` feature to call async-lifted exports" + ) + } + } + // 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 @@ -266,8 +463,6 @@ 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 @@ -302,10 +497,20 @@ where ty: InterfaceType, dst: &Return::Lower, ) -> Result { - assert!(Return::flatten_count() <= MAX_FLAT_RESULTS); Return::lift(cx, ty, dst) } + #[cfg(feature = "component-model-async")] + fn lift_stack_result_raw( + cx: &mut LiftContext<'_>, + ty: InterfaceType, + dst: &[ValRaw], + ) -> Result { + Self::lift_stack_result(cx, ty, unsafe { + crate::component::storage::slice_to_storage(dst) + }) + } + /// Lift the result of a function where the result is stored indirectly on /// the heap. fn lift_heap_result( @@ -328,6 +533,36 @@ where Return::load(cx, ty, bytes) } + #[cfg(feature = "component-model-async")] + fn lift_heap_result_raw( + cx: &mut LiftContext<'_>, + ty: InterfaceType, + dst: &[ValRaw], + ) -> Result { + Self::lift_heap_result(cx, ty, &dst[0]) + } + + #[cfg(feature = "component-model-async")] + fn lower_heap_args_guest( + cx: &mut LowerContext<'_, T>, + params: &Params, + ty: InterfaceType, + dst: &mut MaybeUninit, + ) -> Result<()> { + _ = (cx, params, ty, dst); + todo!() + } + + #[cfg(feature = "component-model-async")] + fn lift_heap_result_guest( + cx: &mut LiftContext<'_>, + ty: InterfaceType, + dst: &[ValRaw], + ) -> Result { + _ = (cx, ty, dst); + todo!() + } + /// See [`Func::post_return`] pub fn post_return(&self, store: impl AsContextMut) -> Result<()> { self.func.post_return(store) @@ -1517,7 +1752,7 @@ pub struct WasmList { } impl WasmList { - fn new( + pub(crate) fn new( ptr: usize, len: usize, cx: &mut LiftContext<'_>, @@ -2469,6 +2704,9 @@ pub fn desc(ty: &InterfaceType) -> &'static str { InterfaceType::Enum(_) => "enum", InterfaceType::Own(_) => "owned resource", InterfaceType::Borrow(_) => "borrowed resource", + InterfaceType::Future(_) => "future", + InterfaceType::Stream(_) => "stream", + InterfaceType::ErrorContext(_) => "error-context", } } diff --git a/crates/wasmtime/src/runtime/component/instance.rs b/crates/wasmtime/src/runtime/component/instance.rs index bb7c337eb842..90a4b068d52b 100644 --- a/crates/wasmtime/src/runtime/component/instance.rs +++ b/crates/wasmtime/src/runtime/component/instance.rs @@ -1,3 +1,4 @@ +use crate::component::concurrent; use crate::component::func::HostFunc; use crate::component::matching::InstanceType; use crate::component::{ @@ -48,7 +49,7 @@ pub(crate) struct InstanceData { // of the component can be thrown away (theoretically). component: Component, - state: OwnedComponentInstance, + pub(crate) state: OwnedComponentInstance, /// Arguments that this instance used to be instantiated. /// @@ -512,9 +513,39 @@ impl<'a> Instantiator<'a> { } } - fn run(&mut self, store: &mut StoreContextMut<'_, T>) -> Result<()> { + fn run(&mut self, store: &mut StoreContextMut<'_, T>) -> Result<()> { let env_component = self.component.env_component(); + self.data.state.set_async_callbacks( + concurrent::task_backpressure::, + concurrent::task_return::, + concurrent::task_wait::, + concurrent::task_poll::, + concurrent::task_yield::, + concurrent::subtask_drop::, + concurrent::async_enter::, + concurrent::async_exit::, + concurrent::future_new::, + concurrent::future_write::, + concurrent::future_read::, + concurrent::future_cancel_write::, + concurrent::future_cancel_read::, + concurrent::future_close_writable::, + concurrent::future_close_readable::, + concurrent::stream_new::, + concurrent::stream_write::, + concurrent::stream_read::, + concurrent::stream_cancel_write::, + concurrent::stream_cancel_read::, + concurrent::stream_close_writable::, + concurrent::stream_close_readable::, + concurrent::flat_stream_write::, + concurrent::flat_stream_read::, + concurrent::error_context_new::, + concurrent::error_context_debug_message::, + concurrent::error_context_drop::, + ); + // Before all initializers are processed configure all destructors for // host-defined resources. No initializer will correspond to these and // it's required to happen before they're needed, so execute this first. @@ -607,6 +638,10 @@ impl<'a> Instantiator<'a> { self.extract_realloc(store.0, realloc) } + GlobalInitializer::ExtractCallback(callback) => { + self.extract_callback(store.0, callback) + } + GlobalInitializer::ExtractPostReturn(post_return) => { self.extract_post_return(store.0, post_return) } @@ -654,6 +689,16 @@ impl<'a> Instantiator<'a> { self.data.state.set_runtime_realloc(realloc.index, func_ref); } + fn extract_callback(&mut self, store: &mut StoreOpaque, callback: &ExtractCallback) { + let func_ref = match self.data.lookup_def(store, &callback.def) { + crate::runtime::vm::Export::Function(f) => f.func_ref, + _ => unreachable!(), + }; + self.data + .state + .set_runtime_callback(callback.index, func_ref); + } + fn extract_post_return(&mut self, store: &mut StoreOpaque, post_return: &ExtractPostReturn) { let func_ref = match self.data.lookup_def(store, &post_return.def) { crate::runtime::vm::Export::Function(f) => f.func_ref, @@ -796,7 +841,10 @@ impl InstancePre { /// Performs the instantiation process into the store specified. // // TODO: needs more docs - pub fn instantiate(&self, store: impl AsContextMut) -> Result { + pub fn instantiate(&self, store: impl AsContextMut) -> Result + where + T: 'static, + { assert!( !store.as_context().async_support(), "must use async instantiation when async support is enabled" @@ -814,7 +862,7 @@ impl InstancePre { mut store: impl AsContextMut, ) -> Result where - T: Send, + T: Send + 'static, { let mut store = store.as_context_mut(); assert!( @@ -824,7 +872,10 @@ impl InstancePre { store.on_fiber(|store| self.instantiate_impl(store)).await? } - fn instantiate_impl(&self, mut store: impl AsContextMut) -> Result { + fn instantiate_impl(&self, mut store: impl AsContextMut) -> Result + where + T: 'static, + { let mut store = store.as_context_mut(); store .engine() diff --git a/crates/wasmtime/src/runtime/component/linker.rs b/crates/wasmtime/src/runtime/component/linker.rs index 31a3d5254884..0e8d71463d95 100644 --- a/crates/wasmtime/src/runtime/component/linker.rs +++ b/crates/wasmtime/src/runtime/component/linker.rs @@ -265,7 +265,10 @@ impl Linker { &self, store: impl AsContextMut, component: &Component, - ) -> Result { + ) -> Result + where + T: 'static, + { assert!( !store.as_context().async_support(), "must use async instantiation when async support is enabled" @@ -290,7 +293,7 @@ impl Linker { component: &Component, ) -> Result where - T: Send, + T: Send + 'static, { assert!( store.as_context().async_support(), @@ -382,7 +385,7 @@ impl LinkerInstance<'_, T> { } } - /// Defines a new host-provided function into this [`Linker`]. + /// Defines a new host-provided function into this [`LinkerInstance`]. /// /// This method is used to give host functions to wasm components. The /// `func` provided will be callable from linked components with the type @@ -404,13 +407,13 @@ impl LinkerInstance<'_, T> { where F: Fn(StoreContextMut, Params) -> Result + Send + Sync + 'static, Params: ComponentNamedList + Lift + 'static, - Return: ComponentNamedList + Lower + 'static, + Return: ComponentNamedList + Lower + Send + Sync + 'static, { self.insert(name, Definition::Func(HostFunc::from_closure(func)))?; Ok(()) } - /// Defines a new host-provided async function into this [`Linker`]. + /// Defines a new host-provided async function into this [`LinkerInstance`]. /// /// This is exactly like [`Self::func_wrap`] except it takes an async /// host function. @@ -425,20 +428,65 @@ impl LinkerInstance<'_, T> { + Sync + 'static, Params: ComponentNamedList + Lift + 'static, - Return: ComponentNamedList + Lower + 'static, + Return: ComponentNamedList + Lower + Send + Sync + 'static, { assert!( self.engine.config().async_support, "cannot use `func_wrap_async` without enabling async support in the config" ); + let ff = move |mut store: StoreContextMut<'_, T>, params: Params| -> Result { - let async_cx = store.as_context_mut().0.async_cx().expect("async cx"); - let mut future = Pin::from(f(store.as_context_mut(), params)); - unsafe { async_cx.block_on(future.as_mut()) }? + #[cfg(feature = "component-model-async")] + { + let async_cx = crate::component::concurrent::AsyncCx::new(&mut store); + let mut future = Pin::from(f(store.as_context_mut(), params)); + unsafe { async_cx.block_on::(future.as_mut(), None) }?.0 + } + #[cfg(not(feature = "component-model-async"))] + { + let async_cx = store.as_context_mut().0.async_cx().expect("async cx"); + let mut future = Pin::from(f(store.as_context_mut(), params)); + unsafe { async_cx.block_on(future.as_mut()) }? + } }; self.func_wrap(name, ff) } + /// Defines a new host-provided async function into this [`LinkerInstance`]. + /// + /// 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. + /// + /// Ideally, we'd have a way to thread a `StoreContextMut` through an + /// arbitrary `Future` such that it has access to the `Store` only while + /// being polled (i.e. between, but not across, await points). However, + /// there's currently no way to express that in async Rust, so we make do + /// with a more awkward scheme: each function registered using + /// `func_wrap_concurrent` gets access to the `Store` twice: once before + /// doing any concurrent operations (i.e. before awaiting) and once + /// afterward. This allows multiple calls to proceed concurrently without + /// any one of them monopolizing the store. + #[cfg(feature = "component-model-async")] + pub fn func_wrap_concurrent(&mut self, name: &str, f: F) -> Result<()> + where + N: FnOnce(StoreContextMut) -> Result + Send + Sync + 'static, + FN: Future + Send + Sync + 'static, + F: Fn(StoreContextMut, Params) -> FN + Send + Sync + 'static, + Params: ComponentNamedList + Lift + '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(()) + } + /// Define a new host-provided function using dynamically typed values. /// /// The `name` provided is the name of the function to define and the @@ -568,13 +616,60 @@ impl LinkerInstance<'_, T> { "cannot use `func_new_async` without enabling async support in the config" ); let ff = move |mut store: StoreContextMut<'_, T>, params: &[Val], results: &mut [Val]| { - let async_cx = store.as_context_mut().0.async_cx().expect("async cx"); - let mut future = Pin::from(f(store.as_context_mut(), params, results)); - unsafe { async_cx.block_on(future.as_mut()) }? + #[cfg(feature = "component-model-async")] + { + let async_cx = crate::component::concurrent::AsyncCx::new(&mut store); + let mut future = Pin::from(f(store.as_context_mut(), params, results)); + unsafe { async_cx.block_on::(future.as_mut(), None) }?.0 + } + #[cfg(not(feature = "component-model-async"))] + { + let async_cx = store.as_context_mut().0.async_cx().expect("async cx"); + let mut future = Pin::from(f(store.as_context_mut(), params, results)); + unsafe { async_cx.block_on(future.as_mut()) }? + } }; self.func_new(name, ff) } + /// Define a new host-provided async function using dynamic types. + /// + /// 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. + /// + /// Ideally, we'd have a way to thread a `StoreContextMut` through an + /// arbitrary `Future` such that it has access to the `Store` only while + /// being polled (i.e. between, but not across, await points). However, + /// there's currently no way to express that in async Rust, so we make do + /// with a more awkward scheme: each function registered using + /// `func_wrap_concurrent` gets access to the `Store` twice: once before + /// doing any concurrent operations (i.e. before awaiting) and once + /// afterward. This allows multiple calls to proceed concurrently without + /// any one of them monopolizing the store. + #[cfg(feature = "component-model-async")] + pub fn func_new_concurrent(&mut self, name: &str, f: F) -> Result<()> + where + N: FnOnce(StoreContextMut) -> Result> + Send + Sync + 'static, + FN: Future + Send + Sync + 'static, + F: Fn(StoreContextMut, Vec) -> FN + 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(move |store, params, _| { + f(store, params) + })), + )?; + Ok(()) + } + /// Defines a [`Module`] within this instance. /// /// This can be used to provide a core wasm [`Module`] as an import to a diff --git a/crates/wasmtime/src/runtime/component/matching.rs b/crates/wasmtime/src/runtime/component/matching.rs index 4222daa6dc62..d6cac001cb9a 100644 --- a/crates/wasmtime/src/runtime/component/matching.rs +++ b/crates/wasmtime/src/runtime/component/matching.rs @@ -1,5 +1,6 @@ use crate::component::func::HostFunc; use crate::component::linker::{Definition, Strings}; +use crate::component::types::{FutureType, StreamType}; use crate::component::ResourceType; use crate::prelude::*; use crate::runtime::vm::component::ComponentInstance; @@ -9,7 +10,7 @@ use alloc::sync::Arc; use core::any::Any; use wasmtime_environ::component::{ ComponentTypes, NameMap, ResourceIndex, TypeComponentInstance, TypeDef, TypeFuncIndex, - TypeModule, TypeResourceTableIndex, + TypeFutureTableIndex, TypeModule, TypeResourceTableIndex, TypeStreamTableIndex, }; use wasmtime_environ::PrimaryMap; @@ -199,6 +200,14 @@ 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) + } } /// Small helper method to downcast an `Arc` borrow into a borrow of a concrete diff --git a/crates/wasmtime/src/runtime/component/mod.rs b/crates/wasmtime/src/runtime/component/mod.rs index 90e7d97f3484..a3deae04138e 100644 --- a/crates/wasmtime/src/runtime/component/mod.rs +++ b/crates/wasmtime/src/runtime/component/mod.rs @@ -101,6 +101,8 @@ #![allow(rustdoc::redundant_explicit_links)] mod component; +#[cfg(feature = "component-model-async")] +pub(crate) mod concurrent; mod func; mod instance; mod linker; @@ -112,6 +114,11 @@ mod store; pub mod types; mod values; pub use self::component::{Component, ComponentExportIndex}; +#[cfg(feature = "component-model-async")] +pub use self::concurrent::{ + for_any, future, stream, ErrorContext, FutureReader, FutureWriter, Promise, PromisesUnordered, + StreamReader, StreamWriter, +}; pub use self::func::{ ComponentNamedList, ComponentType, Func, Lift, Lower, TypedFunc, WasmList, WasmStr, }; @@ -675,3 +682,477 @@ 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 { + use { + crate::{ + component::{ + func::{ComponentType, LiftContext, LowerContext}, + Val, + }, + vm::{VMFuncRef, VMMemoryDefinition, VMOpaqueContext}, + AsContextMut, StoreContextMut, ValRaw, + }, + alloc::{sync::Arc, task::Wake}, + anyhow::Result, + core::{ + future::Future, + marker::PhantomData, + mem::MaybeUninit, + pin::pin, + task::{Context, Poll, Waker}, + }, + wasmtime_environ::component::{ + InterfaceType, RuntimeComponentInstanceIndex, TypeErrorContextTableIndex, + TypeFutureTableIndex, TypeStreamTableIndex, TypeTaskReturnIndex, + }, + }; + + pub fn for_any(fun: F) -> F + where + F: FnOnce(StoreContextMut) -> R + 'static, + R: 'static, + { + fun + } + + fn dummy_waker() -> Waker { + struct DummyWaker; + + impl Wake for DummyWaker { + fn wake(self: Arc) {} + } + + Arc::new(DummyWaker).into() + } + + pub(crate) fn poll_and_block<'a, T, R: Send + Sync + 'static>( + mut store: StoreContextMut<'a, T>, + future: impl Future) -> Result + 'static> + + Send + + Sync + + 'static, + _caller_instance: RuntimeComponentInstanceIndex, + ) -> Result<(R, StoreContextMut<'a, T>)> { + match pin!(future).poll(&mut Context::from_waker(&dummy_waker())) { + Poll::Ready(fun) => { + let result = fun(store.as_context_mut())?; + Ok((result, store)) + } + Poll::Pending => { + unreachable!() + } + } + } + + pub(crate) extern "C" fn task_backpressure( + _cx: *mut VMOpaqueContext, + _caller_instance: RuntimeComponentInstanceIndex, + _enabled: u32, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn task_return( + _cx: *mut VMOpaqueContext, + _ty: TypeTaskReturnIndex, + _storage: *mut MaybeUninit, + _storage_len: usize, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn task_wait( + _cx: *mut VMOpaqueContext, + _caller_instance: RuntimeComponentInstanceIndex, + _async_: bool, + _memory: *mut VMMemoryDefinition, + _payload: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn task_poll( + _cx: *mut VMOpaqueContext, + _caller_instance: RuntimeComponentInstanceIndex, + _async_: bool, + _memory: *mut VMMemoryDefinition, + _payload: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn task_yield(_cx: *mut VMOpaqueContext, _async_: bool) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn subtask_drop( + _cx: *mut VMOpaqueContext, + _caller_instance: RuntimeComponentInstanceIndex, + _task_id: u32, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn async_enter( + _cx: *mut VMOpaqueContext, + _start: *mut VMFuncRef, + _return_: *mut VMFuncRef, + _caller_instance: RuntimeComponentInstanceIndex, + _task_return_type: TypeTaskReturnIndex, + _params: u32, + _results: u32, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn async_exit( + _cx: *mut VMOpaqueContext, + _callback: *mut VMFuncRef, + _caller_instance: RuntimeComponentInstanceIndex, + _callee: *mut VMFuncRef, + _callee_instance: RuntimeComponentInstanceIndex, + _param_count: u32, + _result_count: u32, + _flags: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn future_new( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn future_write( + _vmctx: *mut VMOpaqueContext, + _memory: *mut VMMemoryDefinition, + _realloc: *mut VMFuncRef, + _string_encoding: u8, + _ty: TypeFutureTableIndex, + _future: u32, + _address: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn future_read( + _vmctx: *mut VMOpaqueContext, + _memory: *mut VMMemoryDefinition, + _realloc: *mut VMFuncRef, + _string_encoding: u8, + _ty: TypeFutureTableIndex, + _future: u32, + _address: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn future_cancel_write( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + _async_: bool, + _writer: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn future_cancel_read( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + _async_: bool, + _reader: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn future_close_writable( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + _writer: u32, + _error: u32, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn future_close_readable( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + _reader: u32, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn stream_new( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn stream_write( + _vmctx: *mut VMOpaqueContext, + _memory: *mut VMMemoryDefinition, + _realloc: *mut VMFuncRef, + _string_encoding: u8, + _ty: TypeStreamTableIndex, + _stream: u32, + _address: u32, + _count: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn stream_read( + _vmctx: *mut VMOpaqueContext, + _memory: *mut VMMemoryDefinition, + _realloc: *mut VMFuncRef, + _string_encoding: u8, + _ty: TypeStreamTableIndex, + _stream: u32, + _address: u32, + _count: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn stream_cancel_write( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + _async_: bool, + _writer: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn stream_cancel_read( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + _async_: bool, + _reader: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn stream_close_writable( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + _writer: u32, + _error: u32, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn stream_close_readable( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + _reader: u32, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn flat_stream_write( + _vmctx: *mut VMOpaqueContext, + _memory: *mut VMMemoryDefinition, + _realloc: *mut VMFuncRef, + _ty: TypeStreamTableIndex, + _payload_size: u32, + _payload_align: u32, + _stream: u32, + _address: u32, + _count: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn flat_stream_read( + _vmctx: *mut VMOpaqueContext, + _memory: *mut VMMemoryDefinition, + _realloc: *mut VMFuncRef, + _ty: TypeStreamTableIndex, + _payload_size: u32, + _payload_align: u32, + _stream: u32, + _address: u32, + _count: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn error_context_new( + _vmctx: *mut VMOpaqueContext, + _memory: *mut VMMemoryDefinition, + _realloc: *mut VMFuncRef, + _string_encoding: u8, + _ty: TypeErrorContextTableIndex, + _address: u32, + _count: u32, + ) -> u64 { + unreachable!() + } + + pub(crate) extern "C" fn error_context_debug_message( + _vmctx: *mut VMOpaqueContext, + _memory: *mut VMMemoryDefinition, + _realloc: *mut VMFuncRef, + _string_encoding: u8, + _ty: TypeErrorContextTableIndex, + _handle: u32, + _address: u32, + ) -> bool { + unreachable!() + } + + pub(crate) extern "C" fn error_context_drop( + _vmctx: *mut VMOpaqueContext, + _ty: TypeErrorContextTableIndex, + _error: u32, + ) -> bool { + unreachable!() + } + + pub struct ErrorContext; + + impl ErrorContext { + pub(crate) fn new(_rep: u32) -> Self { + unreachable!() + } + + pub(crate) fn into_val(self) -> Val { + unreachable!() + } + + pub(crate) fn lower( + &self, + _cx: &mut LowerContext<'_, T>, + _ty: InterfaceType, + _dst: &mut MaybeUninit<::Lower>, + ) -> Result<()> { + unreachable!() + } + + pub(crate) fn store( + &self, + _cx: &mut LowerContext<'_, T>, + _ty: InterfaceType, + _offset: usize, + ) -> Result<()> { + unreachable!() + } + + pub(crate) fn lift( + _cx: &mut LiftContext<'_>, + _ty: InterfaceType, + _src: &::Lower, + ) -> Result { + unreachable!() + } + + pub(crate) fn load( + _cx: &mut LiftContext<'_>, + _ty: InterfaceType, + _bytes: &[u8], + ) -> Result { + unreachable!() + } + } + + pub struct StreamReader

{ + _phantom: PhantomData

, + } + + impl

StreamReader

{ + pub(crate) fn new(_rep: u32) -> Self { + unreachable!() + } + + pub(crate) fn into_val(self) -> Val { + unreachable!() + } + + pub(crate) fn lower( + &self, + _cx: &mut LowerContext<'_, T>, + _ty: InterfaceType, + _dst: &mut MaybeUninit<::Lower>, + ) -> Result<()> { + unreachable!() + } + + pub(crate) fn store( + &self, + _cx: &mut LowerContext<'_, T>, + _ty: InterfaceType, + _offset: usize, + ) -> Result<()> { + unreachable!() + } + + pub(crate) fn lift( + _cx: &mut LiftContext<'_>, + _ty: InterfaceType, + _src: &::Lower, + ) -> Result { + unreachable!() + } + + pub(crate) fn load( + _cx: &mut LiftContext<'_>, + _ty: InterfaceType, + _bytes: &[u8], + ) -> Result { + unreachable!() + } + } + + pub struct FutureReader

{ + _phantom: PhantomData

, + } + + impl

FutureReader

{ + pub(crate) fn new(_rep: u32) -> Self { + unreachable!() + } + + pub(crate) fn into_val(self) -> Val { + unreachable!() + } + + pub(crate) fn lower( + &self, + _cx: &mut LowerContext<'_, T>, + _ty: InterfaceType, + _dst: &mut MaybeUninit<::Lower>, + ) -> Result<()> { + unreachable!() + } + + pub(crate) fn store( + &self, + _cx: &mut LowerContext<'_, T>, + _ty: InterfaceType, + _offset: usize, + ) -> Result<()> { + unreachable!() + } + + pub(crate) fn lift( + _cx: &mut LiftContext<'_>, + _ty: InterfaceType, + _src: &::Lower, + ) -> Result { + unreachable!() + } + + pub(crate) fn load( + _cx: &mut LiftContext<'_>, + _ty: InterfaceType, + _bytes: &[u8], + ) -> Result { + unreachable!() + } + } +} diff --git a/crates/wasmtime/src/runtime/component/storage.rs b/crates/wasmtime/src/runtime/component/storage.rs index 01537b42984d..25e43da8c688 100644 --- a/crates/wasmtime/src/runtime/component/storage.rs +++ b/crates/wasmtime/src/runtime/component/storage.rs @@ -37,7 +37,32 @@ 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::()); + assert!( + mem::size_of_val(slice) >= mem::size_of::(), + "needed {}; got {}", + mem::size_of::(), + mem::size_of_val(slice) + ); &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::(); + + // This is an actual runtime assertion which if performance calls for we may + // need to relax to a debug assertion. This notably tries to ensure that we + // 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) + ); + + &*slice.as_ptr().cast() +} diff --git a/crates/wasmtime/src/runtime/component/types.rs b/crates/wasmtime/src/runtime/component/types.rs index 0d63bd664625..f8628094b64d 100644 --- a/crates/wasmtime/src/runtime/component/types.rs +++ b/crates/wasmtime/src/runtime/component/types.rs @@ -7,9 +7,9 @@ use core::fmt; use core::ops::Deref; use wasmtime_environ::component::{ ComponentTypes, InterfaceType, ResourceIndex, TypeComponentIndex, TypeComponentInstanceIndex, - TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex, TypeListIndex, TypeModuleIndex, - TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeTupleIndex, - TypeVariantIndex, + TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex, TypeFutureIndex, TypeFutureTableIndex, + TypeListIndex, TypeModuleIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, + TypeResultIndex, TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, }; use wasmtime_environ::PrimaryMap; @@ -145,6 +145,16 @@ 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, } } @@ -244,6 +254,30 @@ 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]; + self.interface_types_equal(a.payload, b.payload) + } } /// A `list` interface type @@ -416,7 +450,7 @@ impl PartialEq for OptionType { impl Eq for OptionType {} -/// An `expected` interface type +/// A `result` interface type #[derive(Clone, Debug)] pub struct ResultType(Handle); @@ -476,6 +510,55 @@ 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) -> Type { + Type::from(&self.0.types[self.0.index].payload, &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)] @@ -503,6 +586,9 @@ pub enum Type { Flags(Flags), Own(ResourceType), Borrow(ResourceType), + Future(FutureType), + Stream(StreamType), + ErrorContext, } impl Type { @@ -660,6 +746,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, } } @@ -688,6 +777,9 @@ 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 15d99847897d..9c539400ea32 100644 --- a/crates/wasmtime/src/runtime/component/values.rs +++ b/crates/wasmtime/src/runtime/component/values.rs @@ -1,3 +1,4 @@ +use crate::component::concurrent::{ErrorContext, FutureReader, StreamReader}; use crate::component::func::{desc, Lift, LiftContext, Lower, LowerContext}; use crate::component::ResourceAny; use crate::prelude::*; @@ -86,6 +87,9 @@ pub enum Val { Result(Result>, Option>>), Flags(Vec), Resource(ResourceAny), + Future(FutureAny), + Stream(StreamAny), + ErrorContext(ErrorContextAny), } impl Val { @@ -198,6 +202,9 @@ impl Val { Val::Flags(flags.into()) } + InterfaceType::Future(_) => FutureReader::<()>::lift(cx, ty, next(src))?.into_val(), + InterfaceType::Stream(_) => StreamReader::<()>::lift(cx, ty, next(src))?.into_val(), + InterfaceType::ErrorContext(_) => ErrorContext::lift(cx, ty, next(src))?.into_val(), }) } @@ -319,6 +326,9 @@ impl Val { } Val::Flags(flags.into()) } + InterfaceType::Future(_) => FutureReader::<()>::load(cx, ty, bytes)?.into_val(), + InterfaceType::Stream(_) => StreamReader::<()>::load(cx, ty, bytes)?.into_val(), + InterfaceType::ErrorContext(_) => ErrorContext::load(cx, ty, bytes)?.into_val(), }) } @@ -429,6 +439,18 @@ impl Val { Ok(()) } (InterfaceType::Flags(_), _) => unexpected(ty, self), + (InterfaceType::Future(_), Val::Future(FutureAny(rep))) => { + FutureReader::<()>::new(*rep).lower(cx, ty, next_mut(dst)) + } + (InterfaceType::Future(_), _) => unexpected(ty, self), + (InterfaceType::Stream(_), Val::Stream(StreamAny(rep))) => { + StreamReader::<()>::new(*rep).lower(cx, ty, next_mut(dst)) + } + (InterfaceType::Stream(_), _) => unexpected(ty, self), + (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => { + ErrorContext::new(*rep).lower(cx, ty, next_mut(dst)) + } + (InterfaceType::ErrorContext(_), _) => unexpected(ty, self), } } @@ -564,10 +586,22 @@ impl Val { Ok(()) } (InterfaceType::Flags(_), _) => unexpected(ty, self), + (InterfaceType::Future(_), Val::Future(FutureAny(rep))) => { + FutureReader::<()>::new(*rep).store(cx, ty, offset) + } + (InterfaceType::Future(_), _) => unexpected(ty, self), + (InterfaceType::Stream(_), Val::Stream(StreamAny(rep))) => { + StreamReader::<()>::new(*rep).store(cx, ty, offset) + } + (InterfaceType::Stream(_), _) => unexpected(ty, self), + (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => { + ErrorContext::new(*rep).store(cx, ty, offset) + } + (InterfaceType::ErrorContext(_), _) => unexpected(ty, self), } } - fn desc(&self) -> &'static str { + pub(crate) fn desc(&self) -> &'static str { match self { Val::Bool(_) => "bool", Val::U8(_) => "u8", @@ -591,6 +625,9 @@ impl Val { Val::Result(_) => "result", Val::Resource(_) => "resource", Val::Flags(_) => "flags", + Val::Future(_) => "future", + Val::Stream(_) => "stream", + Val::ErrorContext(_) => "error-context", } } @@ -669,6 +706,12 @@ 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, } } } @@ -988,3 +1031,12 @@ fn unexpected(ty: InterfaceType, val: &Val) -> Result { val.desc() ) } + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FutureAny(pub(crate) u32); + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StreamAny(pub(crate) u32); + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ErrorContextAny(pub(crate) u32); diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs index 5cfda2e19983..896506972056 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs @@ -76,6 +76,8 @@ //! contents of `StoreOpaque`. This is an invariant that we, as the authors of //! `wasmtime`, must uphold for the public interface to be safe. +#[cfg(feature = "component-model-async")] +use crate::component::concurrent; use crate::hash_set::HashSet; use crate::instance::InstanceData; use crate::linker::Definition; @@ -226,6 +228,8 @@ pub struct StoreInner { Option) -> Result + Send + Sync>>, // for comments about `ManuallyDrop`, see `Store::into_data` data: ManuallyDrop, + #[cfg(feature = "component-model-async")] + concurrent_state: concurrent::ConcurrentState, } enum ResourceLimiterInner { @@ -592,6 +596,8 @@ impl Store { call_hook: None, epoch_deadline_behavior: None, data: ManuallyDrop::new(data), + #[cfg(feature = "component-model-async")] + concurrent_state: Default::default(), }); // Wasmtime uses the callee argument to host functions to learn about @@ -1106,6 +1112,16 @@ impl<'a, T> StoreContextMut<'a, T> { self.0.data_mut() } + #[cfg(feature = "component-model-async")] + pub(crate) fn concurrent_state(&mut self) -> &mut concurrent::ConcurrentState { + self.0.concurrent_state() + } + + #[cfg(feature = "component-model-async")] + pub(crate) fn has_pkey(&self) -> bool { + self.0.pkey.is_some() + } + /// Returns the underlying [`Engine`] this store is connected to. pub fn engine(&self) -> &Engine { self.0.engine() @@ -1191,6 +1207,11 @@ impl StoreInner { &mut self.data } + #[cfg(feature = "component-model-async")] + fn concurrent_state(&mut self) -> &mut concurrent::ConcurrentState { + &mut self.concurrent_state + } + #[inline] pub fn call_hook(&mut self, s: CallHook) -> Result<()> { if self.inner.pkey.is_none() && self.call_hook.is_none() { diff --git a/crates/wasmtime/src/runtime/vm/component.rs b/crates/wasmtime/src/runtime/vm/component.rs index 813416e134b0..feec2f007a17 100644 --- a/crates/wasmtime/src/runtime/vm/component.rs +++ b/crates/wasmtime/src/runtime/vm/component.rs @@ -29,8 +29,10 @@ const INVALID_PTR: usize = 0xdead_dead_beef_beef_u64 as usize; mod libcalls; mod resources; +mod states; pub use self::resources::{CallContexts, ResourceTable, ResourceTables}; +pub use self::states::StateTable; /// Runtime representation of a component instance and all state necessary for /// the instance itself. @@ -58,6 +60,9 @@ pub struct ComponentInstance { /// is how this field is manipulated. component_resource_tables: PrimaryMap, + component_waitable_tables: PrimaryMap>, + component_error_context_tables: PrimaryMap>, + /// Storage for the type information about resources within this component /// instance. /// @@ -83,6 +88,7 @@ pub struct ComponentInstance { /// which this function pointer was registered. /// * `ty` - the type index, relative to the tables in `vmctx`, that is the /// type of the function being called. +/// * `caller_instance` - The (sub)component instance of the caller. /// * `flags` - the component flags for may_enter/leave corresponding to the /// component instance that the lowering happened within. /// * `opt_memory` - this nullable pointer represents the memory configuration @@ -91,6 +97,7 @@ pub struct ComponentInstance { /// option for the canonical ABI options. /// * `string_encoding` - this is the configured string encoding for the /// canonical ABI this lowering corresponds to. +/// * `async_` - whether the caller is using the async ABI. /// * `args_and_results` - pointer to stack-allocated space in the caller where /// all the arguments are stored as well as where the results will be written /// to. The size and initialized bytes of this depends on the core wasm type @@ -102,7 +109,7 @@ pub struct ComponentInstance { /// or not. On failure this function records trap information in TLS which /// should be suitable for reading later. // -// FIXME: 9 arguments is probably too many. The `data` through `string-encoding` +// FIXME: 11 arguments is probably too many. The `data` through `string-encoding` // parameters should probably get packaged up into the `VMComponentContext`. // Needs benchmarking one way or another though to figure out what the best // balance is here. @@ -110,10 +117,12 @@ pub type VMLoweringCallee = extern "C" fn( vmctx: *mut VMOpaqueContext, data: *mut u8, ty: u32, + caller_instance: u32, flags: *mut u8, opt_memory: *mut VMMemoryDefinition, opt_realloc: *mut VMFuncRef, string_encoding: u8, + async_: u8, args_and_results: *mut mem::MaybeUninit, nargs_and_results: usize, ) -> bool; @@ -130,6 +139,181 @@ pub struct VMLowering { pub data: *mut u8, } +/// Type signature for the host-defined `task.backpressure` built-in function. +pub type VMTaskBackpressureCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + caller_instance: RuntimeComponentInstanceIndex, + arg: u32, +) -> bool; + +/// Type signature for the host-defined `task.return` built-in function. +pub type VMTaskReturnCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + ty: TypeTaskReturnIndex, + args_and_results: *mut mem::MaybeUninit, + nargs_and_results: usize, +) -> bool; + +/// Type signature for the host-defined `task.wait` and `task.poll` built-in functions. +pub type VMTaskWaitOrPollCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + caller_instance: RuntimeComponentInstanceIndex, + async_: bool, + memory: *mut VMMemoryDefinition, + payload: u32, +) -> u64; + +/// Type signature for the host-defined `task.yield` built-in function. +pub type VMTaskYieldCallback = extern "C" fn(vmctx: *mut VMOpaqueContext, async_: bool) -> bool; + +/// Type signature for the host-defined `subtask.drop` built-in function. +pub type VMSubtaskDropCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + instance: RuntimeComponentInstanceIndex, + arg: u32, +) -> bool; + +/// Type signature for the host-defined built-in function to represent starting +/// a call to an async-lowered import in a FACT-generated module. +pub type VMAsyncEnterCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + start: *mut VMFuncRef, + return_: *mut VMFuncRef, + caller_instance: RuntimeComponentInstanceIndex, + task_return_type: TypeTaskReturnIndex, + params: u32, + results: u32, +) -> bool; + +/// Type signature for the host-defined built-in function to represent +/// completing a call to an async-lowered import in a FACT-generated module. +pub type VMAsyncExitCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + callback: *mut VMFuncRef, + caller_instance: RuntimeComponentInstanceIndex, + callee: *mut VMFuncRef, + callee_instance: RuntimeComponentInstanceIndex, + param_count: u32, + result_count: u32, + flags: u32, +) -> u64; + +/// Type signature for the host-defined `future.new` built-in function. +pub type VMFutureNewCallback = + extern "C" fn(vmctx: *mut VMOpaqueContext, ty: TypeFutureTableIndex) -> u64; + +/// Type signature for the host-defined `future.read` and `future.write` +/// built-in functions. +pub type VMFutureTransmitCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeFutureTableIndex, + future: u32, + address: u32, +) -> u64; + +/// Type signature for the host-defined `future.cancel-read` and +/// `future.cancel-write` built-in functions. +pub type VMFutureCancelCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, + async_: bool, + handle: u32, +) -> u64; + +/// Type signature for the host-defined `future.close-readable` built-in function. +pub type VMFutureCloseReadableCallback = + extern "C" fn(vmctx: *mut VMOpaqueContext, ty: TypeFutureTableIndex, handle: u32) -> bool; + +/// Type signature for the host-defined `future.close-writable` built-in function. +pub type VMFutureCloseWritableCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, + handle: u32, + error: u32, +) -> bool; + +/// Type signature for the host-defined `stream.new` built-in function. +pub type VMStreamNewCallback = + extern "C" fn(vmctx: *mut VMOpaqueContext, ty: TypeStreamTableIndex) -> u64; + +/// Type signature for the host-defined `stream.read` and `stream.write` +/// built-in functions +pub type VMStreamTransmitCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeStreamTableIndex, + stream: u32, + address: u32, + count: u32, +) -> u64; + +/// Type signature for the host-defined `stream.read` ans `stream.write` +/// built-in functions for when the payload is trivially `memcpy`-able. +pub type VMFlatStreamTransmitCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + ty: TypeStreamTableIndex, + payload_size: u32, + payload_align: u32, + stream: u32, + address: u32, + count: u32, +) -> u64; + +/// Type signature for the host-defined `stream.close-readable` built-in function. +pub type VMStreamCloseReadableCallback = + extern "C" fn(vmctx: *mut VMOpaqueContext, ty: TypeStreamTableIndex, handle: u32) -> bool; + +/// Type signature for the host-defined `stream.close-writable` built-in function. +pub type VMStreamCloseWritableCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, + handle: u32, + error: u32, +) -> bool; + +/// Type signature for the host-defined `stream.cancel-read` and +/// `stream.cancel-write` built-in functions. +pub type VMStreamCancelCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, + async_: bool, + handle: u32, +) -> u64; + +/// Type signature for the host-defined `error-context.new` built-in function. +pub type VMErrorContextNewCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeErrorContextTableIndex, + address: u32, + count: u32, +) -> u64; + +/// Type signature for the host-defined `error-context.debug-message` built-in +/// function. +pub type VMErrorContextDebugMessageCallback = extern "C" fn( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TypeErrorContextTableIndex, + handle: u32, + address: u32, +) -> bool; + +/// Type signature for the host-defined `error-context.drop` built-in function. +pub type VMErrorContextDropCallback = + extern "C" fn(vmctx: *mut VMOpaqueContext, ty: TypeErrorContextTableIndex, handle: u32) -> bool; + /// This is a marker type to represent the underlying allocation of a /// `VMComponentContext`. /// @@ -148,6 +332,30 @@ pub struct VMComponentContext { _marker: marker::PhantomPinned, } +/// Represents the state of a stream or future handle. +#[derive(Debug, Eq, PartialEq)] +pub enum StreamFutureState { + /// Both the read and write ends are owned by the same component instance. + Local, + /// Only the write end is owned by this component instance. + Write, + /// Only the read end is owned by this component instance. + Read, + /// A read or write is in progress. + Busy, +} + +/// Represents the state of a waitable handle. +#[derive(Debug)] +pub enum WaitableState { + /// Represents a task handle. + Task, + /// Represents a stream handle. + Stream(TypeStreamTableIndex, StreamFutureState), + /// Represents a future handle. + Future(TypeFutureTableIndex, StreamFutureState), +} + impl ComponentInstance { /// Converts the `vmctx` provided into a `ComponentInstance` and runs the /// provided closure with that instance. @@ -197,12 +405,26 @@ impl ComponentInstance { ) { assert!(alloc_size >= Self::alloc_layout(&offsets).size()); - let num_tables = runtime_info.component().num_resource_tables; - let mut component_resource_tables = PrimaryMap::with_capacity(num_tables); - for _ in 0..num_tables { + let num_resource_tables = runtime_info.component().num_resource_tables; + let mut component_resource_tables = PrimaryMap::with_capacity(num_resource_tables); + for _ in 0..num_resource_tables { component_resource_tables.push(ResourceTable::default()); } + let num_waitable_tables = runtime_info.component().num_runtime_component_instances; + let mut component_waitable_tables = + PrimaryMap::with_capacity(usize::try_from(num_waitable_tables).unwrap()); + for _ in 0..num_waitable_tables { + component_waitable_tables.push(StateTable::default()); + } + + let num_error_context_tables = runtime_info.component().num_error_context_tables; + let mut component_error_context_tables = + PrimaryMap::with_capacity(num_error_context_tables); + for _ in 0..num_error_context_tables { + component_error_context_tables.push(StateTable::default()); + } + ptr::write( ptr.as_ptr(), ComponentInstance { @@ -216,6 +438,8 @@ impl ComponentInstance { .unwrap(), ), component_resource_tables, + component_waitable_tables, + component_error_context_tables, runtime_info, resource_types, vmctx: VMComponentContext { @@ -290,6 +514,18 @@ 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 + } + } + /// Returns the post-return pointer corresponding to the index provided. /// /// This can only be called after `idx` has been initialized at runtime @@ -363,6 +599,15 @@ impl ComponentInstance { } } + /// Same as `set_runtime_memory` but for async callback function pointers. + pub fn set_runtime_callback(&mut self, idx: RuntimeCallbackIndex, ptr: NonNull) { + unsafe { + let storage = self.vmctx_plus_offset_mut(self.offsets.runtime_callback(idx)); + debug_assert!(*storage as usize == INVALID_PTR); + *storage = ptr.as_ptr(); + } + } + /// Same as `set_runtime_memory` but for post-return function pointers. pub fn set_runtime_post_return( &mut self, @@ -439,6 +684,75 @@ impl ComponentInstance { } } + /// Set the host-provided callbacks for various async-, future-, stream-, + /// and error-context-related built-in functions. + pub fn set_async_callbacks( + &mut self, + task_backpressure: VMTaskBackpressureCallback, + task_return: VMTaskReturnCallback, + task_wait: VMTaskWaitOrPollCallback, + task_poll: VMTaskWaitOrPollCallback, + task_yield: VMTaskYieldCallback, + subtask_drop: VMSubtaskDropCallback, + async_enter: VMAsyncEnterCallback, + async_exit: VMAsyncExitCallback, + future_new: VMFutureNewCallback, + future_write: VMFutureTransmitCallback, + future_read: VMFutureTransmitCallback, + future_cancel_write: VMFutureCancelCallback, + future_cancel_read: VMFutureCancelCallback, + future_close_writable: VMFutureCloseWritableCallback, + future_close_readable: VMFutureCloseReadableCallback, + stream_new: VMStreamNewCallback, + stream_write: VMStreamTransmitCallback, + stream_read: VMStreamTransmitCallback, + stream_cancel_write: VMStreamCancelCallback, + stream_cancel_read: VMStreamCancelCallback, + stream_close_writable: VMStreamCloseWritableCallback, + stream_close_readable: VMStreamCloseReadableCallback, + flat_stream_write: VMFlatStreamTransmitCallback, + flat_stream_read: VMFlatStreamTransmitCallback, + error_context_new: VMErrorContextNewCallback, + error_context_debug_message: VMErrorContextDebugMessageCallback, + error_context_drop: VMErrorContextDropCallback, + ) { + unsafe { + *self.vmctx_plus_offset_mut(self.offsets.task_backpressure()) = task_backpressure; + *self.vmctx_plus_offset_mut(self.offsets.task_return()) = task_return; + *self.vmctx_plus_offset_mut(self.offsets.task_wait()) = task_wait; + *self.vmctx_plus_offset_mut(self.offsets.task_poll()) = task_poll; + *self.vmctx_plus_offset_mut(self.offsets.task_yield()) = task_yield; + *self.vmctx_plus_offset_mut(self.offsets.subtask_drop()) = subtask_drop; + *self.vmctx_plus_offset_mut(self.offsets.async_enter()) = async_enter; + *self.vmctx_plus_offset_mut(self.offsets.async_exit()) = async_exit; + *self.vmctx_plus_offset_mut(self.offsets.future_new()) = future_new; + *self.vmctx_plus_offset_mut(self.offsets.future_write()) = future_write; + *self.vmctx_plus_offset_mut(self.offsets.future_read()) = future_read; + *self.vmctx_plus_offset_mut(self.offsets.future_cancel_write()) = future_cancel_write; + *self.vmctx_plus_offset_mut(self.offsets.future_cancel_read()) = future_cancel_read; + *self.vmctx_plus_offset_mut(self.offsets.future_close_writable()) = + future_close_writable; + *self.vmctx_plus_offset_mut(self.offsets.future_close_readable()) = + future_close_readable; + *self.vmctx_plus_offset_mut(self.offsets.stream_new()) = stream_new; + *self.vmctx_plus_offset_mut(self.offsets.stream_write()) = stream_write; + *self.vmctx_plus_offset_mut(self.offsets.stream_read()) = stream_read; + *self.vmctx_plus_offset_mut(self.offsets.stream_cancel_write()) = stream_cancel_write; + *self.vmctx_plus_offset_mut(self.offsets.stream_cancel_read()) = stream_cancel_read; + *self.vmctx_plus_offset_mut(self.offsets.stream_close_writable()) = + stream_close_writable; + *self.vmctx_plus_offset_mut(self.offsets.stream_close_readable()) = + stream_close_readable; + *self.vmctx_plus_offset_mut(self.offsets.flat_stream_write()) = flat_stream_write; + *self.vmctx_plus_offset_mut(self.offsets.flat_stream_read()) = flat_stream_read; + *self.vmctx_plus_offset_mut(self.offsets.error_context_debug_message()) = + error_context_new; + *self.vmctx_plus_offset_mut(self.offsets.error_context_debug_message()) = + error_context_debug_message; + *self.vmctx_plus_offset_mut(self.offsets.error_context_drop()) = error_context_drop; + } + } + unsafe fn initialize_vmctx(&mut self, store: *mut dyn VMStore) { *self.vmctx_plus_offset_mut(self.offsets.magic()) = VMCOMPONENT_MAGIC; *self.vmctx_plus_offset_mut(self.offsets.builtins()) = &libcalls::VMComponentBuiltins::INIT; @@ -453,7 +767,7 @@ impl ComponentInstance { } // In debug mode set non-null bad values to all "pointer looking" bits - // and pices related to lowering and such. This'll help detect any + // and pieces related to lowering and such. This'll help detect any // erroneous usage and enable debug assertions above as well to prevent // loading these before they're configured or setting them twice. if cfg!(debug_assertions) { @@ -479,6 +793,11 @@ impl ComponentInstance { let offset = self.offsets.runtime_realloc(i); *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; } + for i in 0..self.offsets.num_runtime_callbacks { + let i = RuntimeCallbackIndex::from_u32(i); + let offset = self.offsets.runtime_callback(i); + *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; + } for i in 0..self.offsets.num_runtime_post_returns { let i = RuntimePostReturnIndex::from_u32(i); let offset = self.offsets.runtime_post_return(i); @@ -573,6 +892,22 @@ impl ComponentInstance { &mut self.component_resource_tables } + /// Retrieves the tables for tracking waitable handles and their states with respect + /// to the components which own them. + pub fn component_waitable_tables( + &mut self, + ) -> &mut PrimaryMap> { + &mut self.component_waitable_tables + } + + /// Retrieves the tables for tracking error-context handles and their reference + /// counts with respect to the components which own them. + pub fn component_error_context_tables( + &mut self, + ) -> &mut PrimaryMap> { + &mut self.component_error_context_tables + } + /// Returns the destructor and instance flags for the specified resource /// table type. /// @@ -633,6 +968,113 @@ impl ComponentInstance { pub(crate) fn resource_exit_call(&mut self) -> Result<()> { self.resource_tables().exit_call() } + + pub(crate) fn future_transfer( + &mut self, + src_idx: u32, + src: TypeFutureTableIndex, + dst: TypeFutureTableIndex, + ) -> Result { + let src_instance = self.component_types()[src].instance; + let dst_instance = self.component_types()[dst].instance; + let [src_table, dst_table] = self + .component_waitable_tables + .get_many_mut([src_instance, dst_instance]) + .unwrap(); + let (rep, WaitableState::Future(src_ty, src_state)) = + src_table.get_mut_by_index(src_idx)? + else { + bail!("invalid future handle"); + }; + if *src_ty != src { + bail!("invalid future handle"); + } + match src_state { + StreamFutureState::Local => { + *src_state = StreamFutureState::Write; + assert!(dst_table.get_mut_by_rep(rep).is_none()); + dst_table.insert(rep, WaitableState::Future(dst, StreamFutureState::Read)) + } + StreamFutureState::Read => { + src_table.remove_by_index(src_idx)?; + if let Some((dst_idx, dst_state)) = dst_table.get_mut_by_rep(rep) { + let WaitableState::Future(dst_ty, dst_state) = dst_state else { + unreachable!(); + }; + assert_eq!(*dst_ty, dst); + assert_eq!(*dst_state, StreamFutureState::Write); + *dst_state = StreamFutureState::Local; + Ok(dst_idx) + } else { + dst_table.insert(rep, WaitableState::Future(dst, StreamFutureState::Read)) + } + } + StreamFutureState::Write => bail!("cannot transfer write end of future"), + StreamFutureState::Busy => bail!("cannot transfer busy future"), + } + } + + pub(crate) fn stream_transfer( + &mut self, + src_idx: u32, + src: TypeStreamTableIndex, + dst: TypeStreamTableIndex, + ) -> Result { + let src_instance = self.component_types()[src].instance; + let dst_instance = self.component_types()[dst].instance; + let [src_table, dst_table] = self + .component_waitable_tables + .get_many_mut([src_instance, dst_instance]) + .unwrap(); + let (rep, WaitableState::Stream(src_ty, src_state)) = + src_table.get_mut_by_index(src_idx)? + else { + bail!("invalid stream handle"); + }; + if *src_ty != src { + bail!("invalid stream handle"); + } + match src_state { + StreamFutureState::Local => { + *src_state = StreamFutureState::Write; + assert!(dst_table.get_mut_by_rep(rep).is_none()); + dst_table.insert(rep, WaitableState::Stream(dst, StreamFutureState::Read)) + } + StreamFutureState::Read => { + src_table.remove_by_index(src_idx)?; + if let Some((dst_idx, dst_state)) = dst_table.get_mut_by_rep(rep) { + let WaitableState::Stream(dst_ty, dst_state) = dst_state else { + unreachable!(); + }; + assert_eq!(*dst_ty, dst); + assert_eq!(*dst_state, StreamFutureState::Write); + *dst_state = StreamFutureState::Local; + Ok(dst_idx) + } else { + dst_table.insert(rep, WaitableState::Stream(dst, StreamFutureState::Read)) + } + } + StreamFutureState::Write => bail!("cannot transfer write end of stream"), + StreamFutureState::Busy => bail!("cannot transfer busy stream"), + } + } + + pub(crate) fn error_context_transfer( + &mut self, + src_idx: u32, + src: TypeErrorContextTableIndex, + dst: TypeErrorContextTableIndex, + ) -> Result { + let (rep, _) = self.component_error_context_tables[src].get_mut_by_index(src_idx)?; + let dst = &mut self.component_error_context_tables[dst]; + + if let Some((dst_idx, dst_state)) = dst.get_mut_by_rep(rep) { + *dst_state += 1; + Ok(dst_idx) + } else { + dst.insert(rep, 1) + } + } } impl VMComponentContext { @@ -653,7 +1095,7 @@ impl VMComponentContext { /// This type can be dereferenced to `ComponentInstance` to access the /// underlying methods. pub struct OwnedComponentInstance { - ptr: SendSyncPtr, + pub(crate) ptr: SendSyncPtr, } impl OwnedComponentInstance { @@ -716,6 +1158,11 @@ impl OwnedComponentInstance { unsafe { self.instance_mut().set_runtime_realloc(idx, ptr) } } + /// See `ComponentInstance::set_runtime_callback` + pub fn set_runtime_callback(&mut self, idx: RuntimeCallbackIndex, ptr: NonNull) { + unsafe { self.instance_mut().set_runtime_callback(idx, ptr) } + } + /// See `ComponentInstance::set_runtime_post_return` pub fn set_runtime_post_return( &mut self, @@ -757,6 +1204,70 @@ impl OwnedComponentInstance { pub fn resource_types_mut(&mut self) -> &mut Arc { unsafe { &mut (*self.ptr.as_ptr()).resource_types } } + + /// See `ComponentInstance::set_async_callbacks` + pub fn set_async_callbacks( + &mut self, + task_backpressure: VMTaskBackpressureCallback, + task_return: VMTaskReturnCallback, + task_wait: VMTaskWaitOrPollCallback, + task_poll: VMTaskWaitOrPollCallback, + task_yield: VMTaskYieldCallback, + subtask_drop: VMSubtaskDropCallback, + async_enter: VMAsyncEnterCallback, + async_exit: VMAsyncExitCallback, + future_new: VMFutureNewCallback, + future_write: VMFutureTransmitCallback, + future_read: VMFutureTransmitCallback, + future_cancel_write: VMFutureCancelCallback, + future_cancel_read: VMFutureCancelCallback, + future_close_writable: VMFutureCloseWritableCallback, + future_close_readable: VMFutureCloseReadableCallback, + stream_new: VMStreamNewCallback, + stream_write: VMStreamTransmitCallback, + stream_read: VMStreamTransmitCallback, + stream_cancel_write: VMStreamCancelCallback, + stream_cancel_read: VMStreamCancelCallback, + stream_close_writable: VMStreamCloseWritableCallback, + stream_close_readable: VMStreamCloseReadableCallback, + flat_stream_write: VMFlatStreamTransmitCallback, + flat_stream_read: VMFlatStreamTransmitCallback, + error_context_new: VMErrorContextNewCallback, + error_context_debug_message: VMErrorContextDebugMessageCallback, + error_context_drop: VMErrorContextDropCallback, + ) { + unsafe { + self.instance_mut().set_async_callbacks( + task_backpressure, + task_return, + task_wait, + task_poll, + task_yield, + subtask_drop, + async_enter, + async_exit, + future_new, + future_write, + future_read, + future_cancel_write, + future_cancel_read, + future_close_writable, + future_close_readable, + stream_new, + stream_write, + stream_read, + stream_cancel_write, + stream_cancel_read, + stream_close_writable, + stream_close_readable, + flat_stream_write, + flat_stream_read, + error_context_new, + error_context_debug_message, + error_context_drop, + ) + } + } } impl Deref for OwnedComponentInstance { diff --git a/crates/wasmtime/src/runtime/vm/component/libcalls.rs b/crates/wasmtime/src/runtime/vm/component/libcalls.rs index 94d83babe75f..ef3b6f60b236 100644 --- a/crates/wasmtime/src/runtime/vm/component/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/component/libcalls.rs @@ -6,7 +6,9 @@ use crate::runtime::vm::HostResultHasUnwindSentinel; use core::cell::Cell; use core::convert::Infallible; use core::slice; -use wasmtime_environ::component::TypeResourceTableIndex; +use wasmtime_environ::component::{ + TypeErrorContextTableIndex, TypeFutureTableIndex, TypeResourceTableIndex, TypeStreamTableIndex, +}; const UTF16_TAG: usize = 1 << 31; @@ -557,3 +559,42 @@ unsafe fn resource_exit_call(vmctx: *mut VMComponentContext) -> Result<()> { unsafe fn trap(_vmctx: *mut VMComponentContext, code: u8) -> Result { Err(wasmtime_environ::Trap::from_u8(code).unwrap().into()) } + +unsafe fn future_transfer( + vmctx: *mut VMComponentContext, + src_idx: u32, + src_table: u32, + dst_table: u32, +) -> Result { + let src_table = TypeFutureTableIndex::from_u32(src_table); + let dst_table = TypeFutureTableIndex::from_u32(dst_table); + ComponentInstance::from_vmctx(vmctx, |instance| { + instance.future_transfer(src_idx, src_table, dst_table) + }) +} + +unsafe fn stream_transfer( + vmctx: *mut VMComponentContext, + src_idx: u32, + src_table: u32, + dst_table: u32, +) -> Result { + let src_table = TypeStreamTableIndex::from_u32(src_table); + let dst_table = TypeStreamTableIndex::from_u32(dst_table); + ComponentInstance::from_vmctx(vmctx, |instance| { + instance.stream_transfer(src_idx, src_table, dst_table) + }) +} + +unsafe fn error_context_transfer( + vmctx: *mut VMComponentContext, + src_idx: u32, + src_table: u32, + dst_table: u32, +) -> Result { + let src_table = TypeErrorContextTableIndex::from_u32(src_table); + let dst_table = TypeErrorContextTableIndex::from_u32(dst_table); + ComponentInstance::from_vmctx(vmctx, |instance| { + instance.error_context_transfer(src_idx, src_table, dst_table) + }) +} diff --git a/crates/wasmtime/src/runtime/vm/component/states.rs b/crates/wasmtime/src/runtime/vm/component/states.rs new file mode 100644 index 000000000000..8a8a9a39ee6a --- /dev/null +++ b/crates/wasmtime/src/runtime/vm/component/states.rs @@ -0,0 +1,126 @@ +use { + alloc::vec::Vec, + anyhow::{bail, Result}, + core::mem, +}; + +/// The maximum handle value is specified in +/// +/// currently and keeps the upper bit free for use in the component. +const MAX_HANDLE: u32 = 1 << 30; + +enum Slot { + Free { next: u32 }, + Occupied { rep: u32, state: T }, +} + +pub struct StateTable { + next: u32, + slots: Vec>, + // TODO: This is a sparse table (where zero means "no entry"); it might make + // more sense to use a `HashMap` here, but we'd need one that's + // no_std-compatible. A `BTreeMap` might also be appropriate if we restrict + // ourselves to `alloc::collections`. + reps_to_indexes: Vec, +} + +impl Default for StateTable { + fn default() -> Self { + Self { + next: 0, + slots: Vec::new(), + reps_to_indexes: Vec::new(), + } + } +} + +impl StateTable { + pub fn insert(&mut self, rep: u32, state: T) -> Result { + if matches!(self + .reps_to_indexes + .get(usize::try_from(rep).unwrap()), Some(idx) if *idx != 0) + { + bail!("rep {rep} already exists in this table"); + } + + let next = self.next as usize; + if next == self.slots.len() { + self.slots.push(Slot::Free { + next: self.next.checked_add(1).unwrap(), + }); + } + let ret = self.next; + self.next = match mem::replace(&mut self.slots[next], Slot::Occupied { rep, state }) { + Slot::Free { next } => next, + _ => unreachable!(), + }; + // The component model reserves index 0 as never allocatable so add one + // to the table index to start the numbering at 1 instead. Also note + // that the component model places an upper-limit per-table on the + // maximum allowed index. + let ret = ret + 1; + if ret >= MAX_HANDLE { + bail!("cannot allocate another handle: index overflow"); + } + + let rep = usize::try_from(rep).unwrap(); + if self.reps_to_indexes.len() <= rep { + self.reps_to_indexes.resize(rep.checked_add(1).unwrap(), 0); + } + + self.reps_to_indexes[rep] = ret; + + Ok(ret) + } + + fn handle_index_to_table_index(&self, idx: u32) -> Option { + // NB: `idx` is decremented by one to account for the `+1` above during + // allocation. + let idx = idx.checked_sub(1)?; + usize::try_from(idx).ok() + } + + fn get_mut(&mut self, idx: u32) -> Result<&mut Slot> { + let slot = self + .handle_index_to_table_index(idx) + .and_then(|i| self.slots.get_mut(i)); + match slot { + None | Some(Slot::Free { .. }) => bail!("unknown handle index {idx}"), + Some(slot) => Ok(slot), + } + } + + pub fn get_mut_by_index(&mut self, idx: u32) -> Result<(u32, &mut T)> { + let slot = self + .handle_index_to_table_index(idx) + .and_then(|i| self.slots.get_mut(i)); + match slot { + None | Some(Slot::Free { .. }) => bail!("unknown handle index {idx}"), + Some(Slot::Occupied { rep, state }) => Ok((*rep, state)), + } + } + + pub fn get_mut_by_rep(&mut self, rep: u32) -> Option<(u32, &mut T)> { + let index = *self.reps_to_indexes.get(usize::try_from(rep).unwrap())?; + if index > 0 { + let (_, state) = self.get_mut_by_index(index).unwrap(); + Some((index, state)) + } else { + None + } + } + + pub fn remove_by_index(&mut self, idx: u32) -> Result<(u32, T)> { + let to_fill = Slot::Free { next: self.next }; + let Slot::Occupied { rep, state } = mem::replace(self.get_mut(idx)?, to_fill) else { + unreachable!() + }; + self.next = idx - 1; + { + let rep = usize::try_from(rep).unwrap(); + assert_eq!(idx, self.reps_to_indexes[rep]); + self.reps_to_indexes[rep] = 0; + } + Ok((rep, state)) + } +} diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs index f16ed6f7f516..ddf8b84f9055 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs @@ -519,6 +519,7 @@ unsafe impl InstanceAllocatorImpl for PoolingInstanceAllocator { LowerImport { .. } | ExtractMemory(_) | ExtractRealloc(_) + | ExtractCallback(_) | ExtractPostReturn(_) | Resource(_) => {} } diff --git a/crates/wasmtime/src/runtime/vm/interpreter.rs b/crates/wasmtime/src/runtime/vm/interpreter.rs index 6d0349b9d504..4a979a651fa5 100644 --- a/crates/wasmtime/src/runtime/vm/interpreter.rs +++ b/crates/wasmtime/src/runtime/vm/interpreter.rs @@ -310,7 +310,7 @@ impl InterpreterRef<'_> { use wasmtime_environ::component::ComponentBuiltinFunctionIndex; if id == const { HostCall::ComponentLowerImport.index() } { - call!(@host VMLoweringCallee(ptr, ptr, u32, ptr, ptr, ptr, u8, ptr, size) -> bool); + call!(@host VMLoweringCallee(ptr, ptr, u32, u32, ptr, ptr, ptr, u8, u8, ptr, size) -> bool); } macro_rules! component { diff --git a/crates/wasmtime/src/runtime/wave/component.rs b/crates/wasmtime/src/runtime/wave/component.rs index b770b6bf4109..656a03136d1d 100644 --- a/crates/wasmtime/src/runtime/wave/component.rs +++ b/crates/wasmtime/src/runtime/wave/component.rs @@ -41,7 +41,11 @@ impl WasmType for component::Type { Self::Result(_) => WasmTypeKind::Result, Self::Flags(_) => WasmTypeKind::Flags, - Self::Own(_) | Self::Borrow(_) => WasmTypeKind::Unsupported, + Self::Own(_) + | Self::Borrow(_) + | Self::Stream(_) + | Self::Future(_) + | Self::ErrorContext => WasmTypeKind::Unsupported, } } @@ -134,7 +138,9 @@ impl WasmValue for component::Val { Self::Option(_) => WasmTypeKind::Option, Self::Result(_) => WasmTypeKind::Result, Self::Flags(_) => WasmTypeKind::Flags, - Self::Resource(_) => WasmTypeKind::Unsupported, + Self::Resource(_) | Self::Stream(_) | Self::Future(_) | Self::ErrorContext(_) => { + WasmTypeKind::Unsupported + } } } diff --git a/crates/wast/src/component.rs b/crates/wast/src/component.rs index 8a7f19dc08d0..1346a7f11361 100644 --- a/crates/wast/src/component.rs +++ b/crates/wast/src/component.rs @@ -284,6 +284,9 @@ 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/Cargo.toml b/crates/wit-bindgen/Cargo.toml index 90e8ea3e9959..9e958081ce96 100644 --- a/crates/wit-bindgen/Cargo.toml +++ b/crates/wit-bindgen/Cargo.toml @@ -20,3 +20,4 @@ indexmap = { workspace = true } [features] std = [] +component-model-async = ['std'] diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 74687f9d673c..0f2b75a761a3 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -59,10 +59,10 @@ struct Wasmtime { opts: Opts, /// A list of all interfaces which were imported by this world. /// - /// The second value here is the contents of the module that this interface - /// generated. The third value is the name of the interface as also present - /// in `self.interface_names`. - import_interfaces: Vec<(InterfaceId, String, InterfaceName)>, + /// The first two values identify the interface; the third is the contents of the + /// module that this interface generated. The fourth value is the name of the + /// interface as also present in `self.interface_names`. + import_interfaces: Vec<(WorldKey, InterfaceId, String, InterfaceName)>, import_functions: Vec, exports: Exports, types: Types, @@ -134,6 +134,21 @@ pub struct Opts { /// Whether or not to use async rust functions and traits. pub async_: AsyncConfig, + /// Whether or not to use `func_wrap_concurrent` when generating code for + /// async imports. + /// + /// Unlike `func_wrap_async`, `func_wrap_concurrent` allows host functions + /// to suspend without monopolizing the `Store`, meaning other guest tasks + /// can make progress concurrently. + pub concurrent_imports: bool, + + /// Whether or not to use `call_concurrent` when generating code for + /// async exports. + /// + /// Unlike `call_async`, `call_concurrent` allows the caller to make + /// multiple concurrent calls on the same component instance. + pub concurrent_exports: bool, + /// A list of "trappable errors" which are used to replace the `E` in /// `result` found in WIT. pub trappable_error_type: Vec, @@ -175,6 +190,15 @@ pub struct Opts { /// Path to the `wasmtime` crate if it's not the default path. pub wasmtime_crate: Option, + + /// If true, write the generated bindings to a file for better error + /// messages from `rustc`. + /// + /// This can also be toggled via the `WASMTIME_DEBUG_BINDGEN` environment + /// variable, but that will affect _all_ `bindgen!` macro invocations (and + /// can sometimes lead to one invocation ovewriting another in unpredictable + /// ways), whereas this option lets you specify it on a case-by-case basis. + pub debug: bool, } #[derive(Debug, Clone)] @@ -213,28 +237,10 @@ pub enum AsyncConfig { OnlyImports(HashSet), } -impl AsyncConfig { - pub fn is_import_async(&self, f: &str) -> bool { - match self { - AsyncConfig::None => false, - AsyncConfig::All => true, - AsyncConfig::AllExceptImports(set) => !set.contains(f), - AsyncConfig::OnlyImports(set) => set.contains(f), - } - } - - pub fn is_drop_async(&self, r: &str) -> bool { - self.is_import_async(&format!("[drop]{r}")) - } - - pub fn maybe_async(&self) -> bool { - match self { - AsyncConfig::None => false, - AsyncConfig::All | AsyncConfig::AllExceptImports(_) | AsyncConfig::OnlyImports(_) => { - true - } - } - } +pub enum CallStyle { + Sync, + Async, + Concurrent, } #[derive(Default, Debug, Clone)] @@ -260,6 +266,22 @@ impl TrappableImports { impl Opts { pub fn generate(&self, resolve: &Resolve, world: WorldId) -> anyhow::Result { + // TODO: Should we refine this test to inspect only types reachable from + // the specified world? + if !cfg!(feature = "component-model-async") + && resolve.types.iter().any(|(_, ty)| { + matches!( + ty.kind, + TypeDefKind::Future(_) | TypeDefKind::Stream(_) | TypeDefKind::ErrorContext + ) + }) + { + anyhow::bail!( + "must enable `component-model-async` feature when using WIT files \ + containing future, stream, or error types" + ); + } + let mut r = Wasmtime::default(); r.sizes.fill(resolve); r.opts = self.clone(); @@ -268,7 +290,41 @@ impl Opts { } fn is_store_data_send(&self) -> bool { - self.async_.maybe_async() || self.require_store_data_send + matches!(self.call_style(), CallStyle::Async | CallStyle::Concurrent) + || self.require_store_data_send + } + + pub fn import_call_style(&self, qualifier: Option<&str>, f: &str) -> CallStyle { + let matched = |names: &HashSet| { + names.contains(f) + || qualifier + .map(|v| names.contains(&format!("{v}#{f}"))) + .unwrap_or(false) + }; + + match &self.async_ { + AsyncConfig::AllExceptImports(names) if matched(names) => CallStyle::Sync, + AsyncConfig::OnlyImports(names) if !matched(names) => CallStyle::Sync, + _ => self.call_style(), + } + } + + pub fn drop_call_style(&self, qualifier: Option<&str>, r: &str) -> CallStyle { + self.import_call_style(qualifier, &format!("[drop]{r}")) + } + + pub fn call_style(&self) -> CallStyle { + match &self.async_ { + AsyncConfig::None => CallStyle::Sync, + + AsyncConfig::All | AsyncConfig::AllExceptImports(_) | AsyncConfig::OnlyImports(_) => { + if self.concurrent_imports { + CallStyle::Concurrent + } else { + CallStyle::Async + } + } + } } } @@ -455,7 +511,7 @@ impl Wasmtime { // resource-related functions get their trait signatures // during `type_resource`. let sig = if let FunctionKind::Freestanding = func.kind { - gen.generate_function_trait_sig(func); + gen.generate_function_trait_sig(func, "Data"); Some(mem::take(&mut gen.src).into()) } else { None @@ -471,14 +527,14 @@ impl Wasmtime { WorldItem::Interface { id, .. } => { gen.gen.interface_last_seen_as_import.insert(*id, true); gen.current_interface = Some((*id, name, false)); - let snake = match name { + let snake = to_rust_ident(&match name { WorldKey::Name(s) => s.to_snake_case(), WorldKey::Interface(id) => resolve.interfaces[*id] .name .as_ref() .unwrap() .to_snake_case(), - }; + }); let module = if gen.gen.name_interface(resolve, *id, name, false) { // If this interface is remapped then that means that it was // provided via the `with` key in the bindgen configuration. @@ -523,8 +579,12 @@ impl Wasmtime { " ) }; - self.import_interfaces - .push((*id, module, self.interface_names[id].clone())); + self.import_interfaces.push(( + name.clone(), + *id, + module, + self.interface_names[id].clone(), + )); let interface_path = self.import_interface_path(id); self.interface_link_options[id] @@ -806,10 +866,11 @@ fn _new( let wt = self.wasmtime_path(); let world_name = &resolve.worlds[world].name; let camel = to_rust_upper_camel_case(&world_name); - let (async_, async__, where_clause, await_) = if self.opts.async_.maybe_async() { - ("async", "_async", "where _T: Send", ".await") - } else { - ("", "", "", "") + let (async_, async__, bounds, await_) = match self.opts.call_style() { + CallStyle::Async | CallStyle::Concurrent => { + ("async", "_async", ": Send + 'static", ".await") + } + CallStyle::Sync => ("", "", ": 'static", ""), }; uwriteln!( self.src, @@ -836,7 +897,7 @@ impl Clone for {camel}Pre {{ }} }} -impl<_T> {camel}Pre<_T> {{ +impl<_T{bounds}> {camel}Pre<_T> {{ /// Creates a new copy of `{camel}Pre` bindings which can then /// be used to instantiate into a particular store. /// @@ -866,7 +927,6 @@ impl<_T> {camel}Pre<_T> {{ &self, mut store: impl {wt}::AsContextMut, ) -> {wt}::Result<{camel}> - {where_clause} {{ let mut store = store.as_context_mut(); let instance = self.instance_pre.instantiate{async__}(&mut store){await_}?; @@ -1031,7 +1091,7 @@ impl<_T> {camel}Pre<_T> {{ component: &{wt}::component::Component, linker: &{wt}::component::Linker<_T>, ) -> {wt}::Result<{camel}> - {where_clause} + where _T{bounds} {{ let pre = linker.instantiate_pre(component)?; {camel}Pre::new(pre)?.instantiate{async__}(store){await_} @@ -1090,7 +1150,12 @@ impl<_T> {camel}Pre<_T> {{ } let imports = mem::take(&mut self.import_interfaces); - self.emit_modules(imports); + self.emit_modules( + imports + .into_iter() + .map(|(_, id, module, path)| (id, module, path)) + .collect(), + ); let exports = mem::take(&mut self.exports.modules); self.emit_modules(exports); @@ -1357,12 +1422,12 @@ impl Wasmtime { let wt = self.wasmtime_path(); let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name); - if self.opts.async_.maybe_async() { + if let CallStyle::Async = self.opts.call_style() { uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]") } uwrite!(self.src, "pub trait {world_camel}Imports"); let mut supertraits = vec![]; - if self.opts.async_.maybe_async() { + if let CallStyle::Async = self.opts.call_style() { supertraits.push("Send".to_string()); } for (_, name) in get_world_resources(resolve, world) { @@ -1404,7 +1469,7 @@ impl Wasmtime { ); // Generate impl WorldImports for &mut WorldImports - let (async_trait, maybe_send) = if self.opts.async_.maybe_async() { + let (async_trait, maybe_send) = if let CallStyle::Async = self.opts.call_style() { ( format!("#[{wt}::component::__internal::async_trait]\n"), "+ Send", @@ -1413,10 +1478,25 @@ impl Wasmtime { (String::new(), "") }; if !self.opts.skip_mut_forwarding_impls { + let maybe_maybe_sized = if let CallStyle::Concurrent = self.opts.call_style() { + "" + } else { + "+ ?Sized" + }; uwriteln!( self.src, - "{async_trait}impl<_T: {world_camel}Imports + ?Sized {maybe_send}> {world_camel}Imports for &mut _T {{" + "{async_trait}impl<_T: {world_camel}Imports {maybe_maybe_sized} {maybe_send}> {world_camel}Imports for &mut _T {{" ); + let has_concurrent_function = self.import_functions.iter().any(|f| { + matches!( + self.opts.import_call_style(None, &f.func.name), + CallStyle::Concurrent + ) + }); + + if has_concurrent_function { + self.src.push_str("type Data = _T::Data;\n"); + } // Forward each method call to &mut T for f in self.import_functions.iter() { if let Some(sig) = &f.sig { @@ -1430,7 +1510,7 @@ impl Wasmtime { uwrite!(self.src, "{},", to_rust_ident(name)); } uwrite!(self.src, ")"); - if self.opts.async_.is_import_async(&f.func.name) { + if let CallStyle::Async = self.opts.import_call_style(None, &f.func.name) { uwrite!(self.src, ".await"); } uwriteln!(self.src, "}}"); @@ -1443,7 +1523,7 @@ impl Wasmtime { fn import_interface_paths(&self) -> Vec<(InterfaceId, String)> { self.import_interfaces .iter() - .map(|(id, _, name)| { + .map(|(_, id, _, name)| { let path = match name { InterfaceName::Path(path) => path.join("::"), InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(), @@ -1470,7 +1550,7 @@ impl Wasmtime { let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name); traits.push(format!("{world_camel}Imports")); } - if self.opts.async_.maybe_async() { + if let CallStyle::Async = self.opts.call_style() { traits.push("Send".to_string()); } traits @@ -1512,6 +1592,7 @@ impl Wasmtime { let gate = FeatureGate::open(&mut self.src, &resolve.worlds[world].stability); for (ty, name) in get_world_resources(resolve, world) { Self::generate_add_resource_to_linker( + None, &mut self.src, &self.opts, &wt, @@ -1528,7 +1609,45 @@ impl Wasmtime { uwriteln!(self.src, "Ok(())\n}}"); } - let host_bounds = format!("U: {}", self.world_host_traits(resolve, world).join(" + ")); + let (host_bounds, data_bounds) = if let CallStyle::Concurrent = self.opts.call_style() { + // TODO: include world imports trait if applicable + let bounds = self + .import_interfaces + .iter() + .map(|(key, id, _, name)| { + ( + key, + id, + match name { + InterfaceName::Path(path) => path.join("::"), + InterfaceName::Remapped { name_at_root, .. } => name_at_root.clone(), + }, + ) + }) + .map(|(key, id, path)| { + format!( + " + {path}::Host{}", + concurrent_constraints( + resolve, + &self.opts, + Some(&resolve.name_world_key(key)), + *id + )("T") + ) + }) + .collect::>() + .concat(); + + ( + format!("U: Send{bounds}"), + format!("T: Send{bounds} + 'static,"), + ) + } else { + ( + format!("U: {}", self.world_host_traits(resolve, world).join(" + ")), + data_bounds.to_string(), + ) + }; if !self.opts.skip_mut_forwarding_impls { uwriteln!( @@ -1584,6 +1703,7 @@ impl Wasmtime { } fn generate_add_resource_to_linker( + qualifier: Option<&str>, src: &mut Source, opts: &Opts, wt: &str, @@ -1593,7 +1713,7 @@ impl Wasmtime { ) { let gate = FeatureGate::open(src, stability); let camel = name.to_upper_camel_case(); - if opts.async_.is_drop_async(name) { + if let CallStyle::Async = opts.drop_call_style(qualifier, name) { uwriteln!( src, "{inst}.resource_async( @@ -1664,8 +1784,9 @@ impl<'a> InterfaceGenerator<'a> { TypeDefKind::Result(r) => self.type_result(id, name, r, &ty.docs), TypeDefKind::List(t) => self.type_list(id, name, t, &ty.docs), TypeDefKind::Type(t) => self.type_alias(id, name, t, &ty.docs), - TypeDefKind::Future(_) => todo!("generate for future"), - TypeDefKind::Stream(_) => todo!("generate for stream"), + TypeDefKind::Future(_) => panic!("future types need not be defined"), + TypeDefKind::Stream(_) => panic!("stream types need not be defined"), + TypeDefKind::ErrorContext => panic!("the error-context type needs not be defined"), TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs), TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs), TypeDefKind::Unknown => unreachable!(), @@ -1709,10 +1830,11 @@ impl<'a> InterfaceGenerator<'a> { } // Generate resource trait - if self.gen.opts.async_.maybe_async() { + if let CallStyle::Async = self.gen.opts.call_style() { uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]") } - uwriteln!(self.src, "pub trait Host{camel} {{"); + + uwriteln!(self.src, "pub trait Host{camel}: Sized {{"); let mut functions = match resource.owner { TypeOwner::World(id) => self.resolve.worlds[id] @@ -1739,12 +1861,29 @@ impl<'a> InterfaceGenerator<'a> { | FunctionKind::Constructor(resource) => id == resource, }); + let has_concurrent_function = functions.iter().any(|func| { + matches!( + self.gen + .opts + .import_call_style(self.qualifier().as_deref(), &func.name), + CallStyle::Concurrent + ) + }); + + if has_concurrent_function { + uwriteln!(self.src, "type {camel}Data;"); + } + for func in &functions { - self.generate_function_trait_sig(func); + self.generate_function_trait_sig(func, &format!("{camel}Data")); self.push_str(";\n"); } - if self.gen.opts.async_.is_drop_async(name) { + if let CallStyle::Async = self + .gen + .opts + .drop_call_style(self.qualifier().as_deref(), name) + { uwrite!(self.src, "async "); } uwrite!( @@ -1756,7 +1895,8 @@ impl<'a> InterfaceGenerator<'a> { // Generate impl HostResource for &mut HostResource if !self.gen.opts.skip_mut_forwarding_impls { - let (async_trait, maybe_send) = if self.gen.opts.async_.maybe_async() { + let (async_trait, maybe_send) = if let CallStyle::Async = self.gen.opts.call_style() + { ( format!("#[{wt}::component::__internal::async_trait]\n"), "+ Send", @@ -1764,27 +1904,51 @@ impl<'a> InterfaceGenerator<'a> { } else { (String::new(), "") }; + let maybe_maybe_sized = if has_concurrent_function { + "" + } else { + "+ ?Sized" + }; uwriteln!( self.src, - "{async_trait}impl <_T: Host{camel} + ?Sized {maybe_send}> Host{camel} for &mut _T {{" + "{async_trait}impl <_T: Host{camel} {maybe_maybe_sized} {maybe_send}> Host{camel} for &mut _T {{" ); + if has_concurrent_function { + uwriteln!(self.src, "type {camel}Data = _T::{camel}Data;"); + } for func in &functions { - self.generate_function_trait_sig(func); - uwrite!( - self.src, - "{{ Host{camel}::{}(*self,", - rust_function_name(func) - ); + let call_style = self + .gen + .opts + .import_call_style(self.qualifier().as_deref(), &func.name); + self.generate_function_trait_sig(func, &format!("{camel}Data")); + if let CallStyle::Concurrent = call_style { + uwrite!( + self.src, + "{{ <_T as Host{camel}>::{}(store,", + rust_function_name(func) + ); + } else { + uwrite!( + self.src, + "{{ Host{camel}::{}(*self,", + rust_function_name(func) + ); + } for (name, _) in func.params.iter() { uwrite!(self.src, "{},", to_rust_ident(name)); } uwrite!(self.src, ")"); - if self.gen.opts.async_.is_import_async(&func.name) { + if let CallStyle::Async = call_style { uwrite!(self.src, ".await"); } uwriteln!(self.src, "}}"); } - if self.gen.opts.async_.is_drop_async(name) { + if let CallStyle::Async = self + .gen + .opts + .drop_call_style(self.qualifier().as_deref(), name) + { uwriteln!(self.src, " async fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()> {{ Host{camel}::drop(*self, rep).await @@ -2087,10 +2251,9 @@ impl<'a> InterfaceGenerator<'a> { self.push_str( "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", ); - self.push_str("write!(f, \"{:?}\", self)"); + self.push_str("write!(f, \"{:?}\", self)\n"); self.push_str("}\n"); self.push_str("}\n"); - self.push_str("\n"); if cfg!(feature = "std") { self.push_str("impl"); @@ -2342,6 +2505,26 @@ impl<'a> InterfaceGenerator<'a> { } } + fn print_result_ty_tuple(&mut self, results: &Results, mode: TypeMode) { + self.push_str("("); + match results { + Results::Named(rs) if rs.is_empty() => self.push_str(")"), + Results::Named(rs) => { + for (i, (_, ty)) in rs.iter().enumerate() { + if i > 0 { + self.push_str(", ") + } + self.print_ty(ty, mode) + } + self.push_str(")"); + } + Results::Anon(ty) => { + self.print_ty(ty, mode); + self.push_str(",)"); + } + } + } + fn special_case_trappable_error( &mut self, func: &Function, @@ -2384,31 +2567,52 @@ impl<'a> InterfaceGenerator<'a> { let owner = TypeOwner::Interface(id); let wt = self.gen.wasmtime_path(); - let is_maybe_async = self.gen.opts.async_.maybe_async(); + let is_maybe_async = matches!(self.gen.opts.call_style(), CallStyle::Async); if is_maybe_async { uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]") } // Generate the `pub trait` which represents the host functionality for // this import which additionally inherits from all resource traits // for this interface defined by `type_resource`. + uwrite!(self.src, "pub trait Host"); let mut host_supertraits = vec![]; if is_maybe_async { host_supertraits.push("Send".to_string()); } + let mut saw_resources = false; for (_, name) in get_resources(self.resolve, id) { + saw_resources = true; host_supertraits.push(format!("Host{}", name.to_upper_camel_case())); } + if saw_resources { + host_supertraits.push("Sized".to_string()); + } if !host_supertraits.is_empty() { uwrite!(self.src, ": {}", host_supertraits.join(" + ")); } uwriteln!(self.src, " {{"); + + let has_concurrent_function = iface.functions.iter().any(|(_, func)| { + matches!(func.kind, FunctionKind::Freestanding) + && matches!( + self.gen + .opts + .import_call_style(self.qualifier().as_deref(), &func.name), + CallStyle::Concurrent + ) + }); + + if has_concurrent_function { + self.push_str("type Data;\n"); + } + for (_, func) in iface.functions.iter() { match func.kind { FunctionKind::Freestanding => {} _ => continue, } - self.generate_function_trait_sig(func); + self.generate_function_trait_sig(func, "Data"); self.push_str(";\n"); } @@ -2456,13 +2660,32 @@ impl<'a> InterfaceGenerator<'a> { } uwriteln!(self.src, "}}"); - let (data_bounds, mut host_bounds) = if self.gen.opts.is_store_data_send() { - ("T: Send,", "Host + Send".to_string()) - } else { - ("", "Host".to_string()) + let (data_bounds, mut host_bounds, mut get_host_bounds) = match self.gen.opts.call_style() { + CallStyle::Async => ( + "T: Send,".to_string(), + "Host + Send".to_string(), + "Host + Send".to_string(), + ), + CallStyle::Concurrent => { + let constraints = concurrent_constraints( + self.resolve, + &self.gen.opts, + self.qualifier().as_deref(), + id, + ); + + ( + "T: Send + 'static,".to_string(), + format!("Host{} + Send", constraints("T")), + format!("Host{} + Send", constraints("D")), + ) + } + CallStyle::Sync => (String::new(), "Host".to_string(), "Host".to_string()), }; + for ty in required_conversion_traits { uwrite!(host_bounds, " + {ty}"); + uwrite!(get_host_bounds, " + {ty}"); } let (options_param, options_arg) = if self.gen.interface_link_options[&id].has_any() { @@ -2474,28 +2697,28 @@ impl<'a> InterfaceGenerator<'a> { uwriteln!( self.src, " - pub trait GetHost: - Fn(T) -> >::Host + pub trait GetHost: + Fn(T) -> >::Host + Send + Sync + Copy + 'static {{ - type Host: {host_bounds}; + type Host: {get_host_bounds}; }} - impl GetHost for F + impl GetHost for F where F: Fn(T) -> O + Send + Sync + Copy + 'static, - O: {host_bounds}, + O: {get_host_bounds}, {{ type Host = O; }} - pub fn add_to_linker_get_host( + pub fn add_to_linker_get_host GetHost<&'a mut T, T, Host: {host_bounds}>>( linker: &mut {wt}::component::Linker, {options_param} - host_getter: impl for<'a> GetHost<&'a mut T>, + host_getter: G, ) -> {wt}::Result<()> where {data_bounds} {{ @@ -2506,6 +2729,7 @@ impl<'a> InterfaceGenerator<'a> { for (ty, name) in get_resources(self.resolve, id) { Wasmtime::generate_add_resource_to_linker( + self.qualifier().as_deref(), &mut self.src, &self.gen.opts, &wt, @@ -2550,23 +2774,46 @@ impl<'a> InterfaceGenerator<'a> { (String::new(), "") }; + let maybe_maybe_sized = if has_concurrent_function { + "" + } else { + "+ ?Sized" + }; + uwriteln!( self.src, - "{async_trait}impl<_T: Host + ?Sized {maybe_send}> Host for &mut _T {{" + "{async_trait}impl<_T: Host {maybe_maybe_sized} {maybe_send}> Host for &mut _T {{" ); + + if has_concurrent_function { + self.push_str("type Data = _T::Data;\n"); + } + // Forward each method call to &mut T for (_, func) in iface.functions.iter() { match func.kind { FunctionKind::Freestanding => {} _ => continue, } - self.generate_function_trait_sig(func); - uwrite!(self.src, "{{ Host::{}(*self,", rust_function_name(func)); + let call_style = self + .gen + .opts + .import_call_style(self.qualifier().as_deref(), &func.name); + self.generate_function_trait_sig(func, "Data"); + if let CallStyle::Concurrent = call_style { + uwrite!( + self.src, + "{{ <_T as Host>::{}(store,", + rust_function_name(func) + ); + } else { + uwrite!(self.src, "{{ Host::{}(*self,", rust_function_name(func)); + } for (name, _) in func.params.iter() { uwrite!(self.src, "{},", to_rust_ident(name)); } uwrite!(self.src, ")"); - if self.gen.opts.async_.is_import_async(&func.name) { + if let CallStyle::Async = call_style { uwrite!(self.src, ".await"); } uwriteln!(self.src, "}}"); @@ -2586,15 +2833,24 @@ impl<'a> InterfaceGenerator<'a> { } } + fn qualifier(&self) -> Option { + self.current_interface + .map(|(_, key, _)| self.resolve.name_world_key(key)) + } + fn generate_add_function_to_linker(&mut self, owner: TypeOwner, func: &Function, linker: &str) { let gate = FeatureGate::open(&mut self.src, &func.stability); uwrite!( self.src, "{linker}.{}(\"{}\", ", - if self.gen.opts.async_.is_import_async(&func.name) { - "func_wrap_async" - } else { - "func_wrap" + match self + .gen + .opts + .import_call_style(self.qualifier().as_deref(), &func.name) + { + CallStyle::Sync => "func_wrap", + CallStyle::Async => "func_wrap_async", + CallStyle::Concurrent => "func_wrap_concurrent", }, func.name ); @@ -2618,16 +2874,20 @@ impl<'a> InterfaceGenerator<'a> { self.src.push_str(") : ("); for (_, ty) in func.params.iter() { - // Lift is required to be impled for this type, so we can't use + // Lift is required to be implied for this type, so we can't use // a borrowed type: self.print_ty(ty, TypeMode::Owned); self.src.push_str(", "); } - self.src.push_str(") |"); - self.src.push_str(" {\n"); + self.src.push_str(")| {\n"); + + let style = self + .gen + .opts + .import_call_style(self.qualifier().as_deref(), &func.name); if self.gen.opts.tracing { - if self.gen.opts.async_.is_import_async(&func.name) { + if let CallStyle::Async = style { self.src.push_str("use tracing::Instrument;\n"); } @@ -2653,7 +2913,7 @@ impl<'a> InterfaceGenerator<'a> { ); } - if self.gen.opts.async_.is_import_async(&func.name) { + if let CallStyle::Async = &style { uwriteln!( self.src, " {wt}::component::__internal::Box::new(async move {{ " @@ -2685,8 +2945,11 @@ impl<'a> InterfaceGenerator<'a> { ); } - self.src - .push_str("let host = &mut host_getter(caller.data_mut());\n"); + self.src.push_str(if let CallStyle::Concurrent = &style { + "let host = caller;\n" + } else { + "let host = &mut host_getter(caller.data_mut());\n" + }); let func_name = rust_function_name(func); let host_trait = match func.kind { FunctionKind::Freestanding => match owner { @@ -2705,15 +2968,32 @@ impl<'a> InterfaceGenerator<'a> { format!("Host{resource}") } }; - uwrite!(self.src, "let r = {host_trait}::{func_name}(host, "); + + if let CallStyle::Concurrent = &style { + uwrite!( + self.src, + "let r = ::{func_name}(host, " + ); + } else { + uwrite!(self.src, "let r = {host_trait}::{func_name}(host, "); + } for (i, _) in func.params.iter().enumerate() { uwrite!(self.src, "arg{},", i); } - if self.gen.opts.async_.is_import_async(&func.name) { - uwrite!(self.src, ").await;\n"); - } else { - uwrite!(self.src, ");\n"); + self.src.push_str(match &style { + CallStyle::Sync | CallStyle::Concurrent => ");\n", + CallStyle::Async => ").await;\n", + }); + + if let CallStyle::Concurrent = &style { + self.src.push_str( + "Box::pin(async move { + let fun = r.await; + Box::new(move |mut caller: wasmtime::StoreContextMut<'_, T>| { + let r = fun(caller); + ", + ); } if self.gen.opts.tracing { @@ -2755,29 +3035,53 @@ impl<'a> InterfaceGenerator<'a> { uwrite!(self.src, "r\n"); } - if self.gen.opts.async_.is_import_async(&func.name) { - // Need to close Box::new and async block - - if self.gen.opts.tracing { - self.src.push_str("}.instrument(span))\n"); - } else { - self.src.push_str("})\n"); + match &style { + CallStyle::Sync => (), + CallStyle::Async => { + if self.gen.opts.tracing { + self.src.push_str("}.instrument(span))\n"); + } else { + self.src.push_str("})\n"); + } + } + CallStyle::Concurrent => { + let old_source = mem::take(&mut self.src); + self.print_result_ty_tuple(&func.results, TypeMode::Owned); + let result_type = String::from(mem::replace(&mut self.src, old_source)); + let box_fn = format!( + "Box) -> \ + wasmtime::Result<{result_type}> + Send + Sync>" + ); + uwriteln!( + self.src, + " }}) as {box_fn} + }}) as ::std::pin::Pin \ + + Send + Sync + 'static>> + " + ); } } - self.src.push_str("}\n"); } - fn generate_function_trait_sig(&mut self, func: &Function) { + fn generate_function_trait_sig(&mut self, func: &Function, data: &str) { let wt = self.gen.wasmtime_path(); self.rustdoc(&func.docs); - if self.gen.opts.async_.is_import_async(&func.name) { + let style = self + .gen + .opts + .import_call_style(self.qualifier().as_deref(), &func.name); + if let CallStyle::Async = &style { self.push_str("async "); } self.push_str("fn "); self.push_str(&rust_function_name(func)); - self.push_str("(&mut self, "); + self.push_str(&if let CallStyle::Concurrent = &style { + format!("(store: wasmtime::StoreContextMut<'_, Self::{data}>, ") + } else { + "(&mut self, ".to_string() + }); for (name, param) in func.params.iter() { let name = to_rust_ident(name); self.push_str(&name); @@ -2788,6 +3092,10 @@ impl<'a> InterfaceGenerator<'a> { self.push_str(")"); self.push_str(" -> "); + if let CallStyle::Concurrent = &style { + uwrite!(self.src, "impl ::std::future::Future) -> "); + } + if !self.gen.opts.trappable_imports.can_trap(func) { self.print_result_ty(&func.results, TypeMode::Owned); } else if let Some((r, _id, error_typename)) = self.special_case_trappable_error(func) { @@ -2810,6 +3118,10 @@ impl<'a> InterfaceGenerator<'a> { self.print_result_ty(&func.results, TypeMode::Owned); self.push_str(">"); } + + if let CallStyle::Concurrent = &style { + self.push_str(" + Send + Sync + 'static> + Send + Sync + 'static where Self: Sized"); + } } fn extract_typed_function(&mut self, func: &Function) -> (String, String) { @@ -2840,12 +3152,16 @@ impl<'a> InterfaceGenerator<'a> { ) { // Exports must be async if anything could be async, it's just imports // that get to be optionally async/sync. - let is_async = self.gen.opts.async_.maybe_async(); - - let (async_, async__, await_) = if is_async { - ("async", "_async", ".await") - } else { - ("", "", "") + let style = self.gen.opts.call_style(); + let (async_, async__, await_, concurrent) = match &style { + CallStyle::Async | CallStyle::Concurrent => { + if self.gen.opts.concurrent_exports { + ("async", "INVALID", "INVALID", true) + } else { + ("async", "_async", ".await", false) + } + } + CallStyle::Sync => ("", "", "", false), }; self.rustdoc(&func.docs); @@ -2857,23 +3173,35 @@ impl<'a> InterfaceGenerator<'a> { func.item_name().to_snake_case(), ); + let param_mode = if let CallStyle::Concurrent = &style { + TypeMode::Owned + } else { + TypeMode::AllBorrowed("'_") + }; + for (i, param) in func.params.iter().enumerate() { uwrite!(self.src, "arg{}: ", i); - self.print_ty(¶m.1, TypeMode::AllBorrowed("'_")); + self.print_ty(¶m.1, param_mode); self.push_str(","); } uwrite!(self.src, ") -> {wt}::Result<"); + if concurrent { + uwrite!(self.src, "{wt}::component::Promise<"); + } self.print_result_ty(&func.results, TypeMode::Owned); - - if is_async { - uwriteln!(self.src, "> where ::Data: Send {{"); - } else { - self.src.push_str("> {\n"); + if concurrent { + uwrite!(self.src, ">"); } - if self.gen.opts.tracing { - if is_async { + uwrite!( + self.src, + "> where ::Data: Send + 'static {{\n" + ); + + // TODO: support tracing concurrent calls + if self.gen.opts.tracing && !concurrent { + if let CallStyle::Async = &style { self.src.push_str("use tracing::Instrument;\n"); } @@ -2893,7 +3221,7 @@ impl<'a> InterfaceGenerator<'a> { func.name, )); - if !is_async { + if !matches!(&style, CallStyle::Async) { self.src.push_str( " let _enter = span.enter(); @@ -2905,7 +3233,7 @@ impl<'a> InterfaceGenerator<'a> { self.src.push_str("let callee = unsafe {\n"); uwrite!(self.src, "{wt}::component::TypedFunc::<("); for (_, ty) in func.params.iter() { - self.print_ty(ty, TypeMode::AllBorrowed("'_")); + self.print_ty(ty, param_mode); self.push_str(", "); } self.src.push_str("), ("); @@ -2923,46 +3251,65 @@ impl<'a> InterfaceGenerator<'a> { func_field_name(self.resolve, func), ); self.src.push_str("};\n"); - self.src.push_str("let ("); - for (i, _) in func.results.iter_types().enumerate() { - uwrite!(self.src, "ret{},", i); - } - uwrite!( - self.src, - ") = callee.call{async__}(store.as_context_mut(), (" - ); - for (i, _) in func.params.iter().enumerate() { - uwrite!(self.src, "arg{}, ", i); - } - let instrument = if is_async && self.gen.opts.tracing { - ".instrument(span.clone())" - } else { - "" - }; - uwriteln!(self.src, ")){instrument}{await_}?;"); - - let instrument = if is_async && self.gen.opts.tracing { - ".instrument(span)" - } else { - "" - }; - uwriteln!( - self.src, - "callee.post_return{async__}(store.as_context_mut()){instrument}{await_}?;" - ); + if concurrent { + uwrite!( + self.src, + "let promise = callee.call_concurrent(store.as_context_mut(), (" + ); + for (i, _) in func.params.iter().enumerate() { + uwrite!(self.src, "arg{i}, "); + } + self.src.push_str(")).await?;"); - self.src.push_str("Ok("); - if func.results.iter_types().len() == 1 { - self.src.push_str("ret0"); + if func.results.iter_types().len() == 1 { + self.src.push_str("Ok(promise.map(|(v,)| v))\n"); + } else { + self.src.push_str("Ok(promise)"); + } } else { - self.src.push_str("("); + self.src.push_str("let ("); for (i, _) in func.results.iter_types().enumerate() { uwrite!(self.src, "ret{},", i); } - self.src.push_str(")"); + uwrite!( + self.src, + ") = callee.call{async__}(store.as_context_mut(), (" + ); + for (i, _) in func.params.iter().enumerate() { + uwrite!(self.src, "arg{}, ", i); + } + + let instrument = if matches!(&style, CallStyle::Async) && self.gen.opts.tracing { + ".instrument(span.clone())" + } else { + "" + }; + uwriteln!(self.src, ")){instrument}{await_}?;"); + + let instrument = if matches!(&style, CallStyle::Async) && self.gen.opts.tracing { + ".instrument(span)" + } else { + "" + }; + + uwriteln!( + self.src, + "callee.post_return{async__}(store.as_context_mut()){instrument}{await_}?;" + ); + + self.src.push_str("Ok("); + if func.results.iter_types().len() == 1 { + self.src.push_str("ret0"); + } else { + self.src.push_str("("); + for (i, _) in func.results.iter_types().enumerate() { + uwrite!(self.src, "ret{},", i); + } + self.src.push_str(")"); + } + self.src.push_str(")\n"); } - self.src.push_str(")\n"); // End function body self.src.push_str("}\n"); @@ -3243,8 +3590,9 @@ fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool { | TypeDefKind::Unknown | TypeDefKind::Flags(_) | TypeDefKind::Handle(_) - | TypeDefKind::Enum(_) => false, - TypeDefKind::Option(ty) => type_contains_lists(*ty, resolve), + | TypeDefKind::Enum(_) + | TypeDefKind::ErrorContext => false, + TypeDefKind::Option(ty) | TypeDefKind::Stream(ty) => type_contains_lists(*ty, resolve), TypeDefKind::Result(Result_ { ok, err }) => { option_type_contains_lists(*ok, resolve) || option_type_contains_lists(*err, resolve) @@ -3263,10 +3611,6 @@ fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool { .any(|case| option_type_contains_lists(case.ty, resolve)), TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve), TypeDefKind::Future(ty) => option_type_contains_lists(*ty, resolve), - TypeDefKind::Stream(Stream { element, end }) => { - option_type_contains_lists(*element, resolve) - || option_type_contains_lists(*end, resolve) - } TypeDefKind::List(_) => true, }, @@ -3358,3 +3702,61 @@ fn get_world_resources<'a>( _ => None, }) } + +fn concurrent_constraints<'a>( + resolve: &'a Resolve, + opts: &Opts, + qualifier: Option<&str>, + id: InterfaceId, +) -> impl Fn(&str) -> String + 'a { + let has_concurrent_function = resolve.interfaces[id].functions.iter().any(|(_, func)| { + matches!(func.kind, FunctionKind::Freestanding) + && matches!( + opts.import_call_style(qualifier, &func.name), + CallStyle::Concurrent + ) + }); + + let types = resolve.interfaces[id] + .types + .iter() + .filter_map(|(name, ty)| match resolve.types[*ty].kind { + TypeDefKind::Resource + if resolve.interfaces[id] + .functions + .values() + .any(|func| match func.kind { + FunctionKind::Freestanding => false, + FunctionKind::Method(resource) + | FunctionKind::Static(resource) + | FunctionKind::Constructor(resource) => { + *ty == resource + && matches!( + opts.import_call_style(qualifier, &func.name), + CallStyle::Concurrent + ) + } + }) => + { + Some(format!("{}Data", name.to_upper_camel_case())) + } + _ => None, + }) + .chain(has_concurrent_function.then_some("Data".to_string())) + .collect::>(); + + move |v| { + if types.is_empty() { + String::new() + } else { + format!( + "<{}>", + types + .iter() + .map(|s| format!("{s} = {v}")) + .collect::>() + .join(", ") + ) + } + } +} diff --git a/crates/wit-bindgen/src/rust.rs b/crates/wit-bindgen/src/rust.rs index d676d095f60d..3792f24666af 100644 --- a/crates/wit-bindgen/src/rust.rs +++ b/crates/wit-bindgen/src/rust.rs @@ -120,7 +120,7 @@ pub trait RustGenerator<'a> { needs_generics(resolve, &resolve.types[*t].kind) } TypeDefKind::Type(Type::String) => true, - TypeDefKind::Type(_) => false, + TypeDefKind::Type(_) | TypeDefKind::ErrorContext => false, TypeDefKind::Unknown => unreachable!(), } } @@ -166,17 +166,18 @@ pub trait RustGenerator<'a> { panic!("unsupported anonymous type reference: enum") } TypeDefKind::Future(ty) => { - self.push_str("Future<"); - self.print_optional_ty(ty.as_ref(), mode); + self.push_str("wasmtime::component::FutureReader<"); + self.print_optional_ty(ty.as_ref(), TypeMode::Owned); self.push_str(">"); } - TypeDefKind::Stream(stream) => { - self.push_str("Stream<"); - self.print_optional_ty(stream.element.as_ref(), mode); - self.push_str(","); - self.print_optional_ty(stream.end.as_ref(), mode); + TypeDefKind::Stream(ty) => { + self.push_str("wasmtime::component::StreamReader<"); + self.print_ty(ty, TypeMode::Owned); self.push_str(">"); } + TypeDefKind::ErrorContext => { + self.push_str("wasmtime::component::ErrorContext"); + } TypeDefKind::Handle(handle) => { self.print_handle(handle); diff --git a/crates/wit-bindgen/src/types.rs b/crates/wit-bindgen/src/types.rs index c45d3d80f159..b29c0da728c1 100644 --- a/crates/wit-bindgen/src/types.rs +++ b/crates/wit-bindgen/src/types.rs @@ -148,10 +148,7 @@ impl Types { info = self.type_info(resolve, ty); info.has_list = true; } - TypeDefKind::Type(ty) => { - info = self.type_info(resolve, ty); - } - TypeDefKind::Option(ty) => { + TypeDefKind::Type(ty) | TypeDefKind::Option(ty) | TypeDefKind::Stream(ty) => { info = self.type_info(resolve, ty); } TypeDefKind::Result(r) => { @@ -161,12 +158,8 @@ impl Types { TypeDefKind::Future(ty) => { info = self.optional_type_info(resolve, ty.as_ref()); } - TypeDefKind::Stream(stream) => { - info = self.optional_type_info(resolve, stream.element.as_ref()); - info |= self.optional_type_info(resolve, stream.end.as_ref()); - } TypeDefKind::Handle(_) => info.has_handle = true, - TypeDefKind::Resource => {} + TypeDefKind::Resource | TypeDefKind::ErrorContext => {} TypeDefKind::Unknown => unreachable!(), } self.type_info.insert(ty, info); diff --git a/tests/all/component_model/dynamic.rs b/tests/all/component_model/dynamic.rs index a27fd52df6e2..a6417b07d3a2 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 results(s), got 0"), + err.to_string().contains("expected 1 result(s), got 0"), "{err}" ); diff --git a/tests/all/pooling_allocator.rs b/tests/all/pooling_allocator.rs index 1fbb138c8c02..c8545e549675 100644 --- a/tests/all/pooling_allocator.rs +++ b/tests/all/pooling_allocator.rs @@ -880,7 +880,7 @@ fn component_instance_size_limit() -> Result<()> { Ok(_) => panic!("should have hit limit"), Err(e) => assert_eq!( e.to_string(), - "instance allocation for this component requires 64 bytes of `VMComponentContext` space \ + "instance allocation for this component requires 272 bytes of `VMComponentContext` space \ which exceeds the configured maximum of 1 bytes" ), }