From f6fc8d0ac628dd364a994ffa60aa4e19c1e18496 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 24 Jan 2025 08:46:20 -0700 Subject: [PATCH] add component-model-async/lift.wast test This is another piece of #9582 which I'm splitting out to make review easier. This test includes two components: one which exports a function using the async-with-callback ABI, and another which uses the async-without-callback ABI. It doesn't actually instantiate or run either component yet. The rest of the changes fill in some TODOs to make the test pass. Signed-off-by: Joel Dice --- crates/fuzzing/src/generators/config.rs | 3 +++ crates/fuzzing/src/generators/module.rs | 2 ++ crates/misc/component-test-util/Cargo.toml | 2 +- crates/misc/component-test-util/src/lib.rs | 3 +++ crates/wasmtime/src/config.rs | 13 ++++++++++ crates/wasmtime/src/engine/serialization.rs | 9 ++++++- .../src/runtime/component/instance.rs | 13 ++++++++-- crates/wasmtime/src/runtime/vm/component.rs | 19 ++++++++++++++ crates/wast-util/src/lib.rs | 1 + crates/wast/Cargo.toml | 2 +- .../component-model-async/lift.wast | 26 +++++++++++++++++++ 11 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 tests/misc_testsuite/component-model-async/lift.wast diff --git a/crates/fuzzing/src/generators/config.rs b/crates/fuzzing/src/generators/config.rs index 0ffabeac9be2..ae1ff5a8c5d0 100644 --- a/crates/fuzzing/src/generators/config.rs +++ b/crates/fuzzing/src/generators/config.rs @@ -139,6 +139,7 @@ impl Config { extended_const, wide_arithmetic, component_model_more_flags, + component_model_async, simd, hogs_memory: _, @@ -151,6 +152,7 @@ impl Config { self.module_config.function_references_enabled = function_references.or(gc).unwrap_or(false); self.module_config.component_model_more_flags = component_model_more_flags.unwrap_or(false); + self.module_config.component_model_async = component_model_async.unwrap_or(false); // Enable/disable proposals that wasm-smith has knobs for which will be // read when creating `wasmtime::Config`. @@ -266,6 +268,7 @@ impl Config { .wasm_wide_arithmetic(self.module_config.config.wide_arithmetic_enabled) .wasm_extended_const(self.module_config.config.extended_const_enabled) .wasm_component_model_more_flags(self.module_config.component_model_more_flags) + .wasm_component_model_async(self.module_config.component_model_async) .native_unwind_info(cfg!(target_os = "windows") || self.wasmtime.native_unwind_info) .cranelift_nan_canonicalization(self.wasmtime.canonicalize_nans) .cranelift_opt_level(self.wasmtime.opt_level.to_wasmtime()) diff --git a/crates/fuzzing/src/generators/module.rs b/crates/fuzzing/src/generators/module.rs index 283edaf1d2b8..9b8715636399 100644 --- a/crates/fuzzing/src/generators/module.rs +++ b/crates/fuzzing/src/generators/module.rs @@ -16,6 +16,7 @@ pub struct ModuleConfig { // config-to-`wasmtime::Config` translation. pub function_references_enabled: bool, pub component_model_more_flags: bool, + pub component_model_async: bool, } impl<'a> Arbitrary<'a> for ModuleConfig { @@ -62,6 +63,7 @@ impl<'a> Arbitrary<'a> for ModuleConfig { Ok(ModuleConfig { component_model_more_flags: false, + component_model_async: false, function_references_enabled: config.gc_enabled, config, }) diff --git a/crates/misc/component-test-util/Cargo.toml b/crates/misc/component-test-util/Cargo.toml index b5dfefddcb50..dc1ce92d029f 100644 --- a/crates/misc/component-test-util/Cargo.toml +++ b/crates/misc/component-test-util/Cargo.toml @@ -11,7 +11,7 @@ publish = false env_logger = { workspace = true } anyhow = { workspace = true } arbitrary = { workspace = true, features = ["derive"] } -wasmtime = { workspace = true, features = ["component-model", "async"] } +wasmtime = { workspace = true, features = ["component-model", "async", "component-model-async"] } wasmtime-environ = { workspace = true } wasmtime-wast-util = { path = '../../wast-util' } target-lexicon = { workspace = true } diff --git a/crates/misc/component-test-util/src/lib.rs b/crates/misc/component-test-util/src/lib.rs index 07d492b298df..2a6e72efb5e6 100644 --- a/crates/misc/component-test-util/src/lib.rs +++ b/crates/misc/component-test-util/src/lib.rs @@ -166,6 +166,7 @@ pub fn apply_test_config(config: &mut Config, test_config: &wasmtime_wast_util:: extended_const, wide_arithmetic, component_model_more_flags, + component_model_async, nan_canonicalization, simd, @@ -184,6 +185,7 @@ pub fn apply_test_config(config: &mut Config, test_config: &wasmtime_wast_util:: let extended_const = extended_const.unwrap_or(false); let wide_arithmetic = wide_arithmetic.unwrap_or(false); let component_model_more_flags = component_model_more_flags.unwrap_or(false); + let component_model_async = component_model_async.unwrap_or(false); let nan_canonicalization = nan_canonicalization.unwrap_or(false); let relaxed_simd = relaxed_simd.unwrap_or(false); @@ -210,5 +212,6 @@ pub fn apply_test_config(config: &mut Config, test_config: &wasmtime_wast_util:: .wasm_extended_const(extended_const) .wasm_wide_arithmetic(wide_arithmetic) .wasm_component_model_more_flags(component_model_more_flags) + .wasm_component_model_async(component_model_async) .cranelift_nan_canonicalization(nan_canonicalization); } diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 0212a071f531..6d6b1f9d4dae 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1111,6 +1111,19 @@ 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. + /// + /// Please note that Wasmtime's support for this feature is _very_ incomplete. + /// + /// [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 6281c123aa4f..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, } @@ -253,7 +254,6 @@ impl Metadata<'_> { assert!(!shared_everything_threads); assert!(!legacy_exceptions); assert!(!stack_switching); - assert!(!component_model_async); Metadata { target: engine.compiler().triple().to_string(), @@ -278,6 +278,7 @@ impl Metadata<'_> { custom_page_sizes, component_model_more_flags, component_model_multiple_returns, + component_model_async, gc_types, wide_arithmetic, }, @@ -488,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; @@ -574,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/instance.rs b/crates/wasmtime/src/runtime/component/instance.rs index 5584cf68b753..611822aa6e87 100644 --- a/crates/wasmtime/src/runtime/component/instance.rs +++ b/crates/wasmtime/src/runtime/component/instance.rs @@ -608,8 +608,7 @@ impl<'a> Instantiator<'a> { } GlobalInitializer::ExtractCallback(callback) => { - _ = callback; - todo!() + self.extract_callback(store.0, callback) } GlobalInitializer::ExtractPostReturn(post_return) => { @@ -659,6 +658,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, diff --git a/crates/wasmtime/src/runtime/vm/component.rs b/crates/wasmtime/src/runtime/vm/component.rs index 41ada5769d02..e57e93704a15 100644 --- a/crates/wasmtime/src/runtime/vm/component.rs +++ b/crates/wasmtime/src/runtime/vm/component.rs @@ -371,6 +371,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, @@ -487,6 +496,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); @@ -728,6 +742,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, diff --git a/crates/wast-util/src/lib.rs b/crates/wast-util/src/lib.rs index 08cd8fb55761..6760128f1cdd 100644 --- a/crates/wast-util/src/lib.rs +++ b/crates/wast-util/src/lib.rs @@ -185,6 +185,7 @@ macro_rules! foreach_config_option { hogs_memory nan_canonicalization component_model_more_flags + component_model_async simd gc_types } diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 599cfae1cdd1..dbe3f4d224b9 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -20,4 +20,4 @@ wast = { workspace = true } log = { workspace = true } [features] -component-model = ['wasmtime/component-model'] +component-model = ['wasmtime/component-model', 'wasmtime/component-model-async'] diff --git a/tests/misc_testsuite/component-model-async/lift.wast b/tests/misc_testsuite/component-model-async/lift.wast new file mode 100644 index 000000000000..f90c65672c96 --- /dev/null +++ b/tests/misc_testsuite/component-model-async/lift.wast @@ -0,0 +1,26 @@ +;;! component_model_async = true + +;; async lift; no callback +(component + (core module $m + (func (export "foo") (param i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "foo") (param "p1" u32) (result u32) + (canon lift (core func $i "foo") async) + ) +) + +;; async lift; with callback +(component + (core module $m + (func (export "callback") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "foo") (param i32) (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "foo") (param "p1" u32) (result u32) + (canon lift (core func $i "foo") async (callback (func $i "callback"))) + ) +)