Skip to content

Commit 42b2673

Browse files
committed
update task.return to match spec
As of WebAssembly/component-model#431, `task.return` takes component-level result types rather than a core function type representing the flattening of those types. This updates `wasm-tools` to match. Signed-off-by: Joel Dice <[email protected]>
1 parent 866672f commit 42b2673

File tree

18 files changed

+200
-117
lines changed

18 files changed

+200
-117
lines changed

crates/wasm-encoder/src/component/builder.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,20 @@ impl ComponentBuilder {
391391
inc(&mut self.core_funcs)
392392
}
393393

394-
/// Declares a new `task.return` intrinsic.
395-
pub fn task_return(&mut self, ty: u32) -> u32 {
396-
self.canonical_functions().task_return(ty);
394+
/// Declares a new `task.return` intrinsic using named results.
395+
pub fn task_return_named<'a, R, T>(&mut self, results: R) -> u32
396+
where
397+
R: IntoIterator<Item = (&'a str, T)>,
398+
R::IntoIter: ExactSizeIterator,
399+
T: Into<ComponentValType>,
400+
{
401+
self.canonical_functions().task_return_named(results);
402+
inc(&mut self.core_funcs)
403+
}
404+
405+
/// Declares a new `task.return` intrinsic using an anonymous result.
406+
pub fn task_return_anon(&mut self, ty: impl Into<ComponentValType>) -> u32 {
407+
self.canonical_functions().task_return_anon(ty);
397408
inc(&mut self.core_funcs)
398409
}
399410

crates/wasm-encoder/src/component/canonicals.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{encode_section, ComponentSection, ComponentSectionId, Encode};
1+
use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentValType, Encode};
22
use alloc::vec::Vec;
33

44
/// Represents options for canonical function definitions.
@@ -188,9 +188,39 @@ impl CanonicalFunctionSection {
188188
/// Defines a function which returns a result to the caller of a lifted
189189
/// export function. This allows the callee to continue executing after
190190
/// returning a result.
191-
pub fn task_return(&mut self, ty: u32) -> &mut Self {
191+
///
192+
/// This version accepts a list of named result types. See
193+
/// [Self::task_return_anon] for a version that accepts a single, anonymous result
194+
/// type.
195+
pub fn task_return_named<'a, R, T>(&mut self, results: R) -> &mut Self
196+
where
197+
R: IntoIterator<Item = (&'a str, T)>,
198+
R::IntoIter: ExactSizeIterator,
199+
T: Into<ComponentValType>,
200+
{
192201
self.bytes.push(0x09);
193-
ty.encode(&mut self.bytes);
202+
self.bytes.push(0x01);
203+
let results = results.into_iter();
204+
results.len().encode(&mut self.bytes);
205+
for (name, ty) in results {
206+
name.encode(&mut self.bytes);
207+
ty.into().encode(&mut self.bytes);
208+
}
209+
self.num_added += 1;
210+
self
211+
}
212+
213+
/// Defines a function which returns a result to the caller of a lifted
214+
/// export function. This allows the callee to continue executing after
215+
/// returning a result.
216+
///
217+
/// This version accepts a single, anonymous result type. See
218+
/// [Self::task_return_named] for a version that accepts a list of named result
219+
/// types.
220+
pub fn task_return_anon(&mut self, ty: impl Into<ComponentValType>) -> &mut Self {
221+
self.bytes.push(0x09);
222+
self.bytes.push(0x00);
223+
ty.into().encode(&mut self.bytes);
194224
self.num_added += 1;
195225
self
196226
}

crates/wasm-encoder/src/reencode/component.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,17 @@ pub mod component_utils {
970970
wasmparser::CanonicalFunction::TaskBackpressure => {
971971
section.task_backpressure();
972972
}
973-
wasmparser::CanonicalFunction::TaskReturn { type_index } => {
974-
section.task_return(reencoder.type_index(type_index));
973+
wasmparser::CanonicalFunction::TaskReturn { results } => {
974+
match results {
975+
wasmparser::ComponentFuncResult::Unnamed(ty) => {
976+
section.task_return_anon(reencoder.component_val_type(ty))
977+
}
978+
wasmparser::ComponentFuncResult::Named(results) => section.task_return_named(
979+
results
980+
.iter()
981+
.map(|(name, ty)| (*name, reencoder.component_val_type(*ty))),
982+
),
983+
};
975984
}
976985
wasmparser::CanonicalFunction::TaskWait { async_, memory } => {
977986
section.task_wait(async_, reencoder.memory_index(memory));

crates/wasmparser/src/readers/component/canonicals.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::limits::MAX_WASM_CANONICAL_OPTIONS;
22
use crate::prelude::*;
3-
use crate::{BinaryReader, FromReader, Result, SectionLimited};
3+
use crate::{BinaryReader, ComponentFuncResult, FromReader, Result, SectionLimited};
44

55
/// Represents options for component functions.
66
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -32,7 +32,7 @@ pub enum CanonicalOption {
3232

3333
/// Represents a canonical function in a WebAssembly component.
3434
#[derive(Debug, Clone, Eq, PartialEq)]
35-
pub enum CanonicalFunction {
35+
pub enum CanonicalFunction<'a> {
3636
/// The function lifts a core WebAssembly function to the canonical ABI.
3737
Lift {
3838
/// The index of the core WebAssembly function to lift.
@@ -80,10 +80,8 @@ pub enum CanonicalFunction {
8080
/// function. This allows the callee to continue executing after returning
8181
/// a result.
8282
TaskReturn {
83-
/// Core function type whose parameters represent the flattened
84-
/// representation of the component-level results to be returned by the
85-
/// currently executing task.
86-
type_index: u32,
83+
/// The result type(s).
84+
results: ComponentFuncResult<'a>,
8785
},
8886
/// A function which waits for at least one outstanding async
8987
/// task/stream/future to make progress, returning the first such event.
@@ -231,10 +229,10 @@ pub enum CanonicalFunction {
231229
}
232230

233231
/// A reader for the canonical section of a WebAssembly component.
234-
pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>;
232+
pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction<'a>>;
235233

236-
impl<'a> FromReader<'a> for CanonicalFunction {
237-
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> {
234+
impl<'a> FromReader<'a> for CanonicalFunction<'a> {
235+
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction<'a>> {
238236
Ok(match reader.read_u8()? {
239237
0x00 => match reader.read_u8()? {
240238
0x00 => {
@@ -275,7 +273,7 @@ impl<'a> FromReader<'a> for CanonicalFunction {
275273
0x06 => CanonicalFunction::ThreadHwConcurrency,
276274
0x08 => CanonicalFunction::TaskBackpressure,
277275
0x09 => CanonicalFunction::TaskReturn {
278-
type_index: reader.read()?,
276+
results: reader.read()?,
279277
},
280278
0x0a => CanonicalFunction::TaskWait {
281279
async_: reader.read()?,

crates/wasmparser/src/validator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,8 +1313,8 @@ impl Validator {
13131313
crate::CanonicalFunction::TaskBackpressure => {
13141314
current.task_backpressure(types, offset, features)
13151315
}
1316-
crate::CanonicalFunction::TaskReturn { type_index } => {
1317-
current.task_return(type_index, types, offset, features)
1316+
crate::CanonicalFunction::TaskReturn { results } => {
1317+
current.task_return(&results, types, offset, features)
13181318
}
13191319
crate::CanonicalFunction::TaskWait { async_, memory } => {
13201320
current.task_wait(async_, memory, types, offset, features)

crates/wasmparser/src/validator/component.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ use crate::prelude::*;
1919
use crate::validator::names::{ComponentName, ComponentNameKind, KebabStr, KebabString};
2020
use crate::{
2121
BinaryReaderError, CanonicalOption, ComponentExportName, ComponentExternalKind,
22-
ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType, CompositeType, ExternalKind,
23-
FuncType, GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, Result, SubType,
24-
TableType, TypeBounds, ValType, WasmFeatures,
22+
ComponentFuncResult, ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType,
23+
ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType,
24+
Result, SubType, TableType, TypeBounds, ValType, WasmFeatures,
2525
};
2626
use core::mem;
2727

@@ -1102,7 +1102,7 @@ impl ComponentState {
11021102

11031103
pub fn task_return(
11041104
&mut self,
1105-
type_index: u32,
1105+
result: &ComponentFuncResult,
11061106
types: &mut TypeAlloc,
11071107
offset: usize,
11081108
features: &WasmFeatures,
@@ -1114,20 +1114,31 @@ impl ComponentState {
11141114
)
11151115
}
11161116

1117-
let id = self.type_id_at(type_index, offset)?;
1118-
let Some(SubType {
1119-
composite_type:
1120-
CompositeType {
1121-
inner: CompositeInnerType::Func(_),
1122-
..
1123-
},
1124-
..
1125-
}) = types.get(id)
1126-
else {
1127-
bail!(offset, "invalid `task.return` type index");
1128-
};
1117+
let info = ComponentFuncType {
1118+
info: TypeInfo::new(),
1119+
params: result
1120+
.iter()
1121+
.map(|(name, ty)| {
1122+
let ty = match ty {
1123+
crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty),
1124+
crate::ComponentValType::Type(index) => {
1125+
ComponentValType::Type(self.defined_type_at(*index, offset)?)
1126+
}
1127+
};
11291128

1130-
self.core_funcs.push(id);
1129+
let Some(name) = KebabString::new(name.unwrap_or("v")) else {
1130+
bail!(offset, "non-kebab name found in `task.return` result list")
1131+
};
1132+
1133+
Ok((name, ty))
1134+
})
1135+
.collect::<Result<_>>()?,
1136+
results: Box::new([]),
1137+
}
1138+
.lower(types, Abi::LiftSync);
1139+
1140+
self.core_funcs
1141+
.push(types.intern_func_type(FuncType::new(info.params.iter(), []), offset));
11311142
Ok(())
11321143
}
11331144

crates/wasmprinter/src/component.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -914,9 +914,19 @@ impl Printer<'_, '_> {
914914
CanonicalFunction::TaskBackpressure => {
915915
self.print_intrinsic(state, "canon task.backpressure", &|_, _| Ok(()))?;
916916
}
917-
CanonicalFunction::TaskReturn { type_index } => {
918-
self.print_intrinsic(state, "canon task.return ", &|me, state| {
919-
me.print_idx(&state.component.type_names, type_index)
917+
CanonicalFunction::TaskReturn { results } => {
918+
self.print_intrinsic(state, "canon task.return", &|me, state| {
919+
for (name, ty) in results.iter() {
920+
me.result.write_str(" ")?;
921+
me.start_group("result ")?;
922+
if let Some(name) = name {
923+
me.print_str(name)?;
924+
me.result.write_str(" ")?;
925+
}
926+
me.print_component_val_type(state, ty)?;
927+
me.end_group()?;
928+
}
929+
Ok(())
920930
})?;
921931
}
922932
CanonicalFunction::TaskWait { async_, memory } => {

crates/wast/src/component/binary.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,30 @@ impl<'a> Encoder<'a> {
363363
}
364364
CanonicalFuncKind::TaskReturn(info) => {
365365
self.core_func_names.push(name);
366-
self.funcs.task_return(info.ty.into());
366+
match &info.results[..] {
367+
[ComponentFunctionResult { name: None, ty }] => {
368+
self.funcs.task_return_anon(ty);
369+
}
370+
results => {
371+
// Note that we synthesize names for any unnamed results
372+
// we encounter.
373+
let results = results
374+
.iter()
375+
.enumerate()
376+
.map(|(index, result)| {
377+
(
378+
result
379+
.name
380+
.map(|s| s.to_string())
381+
.unwrap_or_else(|| format!("v{index}")),
382+
&result.ty,
383+
)
384+
})
385+
.collect::<Vec<_>>();
386+
self.funcs
387+
.task_return_named(results.iter().map(|(n, v)| (n.as_str(), *v)));
388+
}
389+
}
367390
}
368391
CanonicalFuncKind::TaskWait(info) => {
369392
self.core_func_names.push(name);

crates/wast/src/component/func.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -521,16 +521,22 @@ impl<'a> Parse<'a> for CanonThreadHwConcurrency {
521521
/// Information relating to the `task.return` intrinsic.
522522
#[derive(Debug)]
523523
pub struct CanonTaskReturn<'a> {
524-
/// The core function type representing the signature of this intrinsic.
525-
pub ty: Index<'a>,
524+
/// The types (and optionally, names) of the results which may be returned
525+
/// with this intrinsic.
526+
pub results: Box<[ComponentFunctionResult<'a>]>,
526527
}
527528

528529
impl<'a> Parse<'a> for CanonTaskReturn<'a> {
529530
fn parse(parser: Parser<'a>) -> Result<Self> {
530531
parser.parse::<kw::task_return>()?;
531532

533+
let mut results: Vec<ComponentFunctionResult> = Vec::new();
534+
while parser.peek2::<kw::result>()? {
535+
results.push(parser.parens(|p| p.parse())?);
536+
}
537+
532538
Ok(Self {
533-
ty: parser.parse()?,
539+
results: results.into(),
534540
})
535541
}
536542
}

crates/wast/src/component/resolve.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,9 @@ impl<'a> Resolver<'a> {
392392
| CanonicalFuncKind::SubtaskDrop
393393
| CanonicalFuncKind::ErrorContextDrop => {}
394394
CanonicalFuncKind::TaskReturn(info) => {
395-
self.resolve_ns(&mut info.ty, Ns::CoreType)?;
395+
for result in info.results.iter_mut() {
396+
self.component_val_type(&mut result.ty)?;
397+
}
396398
}
397399
CanonicalFuncKind::TaskWait(info) => {
398400
self.core_item_ref(&mut info.memory)?;

0 commit comments

Comments
 (0)