Repository: bytecodealliance/wasm-tools
Pull request #2065 (2025-02-22 00:38:26)

 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
https://github.com/WebAssembly/component-model/issues/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.

alexcrichton: I'll note that this is based on https://github.com/bytecodealliance/wasm-tools/pull/2064, so only the last commit is exclusive to the PR (at this time)

Patch:
diff --git a/crates/wasm-encoder/src/component/builder.rs b/crates/wasm-encoder/src/component/builder.rs
index 13c0eec0..567d1db7 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<impl Into<ComponentValType>>) -> u32 {
-        self.canonical_functions().task_return(ty);
+    pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> u32
+    where
+        O: IntoIterator<Item = CanonicalOption>,
+        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 7c5a253e..7f36a671 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<Item = CanonicalOption>,
         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<Item = CanonicalOption>,
         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<impl Into<ComponentValType>>) -> &mut Self {
+    pub fn task_return<O>(&mut self, ty: Option<ComponentValType>, options: O) -> &mut Self
+    where
+        O: IntoIterator<Item = CanonicalOption>,
+        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<O>(&mut self, options: O) -> &mut Self
+    where
+        O: IntoIterator<Item = CanonicalOption>,
+        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 bb09ff43..e32c75c4 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<u8>, ty: Option<ComponentValType>) {
+    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<u8>);
diff --git a/crates/wasm-encoder/src/reencode/component.rs b/crates/wasm-encoder/src/reencode/component.rs
index 4401cf9d..3eb436dd 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 bd3c06b4..b907bf66 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<ComponentValType>,
+        /// 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<CanonicalFunction> {
         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::<Result<_>>()?;
-                    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::<Result<_>>()?,
+                    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::<Result<_>>()?,
+                options: read_opts(reader)?,
             },
             0x10 => CanonicalFunction::StreamWrite {
                 ty: reader.read()?,
-                options: reader
-                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
-                    .collect::<Result<_>>()?,
+                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::<Result<_>>()?,
+                options: read_opts(reader)?,
             },
             0x17 => CanonicalFunction::FutureWrite {
                 ty: reader.read()?,
-                options: reader
-                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
-                    .collect::<Result<_>>()?,
+                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::<Result<_>>()?,
+                options: read_opts(reader)?,
             },
             0x1d => CanonicalFunction::ErrorContextDebugMessage {
-                options: reader
-                    .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
-                    .collect::<Result<_>>()?,
+                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<Box<[CanonicalOption]>> {
+    reader
+        .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?
+        .collect::<Result<_>>()
+}
+
 impl<'a> FromReader<'a> for CanonicalOption {
     fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
         Ok(match reader.read_u8()? {
diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs
index a9ce0eb2..0bdc1df9 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::<Result<_>>()?;
-                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<ComponentValType>,
 }
 
+pub(crate) fn read_resultlist(reader: &mut BinaryReader<'_>) -> Result<Option<ComponentValType>> {
+    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 11b30088..6f1c3358 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 dfee2584..461878d9 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<CanonicalOption>,
+        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<CanonicalOption>,
+        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<crate::ComponentValType>,
+        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<_>>()?,
             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<CanonicalOption>,
+        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<CanonicalOption>,
+        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<CanonicalOption>,
+        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 f76ca674..67e1addb 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 64378bd8..19861fa2 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 2fc95b97..741d7735 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 f2c3b3ca..72db0ec2 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 ee3e4dec..be025d0a 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::<kw::thread_available_parallelism>()? {
                 Ok(CoreFuncKind::ThreadAvailableParallelism(parser.parse()?))
-            } else if l.peek::<kw::task_backpressure>()? {
-                parser.parse::<kw::task_backpressure>()?;
-                Ok(CoreFuncKind::TaskBackpressure)
+            } else if l.peek::<kw::backpressure_set>()? {
+                parser.parse::<kw::backpressure_set>()?;
+                Ok(CoreFuncKind::BackpressureSet)
             } else if l.peek::<kw::task_return>()? {
                 Ok(CoreFuncKind::TaskReturn(parser.parse()?))
             } else if l.peek::<kw::task_wait>()? {
@@ -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::<Option<kw::r#async>>()?.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<ComponentValType<'a>>,
+    /// The canonical options for storing values.
+    pub opts: Vec<CanonOpt<'a>>,
 }
 
 impl<'a> Parse<'a> for CanonTaskReturn<'a> {
     fn parse(parser: Parser<'a>) -> Result<Self> {
         parser.parse::<kw::task_return>()?;
 
-        let result = if parser.peek2::<kw::result>()? {
-            Some(parser.parens(|p| {
-                p.parse::<kw::result>()?.0;
-                p.parse()
-            })?)
-        } else {
-            None
-        };
-
-        Ok(Self { result })
+        Ok(Self {
+            result: if parser.peek2::<kw::result>()? {
+                Some(parser.parens(|p| {
+                    p.parse::<kw::result>()?.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 aa1187fc..8ca18cdc 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 0cd276e8..e8bb5723 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 628befe7..82a9ad15 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);
+                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,21 @@ 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 },
+    /// Shim for `task.return` to handle a reference to a `memory` which may
+    TaskReturn {
+        /// The interface (optional) that owns `func` below. If `None` then it's
+        /// a world export.
+        interface: Option<InterfaceId>,
+        /// The function that this `task.return` is returning for, owned
+        /// within `interface` above.
+        func: &'a str,
+        /// The WIT type that `func` returns.
+        result: Option<Type>,
+        /// 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 +2126,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 +2140,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);
+                    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 +2505,27 @@ impl<'a> Shims<'a> {
     }
 }
 
+fn task_return_options_and_type(
+    resolve: &Resolve,
+    ty: Option<Type>,
+) -> (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 = 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 +2828,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 9dbf5aa5..d436ac83 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<InterfaceId>, String, Option<Type>),
+    ExportedTaskReturn(WorldKey, Option<InterfaceId>, String, Option<Type>),
 
-    /// 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/src/bin/wasm-tools/dump.rs b/src/bin/wasm-tools/dump.rs
index 8ea31b6c..e133a0fe 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 { .. }


Test patch:
diff --git a/crates/wit-component/tests/components/async-builtins/component.wat b/crates/wit-component/tests/components/async-builtins/component.wat
index b6b937a2..88fd64fd 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 d689ad0e..29ffb5eb 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/tests/local/component-model-async/resources.wast b/tests/local/component-model-async/resources.wast
new file mode 100644
index 00000000..8a48ceb2
--- /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 68c702d2..f006e4e6 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 41ddf502..f95ae5c0 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 00000000..5b91b015
--- /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 00000000..48485f2d
--- /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 6001d1e3..daabb0fe 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 20c01cd7..686f8faf 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 00000000..0851c2de
--- /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 00000000..038cc25c
--- /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 05c40763..00000000
--- 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 05bfe3aa..00000000
--- 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 00000000..86207d78
--- /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 0851c2de..05c40763 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 038cc25c..05bfe3aa 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 c26c0b99..97490cf0 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