diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 15d82b23f8..330c0f66e6 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -116,6 +116,32 @@ fn to_val_type(ty: &WasmType) -> ValType { } } +fn import_func_name(f: &Function) -> String { + match f.kind { + FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => { + format!("import-func-{}", f.item_name()) + } + + // transform `[method]foo.bar` into `import-method-foo-bar` to + // have it be a valid kebab-name which can't conflict with + // anything else. + // + // There's probably a better and more "formal" way to do this + // but quick-and-dirty string manipulation should work well + // enough for now hopefully. + FunctionKind::Method(_) + | FunctionKind::AsyncMethod(_) + | FunctionKind::Static(_) + | FunctionKind::AsyncStatic(_) + | FunctionKind::Constructor(_) => { + format!( + "import-{}", + f.name.replace('[', "").replace([']', '.', ' '], "-") + ) + } + } +} + bitflags::bitflags! { /// Options in the `canon lower` or `canon lift` required for a particular /// function. @@ -394,6 +420,10 @@ pub struct EncodingState<'a> { /// Metadata about the world inferred from the input to `ComponentEncoder`. info: &'a ComponentWorld<'a>, + + /// Maps from original export name to task initialization wrapper function index. + /// Used to wrap exports with __wasm_init_(async_)task calls. + export_task_initialization_wrappers: HashMap, } impl<'a> EncodingState<'a> { @@ -600,6 +630,10 @@ impl<'a> EncodingState<'a> { // at the end. self.instantiate_main_module(&shims)?; + // Create any wrappers needed for initializing tasks if task initialization + // exports are present in the main module. + self.create_export_task_initialization_wrappers()?; + // Separate the adapters according which should be instantiated before // and after indirect lowerings are encoded. let (before, after) = self @@ -688,7 +722,9 @@ impl<'a> EncodingState<'a> { | Export::GeneralPurposeImportRealloc | Export::Initialize | Export::ReallocForAdapter - | Export::IndirectFunctionTable => continue, + | Export::IndirectFunctionTable + | Export::WasmInitTask + | Export::WasmInitAsyncTask => continue, } } @@ -1014,32 +1050,6 @@ impl<'a> EncodingState<'a> { name } } - - fn import_func_name(f: &Function) -> String { - match f.kind { - FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => { - format!("import-func-{}", f.item_name()) - } - - // transform `[method]foo.bar` into `import-method-foo-bar` to - // have it be a valid kebab-name which can't conflict with - // anything else. - // - // There's probably a better and more "formal" way to do this - // but quick-and-dirty string manipulation should work well - // enough for now hopefully. - FunctionKind::Method(_) - | FunctionKind::AsyncMethod(_) - | FunctionKind::Static(_) - | FunctionKind::AsyncStatic(_) - | FunctionKind::Constructor(_) => { - format!( - "import-{}", - f.name.replace('[', "").replace([']', '.', ' '], "-") - ) - } - } - } } fn encode_lift( @@ -1053,8 +1063,14 @@ impl<'a> EncodingState<'a> { let resolve = &self.info.encoder.metadata.resolve; let metadata = self.info.module_metadata_for(module); let instance_index = self.instance_for(module); + // If we generated an init task wrapper for this export, use that, + // otherwise alias the original export. let core_func_index = - self.core_alias_export(Some(core_name), instance_index, core_name, ExportKind::Func); + if let Some(&wrapper_idx) = self.export_task_initialization_wrappers.get(core_name) { + wrapper_idx + } else { + self.core_alias_export(Some(core_name), instance_index, core_name, ExportKind::Func) + }; let exports = self.info.exports_for(module); let options = RequiredOptions::for_export( @@ -2189,6 +2205,199 @@ impl<'a> EncodingState<'a> { .core_alias_export(debug_name, instance, name, kind) }) } + + /// Modules may define `__wasm_init_(async_)task` functions that must be called + /// at the start of every exported function to set up the stack pointer and + /// thread-local storage. To achieve this, we create a wrapper module called + /// `task-init-wrappers` that imports the original exports and the + /// task initialization functions, and defines wrapper functions that call + /// the relevant task initialization function before delegating to the original export. + /// We then instantiate this wrapper module and use its exports as the final + /// exports of the component. If we don't find a `__wasm_init_task` export, + /// we elide the wrapper module entirely. + fn create_export_task_initialization_wrappers(&mut self) -> Result<()> { + let instance_index = self.instance_index.unwrap(); + let resolve = &self.info.encoder.metadata.resolve; + let world = &resolve.worlds[self.info.encoder.metadata.world]; + let exports = self.info.exports_for(CustomModule::Main); + + let wasm_init_task_export = exports.wasm_init_task(); + let wasm_init_async_task_export = exports.wasm_init_async_task(); + if wasm_init_task_export.is_none() || wasm_init_async_task_export.is_none() { + // __wasm_init_(async_)task was not exported by the main module, + // so no wrappers are needed. + return Ok(()); + } + let wasm_init_task = wasm_init_task_export.unwrap(); + let wasm_init_async_task = wasm_init_async_task_export.unwrap(); + + // Collect the exports that we will need to wrap, alongside information + // that we'll need to build the wrappers. + let funcs_to_wrap: Vec<_> = exports + .iter() + .flat_map(|(core_name, export)| match export { + Export::WorldFunc(key, _, abi) => match &world.exports[key] { + WorldItem::Function(f) => Some((core_name, f, abi)), + _ => None, + }, + Export::InterfaceFunc(_, id, func_name, abi) => { + let func = &resolve.interfaces[*id].functions[func_name.as_str()]; + Some((core_name, func, abi)) + } + _ => None, + }) + .collect(); + + if funcs_to_wrap.is_empty() { + // No exports, so no wrappers are needed. + return Ok(()); + } + + // Now we build the wrapper module + let mut types = TypeSection::new(); + let mut imports = ImportSection::new(); + let mut functions = FunctionSection::new(); + let mut exports_section = ExportSection::new(); + let mut code = CodeSection::new(); + + // Type for __wasm_init_(async_)task: () -> () + types.ty().function([], []); + let wasm_init_task_type_idx = 0; + + // Import __wasm_init_task and __wasm_init_async_task into the wrapper module + imports.import( + "", + wasm_init_task, + EntityType::Function(wasm_init_task_type_idx), + ); + imports.import( + "", + wasm_init_async_task, + EntityType::Function(wasm_init_task_type_idx), + ); + let wasm_init_task_func_idx = 0u32; + let wasm_init_async_task_func_idx = 1u32; + + let mut type_indices = HashMap::new(); + let mut next_type_idx = 1u32; + let mut next_func_idx = 2u32; + + // First pass: create all types and import all original functions + struct FuncInfo<'a> { + name: &'a str, + type_idx: u32, + orig_func_idx: u32, + is_async: bool, + n_params: usize, + } + let mut func_info = Vec::new(); + for &(name, func, abi) in funcs_to_wrap.iter() { + let sig = resolve.wasm_signature(*abi, func); + let type_idx = *type_indices.entry(sig.clone()).or_insert_with(|| { + let idx = next_type_idx; + types.ty().function( + sig.params.iter().map(to_val_type), + sig.results.iter().map(to_val_type), + ); + next_type_idx += 1; + idx + }); + + imports.import("", &import_func_name(func), EntityType::Function(type_idx)); + let orig_func_idx = next_func_idx; + next_func_idx += 1; + + func_info.push(FuncInfo { + name, + type_idx, + orig_func_idx, + is_async: abi.is_async(), + n_params: sig.params.len(), + }); + } + + // Second pass: define wrapper functions + for info in func_info.iter() { + let wrapper_func_idx = next_func_idx; + functions.function(info.type_idx); + + let mut func = wasm_encoder::Function::new([]); + if info.is_async { + func.instruction(&Instruction::Call(wasm_init_async_task_func_idx)); + } else { + func.instruction(&Instruction::Call(wasm_init_task_func_idx)); + } + for i in 0..info.n_params as u32 { + func.instruction(&Instruction::LocalGet(i)); + } + func.instruction(&Instruction::Call(info.orig_func_idx)); + func.instruction(&Instruction::End); + code.function(&func); + + exports_section.export(info.name, ExportKind::Func, wrapper_func_idx); + next_func_idx += 1; + } + + let mut wrapper_module = Module::new(); + wrapper_module.section(&types); + wrapper_module.section(&imports); + wrapper_module.section(&functions); + wrapper_module.section(&exports_section); + wrapper_module.section(&code); + + let wrapper_module_idx = self + .component + .core_module(Some("init-task-wrappers"), &wrapper_module); + + // Prepare imports for instantiating the wrapper module + let mut wrapper_imports = Vec::new(); + let init_idx = self.core_alias_export( + Some(wasm_init_task), + instance_index, + wasm_init_task, + ExportKind::Func, + ); + let init_async_idx = self.core_alias_export( + Some(wasm_init_async_task), + instance_index, + wasm_init_async_task, + ExportKind::Func, + ); + wrapper_imports.push((wasm_init_task.into(), ExportKind::Func, init_idx)); + wrapper_imports.push(( + wasm_init_async_task.into(), + ExportKind::Func, + init_async_idx, + )); + + // Import all original exports to be wrapped + for (name, func, _) in &funcs_to_wrap { + let orig_idx = + self.core_alias_export(Some(name), instance_index, name, ExportKind::Func); + wrapper_imports.push((import_func_name(func), ExportKind::Func, orig_idx)); + } + + let wrapper_args_idx = self.component.core_instantiate_exports( + Some("init-task-wrappers-args"), + wrapper_imports.iter().map(|(n, k, i)| (n.as_str(), *k, *i)), + ); + + let wrapper_instance = self.component.core_instantiate( + Some("init-task-wrappers-instance"), + wrapper_module_idx, + [("", ModuleArg::Instance(wrapper_args_idx))], + ); + + // Map original names to wrapper indices + for (name, _, _) in funcs_to_wrap { + let wrapper_idx = + self.core_alias_export(Some(&name), wrapper_instance, &name, ExportKind::Func); + self.export_task_initialization_wrappers + .insert(name.into(), wrapper_idx); + } + + Ok(()) + } } /// A list of "shims" which start out during the component instantiation process @@ -3123,6 +3332,7 @@ impl ComponentEncoder { exported_instances: Default::default(), aliased_core_items: Default::default(), info: &world, + export_task_initialization_wrappers: HashMap::new(), }; state.encode_imports(&self.import_name_map)?; state.encode_core_modules(); diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs index 88d7f80833..54ee808b99 100644 --- a/crates/wit-component/src/validation.rs +++ b/crates/wit-component/src/validation.rs @@ -1111,6 +1111,12 @@ pub enum Export { /// __indirect_function_table, used for `thread.new-indirect` IndirectFunctionTable, + + /// __wasm_init_task, used for initializing export tasks + WasmInitTask, + + /// __wasm_init_async_task, used for initializing export tasks for async-lifted exports + WasmInitAsyncTask, } impl ExportMap { @@ -1209,6 +1215,14 @@ impl ExportMap { let expected = FuncType::new([], []); validate_func_sig(name, &expected, ty)?; return Ok(Some(Export::Initialize)); + } else if Some(name) == names.export_wasm_init_task() { + let expected = FuncType::new([], []); + validate_func_sig(name, &expected, ty)?; + return Ok(Some(Export::WasmInitTask)); + } else if Some(name) == names.export_wasm_init_async_task() { + let expected = FuncType::new([], []); + validate_func_sig(name, &expected, ty)?; + return Ok(Some(Export::WasmInitAsyncTask)); } let full_name = name; @@ -1372,6 +1386,16 @@ impl ExportMap { self.find(|t| matches!(t, Export::IndirectFunctionTable)) } + /// Returns the `__wasm_init_task` function, if exported, for this module. + pub fn wasm_init_task(&self) -> Option<&str> { + self.find(|t| matches!(t, Export::WasmInitTask)) + } + + /// Returns the `__wasm_init_async_task` function, if exported, for this module. + pub fn wasm_init_async_task(&self) -> Option<&str> { + self.find(|t| matches!(t, Export::WasmInitAsyncTask)) + } + /// Returns the `_initialize` intrinsic, if exported, for this module. pub fn initialize(&self) -> Option<&str> { self.find(|m| matches!(m, Export::Initialize)) @@ -1529,6 +1553,8 @@ trait NameMangling { fn export_initialize(&self) -> &str; fn export_realloc(&self) -> &str; fn export_indirect_function_table(&self) -> Option<&str>; + fn export_wasm_init_task(&self) -> Option<&str>; + fn export_wasm_init_async_task(&self) -> Option<&str>; fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>; fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>; fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>; @@ -1673,6 +1699,12 @@ impl NameMangling for Standard { fn export_indirect_function_table(&self) -> Option<&str> { None } + fn export_wasm_init_task(&self) -> Option<&str> { + None + } + fn export_wasm_init_async_task(&self) -> Option<&str> { + None + } fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> { name.strip_suffix("_drop") } @@ -2113,6 +2145,12 @@ impl NameMangling for Legacy { fn export_indirect_function_table(&self) -> Option<&str> { Some("__indirect_function_table") } + fn export_wasm_init_task(&self) -> Option<&str> { + Some("__wasm_init_task") + } + fn export_wasm_init_async_task(&self) -> Option<&str> { + Some("__wasm_init_async_task") + } fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> { name.strip_prefix("[resource-drop]") } diff --git a/crates/wit-component/tests/components/wasm-init-task/component.wat b/crates/wit-component/tests/components/wasm-init-task/component.wat new file mode 100644 index 0000000000..6873484fda --- /dev/null +++ b/crates/wit-component/tests/components/wasm-init-task/component.wat @@ -0,0 +1,162 @@ +(component + (core module $main (;0;) + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32 i32 i32) (result i32))) + (type (;3;) (func (param i32 i32))) + (type (;4;) (func (param i32 i32) (result i32))) + (type (;5;) (func (param i32 i32 i32 i32) (result i32))) + (memory (;0;) 1) + (export "__wasm_init_task" (func 0)) + (export "__wasm_init_async_task" (func 1)) + (export "[async-lift-stackful]async-stackful" (func 2)) + (export "[async-lift]async-callback" (func 3)) + (export "[callback][async-lift]async-callback" (func 4)) + (export "sync" (func 5)) + (export "[async-lift-stackful]async-stackful-argret" (func 6)) + (export "[async-lift]async-callback-argret" (func 7)) + (export "[callback][async-lift]async-callback-argret" (func 8)) + (export "sync-argret" (func 9)) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 10)) + (func (;0;) (type 0) + unreachable + ) + (func (;1;) (type 0) + unreachable + ) + (func (;2;) (type 0) + unreachable + ) + (func (;3;) (type 1) (result i32) + unreachable + ) + (func (;4;) (type 2) (param i32 i32 i32) (result i32) + unreachable + ) + (func (;5;) (type 0) + unreachable + ) + (func (;6;) (type 3) (param i32 i32) + unreachable + ) + (func (;7;) (type 4) (param i32 i32) (result i32) + unreachable + ) + (func (;8;) (type 2) (param i32 i32 i32) (result i32) + unreachable + ) + (func (;9;) (type 4) (param i32 i32) (result i32) + unreachable + ) + (func (;10;) (type 5) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core instance $main (;0;) (instantiate $main)) + (alias core export $main "memory" (core memory $memory (;0;))) + (core module $init-task-wrappers (;1;) + (type (;0;) (func)) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (type (;3;) (func (param i32 i32))) + (type (;4;) (func (param i32 i32) (result i32))) + (type (;5;) (func (param i32 i32) (result i32))) + (import "" "__wasm_init_task" (func (;0;) (type 0))) + (import "" "__wasm_init_async_task" (func (;1;) (type 0))) + (import "" "import-func-async-stackful" (func (;2;) (type 1))) + (import "" "import-func-async-callback" (func (;3;) (type 2))) + (import "" "import-func-sync" (func (;4;) (type 1))) + (import "" "import-func-async-stackful-argret" (func (;5;) (type 3))) + (import "" "import-func-async-callback-argret" (func (;6;) (type 4))) + (import "" "import-func-sync-argret" (func (;7;) (type 5))) + (export "[async-lift-stackful]async-stackful" (func 8)) + (export "[async-lift]async-callback" (func 9)) + (export "sync" (func 10)) + (export "[async-lift-stackful]async-stackful-argret" (func 11)) + (export "[async-lift]async-callback-argret" (func 12)) + (export "sync-argret" (func 13)) + (func (;8;) (type 1) + call 1 + call 2 + ) + (func (;9;) (type 2) (result i32) + call 1 + call 3 + ) + (func (;10;) (type 1) + call 0 + call 4 + ) + (func (;11;) (type 3) (param i32 i32) + call 1 + local.get 0 + local.get 1 + call 5 + ) + (func (;12;) (type 4) (param i32 i32) (result i32) + call 1 + local.get 0 + local.get 1 + call 6 + ) + (func (;13;) (type 5) (param i32 i32) (result i32) + call 0 + local.get 0 + local.get 1 + call 7 + ) + ) + (alias core export $main "__wasm_init_task" (core func $__wasm_init_task (;0;))) + (alias core export $main "__wasm_init_async_task" (core func $__wasm_init_async_task (;1;))) + (alias core export $main "[async-lift-stackful]async-stackful" (core func $"[async-lift-stackful]async-stackful" (;2;))) + (alias core export $main "[async-lift]async-callback" (core func $"[async-lift]async-callback" (;3;))) + (alias core export $main "sync" (core func $sync (;4;))) + (alias core export $main "[async-lift-stackful]async-stackful-argret" (core func $"[async-lift-stackful]async-stackful-argret" (;5;))) + (alias core export $main "[async-lift]async-callback-argret" (core func $"[async-lift]async-callback-argret" (;6;))) + (alias core export $main "sync-argret" (core func $sync-argret (;7;))) + (core instance $init-task-wrappers-args (;1;) + (export "__wasm_init_task" (func $__wasm_init_task)) + (export "__wasm_init_async_task" (func $__wasm_init_async_task)) + (export "import-func-async-stackful" (func $"[async-lift-stackful]async-stackful")) + (export "import-func-async-callback" (func $"[async-lift]async-callback")) + (export "import-func-sync" (func $sync)) + (export "import-func-async-stackful-argret" (func $"[async-lift-stackful]async-stackful-argret")) + (export "import-func-async-callback-argret" (func $"[async-lift]async-callback-argret")) + (export "import-func-sync-argret" (func $sync-argret)) + ) + (core instance $init-task-wrappers-instance (;2;) (instantiate $init-task-wrappers + (with "" (instance $init-task-wrappers-args)) + ) + ) + (alias core export $init-task-wrappers-instance "[async-lift-stackful]async-stackful" (core func $"#core-func8 [async-lift-stackful]async-stackful" (@name "[async-lift-stackful]async-stackful") (;8;))) + (alias core export $init-task-wrappers-instance "[async-lift]async-callback" (core func $"#core-func9 [async-lift]async-callback" (@name "[async-lift]async-callback") (;9;))) + (alias core export $init-task-wrappers-instance "sync" (core func $"#core-func10 sync" (@name "sync") (;10;))) + (alias core export $init-task-wrappers-instance "[async-lift-stackful]async-stackful-argret" (core func $"#core-func11 [async-lift-stackful]async-stackful-argret" (@name "[async-lift-stackful]async-stackful-argret") (;11;))) + (alias core export $init-task-wrappers-instance "[async-lift]async-callback-argret" (core func $"#core-func12 [async-lift]async-callback-argret" (@name "[async-lift]async-callback-argret") (;12;))) + (alias core export $init-task-wrappers-instance "sync-argret" (core func $"#core-func13 sync-argret" (@name "sync-argret") (;13;))) + (type (;0;) (func)) + (alias core export $main "cabi_realloc" (core func $cabi_realloc (;14;))) + (func $async-stackful (;0;) (type 0) (canon lift (core func $"#core-func8 [async-lift-stackful]async-stackful") async)) + (export $"#func1 async-stackful" (@name "async-stackful") (;1;) "async-stackful" (func $async-stackful)) + (alias core export $main "[callback][async-lift]async-callback" (core func $"[callback][async-lift]async-callback" (;15;))) + (func $async-callback (;2;) (type 0) (canon lift (core func $"#core-func9 [async-lift]async-callback") async (callback $"[callback][async-lift]async-callback"))) + (export $"#func3 async-callback" (@name "async-callback") (;3;) "async-callback" (func $async-callback)) + (func $sync (;4;) (type 0) (canon lift (core func $"#core-func10 sync"))) + (export $"#func5 sync" (@name "sync") (;5;) "sync" (func $sync)) + (type (;1;) (func (param "s" string) (result string))) + (func $async-stackful-argret (;6;) (type 1) (canon lift (core func $"#core-func11 [async-lift-stackful]async-stackful-argret") (memory $memory) (realloc $cabi_realloc) string-encoding=utf8 async)) + (export $"#func7 async-stackful-argret" (@name "async-stackful-argret") (;7;) "async-stackful-argret" (func $async-stackful-argret)) + (alias core export $main "[callback][async-lift]async-callback-argret" (core func $"[callback][async-lift]async-callback-argret" (;16;))) + (func $async-callback-argret (;8;) (type 1) (canon lift (core func $"#core-func12 [async-lift]async-callback-argret") (memory $memory) (realloc $cabi_realloc) string-encoding=utf8 async (callback $"[callback][async-lift]async-callback-argret"))) + (export $"#func9 async-callback-argret" (@name "async-callback-argret") (;9;) "async-callback-argret" (func $async-callback-argret)) + (func $sync-argret (;10;) (type 1) (canon lift (core func $"#core-func13 sync-argret") (memory $memory) (realloc $cabi_realloc) string-encoding=utf8)) + (export $"#func11 sync-argret" (@name "sync-argret") (;11;) "sync-argret" (func $sync-argret)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) diff --git a/crates/wit-component/tests/components/wasm-init-task/component.wit.print b/crates/wit-component/tests/components/wasm-init-task/component.wit.print new file mode 100644 index 0000000000..21ce9f8e96 --- /dev/null +++ b/crates/wit-component/tests/components/wasm-init-task/component.wit.print @@ -0,0 +1,10 @@ +package root:component; + +world root { + export async-stackful: func(); + export async-callback: func(); + export sync: func(); + export async-stackful-argret: func(s: string) -> string; + export async-callback-argret: func(s: string) -> string; + export sync-argret: func(s: string) -> string; +} diff --git a/crates/wit-component/tests/components/wasm-init-task/module.wat b/crates/wit-component/tests/components/wasm-init-task/module.wat new file mode 100644 index 0000000000..e831947d87 --- /dev/null +++ b/crates/wit-component/tests/components/wasm-init-task/module.wat @@ -0,0 +1,14 @@ +(module + (func (export "__wasm_init_task") unreachable) + (func (export "__wasm_init_async_task") unreachable) + (func (export "[async-lift-stackful]async-stackful") unreachable) + (func (export "[async-lift]async-callback") (result i32) unreachable) + (func (export "[callback][async-lift]async-callback") (param i32 i32 i32) (result i32) unreachable) + (func (export "sync") unreachable) + (func (export "[async-lift-stackful]async-stackful-argret") (param i32 i32) unreachable) + (func (export "[async-lift]async-callback-argret") (param i32 i32) (result i32) unreachable) + (func (export "[callback][async-lift]async-callback-argret") (param i32 i32 i32) (result i32) unreachable) + (func (export "sync-argret") (param i32 i32) (result i32) unreachable) + (memory (export "memory") 1) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) +) diff --git a/crates/wit-component/tests/components/wasm-init-task/module.wit b/crates/wit-component/tests/components/wasm-init-task/module.wit new file mode 100644 index 0000000000..3c9d33ed62 --- /dev/null +++ b/crates/wit-component/tests/components/wasm-init-task/module.wit @@ -0,0 +1,10 @@ +package foo:foo; + +world module { + export async-stackful: func(); + export async-callback: func(); + export sync: func(); + export async-stackful-argret: func(s: string) -> string; + export async-callback-argret: func(s: string) -> string; + export sync-argret: func(s: string) -> string; +}