From c7c30fb320929392e75715a4423e95e63e8da9a9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 8 Apr 2024 15:06:39 -0600 Subject: [PATCH] Add support for async/streams/futures This adds support for loading, compiling, linking, and running components which use the [Async ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Async.md) along with the [`stream`, `future`, and `error-context`](https://github.com/WebAssembly/component-model/pull/405) types. It also adds support for generating host bindings such that multiple host functions can be run concurrently with guest tasks -- without monopolizing the `Store`. See the [implementation RFC](https://github.com/bytecodealliance/rfcs/pull/38) for details, as well as [this repo](https://github.com/dicej/component-async-demo) containing end-to-end smoke tests. Signed-off-by: Joel Dice fix clippy warnings and bench/fuzzing errors Signed-off-by: Joel Dice revert atomic.wit whitespace change Signed-off-by: Joel Dice fix build when component-model disabled Signed-off-by: Joel Dice bless component-macro expected output Signed-off-by: Joel Dice fix no-std build error Signed-off-by: Joel Dice fix build with --no-default-features --features runtime,component-model Signed-off-by: Joel Dice partly fix no-std build It's still broken due to the use of `std::collections::HashMap` in crates/wasmtime/src/runtime/vm/component.rs. I'll address that as part of the work to avoid exposing global task/future/stream/error-context handles to guests. Signed-off-by: Joel Dice maintain per-instance tables for futures, streams, and error-contexts Signed-off-by: Joel Dice refactor task/stream/future handle lifting/lowering This addresses a couple of issues: - Previously, we were passing task/stream/future/error-context reps directly to instances while keeping track of which instance had access to which rep. That worked fine in that there was no way to forge access to inaccessible reps, but it leaked information about what other instances were doing. Now we maintain per-instance waitable and error-context tables which map the reps to and from the handles which the instance sees. - The `no_std` build was broken due to use of `HashMap` in `runtime::vm::component`, which is now fixed. Note that we use one single table per instance for all tasks, streams, and futures. This is partly necessary because, when async events are delivered to the guest, it wouldn't have enough context to know which stream or future we're talking about if each unique stream and future type had its own table. So at minimum, we need to use the same table for all streams (regardless of payload type), and likewise for futures. Also, per https://github.com/WebAssembly/component-model/issues/395#issuecomment-2486783242, the plan is to move towards a shared table for all resource types as well, so this moves us in that direction. Signed-off-by: Joel Dice fix wave breakage due to new stream/future/error-context types Signed-off-by: Joel Dice switch wasm-tools to v1.220.0-based branch Signed-off-by: Joel Dice check `task.return` type at runtime We can't statically verify a given call to `task.return` corresponds to the expected core signature appropriate for the currently running task, so we must do so at runtime. In order to make that check efficient, we intern the types. My initial plan was to use `ModuleInternedTypeIndex` and/or `VMSharedTypeIndex` for interning, but that got hairy with WasmGC considerations, so instead I added new fields to `ComponentTypes` and `ComponentTypesBuilder`. Signed-off-by: Joel Dice add `TypedFunc::call_concurrent` and refine stream/future APIs This implements what I proposed in https://github.com/dicej/rfcs/blob/component-async/accepted/component-model-async.md#wasmtime. Specifically, it adds: - A new `Promise` type, useful for working with concurrent operations that require access to a `Store` to make progress. - A new `PromisesUnordered` type for `await`ing multiple promises concurrently -`TypedFunc::call_concurrent` (which returns a `Promise`), allowing multiple host->guest calls to run concurrently on the same instance. - Updated `{Stream|Future}{Writer|Reader}` APIs which use `Promise` The upshot is that the embedder can now ergonomically manage arbitrary numbers of concurrent operations. Previously, this was a lot more difficult to do without accidentally starving some of the operations due to another one monopolizing the `Store`. Finally, this includes various refactorings and fixes for bugs exposed by the newer, more versatile APIs. Signed-off-by: Joel Dice clean up verbosity in component/func.rs Signed-off-by: Joel Dice snapshot Signed-off-by: Joel Dice implement stream/future read/write cancellation This required a somewhat viral addition of `Send` and `Sync` bounds for async host function closure types, unfortunately. Signed-off-by: Joel Dice add `Func::call_concurrent` and `LinkerInstance::func_new_concurrent` Signed-off-by: Joel Dice dynamic API support for streams/futures/error-contexts Signed-off-by: Joel Dice support callback-less (AKA stackful) async lifts Signed-off-by: Joel Dice --- Cargo.lock | 35 +- Cargo.toml | 20 +- benches/call.rs | 3 +- crates/component-macro/Cargo.toml | 1 + crates/component-macro/src/bindgen.rs | 48 +- crates/component-macro/tests/expanded/char.rs | 29 +- .../tests/expanded/char_async.rs | 25 +- .../tests/expanded/char_tracing_async.rs | 25 +- .../tests/expanded/conventions.rs | 79 +- .../tests/expanded/conventions_async.rs | 45 +- .../expanded/conventions_tracing_async.rs | 45 +- .../tests/expanded/dead-code.rs | 31 +- .../tests/expanded/dead-code_async.rs | 33 +- .../tests/expanded/dead-code_tracing_async.rs | 33 +- .../tests/expanded/direct-import.rs | 7 +- .../tests/expanded/direct-import_async.rs | 9 +- .../expanded/direct-import_tracing_async.rs | 9 +- .../component-macro/tests/expanded/empty.rs | 7 +- .../tests/expanded/empty_async.rs | 9 +- .../tests/expanded/empty_tracing_async.rs | 9 +- .../component-macro/tests/expanded/flags.rs | 54 +- .../tests/expanded/flags_async.rs | 35 +- .../tests/expanded/flags_tracing_async.rs | 35 +- .../component-macro/tests/expanded/floats.rs | 39 +- .../tests/expanded/floats_async.rs | 29 +- .../tests/expanded/floats_tracing_async.rs | 29 +- .../tests/expanded/function-new.rs | 12 +- .../tests/expanded/function-new_async.rs | 11 +- .../expanded/function-new_tracing_async.rs | 11 +- .../tests/expanded/host-world.rs | 7 +- .../tests/expanded/host-world_async.rs | 9 +- .../expanded/host-world_tracing_async.rs | 9 +- .../tests/expanded/integers.rs | 109 +- .../tests/expanded/integers_async.rs | 57 +- .../tests/expanded/integers_tracing_async.rs | 57 +- .../component-macro/tests/expanded/lists.rs | 164 +- .../tests/expanded/lists_async.rs | 79 +- .../tests/expanded/lists_tracing_async.rs | 79 +- .../tests/expanded/many-arguments.rs | 29 +- .../tests/expanded/many-arguments_async.rs | 25 +- .../expanded/many-arguments_tracing_async.rs | 25 +- .../tests/expanded/multi-return.rs | 44 +- .../tests/expanded/multi-return_async.rs | 31 +- .../expanded/multi-return_tracing_async.rs | 31 +- .../tests/expanded/multiversion.rs | 41 +- .../tests/expanded/multiversion_async.rs | 37 +- .../expanded/multiversion_tracing_async.rs | 37 +- .../component-macro/tests/expanded/path1.rs | 19 +- .../tests/expanded/path1_async.rs | 21 +- .../tests/expanded/path1_tracing_async.rs | 21 +- .../component-macro/tests/expanded/path2.rs | 19 +- .../tests/expanded/path2_async.rs | 21 +- .../tests/expanded/path2_tracing_async.rs | 21 +- .../component-macro/tests/expanded/records.rs | 74 +- .../tests/expanded/records_async.rs | 43 +- .../tests/expanded/records_tracing_async.rs | 43 +- .../component-macro/tests/expanded/rename.rs | 31 +- .../tests/expanded/rename_async.rs | 33 +- .../tests/expanded/rename_tracing_async.rs | 33 +- .../tests/expanded/resources-export.rs | 63 +- .../tests/expanded/resources-export_async.rs | 41 +- .../resources-export_tracing_async.rs | 41 +- .../tests/expanded/resources-import.rs | 103 +- .../tests/expanded/resources-import_async.rs | 99 +- .../resources-import_tracing_async.rs | 99 +- .../tests/expanded/share-types.rs | 33 +- .../tests/expanded/share-types_async.rs | 35 +- .../expanded/share-types_tracing_async.rs | 35 +- .../tests/expanded/simple-functions.rs | 49 +- .../tests/expanded/simple-functions_async.rs | 33 +- .../simple-functions_tracing_async.rs | 33 +- .../tests/expanded/simple-lists.rs | 39 +- .../tests/expanded/simple-lists_async.rs | 29 +- .../expanded/simple-lists_tracing_async.rs | 29 +- .../tests/expanded/simple-wasi.rs | 31 +- .../tests/expanded/simple-wasi_async.rs | 33 +- .../expanded/simple-wasi_tracing_async.rs | 33 +- .../tests/expanded/small-anonymous.rs | 24 +- .../tests/expanded/small-anonymous_async.rs | 23 +- .../expanded/small-anonymous_tracing_async.rs | 23 +- .../tests/expanded/smoke-default.rs | 12 +- .../tests/expanded/smoke-default_async.rs | 11 +- .../expanded/smoke-default_tracing_async.rs | 11 +- .../tests/expanded/smoke-export.rs | 12 +- .../tests/expanded/smoke-export_async.rs | 11 +- .../expanded/smoke-export_tracing_async.rs | 11 +- .../component-macro/tests/expanded/smoke.rs | 16 +- .../tests/expanded/smoke_async.rs | 21 +- .../tests/expanded/smoke_tracing_async.rs | 21 +- .../component-macro/tests/expanded/strings.rs | 34 +- .../tests/expanded/strings_async.rs | 27 +- .../tests/expanded/strings_tracing_async.rs | 27 +- .../tests/expanded/unstable-features.rs | 25 +- .../tests/expanded/unstable-features_async.rs | 27 +- .../unstable-features_tracing_async.rs | 27 +- .../tests/expanded/unversioned-foo.rs | 19 +- .../tests/expanded/unversioned-foo_async.rs | 21 +- .../expanded/unversioned-foo_tracing_async.rs | 21 +- .../tests/expanded/use-paths.rs | 52 +- .../tests/expanded/use-paths_async.rs | 57 +- .../tests/expanded/use-paths_tracing_async.rs | 57 +- .../tests/expanded/variants.rs | 129 +- .../tests/expanded/variants_async.rs | 65 +- .../tests/expanded/variants_tracing_async.rs | 65 +- crates/component-macro/tests/expanded/wat.rs | 7 +- .../tests/expanded/wat_async.rs | 9 +- .../tests/expanded/wat_tracing_async.rs | 9 +- .../tests/expanded/worlds-with-types.rs | 24 +- .../tests/expanded/worlds-with-types_async.rs | 23 +- .../worlds-with-types_tracing_async.rs | 23 +- crates/cranelift/Cargo.toml | 1 + crates/cranelift/src/compiler/component.rs | 1022 +++++++- crates/environ/examples/factc.rs | 4 + crates/environ/src/component.rs | 4 + crates/environ/src/component/dfg.rs | 232 +- crates/environ/src/component/info.rs | 295 ++- crates/environ/src/component/translate.rs | 259 ++- .../environ/src/component/translate/adapt.rs | 20 +- .../environ/src/component/translate/inline.rs | 326 +++ crates/environ/src/component/types.rs | 102 +- crates/environ/src/component/types_builder.rs | 178 +- .../src/component/types_builder/resources.rs | 5 + .../src/component/vmcomponent_offsets.rs | 269 ++- crates/environ/src/fact.rs | 191 +- crates/environ/src/fact/signature.rs | 99 +- crates/environ/src/fact/trampoline.rs | 618 ++++- crates/environ/src/trap_encoding.rs | 7 +- .../fuzzing/src/generators/component_types.rs | 31 +- crates/misc/component-test-util/src/lib.rs | 22 +- crates/wasi-config/Cargo.toml | 2 +- crates/wasi-keyvalue/src/lib.rs | 2 +- crates/wasmtime/Cargo.toml | 10 + crates/wasmtime/src/config.rs | 11 + crates/wasmtime/src/engine/serialization.rs | 9 + .../src/runtime/component/component.rs | 1 + .../src/runtime/component/concurrent.rs | 2065 +++++++++++++++++ .../concurrent/futures_and_streams.rs | 2003 ++++++++++++++++ .../component/concurrent/ready_chunks.rs | 59 + .../src/runtime/component/concurrent/table.rs | 316 +++ crates/wasmtime/src/runtime/component/func.rs | 534 ++++- .../src/runtime/component/func/host.rs | 391 +++- .../src/runtime/component/func/options.rs | 18 +- .../src/runtime/component/func/typed.rs | 268 ++- .../src/runtime/component/instance.rs | 61 +- .../wasmtime/src/runtime/component/linker.rs | 119 +- .../src/runtime/component/matching.rs | 11 +- crates/wasmtime/src/runtime/component/mod.rs | 482 ++++ .../wasmtime/src/runtime/component/storage.rs | 27 +- .../wasmtime/src/runtime/component/types.rs | 100 +- .../wasmtime/src/runtime/component/values.rs | 54 +- crates/wasmtime/src/runtime/store.rs | 21 + crates/wasmtime/src/runtime/vm/component.rs | 512 +++- .../src/runtime/vm/component/libcalls.rs | 43 +- .../src/runtime/vm/component/states.rs | 126 + .../runtime/vm/instance/allocator/pooling.rs | 1 + crates/wasmtime/src/runtime/wave/component.rs | 10 +- crates/wast/src/component.rs | 3 + crates/wit-bindgen/Cargo.toml | 1 + crates/wit-bindgen/src/lib.rs | 734 ++++-- crates/wit-bindgen/src/rust.rs | 17 +- crates/wit-bindgen/src/types.rs | 11 +- tests/all/component_model/dynamic.rs | 2 +- tests/all/pooling_allocator.rs | 2 +- 163 files changed, 13518 insertions(+), 2001 deletions(-) create mode 100644 crates/wasmtime/src/runtime/component/concurrent.rs create mode 100644 crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs create mode 100644 crates/wasmtime/src/runtime/component/concurrent/ready_chunks.rs create mode 100644 crates/wasmtime/src/runtime/component/concurrent/table.rs create mode 100644 crates/wasmtime/src/runtime/vm/component/states.rs 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..78815eebf9c9 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,25 +97,440 @@ 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(), + vec![ir::AbiParam::new(ir::types::I32)], + ), + 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), + ], + vec![ir::AbiParam::new(ir::types::I32)], + ) + } + } + 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), + ], + vec![ir::AbiParam::new(ir::types::I32)], + ) + } + } + 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)], + Vec::new(), + ), + 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), + ], + Vec::new(), + ), + Trampoline::FutureNew { ty } => self.translate_future_or_stream_call( + ty.as_u32(), + None, + self.offsets.future_new(), + Vec::new(), + vec![ir::AbiParam::new(ir::types::I32)], + ), + 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), + ], + vec![ir::AbiParam::new(ir::types::I32)], + ), + 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), + ], + vec![ir::AbiParam::new(ir::types::I32)], + ), + 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)], + Vec::new(), + ), + 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), + ], + Vec::new(), + ), + 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), + ], + vec![ir::AbiParam::new(ir::types::I32)], + ), + 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), + ], + Vec::new(), + ), + Trampoline::ErrorContextDrop { ty } => self.translate_error_context_drop_call(*ty), Trampoline::ResourceTransferOwn => { - self.translate_resource_libcall(host::resource_transfer_own, |me, rets| { + self.translate_host_libcall(host::resource_transfer_own, |me, rets| { rets[0] = me.raise_if_resource_trapped(rets[0]); }) } Trampoline::ResourceTransferBorrow => { - self.translate_resource_libcall(host::resource_transfer_borrow, |me, rets| { + self.translate_host_libcall(host::resource_transfer_borrow, |me, rets| { rets[0] = me.raise_if_resource_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), + ], + Vec::new(), + ) + } + 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), + ], + vec![ir::AbiParam::new(ir::types::I32)], + ) + } + Trampoline::FutureTransfer => { + self.translate_host_libcall(host::future_transfer, |_, _| {}) + } + Trampoline::StreamTransfer => { + self.translate_host_libcall(host::stream_transfer, |_, _| {}) + } + Trampoline::ErrorContextTransfer => { + self.translate_host_libcall(host::error_context_transfer, |_, _| {}) + } + } + } + + 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 load_wasm_results(&mut self, values_vec_ptr: Value, values_vec_len: Value) { + let wasm_func_ty = &self.types[self.signature].unwrap_func(); + + match self.abi { + Abi::Wasm => { + // After the host function has returned the results are loaded from + // `values_vec_ptr` and then returned. + let results = self.compiler.load_values_from_array( + wasm_func_ty.returns(), + &mut self.builder, + values_vec_ptr, + values_vec_len, + ); + self.builder.ins().return_(&results); + } + Abi::Array => { + self.builder.ins().return_(&[]); + } + } + } + + fn translate_task_return_call(&mut self) { + 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); + + // 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); + self.builder + .ins() + .call_indirect(host_sig, host_fn, &callee_args); + + self.load_wasm_results(values_vec_ptr, values_vec_len); + } + + fn translate_async_enter_or_exit( + &mut self, + offset: u32, + callback: Option>, + params: Vec, + results: Vec, + ) { + 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.extend(results); + + // 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); + + let results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); } fn translate_lower_import( @@ -157,10 +572,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 +601,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 +654,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); @@ -550,7 +985,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 +1015,581 @@ 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::I32)); + + let host_sig = self.builder.import_signature(host_sig); + let call = self + .builder + .ins() + .call_indirect(host_sig, host_fn, &host_args); + + let results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + + fn translate_future_or_stream_call( + &mut self, + ty: u32, + options: Option<&CanonicalOptions>, + offset: u32, + params: Vec, + results: Vec, + ) { + 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.extend(results); + + // 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 results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + + 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::I32)]); + + // 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 results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + + fn translate_error_context_call( + &mut self, + ty: TypeErrorContextTableIndex, + options: &CanonicalOptions, + offset: u32, + params: Vec, + results: Vec, + ) { + 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.extend(results); + + // 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 results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + + 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()); + + // 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 results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + + 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()); + + // 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 results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + + 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()); + + // 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 results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + + 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::I32)); + + // 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 results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + + 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 }), + ); + + // 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 results = self.builder.func.dfg.inst_results(call).to_vec(); + self.builder.ins().return_(&results); + } + /// Loads a host function pointer for a libcall stored at the `offset` /// provided in the libcalls array. /// 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..11a2f6b6c6ad 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)] +pub struct FutureInfo { + pub instance: RuntimeComponentInstanceIndex, + pub payload_type: Option, +} + +#[derive(Copy, Clone, Hash, Eq, PartialEq)] +#[allow(missing_docs)] +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..639dae0e74b1 --- /dev/null +++ b/crates/wasmtime/src/runtime/component/concurrent.rs @@ -0,0 +1,2065 @@ +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, 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 handle_result(func: impl FnOnce() -> Result) -> T { + match crate::runtime::vm::catch_unwind_and_longjmp(func) { + Ok(value) => value, + Err(e) => { + log::trace!("handle_result error: {e:?}"); + crate::trap::raise(e) + } + } +} + +pub(crate) extern "C" fn task_backpressure( + cx: *mut VMOpaqueContext, + caller_instance: RuntimeComponentInstanceIndex, + enabled: u32, +) { + unsafe { + handle_result(|| { + 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, +) { + unsafe { + handle_result(|| { + 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, +) -> u32 { + unsafe { + handle_result(|| { + 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, +) -> u32 { + unsafe { + handle_result(|| { + task_check::( + cx, + async_, + TaskCheck::Poll(memory, payload, caller_instance), + ) + }) + } +} + +pub(crate) extern "C" fn task_yield(cx: *mut VMOpaqueContext, async_: bool) { + unsafe { + handle_result(|| task_check::(cx, async_, TaskCheck::Yield)); + } +} + +pub(crate) extern "C" fn subtask_drop( + cx: *mut VMOpaqueContext, + caller_instance: RuntimeComponentInstanceIndex, + task_id: u32, +) { + unsafe { + handle_result(|| { + 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, +) { + unsafe { + handle_result(|| { + 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, +) -> u32 { + unsafe { + handle_result(|| { + 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..e92e3b6936a4 --- /dev/null +++ b/crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs @@ -0,0 +1,2003 @@ +use { + super::{ + events, handle_result, 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) -> u32 { + unsafe { + handle_result(|| { + 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: usize, + count: usize, +) -> usize { + unsafe { + handle_result(|| { + 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), + 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(result) + }) + } +} + +fn guest_read( + vmctx: *mut VMOpaqueContext, + memory: *mut VMMemoryDefinition, + realloc: *mut VMFuncRef, + string_encoding: u8, + ty: TableIndex, + flat_abi: Option, + handle: u32, + address: usize, + count: usize, +) -> usize { + unsafe { + handle_result(|| { + 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), + 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(result) + }) + } +} + +fn guest_cancel_write( + vmctx: *mut VMOpaqueContext, + ty: TableIndex, + writer: u32, + _async_: bool, +) -> u32 { + unsafe { + handle_result(|| { + 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, +) -> u32 { + unsafe { + handle_result(|| { + 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) { + unsafe { + handle_result(|| { + 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) { + unsafe { + handle_result(|| { + 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, +) -> u32 { + 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, +) -> u32 { + u32::try_from(guest_write::( + vmctx, + memory, + realloc, + StringEncoding::from_u8(string_encoding), + TableIndex::Future(ty), + None, + future, + usize::try_from(address).unwrap(), + 1, + )) + .unwrap() +} + +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, +) -> u32 { + u32::try_from(guest_read::( + vmctx, + memory, + realloc, + StringEncoding::from_u8(string_encoding), + TableIndex::Future(ty), + None, + future, + usize::try_from(address).unwrap(), + 1, + )) + .unwrap() +} + +pub(crate) extern "C" fn future_cancel_write( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, + async_: bool, + writer: u32, +) -> u32 { + 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, +) -> u32 { + 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, +) { + guest_close_writable::(vmctx, TableIndex::Future(ty), writer, error) +} + +pub(crate) extern "C" fn future_close_readable( + vmctx: *mut VMOpaqueContext, + ty: TypeFutureTableIndex, + reader: u32, +) { + guest_close_readable::(vmctx, TableIndex::Future(ty), reader) +} + +pub(crate) extern "C" fn stream_new( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, +) -> u32 { + 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, +) -> u32 { + u32::try_from(guest_write::( + vmctx, + memory, + realloc, + StringEncoding::from_u8(string_encoding), + TableIndex::Stream(ty), + None, + stream, + usize::try_from(address).unwrap(), + usize::try_from(count).unwrap(), + )) + .unwrap() +} + +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, +) -> u32 { + u32::try_from(guest_read::( + vmctx, + memory, + realloc, + StringEncoding::from_u8(string_encoding), + TableIndex::Stream(ty), + None, + stream, + usize::try_from(address).unwrap(), + usize::try_from(count).unwrap(), + )) + .unwrap() +} + +pub(crate) extern "C" fn stream_cancel_write( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, + async_: bool, + writer: u32, +) -> u32 { + 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, +) -> u32 { + 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, +) { + guest_close_writable::(vmctx, TableIndex::Stream(ty), writer, error) +} + +pub(crate) extern "C" fn stream_close_readable( + vmctx: *mut VMOpaqueContext, + ty: TypeStreamTableIndex, + reader: u32, +) { + 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, +) -> u32 { + u32::try_from(guest_write::( + vmctx, + memory, + realloc, + StringEncoding::Utf8, + TableIndex::Stream(ty), + Some(FlatAbi { + size: payload_size, + align: payload_align, + }), + stream, + usize::try_from(address).unwrap(), + usize::try_from(count).unwrap(), + )) + .unwrap() +} + +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, +) -> u32 { + u32::try_from(guest_read::( + vmctx, + memory, + realloc, + StringEncoding::Utf8, + TableIndex::Stream(ty), + Some(FlatAbi { + size: payload_size, + align: payload_align, + }), + stream, + usize::try_from(address).unwrap(), + usize::try_from(count).unwrap(), + )) + .unwrap() +} + +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, +) -> u32 { + unsafe { + handle_result(|| { + _ = ( + vmctx, + memory, + realloc, + StringEncoding::from_u8(string_encoding), + 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, +) { + unsafe { + handle_result(|| { + _ = ( + vmctx, + memory, + realloc, + StringEncoding::from_u8(string_encoding), + 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, +) { + unsafe { + handle_result(|| { + 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..c42d79283f00 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_: bool, 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_, 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_: bool, 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_, 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..36e9556050aa 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,478 @@ 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, StringEncoding, + 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, + ) { + unreachable!() + } + + pub(crate) extern "C" fn task_return( + _cx: *mut VMOpaqueContext, + _ty: TypeTaskReturnIndex, + _storage: *mut MaybeUninit, + _storage_len: usize, + ) { + unreachable!() + } + + pub(crate) extern "C" fn task_wait( + _cx: *mut VMOpaqueContext, + _caller_instance: RuntimeComponentInstanceIndex, + _async_: bool, + _memory: *mut VMMemoryDefinition, + _payload: u32, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn task_poll( + _cx: *mut VMOpaqueContext, + _caller_instance: RuntimeComponentInstanceIndex, + _async_: bool, + _memory: *mut VMMemoryDefinition, + _payload: u32, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn task_yield(_cx: *mut VMOpaqueContext, _async_: bool) { + unreachable!() + } + + pub(crate) extern "C" fn subtask_drop( + _cx: *mut VMOpaqueContext, + _caller_instance: RuntimeComponentInstanceIndex, + _task_id: u32, + ) { + 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, + ) { + 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, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn future_new( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + ) -> u32 { + 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, + ) -> u32 { + 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, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn future_cancel_write( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + _async_: bool, + _writer: u32, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn future_cancel_read( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + _async_: bool, + _reader: u32, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn future_close_writable( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + _writer: u32, + _error: u32, + ) { + unreachable!() + } + + pub(crate) extern "C" fn future_close_readable( + _vmctx: *mut VMOpaqueContext, + _ty: TypeFutureTableIndex, + _reader: u32, + ) { + unreachable!() + } + + pub(crate) extern "C" fn stream_new( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + ) -> u32 { + 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, + ) -> u32 { + 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, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn stream_cancel_write( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + _async_: bool, + _writer: u32, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn stream_cancel_read( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + _async_: bool, + _reader: u32, + ) -> u32 { + unreachable!() + } + + pub(crate) extern "C" fn stream_close_writable( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + _writer: u32, + _error: u32, + ) { + unreachable!() + } + + pub(crate) extern "C" fn stream_close_readable( + _vmctx: *mut VMOpaqueContext, + _ty: TypeStreamTableIndex, + _reader: u32, + ) { + 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, + ) -> u32 { + 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, + ) -> u32 { + 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, + ) -> u32 { + 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, + ) { + unreachable!() + } + + pub(crate) extern "C" fn error_context_drop( + _vmctx: *mut VMOpaqueContext, + _ty: TypeErrorContextTableIndex, + _error: u32, + ) { + 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..50ecaafe6887 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_: bool, args_and_results: *mut mem::MaybeUninit, nargs_and_results: usize, ) -> bool; @@ -130,6 +139,170 @@ 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, +); + +/// 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, +); + +/// 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, +) -> u32; + +/// Type signature for the host-defined `task.yield` built-in function. +pub type VMTaskYieldCallback = extern "C" fn(vmctx: *mut VMOpaqueContext, async_: 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); + +/// 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, +); + +/// 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, +) -> u32; + +/// Type signature for the host-defined `future.new` built-in function. +pub type VMFutureNewCallback = + extern "C" fn(vmctx: *mut VMOpaqueContext, ty: TypeFutureTableIndex) -> u32; + +/// 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, +) -> u32; + +/// 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, +) -> u32; + +/// 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); + +/// 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); + +/// Type signature for the host-defined `stream.new` built-in function. +pub type VMStreamNewCallback = + extern "C" fn(vmctx: *mut VMOpaqueContext, ty: TypeStreamTableIndex) -> u32; + +/// 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, +) -> u32; + +/// 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, +) -> u32; + +/// 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); + +/// 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); + +/// 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, +) -> u32; + +/// 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, +) -> u32; + +/// 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, +); + +/// 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); + /// This is a marker type to represent the underlying allocation of a /// `VMComponentContext`. /// @@ -148,6 +321,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 +394,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 +427,8 @@ impl ComponentInstance { .unwrap(), ), component_resource_tables, + component_waitable_tables, + component_error_context_tables, runtime_info, resource_types, vmctx: VMComponentContext { @@ -290,6 +503,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 +588,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 +673,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 +756,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 +782,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 +881,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 +957,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 +1084,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 +1147,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 +1193,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/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" ), }