From 37d71499f95064719cd3614f6f2bf5ee6967d934 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 20 Feb 2025 16:10:38 -0800 Subject: [PATCH 1/2] Synchronize some component model intrinsics with the spec This commit goes through a few component model intrinsics and synchronizes them with the current specification, mainly centered around async intrinsics. This doesn't synchronize all of them but is at least a start. Changes here include: * Support for `resource.drop async` intrinsics. * Renaming `task.backpressure` to `backpressure.set`. * Adding canonical ABI options to `task.return`. * A number of refactorings to simplify some constructs, reduce duplication, etc. The validation of `task.return` has been updated to take WebAssembly/component-model#453 into account with the new set of options that are allowed on it. Additionally `wit-component` was updated to set options for `task.return` in the same manner as the `canon lift`'d function on the other end. --- crates/wasm-encoder/src/component/builder.rs | 20 ++- .../wasm-encoder/src/component/canonicals.rs | 86 +++++------ crates/wasm-encoder/src/component/types.rs | 24 +-- crates/wasm-encoder/src/reencode/component.rs | 15 +- .../src/readers/component/canonicals.rs | 85 ++++------- .../wasmparser/src/readers/component/types.rs | 20 ++- crates/wasmparser/src/validator.rs | 27 ++-- crates/wasmparser/src/validator/component.rs | 87 ++++++----- .../src/validator/component_types.rs | 40 ++++- crates/wasmprinter/src/component.rs | 13 +- crates/wast/src/component/binary.rs | 11 +- crates/wast/src/component/expand.rs | 6 +- crates/wast/src/component/func.rs | 36 +++-- crates/wast/src/component/resolve.rs | 5 +- crates/wast/src/lib.rs | 2 +- crates/wit-component/src/encoding.rs | 143 ++++++++++++++++-- crates/wit-component/src/validation.rs | 20 +-- .../components/async-builtins/component.wat | 51 ++++--- .../components/async-builtins/module.wat | 4 +- src/bin/wasm-tools/dump.rs | 7 +- .../component-model-async/resources.wast | 4 + .../component-model-async/task-builtins.wast | 49 ++++-- .../component-model/async.wast | 17 ++- .../component-model-async/resources.wast.json | 11 ++ .../resources.wast/0.print | 4 + .../task-builtins.wast.json | 59 ++++++-- .../task-builtins.wast/0.print | 6 +- .../task-builtins.wast/11.print | 14 ++ .../task-builtins.wast/13.print | 14 ++ .../task-builtins.wast/3.print | 20 --- .../task-builtins.wast/5.print | 20 --- .../task-builtins.wast/6.print | 19 +++ .../task-builtins.wast/7.print | 22 ++- .../task-builtins.wast/9.print | 22 ++- .../component-model/async.wast.json | 9 +- 35 files changed, 644 insertions(+), 348 deletions(-) create mode 100644 tests/local/component-model-async/resources.wast create mode 100644 tests/snapshots/local/component-model-async/resources.wast.json create mode 100644 tests/snapshots/local/component-model-async/resources.wast/0.print create mode 100644 tests/snapshots/local/component-model-async/task-builtins.wast/11.print create mode 100644 tests/snapshots/local/component-model-async/task-builtins.wast/13.print delete mode 100644 tests/snapshots/local/component-model-async/task-builtins.wast/3.print delete mode 100644 tests/snapshots/local/component-model-async/task-builtins.wast/5.print create mode 100644 tests/snapshots/local/component-model-async/task-builtins.wast/6.print diff --git a/crates/wasm-encoder/src/component/builder.rs b/crates/wasm-encoder/src/component/builder.rs index 13c0eec03f..567d1db7d1 100644 --- a/crates/wasm-encoder/src/component/builder.rs +++ b/crates/wasm-encoder/src/component/builder.rs @@ -361,6 +361,12 @@ impl ComponentBuilder { inc(&mut self.core_funcs) } + /// Declares a new `resource.drop` intrinsic. + pub fn resource_drop_async(&mut self, ty: u32) -> u32 { + self.canonical_functions().resource_drop_async(ty); + inc(&mut self.core_funcs) + } + /// Declares a new `resource.new` intrinsic. pub fn resource_new(&mut self, ty: u32) -> u32 { self.canonical_functions().resource_new(ty); @@ -385,15 +391,19 @@ impl ComponentBuilder { inc(&mut self.core_funcs) } - /// Declares a new `task.backpressure` intrinsic. - pub fn task_backpressure(&mut self) -> u32 { - self.canonical_functions().task_backpressure(); + /// Declares a new `backpressure.set` intrinsic. + pub fn backpressure_set(&mut self) -> u32 { + self.canonical_functions().backpressure_set(); inc(&mut self.core_funcs) } /// Declares a new `task.return` intrinsic. - pub fn task_return(&mut self, ty: Option>) -> u32 { - self.canonical_functions().task_return(ty); + pub fn task_return(&mut self, ty: Option, options: O) -> u32 + where + O: IntoIterator, + O::IntoIter: ExactSizeIterator, + { + self.canonical_functions().task_return(ty, options); inc(&mut self.core_funcs) } diff --git a/crates/wasm-encoder/src/component/canonicals.rs b/crates/wasm-encoder/src/component/canonicals.rs index 7c5a253ea8..7f36a671ca 100644 --- a/crates/wasm-encoder/src/component/canonicals.rs +++ b/crates/wasm-encoder/src/component/canonicals.rs @@ -101,14 +101,10 @@ impl CanonicalFunctionSection { O: IntoIterator, O::IntoIter: ExactSizeIterator, { - let options = options.into_iter(); self.bytes.push(0x00); self.bytes.push(0x00); core_func_index.encode(&mut self.bytes); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); type_index.encode(&mut self.bytes); self.num_added += 1; self @@ -120,14 +116,10 @@ impl CanonicalFunctionSection { O: IntoIterator, O::IntoIter: ExactSizeIterator, { - let options = options.into_iter(); self.bytes.push(0x01); self.bytes.push(0x00); func_index.encode(&mut self.bytes); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -149,6 +141,14 @@ impl CanonicalFunctionSection { self } + /// Defines a function which will drop the specified type of handle. + pub fn resource_drop_async(&mut self, ty_index: u32) -> &mut Self { + self.bytes.push(0x07); + ty_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + /// Defines a function which will return the representation of the specified /// resource type. pub fn resource_rep(&mut self, ty_index: u32) -> &mut Self { @@ -179,7 +179,7 @@ impl CanonicalFunctionSection { /// backpressure for the caller's instance. When backpressure is enabled, /// the host must not start any new calls to that instance until /// backpressure is disabled. - pub fn task_backpressure(&mut self) -> &mut Self { + pub fn backpressure_set(&mut self) -> &mut Self { self.bytes.push(0x08); self.num_added += 1; self @@ -188,15 +188,14 @@ impl CanonicalFunctionSection { /// Defines a function which returns a result to the caller of a lifted /// export function. This allows the callee to continue executing after /// returning a result. - pub fn task_return(&mut self, ty: Option>) -> &mut Self { + pub fn task_return(&mut self, ty: Option, options: O) -> &mut Self + where + O: IntoIterator, + O::IntoIter: ExactSizeIterator, + { self.bytes.push(0x09); - if let Some(ty) = ty { - self.bytes.push(0x00); - ty.into().encode(&mut self.bytes); - } else { - self.bytes.push(0x01); - 0_usize.encode(&mut self.bytes); - } + crate::encode_resultlist(&mut self.bytes, ty); + self.encode_options(options); self.num_added += 1; self } @@ -261,11 +260,7 @@ impl CanonicalFunctionSection { { self.bytes.push(0x0f); ty.encode(&mut self.bytes); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -278,11 +273,7 @@ impl CanonicalFunctionSection { { self.bytes.push(0x10); ty.encode(&mut self.bytes); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -342,11 +333,7 @@ impl CanonicalFunctionSection { { self.bytes.push(0x16); ty.encode(&mut self.bytes); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -359,11 +346,7 @@ impl CanonicalFunctionSection { { self.bytes.push(0x17); ty.encode(&mut self.bytes); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -414,11 +397,7 @@ impl CanonicalFunctionSection { O::IntoIter: ExactSizeIterator, { self.bytes.push(0x1c); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -434,11 +413,7 @@ impl CanonicalFunctionSection { O::IntoIter: ExactSizeIterator, { self.bytes.push(0x1d); - let options = options.into_iter(); - options.len().encode(&mut self.bytes); - for option in options { - option.encode(&mut self.bytes); - } + self.encode_options(options); self.num_added += 1; self } @@ -449,6 +424,19 @@ impl CanonicalFunctionSection { self.num_added += 1; self } + + fn encode_options(&mut self, options: O) -> &mut Self + where + O: IntoIterator, + O::IntoIter: ExactSizeIterator, + { + let options = options.into_iter(); + options.len().encode(&mut self.bytes); + for option in options { + option.encode(&mut self.bytes); + } + self + } } impl Encode for CanonicalFunctionSection { diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index bb09ff4397..e32c75c464 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -405,20 +405,24 @@ impl<'a> ComponentFuncTypeEncoder<'a> { assert!(self.params_encoded); assert!(!self.results_encoded); self.results_encoded = true; - match ty { - Some(ty) => { - self.sink.push(0x00); - ty.encode(self.sink); - } - None => { - self.sink.push(0x01); - self.sink.push(0x00); - } - } + encode_resultlist(self.sink, ty); self } } +pub(crate) fn encode_resultlist(sink: &mut Vec, ty: Option) { + match ty { + Some(ty) => { + sink.push(0x00); + ty.encode(sink); + } + None => { + sink.push(0x01); + sink.push(0x00); + } + } +} + /// Used to encode component and instance types. #[derive(Debug)] pub struct ComponentTypeEncoder<'a>(&'a mut Vec); diff --git a/crates/wasm-encoder/src/reencode/component.rs b/crates/wasm-encoder/src/reencode/component.rs index 4401cf9dd2..3eb436ddb8 100644 --- a/crates/wasm-encoder/src/reencode/component.rs +++ b/crates/wasm-encoder/src/reencode/component.rs @@ -945,6 +945,10 @@ pub mod component_utils { let resource = reencoder.component_type_index(resource); section.resource_drop(resource); } + wasmparser::CanonicalFunction::ResourceDropAsync { resource } => { + let resource = reencoder.component_type_index(resource); + section.resource_drop_async(resource); + } wasmparser::CanonicalFunction::ResourceRep { resource } => { let resource = reencoder.component_type_index(resource); section.resource_rep(resource); @@ -956,11 +960,14 @@ pub mod component_utils { wasmparser::CanonicalFunction::ThreadAvailableParallelism => { section.thread_available_parallelism(); } - wasmparser::CanonicalFunction::TaskBackpressure => { - section.task_backpressure(); + wasmparser::CanonicalFunction::BackpressureSet => { + section.backpressure_set(); } - wasmparser::CanonicalFunction::TaskReturn { result } => { - section.task_return(result.map(|ty| reencoder.component_val_type(ty))); + wasmparser::CanonicalFunction::TaskReturn { result, options } => { + section.task_return( + result.map(|ty| reencoder.component_val_type(ty)), + options.iter().map(|o| reencoder.canonical_option(*o)), + ); } wasmparser::CanonicalFunction::TaskWait { async_, memory } => { section.task_wait(async_, reencoder.memory_index(memory)); diff --git a/crates/wasmparser/src/readers/component/canonicals.rs b/crates/wasmparser/src/readers/component/canonicals.rs index bd3c06b4c7..b907bf66ea 100644 --- a/crates/wasmparser/src/readers/component/canonicals.rs +++ b/crates/wasmparser/src/readers/component/canonicals.rs @@ -1,8 +1,6 @@ use crate::limits::MAX_WASM_CANONICAL_OPTIONS; use crate::prelude::*; -use crate::{ - BinaryReader, BinaryReaderError, ComponentValType, FromReader, Result, SectionLimited, -}; +use crate::{BinaryReader, ComponentValType, FromReader, Result, SectionLimited}; /// Represents options for component functions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -61,6 +59,11 @@ pub enum CanonicalFunction { /// The type index of the resource that's being dropped. resource: u32, }, + /// Same as `ResourceDrop`, but implements the `async` ABI. + ResourceDropAsync { + /// The type index of the resource that's being dropped. + resource: u32, + }, /// A function which returns the underlying i32-based representation of the /// specified resource. ResourceRep { @@ -77,13 +80,15 @@ pub enum CanonicalFunction { ThreadAvailableParallelism, /// A function which tells the host to enable or disable backpressure for /// the caller's instance. - TaskBackpressure, + BackpressureSet, /// A function which returns a result to the caller of a lifted export /// function. This allows the callee to continue executing after returning /// a result. TaskReturn { /// The result type, if any. result: Option, + /// The canonical options for the function. + options: Box<[CanonicalOption]>, }, /// A function which waits for at least one outstanding async /// task/stream/future to make progress, returning the first such event. @@ -237,26 +242,17 @@ impl<'a> FromReader<'a> for CanonicalFunction { fn from_reader(reader: &mut BinaryReader<'a>) -> Result { Ok(match reader.read_u8()? { 0x00 => match reader.read_u8()? { - 0x00 => { - let core_func_index = reader.read_var_u32()?; - let options = reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::>()?; - let type_index = reader.read_var_u32()?; - CanonicalFunction::Lift { - core_func_index, - options, - type_index, - } - } + 0x00 => CanonicalFunction::Lift { + core_func_index: reader.read_var_u32()?, + options: read_opts(reader)?, + type_index: reader.read_var_u32()?, + }, x => return reader.invalid_leading_byte(x, "canonical function lift"), }, 0x01 => match reader.read_u8()? { 0x00 => CanonicalFunction::Lower { func_index: reader.read_var_u32()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::>()?, + options: read_opts(reader)?, }, x => return reader.invalid_leading_byte(x, "canonical function lower"), }, @@ -266,6 +262,9 @@ impl<'a> FromReader<'a> for CanonicalFunction { 0x03 => CanonicalFunction::ResourceDrop { resource: reader.read()?, }, + 0x07 => CanonicalFunction::ResourceDropAsync { + resource: reader.read()?, + }, 0x04 => CanonicalFunction::ResourceRep { resource: reader.read()?, }, @@ -273,22 +272,10 @@ impl<'a> FromReader<'a> for CanonicalFunction { func_ty_index: reader.read()?, }, 0x06 => CanonicalFunction::ThreadAvailableParallelism, - 0x08 => CanonicalFunction::TaskBackpressure, + 0x08 => CanonicalFunction::BackpressureSet, 0x09 => CanonicalFunction::TaskReturn { - result: match reader.read_u8()? { - 0x00 => Some(reader.read()?), - 0x01 => { - if reader.read_u8()? == 0 { - None - } else { - return Err(BinaryReaderError::new( - "named results not allowed for `task.return` intrinsic", - reader.original_position() - 2, - )); - } - } - x => return reader.invalid_leading_byte(x, "`task.return` result"), - }, + result: crate::read_resultlist(reader)?, + options: read_opts(reader)?, }, 0x0a => CanonicalFunction::TaskWait { async_: reader.read()?, @@ -305,15 +292,11 @@ impl<'a> FromReader<'a> for CanonicalFunction { 0x0e => CanonicalFunction::StreamNew { ty: reader.read()? }, 0x0f => CanonicalFunction::StreamRead { ty: reader.read()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::>()?, + options: read_opts(reader)?, }, 0x10 => CanonicalFunction::StreamWrite { ty: reader.read()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::>()?, + options: read_opts(reader)?, }, 0x11 => CanonicalFunction::StreamCancelRead { ty: reader.read()?, @@ -328,15 +311,11 @@ impl<'a> FromReader<'a> for CanonicalFunction { 0x15 => CanonicalFunction::FutureNew { ty: reader.read()? }, 0x16 => CanonicalFunction::FutureRead { ty: reader.read()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::>()?, + options: read_opts(reader)?, }, 0x17 => CanonicalFunction::FutureWrite { ty: reader.read()?, - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::>()?, + options: read_opts(reader)?, }, 0x18 => CanonicalFunction::FutureCancelRead { ty: reader.read()?, @@ -349,14 +328,10 @@ impl<'a> FromReader<'a> for CanonicalFunction { 0x1a => CanonicalFunction::FutureCloseReadable { ty: reader.read()? }, 0x1b => CanonicalFunction::FutureCloseWritable { ty: reader.read()? }, 0x1c => CanonicalFunction::ErrorContextNew { - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::>()?, + options: read_opts(reader)?, }, 0x1d => CanonicalFunction::ErrorContextDebugMessage { - options: reader - .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? - .collect::>()?, + options: read_opts(reader)?, }, 0x1e => CanonicalFunction::ErrorContextDrop, x => return reader.invalid_leading_byte(x, "canonical function"), @@ -364,6 +339,12 @@ impl<'a> FromReader<'a> for CanonicalFunction { } } +fn read_opts(reader: &mut BinaryReader<'_>) -> Result> { + reader + .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? + .collect::>() +} + impl<'a> FromReader<'a> for CanonicalOption { fn from_reader(reader: &mut BinaryReader<'a>) -> Result { Ok(match reader.read_u8()? { diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index a9ce0eb261..0bdc1df956 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -287,14 +287,7 @@ impl<'a> FromReader<'a> for ComponentType<'a> { let params = reader .read_iter(MAX_WASM_FUNCTION_PARAMS, "component function parameters")? .collect::>()?; - let result = match reader.read_u8()? { - 0x00 => Some(reader.read()?), - 0x01 => match reader.read_u8()? { - 0x00 => None, - x => return reader.invalid_leading_byte(x, "number of results"), - }, - x => return reader.invalid_leading_byte(x, "component function results"), - }; + let result = read_resultlist(reader)?; ComponentType::Func(ComponentFuncType { params, result }) } 0x41 => ComponentType::Component( @@ -401,6 +394,17 @@ pub struct ComponentFuncType<'a> { pub result: Option, } +pub(crate) fn read_resultlist(reader: &mut BinaryReader<'_>) -> Result> { + match reader.read_u8()? { + 0x00 => Ok(Some(reader.read()?)), + 0x01 => match reader.read_u8()? { + 0x00 => Ok(None), + x => return reader.invalid_leading_byte(x, "number of results"), + }, + x => return reader.invalid_leading_byte(x, "component function results"), + } +} + /// Represents a case in a variant type. #[derive(Debug, Clone, PartialEq, Eq)] pub struct VariantCase<'a> { diff --git a/crates/wasmparser/src/validator.rs b/crates/wasmparser/src/validator.rs index 11b30088ca..6f1c3358ac 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -1280,7 +1280,7 @@ impl Validator { } => current.lift_function( core_func_index, type_index, - options.into_vec(), + &options, types, offset, features, @@ -1288,19 +1288,16 @@ impl Validator { crate::CanonicalFunction::Lower { func_index, options, - } => current.lower_function( - func_index, - options.into_vec(), - types, - offset, - features, - ), + } => current.lower_function(func_index, &options, types, offset, features), crate::CanonicalFunction::ResourceNew { resource } => { current.resource_new(resource, types, offset) } crate::CanonicalFunction::ResourceDrop { resource } => { current.resource_drop(resource, types, offset) } + crate::CanonicalFunction::ResourceDropAsync { resource } => { + current.resource_drop_async(resource, types, offset, features) + } crate::CanonicalFunction::ResourceRep { resource } => { current.resource_rep(resource, types, offset) } @@ -1310,11 +1307,11 @@ impl Validator { crate::CanonicalFunction::ThreadAvailableParallelism => { current.thread_available_parallelism(types, offset, features) } - crate::CanonicalFunction::TaskBackpressure => { - current.task_backpressure(types, offset, features) + crate::CanonicalFunction::BackpressureSet => { + current.backpressure_set(types, offset, features) } - crate::CanonicalFunction::TaskReturn { result } => { - current.task_return(&result, types, offset, features) + crate::CanonicalFunction::TaskReturn { result, options } => { + current.task_return(&result, &options, types, offset, features) } crate::CanonicalFunction::TaskWait { async_, memory } => { current.task_wait(async_, memory, types, offset, features) @@ -1332,10 +1329,10 @@ impl Validator { current.stream_new(ty, types, offset, features) } crate::CanonicalFunction::StreamRead { ty, options } => { - current.stream_read(ty, options.into_vec(), types, offset, features) + current.stream_read(ty, &options, types, offset, features) } crate::CanonicalFunction::StreamWrite { ty, options } => { - current.stream_write(ty, options.into_vec(), types, offset, features) + current.stream_write(ty, &options, types, offset, features) } crate::CanonicalFunction::StreamCancelRead { ty, async_ } => { current.stream_cancel_read(ty, async_, types, offset, features) @@ -1353,7 +1350,7 @@ impl Validator { current.future_new(ty, types, offset, features) } crate::CanonicalFunction::FutureRead { ty, options } => { - current.future_read(ty, options.into_vec(), types, offset, features) + current.future_read(ty, &options, types, offset, features) } crate::CanonicalFunction::FutureWrite { ty, options } => { current.future_write(ty, options.into_vec(), types, offset, features) diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index dfee2584c0..461878d9e3 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -955,7 +955,7 @@ impl ComponentState { &mut self, core_func_index: u32, type_index: u32, - options: Vec, + options: &[CanonicalOption], types: &TypeList, offset: usize, features: &WasmFeatures, @@ -965,30 +965,8 @@ impl ComponentState { // Lifting a function is for an export, so match the expected canonical ABI // export signature - let info = ty.lower( - types, - if options.contains(&CanonicalOption::Async) { - if options - .iter() - .any(|v| matches!(v, CanonicalOption::Callback(_))) - { - Abi::LiftAsync - } else { - Abi::LiftAsyncStackful - } - } else { - Abi::LiftSync - }, - ); - self.check_options( - Some(core_ty), - &info, - &options, - types, - offset, - features, - true, - )?; + let info = ty.lower(types, Abi::for_lift(options)); + self.check_options(Some(core_ty), &info, options, types, offset, features, true)?; if core_ty.params() != info.params.as_slice() { bail!( @@ -1019,7 +997,7 @@ impl ComponentState { pub fn lower_function( &mut self, func_index: u32, - options: Vec, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, features: &WasmFeatures, @@ -1037,7 +1015,7 @@ impl ComponentState { }, ); - self.check_options(None, &info, &options, types, offset, features, true)?; + self.check_options(None, &info, options, types, offset, features, true)?; let id = types.intern_func_type(info.into_func_type(), offset); self.core_funcs.push(id); @@ -1069,6 +1047,25 @@ impl ComponentState { Ok(()) } + pub fn resource_drop_async( + &mut self, + resource: u32, + types: &mut TypeAlloc, + offset: usize, + features: &WasmFeatures, + ) -> Result<()> { + if !features.component_model_async() { + bail!( + offset, + "`resource.drop` as `async` requires the component model async feature" + ) + } + self.resource_at(resource, types, offset)?; + let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset); + self.core_funcs.push(id); + Ok(()) + } + pub fn resource_rep( &mut self, resource: u32, @@ -1081,7 +1078,7 @@ impl ComponentState { Ok(()) } - pub fn task_backpressure( + pub fn backpressure_set( &mut self, types: &mut TypeAlloc, offset: usize, @@ -1090,7 +1087,7 @@ impl ComponentState { if !features.component_model_async() { bail!( offset, - "`task.backpressure` requires the component model async feature" + "`backpressure.set` requires the component model async feature" ) } @@ -1102,6 +1099,7 @@ impl ComponentState { pub fn task_return( &mut self, result: &Option, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, features: &WasmFeatures, @@ -1113,6 +1111,21 @@ impl ComponentState { ) } + for option in options { + let invalid = match option { + CanonicalOption::UTF8 + | CanonicalOption::UTF16 + | CanonicalOption::CompactUTF16 + | CanonicalOption::Memory(_) + | CanonicalOption::Realloc(_) => continue, + + CanonicalOption::PostReturn(_) => "post-return", + CanonicalOption::Async => "async", + CanonicalOption::Callback(_) => "callback", + }; + bail!(offset, "cannot specify `{invalid}` option on `task.return`") + } + let info = ComponentFuncType { info: TypeInfo::new(), params: result @@ -1133,7 +1146,9 @@ impl ComponentState { .collect::>()?, result: None, } - .lower(types, Abi::LiftSync); + .lower(types, Abi::LowerSync); + + self.check_options(None, &info, options, types, offset, features, true)?; assert!(info.results.iter().next().is_none()); @@ -1250,7 +1265,7 @@ impl ComponentState { pub fn stream_read( &mut self, ty: u32, - options: Vec, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, features: &WasmFeatures, @@ -1272,7 +1287,7 @@ impl ComponentState { info.requires_realloc = payload_type .map(|ty| ty.contains_ptr(types)) .unwrap_or_default(); - self.check_options(None, &info, &options, types, offset, features, true)?; + self.check_options(None, &info, options, types, offset, features, true)?; self.core_funcs .push(types.intern_func_type(FuncType::new([ValType::I32; 3], [ValType::I32]), offset)); @@ -1282,7 +1297,7 @@ impl ComponentState { pub fn stream_write( &mut self, ty: u32, - options: Vec, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, features: &WasmFeatures, @@ -1302,7 +1317,7 @@ impl ComponentState { let mut info = LoweringInfo::default(); info.requires_memory = true; info.requires_realloc = false; - self.check_options(None, &info, &options, types, offset, features, true)?; + self.check_options(None, &info, options, types, offset, features, true)?; self.core_funcs .push(types.intern_func_type(FuncType::new([ValType::I32; 3], [ValType::I32]), offset)); @@ -1434,7 +1449,7 @@ impl ComponentState { pub fn future_read( &mut self, ty: u32, - options: Vec, + options: &[CanonicalOption], types: &mut TypeAlloc, offset: usize, features: &WasmFeatures, @@ -1456,7 +1471,7 @@ impl ComponentState { info.requires_realloc = payload_type .map(|ty| ty.contains_ptr(types)) .unwrap_or_default(); - self.check_options(None, &info, &options, types, offset, features, true)?; + self.check_options(None, &info, options, types, offset, features, true)?; self.core_funcs .push(types.intern_func_type(FuncType::new([ValType::I32; 2], [ValType::I32]), offset)); diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs index f76ca674ce..67e1addbf6 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -7,7 +7,8 @@ use crate::validator::types::{ CoreTypeId, EntityType, SnapshotList, TypeAlloc, TypeData, TypeIdentifier, TypeInfo, TypeList, Types, TypesKind, TypesRef, TypesRefKind, }; -use crate::{BinaryReaderError, FuncType, PrimitiveValType, Result, ValType}; +use crate::{BinaryReaderError, CanonicalOption, FuncType, PrimitiveValType, Result, ValType}; +use core::fmt; use core::ops::Index; use core::sync::atomic::{AtomicUsize, Ordering}; use core::{ @@ -86,7 +87,14 @@ impl LoweredTypes { } } +impl fmt::Debug for LoweredTypes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_slice().fmt(f) + } +} + /// Represents information about a component function type lowering. +#[derive(Debug)] pub(crate) struct LoweringInfo { pub(crate) params: LoweredTypes, pub(crate) results: LoweredTypes, @@ -894,13 +902,43 @@ impl TypeData for ComponentFuncType { #[derive(Copy, Clone, Debug)] pub(crate) enum Abi { + /// Use to generate the core wasm signature of a component model function + /// that is `canon lower`'d with the synchronous ABI option set. LowerSync, + /// Use to generate the core wasm signature of a component model function + /// that is `canon lower`'d with the asynchronous ABI option set. LowerAsync, + /// Use to generate the core wasm signature that when `canon lift`'d with + /// the synchronous ABI option set will generate a component model function + /// type. LiftSync, + /// Use to generate the core wasm signature that when `canon lift`'d with + /// the asynchronous + callback ABI options set will generate a component + /// model function type. LiftAsync, + /// Use to generate the core wasm signature that when `canon lift`'d with + /// the asynchronou ABI option set will generate a component + /// model function type. LiftAsyncStackful, } +impl Abi { + pub(crate) fn for_lift(options: &[CanonicalOption]) -> Abi { + if options.contains(&CanonicalOption::Async) { + if options + .iter() + .any(|v| matches!(v, CanonicalOption::Callback(_))) + { + Abi::LiftAsync + } else { + Abi::LiftAsyncStackful + } + } else { + Abi::LiftSync + } + } +} + impl ComponentFuncType { /// Lowers the component function type to core parameter and result types for the /// canonical ABI. diff --git a/crates/wasmprinter/src/component.rs b/crates/wasmprinter/src/component.rs index 64378bd893..19861fa229 100644 --- a/crates/wasmprinter/src/component.rs +++ b/crates/wasmprinter/src/component.rs @@ -881,6 +881,12 @@ impl Printer<'_, '_> { me.print_idx(&state.component.type_names, resource) })?; } + CanonicalFunction::ResourceDropAsync { resource } => { + self.print_intrinsic(state, "canon resource.drop ", &|me, state| { + me.print_idx(&state.component.type_names, resource)?; + me.print_type_keyword(" async") + })?; + } CanonicalFunction::ResourceRep { resource } => { self.print_intrinsic(state, "canon resource.rep ", &|me, state| { me.print_idx(&state.component.type_names, resource) @@ -907,10 +913,10 @@ impl Printer<'_, '_> { self.end_group()?; state.core.funcs += 1; } - CanonicalFunction::TaskBackpressure => { - self.print_intrinsic(state, "canon task.backpressure", &|_, _| Ok(()))?; + CanonicalFunction::BackpressureSet => { + self.print_intrinsic(state, "canon backpressure.set", &|_, _| Ok(()))?; } - CanonicalFunction::TaskReturn { result } => { + CanonicalFunction::TaskReturn { result, options } => { self.print_intrinsic(state, "canon task.return", &|me, state| { if let Some(ty) = result { me.result.write_str(" ")?; @@ -918,6 +924,7 @@ impl Printer<'_, '_> { me.print_component_val_type(state, &ty)?; me.end_group()?; } + me.print_canonical_options(state, &options)?; Ok(()) })?; } diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 2fc95b9735..741d773526 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -339,7 +339,11 @@ impl<'a> Encoder<'a> { } CanonicalFuncKind::ResourceDrop(info) => { self.core_func_names.push(name); - self.funcs.resource_drop(info.ty.into()); + if info.async_ { + self.funcs.resource_drop_async(info.ty.into()); + } else { + self.funcs.resource_drop(info.ty.into()); + } } CanonicalFuncKind::ResourceRep(info) => { self.core_func_names.push(name); @@ -353,9 +357,9 @@ impl<'a> Encoder<'a> { self.core_func_names.push(name); self.funcs.thread_available_parallelism(); } - CanonicalFuncKind::TaskBackpressure => { + CanonicalFuncKind::BackpressureSet => { self.core_func_names.push(name); - self.funcs.task_backpressure(); + self.funcs.backpressure_set(); } CanonicalFuncKind::TaskReturn(info) => { self.core_func_names.push(name); @@ -363,6 +367,7 @@ impl<'a> Encoder<'a> { info.result .as_ref() .map(|ty| wasm_encoder::ComponentValType::from(ty)), + info.opts.iter().map(Into::into), ); } CanonicalFuncKind::TaskWait(info) => { diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs index f2c3b3ca6e..72db0ec299 100644 --- a/crates/wast/src/component/expand.rs +++ b/crates/wast/src/component/expand.rs @@ -270,7 +270,7 @@ impl<'a> Expander<'a> { | CanonicalFuncKind::ResourceDrop(_) | CanonicalFuncKind::ThreadSpawn(_) | CanonicalFuncKind::ThreadAvailableParallelism(_) - | CanonicalFuncKind::TaskBackpressure + | CanonicalFuncKind::BackpressureSet | CanonicalFuncKind::TaskReturn(_) | CanonicalFuncKind::TaskWait(_) | CanonicalFuncKind::TaskPoll(_) @@ -346,11 +346,11 @@ impl<'a> Expander<'a> { kind: CanonicalFuncKind::ThreadAvailableParallelism(info), }) } - CoreFuncKind::TaskBackpressure => ComponentField::CanonicalFunc(CanonicalFunc { + CoreFuncKind::BackpressureSet => ComponentField::CanonicalFunc(CanonicalFunc { span: func.span, id: func.id, name: func.name, - kind: CanonicalFuncKind::TaskBackpressure, + kind: CanonicalFuncKind::BackpressureSet, }), CoreFuncKind::TaskReturn(info) => ComponentField::CanonicalFunc(CanonicalFunc { span: func.span, diff --git a/crates/wast/src/component/func.rs b/crates/wast/src/component/func.rs index ee3e4dec3f..be025d0af7 100644 --- a/crates/wast/src/component/func.rs +++ b/crates/wast/src/component/func.rs @@ -53,7 +53,7 @@ pub enum CoreFuncKind<'a> { ResourceRep(CanonResourceRep<'a>), ThreadSpawn(CanonThreadSpawn<'a>), ThreadAvailableParallelism(CanonThreadAvailableParallelism), - TaskBackpressure, + BackpressureSet, TaskReturn(CanonTaskReturn<'a>), TaskWait(CanonTaskWait<'a>), TaskPoll(CanonTaskPoll<'a>), @@ -102,9 +102,9 @@ impl<'a> Parse<'a> for CoreFuncKind<'a> { Ok(CoreFuncKind::ThreadSpawn(parser.parse()?)) } else if l.peek::()? { Ok(CoreFuncKind::ThreadAvailableParallelism(parser.parse()?)) - } else if l.peek::()? { - parser.parse::()?; - Ok(CoreFuncKind::TaskBackpressure) + } else if l.peek::()? { + parser.parse::()?; + Ok(CoreFuncKind::BackpressureSet) } else if l.peek::()? { Ok(CoreFuncKind::TaskReturn(parser.parse()?)) } else if l.peek::()? { @@ -343,7 +343,7 @@ pub enum CanonicalFuncKind<'a> { ThreadSpawn(CanonThreadSpawn<'a>), ThreadAvailableParallelism(CanonThreadAvailableParallelism), - TaskBackpressure, + BackpressureSet, TaskReturn(CanonTaskReturn<'a>), TaskWait(CanonTaskWait<'a>), TaskPoll(CanonTaskPoll<'a>), @@ -461,6 +461,8 @@ impl<'a> Parse<'a> for CanonResourceNew<'a> { pub struct CanonResourceDrop<'a> { /// The resource type that this intrinsic is dropping. pub ty: Index<'a>, + /// Whether or not this function is async + pub async_: bool, } impl<'a> Parse<'a> for CanonResourceDrop<'a> { @@ -469,6 +471,7 @@ impl<'a> Parse<'a> for CanonResourceDrop<'a> { Ok(Self { ty: parser.parse()?, + async_: parser.parse::>()?.is_some(), }) } } @@ -523,22 +526,25 @@ impl<'a> Parse<'a> for CanonThreadAvailableParallelism { pub struct CanonTaskReturn<'a> { /// The type of the result which may be returned with this intrinsic. pub result: Option>, + /// The canonical options for storing values. + pub opts: Vec>, } impl<'a> Parse<'a> for CanonTaskReturn<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; - let result = if parser.peek2::()? { - Some(parser.parens(|p| { - p.parse::()?.0; - p.parse() - })?) - } else { - None - }; - - Ok(Self { result }) + Ok(Self { + result: if parser.peek2::()? { + Some(parser.parens(|p| { + p.parse::()?.0; + p.parse() + })?) + } else { + None + }, + opts: parser.parse()?, + }) } } diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index aa1187fc9f..8ca18cdcde 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -387,7 +387,7 @@ impl<'a> Resolver<'a> { self.resolve_ns(&mut info.ty, Ns::CoreType)?; } CanonicalFuncKind::ThreadAvailableParallelism(_) - | CanonicalFuncKind::TaskBackpressure + | CanonicalFuncKind::BackpressureSet | CanonicalFuncKind::TaskYield(_) | CanonicalFuncKind::SubtaskDrop | CanonicalFuncKind::ErrorContextDrop => {} @@ -395,6 +395,7 @@ impl<'a> Resolver<'a> { if let Some(ty) = &mut info.result { self.component_val_type(ty)?; } + self.canon_opts(&mut info.opts)?; } CanonicalFuncKind::TaskWait(info) => { self.core_item_ref(&mut info.memory)?; @@ -965,7 +966,7 @@ impl<'a> ComponentState<'a> { | CanonicalFuncKind::ResourceDrop(_) | CanonicalFuncKind::ThreadSpawn(_) | CanonicalFuncKind::ThreadAvailableParallelism(_) - | CanonicalFuncKind::TaskBackpressure + | CanonicalFuncKind::BackpressureSet | CanonicalFuncKind::TaskReturn(_) | CanonicalFuncKind::TaskWait(_) | CanonicalFuncKind::TaskPoll(_) diff --git a/crates/wast/src/lib.rs b/crates/wast/src/lib.rs index 0cd276e8ed..e8bb5723ad 100644 --- a/crates/wast/src/lib.rs +++ b/crates/wast/src/lib.rs @@ -556,7 +556,7 @@ pub mod kw { custom_keyword!(thread); custom_keyword!(thread_spawn = "thread.spawn"); custom_keyword!(thread_available_parallelism = "thread.available_parallelism"); - custom_keyword!(task_backpressure = "task.backpressure"); + custom_keyword!(backpressure_set = "backpressure.set"); custom_keyword!(task_return = "task.return"); custom_keyword!(task_wait = "task.wait"); custom_keyword!(task_poll = "task.poll"); diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 628befe7ee..8da856d378 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -81,7 +81,7 @@ use std::collections::HashMap; use std::hash::Hash; use std::mem; use wasm_encoder::*; -use wasmparser::Validator; +use wasmparser::{Validator, WasmFeatures}; use wit_parser::{ abi::{AbiVariant, WasmSignature, WasmType}, Function, FunctionKind, InterfaceId, LiveTypes, Resolve, Stability, Type, TypeDefKind, TypeId, @@ -1339,6 +1339,30 @@ impl<'a> EncodingState<'a> { realloc_index, )?) } + ShimKind::TaskReturn { + interface, + func, + result, + encoding, + for_module, + } => { + let mut encoder = self.root_export_type_encoder(*interface); + let result = match result { + Some(ty) => Some(encoder.encode_valtype(resolve, ty)?), + None => None, + }; + + let exports = self.info.exports_for(*for_module); + let realloc = exports.import_realloc_for(*interface, func); + + let instance_index = self.instance_for(*for_module); + let realloc_index = realloc + .map(|r| self.core_alias_export(instance_index, r, ExportKind::Func)); + let options = + shim.options + .into_iter(*encoding, self.memory_index, realloc_index)?; + self.component.task_return(result, options) + } }; exports.push((shim.name.as_str(), ExportKind::Func, core_func_index)); @@ -1590,19 +1614,34 @@ impl<'a> EncodingState<'a> { AbiVariant::GuestImport, ) } - Import::ExportedTaskReturn(interface, _function, result) => { - let mut encoder = self.root_export_type_encoder(*interface); - - let result = match result { - Some(ty) => Some(encoder.encode_valtype(resolve, ty)?), - None => None, - }; - - let index = self.component.task_return(result); - Ok((ExportKind::Func, index)) + Import::ExportedTaskReturn(key, interface, func, result) => { + let (options, _sig) = task_return_options_and_type(resolve, *result, false); + if options.is_empty() { + let mut encoder = self.root_export_type_encoder(*interface); + + let result = match result { + Some(ty) => Some(encoder.encode_valtype(resolve, ty)?), + None => None, + }; + let index = self.component.task_return(result, []); + Ok((ExportKind::Func, index)) + } else { + let metadata = &self.info.encoder.metadata.metadata; + let encoding = metadata.export_encodings.get(resolve, key, func).unwrap(); + Ok(self.materialize_shim_import( + shims, + &ShimKind::TaskReturn { + for_module, + interface: *interface, + func, + result: *result, + encoding, + }, + )) + } } - Import::TaskBackpressure => { - let index = self.component.task_backpressure(); + Import::BackpressureSet => { + let index = self.component.backpressure_set(); Ok((ExportKind::Func, index)) } Import::TaskWait { async_ } => { @@ -2006,6 +2045,19 @@ enum ShimKind<'a> { /// A shim used for the `task.poll` built-in function, which must refer to /// the core module instance's memory to which results will be written. TaskPoll { async_: bool }, + /// TODO + TaskReturn { + /// TODO + interface: Option, + /// TODO + func: &'a str, + /// TODO + result: Option, + /// Which instance to pull the `realloc` function from, if necessary. + for_module: CustomModule<'a>, + /// String encoding to use in the ABI options. + encoding: StringEncoding, + }, /// A shim used for the `error-context.new` built-in function, which must /// refer to the core module instance's memory from which the debug message /// will be read. @@ -2072,10 +2124,9 @@ impl<'a> Shims<'a> { | Import::ExportedResourceRep(..) | Import::ExportedResourceNew(..) | Import::ErrorContextDrop - | Import::TaskBackpressure + | Import::BackpressureSet | Import::TaskYield { .. } | Import::SubtaskDrop - | Import::ExportedTaskReturn(..) | Import::FutureNew(..) | Import::StreamNew(..) | Import::FutureCancelRead { .. } @@ -2087,6 +2138,40 @@ impl<'a> Shims<'a> { | Import::StreamCloseWritable { .. } | Import::StreamCloseReadable { .. } => {} + // If `task.return` needs to be indirect then generate a shim + // for it, otherwise skip the shim and let it get materialized + // naturally later. + Import::ExportedTaskReturn(key, interface, func, ty) => { + let (options, sig) = task_return_options_and_type(resolve, *ty, false); + if options.is_empty() { + continue; + } + let name = self.shims.len().to_string(); + let encoding = world + .module_metadata_for(for_module) + .export_encodings + .get(resolve, key, func) + .ok_or_else(|| { + anyhow::anyhow!( + "missing component metadata for export of \ + `{module}::{field}`" + ) + })?; + self.push(Shim { + name, + debug_name: format!("task-return-{func}"), + options, + kind: ShimKind::TaskReturn { + interface: *interface, + func, + result: *ty, + for_module, + encoding, + }, + sig, + }); + } + Import::FutureWrite { async_, info } => { self.append_indirect_payload_push( resolve, @@ -2418,6 +2503,32 @@ impl<'a> Shims<'a> { } } +fn task_return_options_and_type( + resolve: &Resolve, + ty: Option, + async_: bool, +) -> (RequiredOptions, WasmSignature) { + let func_tmp = Function { + name: String::new(), + kind: FunctionKind::Freestanding, + params: match ty { + Some(ty) => vec![("a".to_string(), ty)], + None => Vec::new(), + }, + result: None, + docs: Default::default(), + stability: Stability::Unknown, + }; + let abi = if async_ { + AbiVariant::GuestImportAsync + } else { + AbiVariant::GuestImport + }; + let options = RequiredOptions::for_import(resolve, &func_tmp, abi); + let sig = resolve.wasm_signature(abi, &func_tmp); + (options, sig) +} + /// Alias argument to an instantiation #[derive(Clone, Debug)] pub struct Item { @@ -2720,7 +2831,7 @@ impl ComponentEncoder { let bytes = state.component.finish(); if self.validate { - Validator::new() + Validator::new_with_features(WasmFeatures::all()) .validate_all(&bytes) .context("failed to validate component output")?; } diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs index 9dbf5aa5e7..d436ac83cb 100644 --- a/crates/wit-component/src/validation.rs +++ b/crates/wit-component/src/validation.rs @@ -253,13 +253,13 @@ pub enum Import { /// As of this writing, only async-lifted exports use `task.return`, but the /// plan is to also support it for sync-lifted exports in the future as /// well. - ExportedTaskReturn(Option, String, Option), + ExportedTaskReturn(WorldKey, Option, String, Option), - /// A `canon task.backpressure` intrinsic. + /// A `canon backpressure.set` intrinsic. /// /// This allows the guest to dynamically indicate whether it's ready for /// additional concurrent calls. - TaskBackpressure, + BackpressureSet, /// A `canon task.wait` intrinsic. /// @@ -550,10 +550,10 @@ impl ImportMap { return Ok(Import::ErrorContextDrop); } - if Some(name) == names.task_backpressure() { + if Some(name) == names.backpressure_set() { let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; - return Ok(Import::TaskBackpressure); + return Ok(Import::BackpressureSet); } if Some(name) == names.task_wait() { @@ -776,9 +776,11 @@ impl ImportMap { } if let Some(name) = names.task_return_name(name) { let func = get_function(resolve, world, name, id, import)?; + let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string())); // TODO: should call `validate_func_sig` but would require // calculating the expected signature based of `func.result`. return Ok(Some(Import::ExportedTaskReturn( + key, None, func.name.clone(), func.result, @@ -1364,7 +1366,7 @@ trait NameMangling { fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str>; fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str>; fn task_return_name<'a>(&self, s: &'a str) -> Option<&'a str>; - fn task_backpressure(&self) -> Option<&str>; + fn backpressure_set(&self) -> Option<&str>; fn task_wait(&self) -> Option<&str>; fn task_poll(&self) -> Option<&str>; fn task_yield(&self) -> Option<&str>; @@ -1436,7 +1438,7 @@ impl NameMangling for Standard { _ = s; None } - fn task_backpressure(&self) -> Option<&str> { + fn backpressure_set(&self) -> Option<&str> { None } fn task_wait(&self) -> Option<&str> { @@ -1612,8 +1614,8 @@ impl NameMangling for Legacy { fn task_return_name<'a>(&self, s: &'a str) -> Option<&'a str> { s.strip_prefix("[task-return]") } - fn task_backpressure(&self) -> Option<&str> { - Some("[task-backpressure]") + fn backpressure_set(&self) -> Option<&str> { + Some("[backpressure-set]") } fn task_wait(&self) -> Option<&str> { Some("[task-wait]") diff --git a/crates/wit-component/tests/components/async-builtins/component.wat b/crates/wit-component/tests/components/async-builtins/component.wat index b6b937a2b3..88fd64fd97 100644 --- a/crates/wit-component/tests/components/async-builtins/component.wat +++ b/crates/wit-component/tests/components/async-builtins/component.wat @@ -6,7 +6,7 @@ (type (;3;) (func)) (type (;4;) (func (param i32 i32) (result i32))) (type (;5;) (func (param i32 i32 i32 i32) (result i32))) - (import "$root" "[task-backpressure]" (func (;0;) (type 0))) + (import "$root" "[backpressure-set]" (func (;0;) (type 0))) (import "[export]$root" "[task-return]foo" (func (;1;) (type 1))) (import "[export]foo:foo/bar" "[task-return]foo" (func (;2;) (type 1))) (import "$root" "[task-wait]" (func (;3;) (type 2))) @@ -39,11 +39,13 @@ (type (;0;) (func (param i32) (result i32))) (type (;1;) (func (param i32 i32) (result i32))) (type (;2;) (func (param i32 i32))) - (table (;0;) 4 4 funcref) + (type (;3;) (func (param i32 i32))) + (table (;0;) 5 5 funcref) (export "0" (func $task-wait)) (export "1" (func $task-poll)) (export "2" (func $error-new)) (export "3" (func $error-debug-message)) + (export "4" (func $task-return-foo)) (export "$imports" (table 0)) (func $task-wait (;0;) (type 0) (param i32) (result i32) local.get 0 @@ -67,6 +69,12 @@ i32.const 3 call_indirect (type 2) ) + (func $task-return-foo (;4;) (type 3) (param i32 i32) + local.get 0 + local.get 1 + i32.const 4 + call_indirect (type 3) + ) (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) @@ -75,18 +83,20 @@ (type (;0;) (func (param i32) (result i32))) (type (;1;) (func (param i32 i32) (result i32))) (type (;2;) (func (param i32 i32))) + (type (;3;) (func (param i32 i32))) (import "" "0" (func (;0;) (type 0))) (import "" "1" (func (;1;) (type 0))) (import "" "2" (func (;2;) (type 1))) (import "" "3" (func (;3;) (type 2))) - (import "" "$imports" (table (;0;) 4 4 funcref)) - (elem (;0;) (i32.const 0) func 0 1 2 3) + (import "" "4" (func (;4;) (type 3))) + (import "" "$imports" (table (;0;) 5 5 funcref)) + (elem (;0;) (i32.const 0) func 0 1 2 3 4) (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) ) (core instance (;0;) (instantiate 1)) - (core func (;0;) (canon task.backpressure)) + (core func (;0;) (canon backpressure.set)) (alias core export 0 "0" (core func (;1;))) (alias core export 0 "1" (core func (;2;))) (core func (;3;) (canon task.yield)) @@ -95,7 +105,7 @@ (alias core export 0 "3" (core func (;6;))) (core func (;7;) (canon error-context.drop)) (core instance (;1;) - (export "[task-backpressure]" (func 0)) + (export "[backpressure-set]" (func 0)) (export "[task-wait]" (func 1)) (export "[task-poll]" (func 2)) (export "[task-yield]" (func 3)) @@ -104,13 +114,12 @@ (export "[error-context-debug-message;encoding=utf8;realloc=cabi_realloc]" (func 6)) (export "[error-context-drop]" (func 7)) ) - (core func (;8;) (canon task.return (result string))) + (alias core export 0 "4" (core func (;8;))) (core instance (;2;) (export "[task-return]foo" (func 8)) ) - (core func (;9;) (canon task.return (result string))) (core instance (;3;) - (export "[task-return]foo" (func 9)) + (export "[task-return]foo" (func 8)) ) (core instance (;4;) (instantiate 0 (with "$root" (instance 1)) @@ -120,17 +129,19 @@ ) (alias core export 4 "memory" (core memory (;0;))) (alias core export 0 "$imports" (core table (;0;))) - (core func (;10;) (canon task.wait (memory 0))) - (core func (;11;) (canon task.poll (memory 0))) - (core func (;12;) (canon error-context.new (memory 0) string-encoding=utf8)) - (alias core export 4 "cabi_realloc" (core func (;13;))) - (core func (;14;) (canon error-context.debug-message (memory 0) (realloc 13) string-encoding=utf8)) + (core func (;9;) (canon task.wait (memory 0))) + (core func (;10;) (canon task.poll (memory 0))) + (core func (;11;) (canon error-context.new (memory 0) string-encoding=utf8)) + (alias core export 4 "cabi_realloc" (core func (;12;))) + (core func (;13;) (canon error-context.debug-message (memory 0) (realloc 12) string-encoding=utf8)) + (core func (;14;) (canon task.return (result string) (memory 0) string-encoding=utf8)) (core instance (;5;) (export "$imports" (table 0)) - (export "0" (func 10)) - (export "1" (func 11)) - (export "2" (func 12)) - (export "3" (func 14)) + (export "0" (func 9)) + (export "1" (func 10)) + (export "2" (func 11)) + (export "3" (func 13)) + (export "4" (func 14)) ) (core instance (;6;) (instantiate 2 (with "" (instance 5)) @@ -138,11 +149,11 @@ ) (type (;0;) (func (param "s" string) (result string))) (alias core export 4 "[async-stackful]foo" (core func (;15;))) - (func (;0;) (type 0) (canon lift (core func 15) (memory 0) (realloc 13) string-encoding=utf8 async)) + (func (;0;) (type 0) (canon lift (core func 15) (memory 0) (realloc 12) string-encoding=utf8 async)) (export (;1;) "foo" (func 0)) (type (;1;) (func (param "s" string) (result string))) (alias core export 4 "[async-stackful]foo:foo/bar#foo" (core func (;16;))) - (func (;2;) (type 1) (canon lift (core func 16) (memory 0) (realloc 13) string-encoding=utf8 async)) + (func (;2;) (type 1) (canon lift (core func 16) (memory 0) (realloc 12) string-encoding=utf8 async)) (component (;0;) (type (;0;) (func (param "s" string) (result string))) (import "import-func-foo" (func (;0;) (type 0))) diff --git a/crates/wit-component/tests/components/async-builtins/module.wat b/crates/wit-component/tests/components/async-builtins/module.wat index d689ad0e8c..29ffb5ebf4 100644 --- a/crates/wit-component/tests/components/async-builtins/module.wat +++ b/crates/wit-component/tests/components/async-builtins/module.wat @@ -1,7 +1,7 @@ (module - (import "$root" "[task-backpressure]" (func (param i32))) + (import "$root" "[backpressure-set]" (func (param i32))) (import "[export]$root" "[task-return]foo" (func (param i32 i32))) - (import "[export]foo:foo/bar" "[task-return]foo" (func (param i32 i32))) + (import "[export]foo:foo/bar" "[task-return]foo" (func (param i32 i32))) (import "$root" "[task-wait]" (func (param i32) (result i32))) (import "$root" "[task-poll]" (func (param i32) (result i32))) (import "$root" "[task-yield]" (func)) diff --git a/src/bin/wasm-tools/dump.rs b/src/bin/wasm-tools/dump.rs index 8ea31b6c15..e133a0feb3 100644 --- a/src/bin/wasm-tools/dump.rs +++ b/src/bin/wasm-tools/dump.rs @@ -417,12 +417,11 @@ impl<'a> Dump<'a> { CanonicalFunction::Lower { .. } | CanonicalFunction::ResourceNew { .. } | CanonicalFunction::ResourceDrop { .. } + | CanonicalFunction::ResourceDropAsync { .. } | CanonicalFunction::ResourceRep { .. } | CanonicalFunction::ThreadSpawn { .. } - | CanonicalFunction::ThreadAvailableParallelism => { - ("core func", &mut i.core_funcs) - } - CanonicalFunction::TaskBackpressure + | CanonicalFunction::ThreadAvailableParallelism + | CanonicalFunction::BackpressureSet | CanonicalFunction::TaskReturn { .. } | CanonicalFunction::TaskWait { .. } | CanonicalFunction::TaskPoll { .. } diff --git a/tests/local/component-model-async/resources.wast b/tests/local/component-model-async/resources.wast new file mode 100644 index 0000000000..8a48ceb208 --- /dev/null +++ b/tests/local/component-model-async/resources.wast @@ -0,0 +1,4 @@ +(component + (type $t (resource (rep i32))) + (core func $f (canon resource.drop $t async)) +) diff --git a/tests/local/component-model-async/task-builtins.wast b/tests/local/component-model-async/task-builtins.wast index 68c702d2b0..f006e4e68f 100644 --- a/tests/local/component-model-async/task-builtins.wast +++ b/tests/local/component-model-async/task-builtins.wast @@ -1,22 +1,22 @@ -;; task.backpressure +;; backpressure.set (component (core module $m - (import "" "task.backpressure" (func $task-backpressure (param i32))) + (import "" "backpressure.set" (func $backpressure.set (param i32))) ) - (core func $task-backpressure (canon task.backpressure)) - (core instance $i (instantiate $m (with "" (instance (export "task.backpressure" (func $task-backpressure)))))) + (core func $backpressure.set (canon backpressure.set)) + (core instance $i (instantiate $m (with "" (instance (export "backpressure.set" (func $backpressure.set)))))) ) -;; task.backpressure; incorrect type +;; backpressure.set; incorrect type (assert_invalid (component (core module $m - (import "" "task.backpressure" (func $task-backpressure (param i32 i32))) + (import "" "backpressure.set" (func $backpressure.set (param i32 i32))) ) - (core func $task-backpressure (canon task.backpressure)) - (core instance $i (instantiate $m (with "" (instance (export "task.backpressure" (func $task-backpressure)))))) + (core func $backpressure.set (canon backpressure.set)) + (core instance $i (instantiate $m (with "" (instance (export "backpressure.set" (func $backpressure.set)))))) ) - "type mismatch for export `task.backpressure` of module instantiation argument ``" + "type mismatch for export `backpressure.set` of module instantiation argument ``" ) ;; task.return @@ -28,6 +28,37 @@ (core instance $i (instantiate $m (with "" (instance (export "task.return" (func $task-return)))))) ) +(assert_invalid + (component (core func $task-return (canon task.return (result u32) async))) + "cannot specify `async` option on `task.return`") + +(assert_invalid + (component + (core func $f (canon backpressure.set)) + (core func $task-return (canon task.return (result u32) (callback $f))) + ) + "cannot specify `callback` option on `task.return`") + +(assert_invalid + (component + (core func $f (canon backpressure.set)) + (core func $task-return (canon task.return (result u32) (post-return $f))) + ) + "cannot specify `post-return` option on `task.return`") + +(component + (core module $m + (memory (export "m") 1) + (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + (core func (canon task.return (result u32) string-encoding=utf8)) + (core func (canon task.return (result u32) string-encoding=utf16)) + (core func (canon task.return (result u32) string-encoding=latin1+utf16)) + (core func (canon task.return (result u32) (memory $i "m"))) + (core func (canon task.return (result u32) (realloc (func $i "r")))) +) + ;; task.wait (component (core module $libc (memory (export "memory") 1)) diff --git a/tests/local/missing-features/component-model/async.wast b/tests/local/missing-features/component-model/async.wast index 41ddf50221..f95ae5c0b9 100644 --- a/tests/local/missing-features/component-model/async.wast +++ b/tests/local/missing-features/component-model/async.wast @@ -28,16 +28,16 @@ "canonical option `async` requires the component model async feature" ) -;; task.backpressure +;; backpressure.set (assert_invalid (component (core module $m - (import "" "task.backpressure" (func $task-backpressure (param i32))) + (import "" "backpressure.set" (func $backpressure-set (param i32))) ) - (core func $task-backpressure (canon task.backpressure)) - (core instance $i (instantiate $m (with "" (instance (export "task.backpressure" (func $task-backpressure)))))) + (core func $backpressure.set (canon backpressure.set)) + (core instance $i (instantiate $m (with "" (instance (export "backpressure.set" (func $backpressure.set)))))) ) - "`task.backpressure` requires the component model async feature" + "`backpressure.set` requires the component model async feature" ) ;; task.return @@ -350,3 +350,10 @@ (component (type error-context)) "requires the component model async feature" ) +(assert_invalid + (component + (type $t (resource (rep i32))) + (core func $f (canon resource.drop $t async)) + ) + "requires the component model async feature" +) diff --git a/tests/snapshots/local/component-model-async/resources.wast.json b/tests/snapshots/local/component-model-async/resources.wast.json new file mode 100644 index 0000000000..5b91b01551 --- /dev/null +++ b/tests/snapshots/local/component-model-async/resources.wast.json @@ -0,0 +1,11 @@ +{ + "source_filename": "tests/local/component-model-async/resources.wast", + "commands": [ + { + "type": "module", + "line": 1, + "filename": "resources.0.wasm", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/component-model-async/resources.wast/0.print b/tests/snapshots/local/component-model-async/resources.wast/0.print new file mode 100644 index 0000000000..48485f2d07 --- /dev/null +++ b/tests/snapshots/local/component-model-async/resources.wast/0.print @@ -0,0 +1,4 @@ +(component + (type $t (;0;) (resource (rep i32))) + (core func $f (;0;) (canon resource.drop $t async)) +) diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast.json b/tests/snapshots/local/component-model-async/task-builtins.wast.json index 6001d1e348..daabb0fe82 100644 --- a/tests/snapshots/local/component-model-async/task-builtins.wast.json +++ b/tests/snapshots/local/component-model-async/task-builtins.wast.json @@ -12,7 +12,7 @@ "line": 12, "filename": "task-builtins.1.wasm", "module_type": "binary", - "text": "type mismatch for export `task.backpressure` of module instantiation argument ``" + "text": "type mismatch for export `backpressure.set` of module instantiation argument ``" }, { "type": "module", @@ -21,54 +21,81 @@ "module_type": "binary" }, { - "type": "module", + "type": "assert_invalid", "line": 32, "filename": "task-builtins.3.wasm", - "module_type": "binary" + "module_type": "binary", + "text": "cannot specify `async` option on `task.return`" }, { "type": "assert_invalid", - "line": 44, + "line": 36, "filename": "task-builtins.4.wasm", "module_type": "binary", + "text": "cannot specify `callback` option on `task.return`" + }, + { + "type": "assert_invalid", + "line": 43, + "filename": "task-builtins.5.wasm", + "module_type": "binary", + "text": "cannot specify `post-return` option on `task.return`" + }, + { + "type": "module", + "line": 49, + "filename": "task-builtins.6.wasm", + "module_type": "binary" + }, + { + "type": "module", + "line": 63, + "filename": "task-builtins.7.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 75, + "filename": "task-builtins.8.wasm", + "module_type": "binary", "text": "type mismatch for export `task.wait` of module instantiation argument ``" }, { "type": "module", - "line": 57, - "filename": "task-builtins.5.wasm", + "line": 88, + "filename": "task-builtins.9.wasm", "module_type": "binary" }, { "type": "assert_invalid", - "line": 69, - "filename": "task-builtins.6.wasm", + "line": 100, + "filename": "task-builtins.10.wasm", "module_type": "binary", "text": "type mismatch for export `task.poll` of module instantiation argument ``" }, { "type": "module", - "line": 82, - "filename": "task-builtins.7.wasm", + "line": 113, + "filename": "task-builtins.11.wasm", "module_type": "binary" }, { "type": "assert_invalid", - "line": 92, - "filename": "task-builtins.8.wasm", + "line": 123, + "filename": "task-builtins.12.wasm", "module_type": "binary", "text": "type mismatch for export `task.yield` of module instantiation argument ``" }, { "type": "module", - "line": 103, - "filename": "task-builtins.9.wasm", + "line": 134, + "filename": "task-builtins.13.wasm", "module_type": "binary" }, { "type": "assert_invalid", - "line": 113, - "filename": "task-builtins.10.wasm", + "line": 144, + "filename": "task-builtins.14.wasm", "module_type": "binary", "text": "type mismatch for export `subtask.drop` of module instantiation argument ``" } diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast/0.print b/tests/snapshots/local/component-model-async/task-builtins.wast/0.print index 20c01cd721..686f8faf09 100644 --- a/tests/snapshots/local/component-model-async/task-builtins.wast/0.print +++ b/tests/snapshots/local/component-model-async/task-builtins.wast/0.print @@ -1,11 +1,11 @@ (component (core module $m (;0;) (type (;0;) (func (param i32))) - (import "" "task.backpressure" (func $task-backpressure (;0;) (type 0))) + (import "" "backpressure.set" (func $backpressure.set (;0;) (type 0))) ) - (core func $task-backpressure (;0;) (canon task.backpressure)) + (core func $backpressure.set (;0;) (canon backpressure.set)) (core instance (;0;) - (export "task.backpressure" (func $task-backpressure)) + (export "backpressure.set" (func $backpressure.set)) ) (core instance $i (;1;) (instantiate $m (with "" (instance 0)) diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast/11.print b/tests/snapshots/local/component-model-async/task-builtins.wast/11.print new file mode 100644 index 0000000000..0851c2de88 --- /dev/null +++ b/tests/snapshots/local/component-model-async/task-builtins.wast/11.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func)) + (import "" "task.yield" (func $task-yield (;0;) (type 0))) + ) + (core func $task-yield (;0;) (canon task.yield async)) + (core instance (;0;) + (export "task.yield" (func $task-yield)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast/13.print b/tests/snapshots/local/component-model-async/task-builtins.wast/13.print new file mode 100644 index 0000000000..038cc25c37 --- /dev/null +++ b/tests/snapshots/local/component-model-async/task-builtins.wast/13.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32))) + (import "" "subtask.drop" (func $subtask-drop (;0;) (type 0))) + ) + (core func $subtask-drop (;0;) (canon subtask.drop)) + (core instance (;0;) + (export "subtask.drop" (func $subtask-drop)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast/3.print b/tests/snapshots/local/component-model-async/task-builtins.wast/3.print deleted file mode 100644 index 05c4076330..0000000000 --- a/tests/snapshots/local/component-model-async/task-builtins.wast/3.print +++ /dev/null @@ -1,20 +0,0 @@ -(component - (core module $libc (;0;) - (memory (;0;) 1) - (export "memory" (memory 0)) - ) - (core instance $libc (;0;) (instantiate $libc)) - (core module $m (;1;) - (type (;0;) (func (param i32) (result i32))) - (import "" "task.wait" (func $task-wait (;0;) (type 0))) - ) - (alias core export $libc "memory" (core memory (;0;))) - (core func $task-wait (;0;) (canon task.wait async (memory 0))) - (core instance (;1;) - (export "task.wait" (func $task-wait)) - ) - (core instance $i (;2;) (instantiate $m - (with "" (instance 1)) - ) - ) -) diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast/5.print b/tests/snapshots/local/component-model-async/task-builtins.wast/5.print deleted file mode 100644 index 05bfe3aa76..0000000000 --- a/tests/snapshots/local/component-model-async/task-builtins.wast/5.print +++ /dev/null @@ -1,20 +0,0 @@ -(component - (core module $libc (;0;) - (memory (;0;) 1) - (export "memory" (memory 0)) - ) - (core instance $libc (;0;) (instantiate $libc)) - (core module $m (;1;) - (type (;0;) (func (param i32) (result i32))) - (import "" "task.poll" (func $task-poll (;0;) (type 0))) - ) - (alias core export $libc "memory" (core memory (;0;))) - (core func $task-poll (;0;) (canon task.poll async (memory 0))) - (core instance (;1;) - (export "task.poll" (func $task-poll)) - ) - (core instance $i (;2;) (instantiate $m - (with "" (instance 1)) - ) - ) -) diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast/6.print b/tests/snapshots/local/component-model-async/task-builtins.wast/6.print new file mode 100644 index 0000000000..86207d78a2 --- /dev/null +++ b/tests/snapshots/local/component-model-async/task-builtins.wast/6.print @@ -0,0 +1,19 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (memory (;0;) 1) + (export "m" (memory 0)) + (export "r" (func 0)) + (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + ) + (core instance $i (;0;) (instantiate $m)) + (core func (;0;) (canon task.return (result u32) string-encoding=utf8)) + (core func (;1;) (canon task.return (result u32) string-encoding=utf16)) + (core func (;2;) (canon task.return (result u32) string-encoding=latin1+utf16)) + (alias core export $i "m" (core memory (;0;))) + (core func (;3;) (canon task.return (result u32) (memory 0))) + (alias core export $i "r" (core func (;4;))) + (core func (;5;) (canon task.return (result u32) (realloc 4))) +) diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast/7.print b/tests/snapshots/local/component-model-async/task-builtins.wast/7.print index 0851c2de88..05c4076330 100644 --- a/tests/snapshots/local/component-model-async/task-builtins.wast/7.print +++ b/tests/snapshots/local/component-model-async/task-builtins.wast/7.print @@ -1,14 +1,20 @@ (component - (core module $m (;0;) - (type (;0;) (func)) - (import "" "task.yield" (func $task-yield (;0;) (type 0))) + (core module $libc (;0;) + (memory (;0;) 1) + (export "memory" (memory 0)) ) - (core func $task-yield (;0;) (canon task.yield async)) - (core instance (;0;) - (export "task.yield" (func $task-yield)) + (core instance $libc (;0;) (instantiate $libc)) + (core module $m (;1;) + (type (;0;) (func (param i32) (result i32))) + (import "" "task.wait" (func $task-wait (;0;) (type 0))) ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) + (alias core export $libc "memory" (core memory (;0;))) + (core func $task-wait (;0;) (canon task.wait async (memory 0))) + (core instance (;1;) + (export "task.wait" (func $task-wait)) + ) + (core instance $i (;2;) (instantiate $m + (with "" (instance 1)) ) ) ) diff --git a/tests/snapshots/local/component-model-async/task-builtins.wast/9.print b/tests/snapshots/local/component-model-async/task-builtins.wast/9.print index 038cc25c37..05bfe3aa76 100644 --- a/tests/snapshots/local/component-model-async/task-builtins.wast/9.print +++ b/tests/snapshots/local/component-model-async/task-builtins.wast/9.print @@ -1,14 +1,20 @@ (component - (core module $m (;0;) - (type (;0;) (func (param i32))) - (import "" "subtask.drop" (func $subtask-drop (;0;) (type 0))) + (core module $libc (;0;) + (memory (;0;) 1) + (export "memory" (memory 0)) ) - (core func $subtask-drop (;0;) (canon subtask.drop)) - (core instance (;0;) - (export "subtask.drop" (func $subtask-drop)) + (core instance $libc (;0;) (instantiate $libc)) + (core module $m (;1;) + (type (;0;) (func (param i32) (result i32))) + (import "" "task.poll" (func $task-poll (;0;) (type 0))) ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) + (alias core export $libc "memory" (core memory (;0;))) + (core func $task-poll (;0;) (canon task.poll async (memory 0))) + (core instance (;1;) + (export "task.poll" (func $task-poll)) + ) + (core instance $i (;2;) (instantiate $m + (with "" (instance 1)) ) ) ) diff --git a/tests/snapshots/local/missing-features/component-model/async.wast.json b/tests/snapshots/local/missing-features/component-model/async.wast.json index c26c0b997a..97490cf07c 100644 --- a/tests/snapshots/local/missing-features/component-model/async.wast.json +++ b/tests/snapshots/local/missing-features/component-model/async.wast.json @@ -20,7 +20,7 @@ "line": 33, "filename": "async.2.wasm", "module_type": "binary", - "text": "`task.backpressure` requires the component model async feature" + "text": "`backpressure.set` requires the component model async feature" }, { "type": "assert_invalid", @@ -196,6 +196,13 @@ "filename": "async.27.wasm", "module_type": "binary", "text": "requires the component model async feature" + }, + { + "type": "assert_invalid", + "line": 354, + "filename": "async.28.wasm", + "module_type": "binary", + "text": "requires the component model async feature" } ] } \ No newline at end of file From 0a76357d9c9d06a1550f0209f13976163ba71c30 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 24 Feb 2025 10:38:21 -0800 Subject: [PATCH 2/2] Review comments --- crates/wit-component/src/encoding.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 8da856d378..82a9ad15fc 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -1615,7 +1615,7 @@ impl<'a> EncodingState<'a> { ) } Import::ExportedTaskReturn(key, interface, func, result) => { - let (options, _sig) = task_return_options_and_type(resolve, *result, false); + let (options, _sig) = task_return_options_and_type(resolve, *result); if options.is_empty() { let mut encoder = self.root_export_type_encoder(*interface); @@ -2045,13 +2045,15 @@ enum ShimKind<'a> { /// A shim used for the `task.poll` built-in function, which must refer to /// the core module instance's memory to which results will be written. TaskPoll { async_: bool }, - /// TODO + /// Shim for `task.return` to handle a reference to a `memory` which may TaskReturn { - /// TODO + /// The interface (optional) that owns `func` below. If `None` then it's + /// a world export. interface: Option, - /// TODO + /// The function that this `task.return` is returning for, owned + /// within `interface` above. func: &'a str, - /// TODO + /// The WIT type that `func` returns. result: Option, /// Which instance to pull the `realloc` function from, if necessary. for_module: CustomModule<'a>, @@ -2142,7 +2144,7 @@ impl<'a> Shims<'a> { // for it, otherwise skip the shim and let it get materialized // naturally later. Import::ExportedTaskReturn(key, interface, func, ty) => { - let (options, sig) = task_return_options_and_type(resolve, *ty, false); + let (options, sig) = task_return_options_and_type(resolve, *ty); if options.is_empty() { continue; } @@ -2506,7 +2508,6 @@ impl<'a> Shims<'a> { fn task_return_options_and_type( resolve: &Resolve, ty: Option, - async_: bool, ) -> (RequiredOptions, WasmSignature) { let func_tmp = Function { name: String::new(), @@ -2519,11 +2520,7 @@ fn task_return_options_and_type( docs: Default::default(), stability: Stability::Unknown, }; - let abi = if async_ { - AbiVariant::GuestImportAsync - } else { - AbiVariant::GuestImport - }; + let abi = AbiVariant::GuestImport; let options = RequiredOptions::for_import(resolve, &func_tmp, abi); let sig = resolve.wasm_signature(abi, &func_tmp); (options, sig)