From d6a6545059ff89139f9fb17d9ec107c5e9f620b5 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Thu, 4 Sep 2025 13:10:57 +0100 Subject: [PATCH 1/7] Implement co-op threading builtins --- crates/wasm-encoder/src/component/builder.rs | 53 ++- .../wasm-encoder/src/component/canonicals.rs | 59 +++- crates/wasm-encoder/src/reencode/component.rs | 41 ++- crates/wasmparser/src/features.rs | 22 +- .../src/readers/component/canonicals.rs | 57 +++- crates/wasmparser/src/validator/component.rs | 242 ++++++++++--- crates/wasmprinter/src/component.rs | 68 +++- crates/wast/src/component/binary.rs | 29 +- crates/wast/src/component/func.rs | 105 +++++- crates/wast/src/component/resolve.rs | 11 +- crates/wast/src/lib.rs | 9 +- crates/wit-component/src/dummy.rs | 12 +- crates/wit-component/src/encoding.rs | 144 ++++++-- crates/wit-component/src/encoding/world.rs | 10 +- crates/wit-component/src/validation.rs | 239 ++++++++++++- .../component.wat | 153 ++++++--- .../component.wit.print | 0 .../{async-builtins => threading}/module.wat | 16 +- .../{async-builtins => threading}/module.wit | 0 src/bin/wasm-tools/dump.rs | 10 +- tests/cli/component-model-async/abi.wast | 2 +- tests/cli/component-model-async/futures.wast | 2 +- tests/cli/component-model-async/lift.wast | 2 +- .../cli/component-model-async/resources.wast | 2 +- tests/cli/component-model-async/streams.wast | 2 +- .../{task-builtins.wast => threading.wast} | 177 ++++++++-- .../cli/missing-features/async-builtins.wast | 43 --- .../cli/missing-features/async-stackful.wast | 51 --- .../component-model/async.wast | 18 +- .../component-model/threading.wast | 101 ++++++ .../cli/validate-unknown-features.wat.stderr | 2 +- .../task-builtins.wast/19.print | 4 +- .../component-model-async/threading.wast.json | 322 ++++++++++++++++++ .../threading.wast/0.print | 14 + .../threading.wast/11.print | 20 ++ .../threading.wast/13.print | 20 ++ .../threading.wast/15.print | 14 + .../threading.wast/17.print | 14 + .../threading.wast/19.print | 14 + .../threading.wast/2.print | 14 + .../threading.wast/21.print | 14 + .../threading.wast/23.print | 14 + .../threading.wast/25.print | 24 ++ .../threading.wast/36.print | 10 + .../threading.wast/37.print | 21 ++ .../threading.wast/38.print | 10 + .../threading.wast/39.print | 21 ++ .../threading.wast/40.print | 69 ++++ .../threading.wast/41.print | 4 + .../threading.wast/42.print | 14 + .../threading.wast/43.print | 4 + .../threading.wast/44.print | 14 + .../threading.wast/46.print | 97 ++++++ .../threading.wast/47.print | 4 + .../threading.wast/7.print | 12 + .../threading.wast/8.print | 14 + .../threading.wast/9.print | 14 + .../missing-features/async-builtins.wast.json | 52 --- .../missing-features/async-stackful.wast.json | 51 --- .../async-stackful.wast/6.print | 2 +- .../component-model/async.wast.json | 55 ++- .../component-model/threading.wast.json | 105 ++++++ .../component-model/threading.wast/10.print | 8 + .../component-model/threading.wast/11.print | 8 + .../component-model/threading.wast/12.print | 4 + .../component-model/threading.wast/13.print | 4 + .../component-model/threading.wast/2.print | 9 + .../component-model/threading.wast/4.print | 9 + .../component-model/threading.wast/6.print | 3 + 69 files changed, 2307 insertions(+), 481 deletions(-) rename crates/wit-component/tests/components/{async-builtins => threading}/component.wat (59%) rename crates/wit-component/tests/components/{async-builtins => threading}/component.wit.print (100%) rename crates/wit-component/tests/components/{async-builtins => threading}/module.wat (66%) rename crates/wit-component/tests/components/{async-builtins => threading}/module.wit (100%) rename tests/cli/component-model-async/{task-builtins.wast => threading.wast} (67%) delete mode 100644 tests/cli/missing-features/async-builtins.wast delete mode 100644 tests/cli/missing-features/async-stackful.wast create mode 100644 tests/cli/missing-features/component-model/threading.wast create mode 100644 tests/snapshots/cli/component-model-async/threading.wast.json create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/0.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/11.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/13.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/15.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/17.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/19.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/2.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/21.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/23.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/25.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/36.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/37.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/38.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/39.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/40.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/41.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/42.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/43.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/44.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/46.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/47.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/7.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/8.print create mode 100644 tests/snapshots/cli/component-model-async/threading.wast/9.print delete mode 100644 tests/snapshots/cli/missing-features/async-builtins.wast.json delete mode 100644 tests/snapshots/cli/missing-features/async-stackful.wast.json create mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast.json create mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/10.print create mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/11.print create mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/12.print create mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/13.print create mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/2.print create mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/4.print create mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/6.print diff --git a/crates/wasm-encoder/src/component/builder.rs b/crates/wasm-encoder/src/component/builder.rs index d660ae55a7..0413fac639 100644 --- a/crates/wasm-encoder/src/component/builder.rs +++ b/crates/wasm-encoder/src/component/builder.rs @@ -425,9 +425,9 @@ impl ComponentBuilder { inc(&mut self.core_funcs) } - /// Declares a new `task.yield` intrinsic. - pub fn yield_(&mut self, async_: bool) -> u32 { - self.canonical_functions().yield_(async_); + /// Declares a new `thread.yield` intrinsic. + pub fn thread_yield(&mut self, cancellable: bool) -> u32 { + self.canonical_functions().thread_yield(cancellable); inc(&mut self.core_funcs) } @@ -577,14 +577,16 @@ impl ComponentBuilder { } /// Declares a new `waitable-set.wait` intrinsic. - pub fn waitable_set_wait(&mut self, async_: bool, memory: u32) -> u32 { - self.canonical_functions().waitable_set_wait(async_, memory); + pub fn waitable_set_wait(&mut self, cancellable: bool, memory: u32) -> u32 { + self.canonical_functions() + .waitable_set_wait(cancellable, memory); inc(&mut self.core_funcs) } /// Declares a new `waitable-set.poll` intrinsic. - pub fn waitable_set_poll(&mut self, async_: bool, memory: u32) -> u32 { - self.canonical_functions().waitable_set_poll(async_, memory); + pub fn waitable_set_poll(&mut self, cancellable: bool, memory: u32) -> u32 { + self.canonical_functions() + .waitable_set_poll(cancellable, memory); inc(&mut self.core_funcs) } @@ -600,6 +602,43 @@ impl ComponentBuilder { inc(&mut self.core_funcs) } + /// Declares a new `thread.index` intrinsic. + pub fn thread_index(&mut self) -> u32 { + self.canonical_functions().thread_index(); + inc(&mut self.core_funcs) + } + + /// Declares a new `thread.new_indirect` intrinsic. + pub fn thread_new_indirect(&mut self, func_ty_idx: u32, table_index: u32) -> u32 { + self.canonical_functions() + .thread_new_indirect(func_ty_idx, table_index); + inc(&mut self.core_funcs) + } + + /// Declares a new `thread.switch-to` intrinsic. + pub fn thread_switch_to(&mut self, cancellable: bool) -> u32 { + self.canonical_functions().thread_switch_to(cancellable); + inc(&mut self.core_funcs) + } + + /// Declares a new `thread.suspend` intrinsic. + pub fn thread_suspend(&mut self, cancellable: bool) -> u32 { + self.canonical_functions().thread_suspend(cancellable); + inc(&mut self.core_funcs) + } + + /// Declares a new `thread.resume-later` intrinsic. + pub fn thread_resume_later(&mut self) -> u32 { + self.canonical_functions().thread_resume_later(); + inc(&mut self.core_funcs) + } + + /// Declares a new `thread.yield-to` intrinsic. + pub fn thread_yield_to(&mut self, cancellable: bool) -> u32 { + self.canonical_functions().thread_yield_to(cancellable); + inc(&mut self.core_funcs) + } + /// Adds a new custom section to this component. pub fn custom_section(&mut self, section: &CustomSection<'_>) { self.flush(); diff --git a/crates/wasm-encoder/src/component/canonicals.rs b/crates/wasm-encoder/src/component/canonicals.rs index 8724a1dd49..93310c28dc 100644 --- a/crates/wasm-encoder/src/component/canonicals.rs +++ b/crates/wasm-encoder/src/component/canonicals.rs @@ -249,10 +249,10 @@ impl CanonicalFunctionSection { /// Defines a function which yields control to the host so that other tasks /// are able to make progress, if any. /// - /// If `async_` is true, the caller instance may be reentered. - pub fn yield_(&mut self, async_: bool) -> &mut Self { + /// If `cancellable` is true, the caller instance may be reentered. + pub fn thread_yield(&mut self, cancellable: bool) -> &mut Self { self.bytes.push(0x0c); - self.bytes.push(if async_ { 1 } else { 0 }); + self.bytes.push(if cancellable { 1 } else { 0 }); self.num_added += 1; self } @@ -498,6 +498,59 @@ impl CanonicalFunctionSection { self } + /// Declare a new `thread.index` intrinsic, used to get the index of the + /// current thread. + pub fn thread_index(&mut self) -> &mut Self { + self.bytes.push(0x26); + self.num_added += 1; + self + } + + /// Declare a new `thread.new_indirect` intrinsic, used to create a new + /// thread by invoking a function indirectly through a `funcref` table. + pub fn thread_new_indirect(&mut self, ty_index: u32, table_index: u32) -> &mut Self { + self.bytes.push(0x27); + ty_index.encode(&mut self.bytes); + table_index.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Declare a new `thread.switch-to` intrinsic, used to switch execution to + /// another thread. + pub fn thread_switch_to(&mut self, cancellable: bool) -> &mut Self { + self.bytes.push(0x28); + self.bytes.push(if cancellable { 1 } else { 0 }); + self.num_added += 1; + self + } + + /// Declare a new `thread.suspend` intrinsic, used to suspend execution of + /// the current thread. + pub fn thread_suspend(&mut self, cancellable: bool) -> &mut Self { + self.bytes.push(0x29); + self.bytes.push(if cancellable { 1 } else { 0 }); + self.num_added += 1; + self + } + + /// Declare a new `thread.resume-later` intrinsic, used to resume execution + /// of the given thread. + pub fn thread_resume_later(&mut self) -> &mut Self { + self.bytes.push(0x2a); + self.num_added += 1; + self + } + + /// Declare a new `thread.yield-to` intrinsic, used to yield execution to + /// a given thread. + pub fn thread_yield_to(&mut self, cancellable: bool) -> &mut Self { + self.bytes.push(0x2b); + self.bytes.push(if cancellable { 1 } else { 0 }); + self.num_added += 1; + self + } + fn encode_options(&mut self, options: O) -> &mut Self where O: IntoIterator, diff --git a/crates/wasm-encoder/src/reencode/component.rs b/crates/wasm-encoder/src/reencode/component.rs index 9f53eaed97..417c5a99e9 100644 --- a/crates/wasm-encoder/src/reencode/component.rs +++ b/crates/wasm-encoder/src/reencode/component.rs @@ -995,8 +995,8 @@ pub mod component_utils { wasmparser::CanonicalFunction::ContextSet(i) => { section.context_set(i); } - wasmparser::CanonicalFunction::Yield { async_ } => { - section.yield_(async_); + wasmparser::CanonicalFunction::ThreadYield { cancellable } => { + section.thread_yield(cancellable); } wasmparser::CanonicalFunction::SubtaskDrop => { section.subtask_drop(); @@ -1082,11 +1082,17 @@ pub mod component_utils { wasmparser::CanonicalFunction::WaitableSetNew => { section.waitable_set_new(); } - wasmparser::CanonicalFunction::WaitableSetWait { async_, memory } => { - section.waitable_set_wait(async_, reencoder.memory_index(memory)?); + wasmparser::CanonicalFunction::WaitableSetWait { + cancellable, + memory, + } => { + section.waitable_set_wait(cancellable, reencoder.memory_index(memory)?); } - wasmparser::CanonicalFunction::WaitableSetPoll { async_, memory } => { - section.waitable_set_poll(async_, reencoder.memory_index(memory)?); + wasmparser::CanonicalFunction::WaitableSetPoll { + cancellable, + memory, + } => { + section.waitable_set_poll(cancellable, reencoder.memory_index(memory)?); } wasmparser::CanonicalFunction::WaitableSetDrop => { section.waitable_set_drop(); @@ -1094,6 +1100,29 @@ pub mod component_utils { wasmparser::CanonicalFunction::WaitableJoin => { section.waitable_join(); } + wasmparser::CanonicalFunction::ThreadIndex => { + section.thread_index(); + } + wasmparser::CanonicalFunction::ThreadNewIndirect { + func_ty_index, + table_index, + } => { + let func_ty = reencoder.type_index(func_ty_index)?; + let table_index = reencoder.table_index(table_index)?; + section.thread_new_indirect(func_ty, table_index); + } + wasmparser::CanonicalFunction::ThreadSwitchTo { cancellable } => { + section.thread_switch_to(cancellable); + } + wasmparser::CanonicalFunction::ThreadSuspend { cancellable } => { + section.thread_suspend(cancellable); + } + wasmparser::CanonicalFunction::ThreadResumeLater => { + section.thread_resume_later(); + } + wasmparser::CanonicalFunction::ThreadYieldTo { cancellable } => { + section.thread_yield_to(cancellable); + } } Ok(()) } diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index 2ef63ac5a5..416ddfd9f3 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -254,33 +254,27 @@ define_wasm_features! { /// Corresponds to the ๐Ÿ”€ character in /// . pub cm_async: CM_ASYNC(1 << 27) = false; - /// Gates the "stackful ABI" in the component model async proposal. + /// Support for threading in the component model proposal. /// - /// Corresponds to the ๐ŸšŸ character in + /// Corresponds to the ๐Ÿงต character in /// . - pub cm_async_stackful: CM_ASYNC_STACKFUL(1 << 28) = false; - /// Gates some intrinsics being marked with `async` in the component - /// model async proposal. - /// - /// Corresponds to the ๐Ÿš character in - /// . - pub cm_async_builtins: CM_ASYNC_BUILTINS(1 << 29) = false; + pub cm_threading: CM_THREADING(1 << 28) = false; /// Gates some intrinsics being marked with `error-context` in the component /// model async proposal. /// /// Corresponds to the ๐Ÿ“ character in /// . - pub cm_error_context: CM_ERROR_CONTEXT(1 << 30) = false; + pub cm_error_context: CM_ERROR_CONTEXT(1 << 29) = false; /// Support for fixed size lists /// /// Corresponds to the ๐Ÿ”ง character in /// . - pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 31) = false; + pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 30) = false; /// Support for Wasm GC in the component model proposal. /// /// Corresponds to the ๐Ÿ›ธ character in /// . - pub cm_gc: CM_GC(1 << 32) = false; + pub cm_gc: CM_GC(1 << 31) = false; /// Subset of the reference-types WebAssembly proposal which only /// encompasses the leb-encoding of the table immediate to the @@ -288,13 +282,13 @@ define_wasm_features! { /// integer for example. /// /// This is a subcomponent of the "lime1" feature. - pub call_indirect_overlong: CALL_INDIRECT_OVERLONG(1 << 33) = true; + pub call_indirect_overlong: CALL_INDIRECT_OVERLONG(1 << 32) = true; /// Subset of the bulk-memory proposal covering just the `memory.copy` /// and `memory.fill` instructions. /// /// This is a subcomponent of the "lime1" feature. - pub bulk_memory_opt: BULK_MEMORY_OPT(1 << 34) = true; + pub bulk_memory_opt: BULK_MEMORY_OPT(1 << 33) = true; } } diff --git a/crates/wasmparser/src/readers/component/canonicals.rs b/crates/wasmparser/src/readers/component/canonicals.rs index 2df2e9d1e6..50132d9392 100644 --- a/crates/wasmparser/src/readers/component/canonicals.rs +++ b/crates/wasmparser/src/readers/component/canonicals.rs @@ -110,9 +110,9 @@ pub enum CanonicalFunction { ContextSet(u32), /// A function which yields control to the host so that other tasks are able /// to make progress, if any. - Yield { + ThreadYield { /// If `true`, indicates the caller instance maybe reentered. - async_: bool, + cancellable: bool, }, /// A function to drop a specified task which has completed. SubtaskDrop, @@ -246,7 +246,7 @@ pub enum CanonicalFunction { WaitableSetWait { /// Whether or not the guest can be reentered while calling this /// function. - async_: bool, + cancellable: bool, /// Which memory the results of this operation are stored in. memory: u32, }, @@ -254,7 +254,7 @@ pub enum CanonicalFunction { WaitableSetPoll { /// Whether or not the guest can be reentered while calling this /// function. - async_: bool, + cancellable: bool, /// Which memory the results of this operation are stored in. memory: u32, }, @@ -262,6 +262,32 @@ pub enum CanonicalFunction { WaitableSetDrop, /// A function to add an item to a `waitable-set`. WaitableJoin, + /// A function to get the index of the current thread. + ThreadIndex, + /// A function to create a new thread with the specified start function. + ThreadNewIndirect { + /// The index of the function type to use as the start function. + func_ty_index: u32, + /// The index of the table to use. + table_index: u32, + }, + /// A function to suspend the current thread and switch to the given thread. + ThreadSwitchTo { + /// Whether or not the thread can be cancelled while awaiting resumption. + cancellable: bool, + }, + /// A function to suspend the current thread, immediately yielding to any transitive async-lowered calling component. + ThreadSuspend { + /// Whether or not the thread can be cancelled while suspended. + cancellable: bool, + }, + /// A function to schedule the given thread to be resumed later. + ThreadResumeLater, + /// A function to suspend the current thread and switch to the given thread. + ThreadYieldTo { + /// Whether or not the thread can be cancelled while yielding. + cancellable: bool, + }, } /// A reader for the canonical section of a WebAssembly component. @@ -310,8 +336,8 @@ impl<'a> FromReader<'a> for CanonicalFunction { 0x7f => CanonicalFunction::ContextSet(reader.read_var_u32()?), x => return reader.invalid_leading_byte(x, "context.set intrinsic type"), }, - 0x0c => CanonicalFunction::Yield { - async_: reader.read()?, + 0x0c => CanonicalFunction::ThreadYield { + cancellable: reader.read()?, }, 0x0d => CanonicalFunction::SubtaskDrop, 0x0e => CanonicalFunction::StreamNew { ty: reader.read()? }, @@ -362,15 +388,30 @@ impl<'a> FromReader<'a> for CanonicalFunction { 0x1f => CanonicalFunction::WaitableSetNew, 0x20 => CanonicalFunction::WaitableSetWait { - async_: reader.read()?, + cancellable: reader.read()?, memory: reader.read()?, }, 0x21 => CanonicalFunction::WaitableSetPoll { - async_: reader.read()?, + cancellable: reader.read()?, memory: reader.read()?, }, 0x22 => CanonicalFunction::WaitableSetDrop, 0x23 => CanonicalFunction::WaitableJoin, + 0x26 => CanonicalFunction::ThreadIndex, + 0x27 => CanonicalFunction::ThreadNewIndirect { + func_ty_index: reader.read()?, + table_index: reader.read()?, + }, + 0x28 => CanonicalFunction::ThreadSwitchTo { + cancellable: reader.read()?, + }, + 0x29 => CanonicalFunction::ThreadSuspend { + cancellable: reader.read()?, + }, + 0x2a => CanonicalFunction::ThreadResumeLater, + 0x2b => CanonicalFunction::ThreadYieldTo { + cancellable: reader.read()?, + }, 0x06 => CanonicalFunction::SubtaskCancel { async_: reader.read()?, }, diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index e2e58330cc..9721a4f643 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -363,8 +363,8 @@ impl CanonicalOptions { match self.concurrency { Concurrency::Sync => {} - Concurrency::Async { callback: None } if !state.features.cm_async_stackful() => { - bail!(offset, "requires the async stackful feature") + Concurrency::Async { callback: None } if !state.features.cm_threading() => { + bail!(offset, "requires the component model threading feature") } Concurrency::Async { callback: None } => {} @@ -1189,7 +1189,9 @@ impl ComponentState { CanonicalFunction::TaskCancel => self.task_cancel(types, offset), CanonicalFunction::ContextGet(i) => self.context_get(i, types, offset), CanonicalFunction::ContextSet(i) => self.context_set(i, types, offset), - CanonicalFunction::Yield { async_ } => self.yield_(async_, types, offset), + CanonicalFunction::ThreadYield { cancellable } => { + self.thread_yield(cancellable, types, offset) + } CanonicalFunction::SubtaskDrop => self.subtask_drop(types, offset), CanonicalFunction::SubtaskCancel { async_ } => { self.subtask_cancel(async_, types, offset) @@ -1240,14 +1242,32 @@ impl ComponentState { } CanonicalFunction::ErrorContextDrop => self.error_context_drop(types, offset), CanonicalFunction::WaitableSetNew => self.waitable_set_new(types, offset), - CanonicalFunction::WaitableSetWait { async_, memory } => { - self.waitable_set_wait(async_, memory, types, offset) - } - CanonicalFunction::WaitableSetPoll { async_, memory } => { - self.waitable_set_poll(async_, memory, types, offset) - } + CanonicalFunction::WaitableSetWait { + cancellable, + memory, + } => self.waitable_set_wait(cancellable, memory, types, offset), + CanonicalFunction::WaitableSetPoll { + cancellable, + memory, + } => self.waitable_set_poll(cancellable, memory, types, offset), CanonicalFunction::WaitableSetDrop => self.waitable_set_drop(types, offset), CanonicalFunction::WaitableJoin => self.waitable_join(types, offset), + CanonicalFunction::ThreadIndex => self.thread_index(types, offset), + CanonicalFunction::ThreadNewIndirect { + func_ty_index, + table_index, + } => self.thread_new_indirect(func_ty_index, table_index, types, offset), + CanonicalFunction::ThreadSwitchTo { cancellable } => { + self.thread_switch_to(cancellable, types, offset) + } + CanonicalFunction::ThreadSuspend { cancellable } => { + self.thread_suspend(cancellable, types, offset) + } + CanonicalFunction::ThreadResumeLater => self.thread_resume_later(types, offset), + + CanonicalFunction::ThreadYieldTo { cancellable } => { + self.thread_yield_to(cancellable, types, offset) + } } } @@ -1349,10 +1369,10 @@ impl ComponentState { types: &mut TypeAlloc, offset: usize, ) -> Result<()> { - if !self.features.cm_async_builtins() { + if !self.features.cm_threading() { bail!( offset, - "`resource.drop` as `async` requires the component model async builtins feature" + "`resource.drop` as `async` requires the component model threading feature" ) } self.resource_at(resource, types, offset)?; @@ -1456,8 +1476,8 @@ impl ComponentState { "`context.get` requires the component model async feature" ) } - if i > 0 { - bail!(offset, "`context.get` immediate must be zero: {i}") + if i > 1 { + bail!(offset, "`context.get` immediate must be zero or one: {i}") } self.core_funcs @@ -1472,8 +1492,8 @@ impl ComponentState { "`context.set` requires the component model async feature" ) } - if i > 0 { - bail!(offset, "`context.set` immediate must be zero: {i}") + if i > 1 { + bail!(offset, "`context.set` immediate must be zero or one: {i}") } self.core_funcs @@ -1481,14 +1501,22 @@ impl ComponentState { Ok(()) } - fn yield_(&mut self, async_: bool, types: &mut TypeAlloc, offset: usize) -> Result<()> { + fn thread_yield( + &mut self, + cancellable: bool, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { if !self.features.cm_async() { - bail!(offset, "`yield` requires the component model async feature") + bail!( + offset, + "`thread.yield` requires the component model async feature" + ) } - if async_ && !self.features.cm_async_stackful() { + if cancellable && !self.features.cm_threading() { bail!( offset, - "async `yield` requires the component model async stackful feature" + "cancellable `thread.yield` requires the component model threading feature" ) } @@ -1517,10 +1545,10 @@ impl ComponentState { "`subtask.cancel` requires the component model async feature" ) } - if async_ && !self.features.cm_async_builtins() { + if async_ && !self.features.cm_threading() { bail!( offset, - "async `subtask.cancel` requires the component model async builtins feature" + "async `subtask.cancel` requires the component model threading feature" ) } @@ -1617,7 +1645,7 @@ impl ComponentState { fn stream_cancel_read( &mut self, ty: u32, - async_: bool, + cancellable: bool, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -1627,10 +1655,10 @@ impl ComponentState { "`stream.cancel-read` requires the component model async feature" ) } - if async_ && !self.features.cm_async_builtins() { + if cancellable && !self.features.cm_threading() { bail!( offset, - "async `stream.cancel-read` requires the component model async builtins feature" + "async `stream.cancel-read` requires the component model threading feature" ) } @@ -1647,7 +1675,7 @@ impl ComponentState { fn stream_cancel_write( &mut self, ty: u32, - async_: bool, + cancellable: bool, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -1657,10 +1685,10 @@ impl ComponentState { "`stream.cancel-write` requires the component model async feature" ) } - if async_ && !self.features.cm_async_builtins() { + if cancellable && !self.features.cm_threading() { bail!( offset, - "async `stream.cancel-write` requires the component model async builtins feature" + "async `stream.cancel-write` requires the component model threading feature" ) } @@ -1807,7 +1835,7 @@ impl ComponentState { fn future_cancel_read( &mut self, ty: u32, - async_: bool, + cancellable: bool, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -1817,10 +1845,10 @@ impl ComponentState { "`future.cancel-read` requires the component model async feature" ) } - if async_ && !self.features.cm_async_builtins() { + if cancellable && !self.features.cm_threading() { bail!( offset, - "async `future.cancel-read` requires the component model async builtins feature" + "async `future.cancel-read` requires the component model threading feature" ) } @@ -1837,7 +1865,7 @@ impl ComponentState { fn future_cancel_write( &mut self, ty: u32, - async_: bool, + cancellable: bool, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -1847,10 +1875,10 @@ impl ComponentState { "`future.cancel-write` requires the component model async feature" ) } - if async_ && !self.features.cm_async_builtins() { + if cancellable && !self.features.cm_threading() { bail!( offset, - "async `future.cancel-write` requires the component model async builtins feature" + "async `future.cancel-write` requires the component model threading feature" ) } @@ -1991,7 +2019,7 @@ impl ComponentState { fn waitable_set_wait( &mut self, - async_: bool, + cancellable: bool, memory: u32, types: &mut TypeAlloc, offset: usize, @@ -2002,10 +2030,10 @@ impl ComponentState { "`waitable-set.wait` requires the component model async feature" ) } - if async_ && !self.features.cm_async_stackful() { + if cancellable && !self.features.cm_threading() { bail!( offset, - "async `waitable-set.wait` requires the component model async stackful feature" + "cancellable `waitable-set.wait` requires the component model threading feature" ) } @@ -2018,7 +2046,7 @@ impl ComponentState { fn waitable_set_poll( &mut self, - async_: bool, + cancellable: bool, memory: u32, types: &mut TypeAlloc, offset: usize, @@ -2029,10 +2057,10 @@ impl ComponentState { "`waitable-set.poll` requires the component model async feature" ) } - if async_ && !self.features.cm_async_stackful() { + if cancellable && !self.features.cm_threading() { bail!( offset, - "async `waitable-set.poll` requires the component model async stackful feature" + "cancellable `waitable-set.poll` requires the component model threading feature" ) } @@ -2069,6 +2097,142 @@ impl ComponentState { Ok(()) } + fn thread_index(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.index` requires the component model threading feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); + Ok(()) + } + + fn thread_new_indirect( + &mut self, + func_ty_index: u32, + table_index: u32, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.new_indirect` requires the component model threading feature" + ) + } + + let core_type_id = match self.core_type_at(func_ty_index, offset)? { + ComponentCoreTypeId::Sub(c) => c, + ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"), + }; + let sub_ty = &types[core_type_id]; + match &sub_ty.composite_type.inner { + CompositeInnerType::Func(func_ty) => { + if func_ty.params() != [ValType::I32] { + bail!( + offset, + "start function must take a single `i32` argument (currently)" + ); + } + if func_ty.results() != [] { + bail!(offset, "start function must not return any values"); + } + } + _ => bail!(offset, "start type must be a function"), + } + + let table = self.table_at(table_index, offset)?; + + SubtypeCx::table_type( + table, + &TableType { + initial: 0, + maximum: None, + table64: false, + shared: false, + element_type: RefType::FUNCREF, + }, + offset, + ) + .map_err(|mut e| { + e.add_context("table is not a 32-bit table of (ref null (func))".into()); + e + })?; + + self.core_funcs.push(types.intern_func_type( + FuncType::new([ValType::I32, ValType::I32], [ValType::I32]), + offset, + )); + Ok(()) + } + + fn thread_switch_to( + &mut self, + _cancellable: bool, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.switch_to` requires the component model threading feature" + ) + } + + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset)); + Ok(()) + } + + fn thread_suspend( + &mut self, + _cancellable: bool, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.suspend` requires the component model threading feature" + ) + } + self.core_funcs + .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); + Ok(()) + } + + fn thread_resume_later(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.resume_later` requires the component model threading feature" + ) + } + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); + Ok(()) + } + + fn thread_yield_to( + &mut self, + _cancellable: bool, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + if !self.features.cm_threading() { + bail!( + offset, + "`thread.yield_to` requires the component model threading feature" + ) + } + self.core_funcs + .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset)); + Ok(()) + } + fn check_local_resource(&self, idx: u32, types: &TypeList, offset: usize) -> Result { let resource = self.resource_at(idx, types, offset)?; match self diff --git a/crates/wasmprinter/src/component.rs b/crates/wasmprinter/src/component.rs index 339389a538..3565bb17a1 100644 --- a/crates/wasmprinter/src/component.rs +++ b/crates/wasmprinter/src/component.rs @@ -974,10 +974,10 @@ impl Printer<'_, '_> { Ok(()) })?; } - CanonicalFunction::Yield { async_ } => { - self.print_intrinsic(state, "canon yield", &|me, _| { - if async_ { - me.print_type_keyword(" async")?; + CanonicalFunction::ThreadYield { cancellable } => { + self.print_intrinsic(state, "canon thread.yield", &|me, _| { + if cancellable { + me.print_type_keyword(" cancellable")?; } Ok(()) })?; @@ -1101,20 +1101,26 @@ impl Printer<'_, '_> { CanonicalFunction::WaitableSetNew => { self.print_intrinsic(state, "canon waitable-set.new", &|_, _| Ok(()))?; } - CanonicalFunction::WaitableSetWait { async_, memory } => { + CanonicalFunction::WaitableSetWait { + cancellable, + memory, + } => { self.print_intrinsic(state, "canon waitable-set.wait ", &|me, state| { - if async_ { - me.result.write_str("async ")?; + if cancellable { + me.result.write_str("cancellable ")?; } me.start_group("memory ")?; me.print_idx(&state.core.memory_names, memory)?; me.end_group() })?; } - CanonicalFunction::WaitableSetPoll { async_, memory } => { + CanonicalFunction::WaitableSetPoll { + cancellable, + memory, + } => { self.print_intrinsic(state, "canon waitable-set.poll ", &|me, state| { - if async_ { - me.result.write_str("async ")?; + if cancellable { + me.result.write_str("cancellable ")?; } me.start_group("memory ")?; me.print_idx(&state.core.memory_names, memory)?; @@ -1127,6 +1133,48 @@ impl Printer<'_, '_> { CanonicalFunction::WaitableJoin => { self.print_intrinsic(state, "canon waitable.join", &|_, _| Ok(()))?; } + CanonicalFunction::ThreadIndex => { + self.print_intrinsic(state, "canon thread.index", &|_, _| Ok(()))?; + } + CanonicalFunction::ThreadNewIndirect { + func_ty_index, + table_index, + } => { + self.print_intrinsic(state, "canon thread.new_indirect ", &|me, state| { + me.print_idx(&state.core.type_names, func_ty_index)?; + me.result.write_str(" ")?; + me.start_group("table ")?; + me.print_idx(&state.core.table_names, table_index)?; + me.end_group() + })?; + } + CanonicalFunction::ThreadSwitchTo { cancellable } => { + self.print_intrinsic(state, "canon thread.switch-to", &|me, _| { + if cancellable { + me.result.write_str(" cancellable")?; + } + Ok(()) + })?; + } + CanonicalFunction::ThreadSuspend { cancellable } => { + self.print_intrinsic(state, "canon thread.suspend", &|me, _| { + if cancellable { + me.result.write_str(" cancellable")?; + } + Ok(()) + })?; + } + CanonicalFunction::ThreadResumeLater => { + self.print_intrinsic(state, "canon thread.resume-later", &|_, _| Ok(()))?; + } + CanonicalFunction::ThreadYieldTo { cancellable } => { + self.print_intrinsic(state, "canon thread.yield-to", &|me, _| { + if cancellable { + me.result.write_str(" cancellable")?; + } + Ok(()) + })?; + } } } diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 64d717d245..6b14e7db6b 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -395,9 +395,9 @@ impl<'a> Encoder<'a> { self.core_func_names.push(name); self.funcs.context_set(*i); } - CoreFuncKind::Yield(info) => { + CoreFuncKind::ThreadYield(info) => { self.core_func_names.push(name); - self.funcs.yield_(info.async_); + self.funcs.thread_yield(info.cancellable); } CoreFuncKind::SubtaskDrop => { self.core_func_names.push(name); @@ -503,6 +503,31 @@ impl<'a> Encoder<'a> { self.core_func_names.push(name); self.funcs.waitable_join(); } + CoreFuncKind::ThreadIndex => { + self.core_func_names.push(name); + self.funcs.thread_index(); + } + CoreFuncKind::ThreadNewIndirect(info) => { + self.core_func_names.push(name); + self.funcs + .thread_new_indirect(info.ty.into(), info.table.idx.into()); + } + CoreFuncKind::ThreadSwitchTo(info) => { + self.core_func_names.push(name); + self.funcs.thread_switch_to(info.cancellable); + } + CoreFuncKind::ThreadSuspend(info) => { + self.core_func_names.push(name); + self.funcs.thread_suspend(info.cancellable); + } + CoreFuncKind::ThreadResumeLater => { + self.core_func_names.push(name); + self.funcs.thread_resume_later(); + } + CoreFuncKind::ThreadYieldTo(info) => { + self.core_func_names.push(name); + self.funcs.thread_yield_to(info.cancellable); + } }, } diff --git a/crates/wast/src/component/func.rs b/crates/wast/src/component/func.rs index e967bfbb65..dfed403781 100644 --- a/crates/wast/src/component/func.rs +++ b/crates/wast/src/component/func.rs @@ -59,7 +59,7 @@ pub enum CoreFuncKind<'a> { TaskCancel, ContextGet(u32), ContextSet(u32), - Yield(CanonYield), + ThreadYield(CanonThreadYield), SubtaskDrop, SubtaskCancel(CanonSubtaskCancel), StreamNew(CanonStreamNew<'a>), @@ -84,6 +84,12 @@ pub enum CoreFuncKind<'a> { WaitableSetPoll(CanonWaitableSetPoll<'a>), WaitableSetDrop, WaitableJoin, + ThreadIndex, + ThreadNewIndirect(CanonThreadNewIndirect<'a>), + ThreadSwitchTo(CanonThreadSwitchTo), + ThreadSuspend(CanonThreadSuspend), + ThreadResumeLater, + ThreadYieldTo(CanonThreadYieldTo), } impl<'a> Parse<'a> for CoreFuncKind<'a> { @@ -134,8 +140,8 @@ impl<'a> CoreFuncKind<'a> { parser.parse::()?; parser.parse::()?; Ok(CoreFuncKind::ContextSet(parser.parse()?)) - } else if l.peek::()? { - Ok(CoreFuncKind::Yield(parser.parse()?)) + } else if l.peek::()? { + Ok(CoreFuncKind::ThreadYield(parser.parse()?)) } else if l.peek::()? { parser.parse::()?; Ok(CoreFuncKind::SubtaskDrop) @@ -189,6 +195,20 @@ impl<'a> CoreFuncKind<'a> { } else if l.peek::()? { parser.parse::()?; Ok(CoreFuncKind::WaitableJoin) + } else if l.peek::()? { + parser.parse::()?; + Ok(CoreFuncKind::ThreadIndex) + } else if l.peek::()? { + Ok(CoreFuncKind::ThreadNewIndirect(parser.parse()?)) + } else if l.peek::()? { + Ok(CoreFuncKind::ThreadSwitchTo(parser.parse()?)) + } else if l.peek::()? { + Ok(CoreFuncKind::ThreadSuspend(parser.parse()?)) + } else if l.peek::()? { + parser.parse::()?; + Ok(CoreFuncKind::ThreadResumeLater) + } else if l.peek::()? { + Ok(CoreFuncKind::ThreadYieldTo(parser.parse()?)) } else { Err(l.error()) } @@ -569,7 +589,7 @@ pub struct CanonWaitableSetWait<'a> { impl<'a> Parse<'a> for CanonWaitableSetWait<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; - let async_ = parser.parse::>()?.is_some(); + let async_ = parser.parse::>()?.is_some(); let memory = parser.parens(|p| p.parse())?; Ok(Self { async_, memory }) @@ -589,27 +609,27 @@ pub struct CanonWaitableSetPoll<'a> { impl<'a> Parse<'a> for CanonWaitableSetPoll<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; - let async_ = parser.parse::>()?.is_some(); + let async_ = parser.parse::>()?.is_some(); let memory = parser.parens(|p| p.parse())?; Ok(Self { async_, memory }) } } -/// Information relating to the `yield` intrinsic. +/// Information relating to the `thread.yield` intrinsic. #[derive(Debug)] -pub struct CanonYield { +pub struct CanonThreadYield { /// If true, the component instance may be reentered during a call to this /// intrinsic. - pub async_: bool, + pub cancellable: bool, } -impl<'a> Parse<'a> for CanonYield { +impl<'a> Parse<'a> for CanonThreadYield { fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let async_ = parser.parse::>()?.is_some(); + parser.parse::()?; + let cancellable = parser.parse::>()?.is_some(); - Ok(Self { async_ }) + Ok(Self { cancellable }) } } @@ -930,6 +950,67 @@ impl<'a> Parse<'a> for CanonErrorContextDebugMessage<'a> { } } +/// Information relating to the `thread.new_indirect` intrinsic. +#[derive(Debug)] +pub struct CanonThreadNewIndirect<'a> { + /// The function type for the thread start function. + pub ty: Index<'a>, + /// The table to index. + pub table: CoreItemRef<'a, kw::table>, +} + +impl<'a> Parse<'a> for CanonThreadNewIndirect<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let ty = parser.parse()?; + let table = parser.parens(|p| p.parse())?; + Ok(Self { ty, table }) + } +} + +/// Information relating to the `thread.switch-to` intrinsic. +#[derive(Debug)] +pub struct CanonThreadSwitchTo { + /// Whether the thread can be cancelled while suspended at this point. + pub cancellable: bool, +} + +impl<'a> Parse<'a> for CanonThreadSwitchTo { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let cancellable = parser.parse::>()?.is_some(); + Ok(Self { cancellable }) + } +} + +/// Information relating to the `thread.suspend` intrinsic. +#[derive(Debug)] +pub struct CanonThreadSuspend { + /// Whether the thread can be cancelled while suspended at this point. + pub cancellable: bool, +} +impl<'a> Parse<'a> for CanonThreadSuspend { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let cancellable = parser.parse::>()?.is_some(); + Ok(Self { cancellable }) + } +} + +/// Information relating to the `thread.yield-to` intrinsic. +#[derive(Debug)] +pub struct CanonThreadYieldTo { + /// Whether the thread can be cancelled while yielding at this point. + pub cancellable: bool, +} +impl<'a> Parse<'a> for CanonThreadYieldTo { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let cancellable = parser.parse::>()?.is_some(); + Ok(Self { cancellable }) + } +} + #[derive(Debug)] /// Canonical ABI options. pub enum CanonOpt<'a> { diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index 54e6f3e272..aff8b38694 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -397,7 +397,7 @@ impl<'a> Resolver<'a> { CoreFuncKind::ThreadAvailableParallelism(_) | CoreFuncKind::BackpressureSet | CoreFuncKind::TaskCancel - | CoreFuncKind::Yield(_) + | CoreFuncKind::ThreadYield(_) | CoreFuncKind::SubtaskDrop | CoreFuncKind::SubtaskCancel(_) | CoreFuncKind::ErrorContextDrop => {} @@ -469,6 +469,15 @@ impl<'a> Resolver<'a> { } CoreFuncKind::WaitableSetDrop => {} CoreFuncKind::WaitableJoin => {} + CoreFuncKind::ThreadIndex => {} + CoreFuncKind::ThreadNewIndirect(info) => { + self.resolve_ns(&mut info.ty, Ns::CoreType)?; + self.core_item_ref(&mut info.table)?; + } + CoreFuncKind::ThreadSwitchTo(_) => {} + CoreFuncKind::ThreadSuspend(_) => {} + CoreFuncKind::ThreadResumeLater => {} + CoreFuncKind::ThreadYieldTo(_) => {} }, } diff --git a/crates/wast/src/lib.rs b/crates/wast/src/lib.rs index d1fdbe6380..ee6f5a40f7 100644 --- a/crates/wast/src/lib.rs +++ b/crates/wast/src/lib.rs @@ -563,7 +563,7 @@ pub mod kw { custom_keyword!(backpressure_set = "backpressure.set"); custom_keyword!(task_return = "task.return"); custom_keyword!(task_cancel = "task.cancel"); - custom_keyword!(yield_ = "yield"); + custom_keyword!(thread_yield = "thread.yield"); custom_keyword!(subtask_drop = "subtask.drop"); custom_keyword!(subtask_cancel = "subtask.cancel"); custom_keyword!(stream_new = "stream.new"); @@ -597,6 +597,13 @@ pub mod kw { custom_keyword!(waitable_join = "waitable.join"); custom_keyword!(context_get = "context.get"); custom_keyword!(context_set = "context.set"); + custom_keyword!(thread_index = "thread.index"); + custom_keyword!(thread_new_indirect = "thread.new_indirect"); + custom_keyword!(thread_switch_to = "thread.switch-to"); + custom_keyword!(thread_suspend = "thread.suspend"); + custom_keyword!(thread_resume_later = "thread.resume-later"); + custom_keyword!(thread_yield_to = "thread.yield-to"); + custom_keyword!(cancellable); } /// Common annotations used to parse WebAssembly text files. diff --git a/crates/wit-component/src/dummy.rs b/crates/wit-component/src/dummy.rs index 50341052a8..940adb1eb5 100644 --- a/crates/wit-component/src/dummy.rs +++ b/crates/wit-component/src/dummy.rs @@ -379,7 +379,7 @@ fn push_root_async_intrinsics(dst: &mut String) { (import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32))) (import "$root" "[waitable-set-drop]" (func (param i32))) (import "$root" "[waitable-join]" (func (param i32 i32))) -(import "$root" "[yield]" (func (result i32))) +(import "$root" "[thread-yield]" (func (result i32))) (import "$root" "[subtask-drop]" (func (param i32))) (import "$root" "[subtask-cancel]" (func (param i32) (result i32))) (import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32))) @@ -392,10 +392,12 @@ fn push_root_async_intrinsics(dst: &mut String) { (import "$root" "[context-get-0]" (func (result i32))) (import "$root" "[context-set-0]" (func (param i32))) -;; deferred behind ๐Ÿš or ๐ŸšŸ upstream -;;(import "$root" "[async-lower][waitable-set-wait]" (func (param i32 i32) (result i32))) -;;(import "$root" "[async-lower][waitable-set-poll]" (func (param i32 i32) (result i32))) -;;(import "$root" "[async-lower][yield]" (func (result i32))) +;; deferred behind ๐Ÿงต upstream +;;(import "$root" "[cancellable][waitable-set-wait]" (func (param i32 i32) (result i32))) +;;(import "$root" "[cancellable][waitable-set-poll]" (func (param i32 i32) (result i32))) +;;(import "$root" "[cancellable][thread-yield]" (func (result i32))) +;;(import "$root" "[context-get-1]" (func (result i32))) +;;(import "$root" "[context-set-1]" (func (param i32))) "#, ); } diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 176584ec75..2184e751c8 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -80,6 +80,7 @@ use std::borrow::Cow; use std::collections::HashMap; use std::hash::Hash; use std::mem; +use wasm_encoder::reencode::{Reencode, RoundtripReencoder}; use wasm_encoder::*; use wasmparser::{Validator, WasmFeatures}; use wit_parser::{ @@ -671,7 +672,8 @@ impl<'a> EncodingState<'a> { | Export::GeneralPurposeExportRealloc | Export::GeneralPurposeImportRealloc | Export::Initialize - | Export::ReallocForAdapter => continue, + | Export::ReallocForAdapter + | Export::FuncTable(_) => continue, } } @@ -1319,12 +1321,12 @@ impl<'a> EncodingState<'a> { } } - ShimKind::WaitableSetWait { async_ } => self + ShimKind::WaitableSetWait { cancellable } => self .component - .waitable_set_wait(*async_, self.memory_index.unwrap()), - ShimKind::WaitableSetPoll { async_ } => self + .waitable_set_wait(*cancellable, self.memory_index.unwrap()), + ShimKind::WaitableSetPoll { cancellable } => self .component - .waitable_set_poll(*async_, self.memory_index.unwrap()), + .waitable_set_poll(*cancellable, self.memory_index.unwrap()), ShimKind::ErrorContextNew { encoding } => self.component.error_context_new( shim.options.into_iter(*encoding, self.memory_index, None)?, ), @@ -1374,6 +1376,30 @@ impl<'a> EncodingState<'a> { .into_iter(*encoding, self.memory_index, realloc_index)?; self.component.task_return(result, options) } + ShimKind::ThreadNewIndirect { + for_module, + func_ty, + table_idx, + } => { + // Encode the function type for the thread start function so we can reference it in the `canon` call. + let (func_ty_idx, f) = self.component.core_type(); + f.core().func_type(func_ty); + + // In order for the funcref table referenced by `thread.new_indirect` to be used, + // it must have been imported by the model. We check this here, which also validates + // that the table is indeed a funcref table, as we couldn't check this during initial validation. + let exports = self.info.exports_for(*for_module); + let instance_index = self.instance_for(*for_module); + let table_idx = exports.func_table(*table_idx).map(|table| { + self.core_alias_export(instance_index, table, ExportKind::Table) + }).ok_or_else(|| { + anyhow!( + "table at index {table_idx} must be an exported funcref table for thread.new_indirect" + ) + })?; + + self.component.thread_new_indirect(func_ty_idx, table_idx) + } }; exports.push((shim.name.as_str(), ExportKind::Func, core_func_index)); @@ -1692,16 +1718,20 @@ impl<'a> EncodingState<'a> { let index = self.component.backpressure_set(); Ok((ExportKind::Func, index)) } - Import::WaitableSetWait { async_ } => { - Ok(self - .materialize_shim_import(shims, &ShimKind::WaitableSetWait { async_: *async_ })) - } - Import::WaitableSetPoll { async_ } => { - Ok(self - .materialize_shim_import(shims, &ShimKind::WaitableSetPoll { async_: *async_ })) - } - Import::Yield { async_ } => { - let index = self.component.yield_(*async_); + Import::WaitableSetWait { cancellable } => Ok(self.materialize_shim_import( + shims, + &ShimKind::WaitableSetWait { + cancellable: *cancellable, + }, + )), + Import::WaitableSetPoll { cancellable } => Ok(self.materialize_shim_import( + shims, + &ShimKind::WaitableSetPoll { + cancellable: *cancellable, + }, + )), + Import::ThreadYield { cancellable } => { + let index = self.component.thread_yield(*cancellable); Ok((ExportKind::Func, index)) } Import::SubtaskDrop => { @@ -1839,6 +1869,34 @@ impl<'a> EncodingState<'a> { let index = self.component.task_cancel(); Ok((ExportKind::Func, index)) } + Import::ThreadIndex => { + let index = self.component.thread_index(); + Ok((ExportKind::Func, index)) + } + Import::ThreadNewIndirect { func_ty, table_idx } => Ok(self.materialize_shim_import( + shims, + &ShimKind::ThreadNewIndirect { + for_module, + func_ty: RoundtripReencoder.func_type(func_ty.clone())?, + table_idx: *table_idx, + }, + )), + Import::ThreadSwitchTo { cancellable } => { + let index = self.component.thread_switch_to(*cancellable); + Ok((ExportKind::Func, index)) + } + Import::ThreadSuspend { cancellable } => { + let index = self.component.thread_suspend(*cancellable); + Ok((ExportKind::Func, index)) + } + Import::ThreadResumeLater => { + let index = self.component.thread_resume_later(); + Ok((ExportKind::Func, index)) + } + Import::ThreadYieldTo { cancellable } => { + let index = self.component.thread_yield_to(*cancellable); + Ok((ExportKind::Func, index)) + } } } @@ -2119,11 +2177,11 @@ enum ShimKind<'a> { /// A shim used for the `waitable-set.wait` built-in function, which must /// refer to the core module instance's memory to which results will be /// written. - WaitableSetWait { async_: bool }, + WaitableSetWait { cancellable: bool }, /// A shim used for the `waitable-set.poll` built-in function, which must /// refer to the core module instance's memory to which results will be /// written. - WaitableSetPoll { async_: bool }, + WaitableSetPoll { cancellable: 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 @@ -2155,6 +2213,17 @@ enum ShimKind<'a> { /// The string encoding to use when lowering the debug message. encoding: StringEncoding, }, + /// A shim used for the `thread.new_indirect` built-in function, which + /// must refer to the core module instance's indirect function table. + ThreadNewIndirect { + /// Which instance to pull the function table from. + for_module: CustomModule<'a>, + /// The function type to use when creating the thread. + func_ty: FuncType, + /// The indirect function table to use when creating the thread. + /// This must be exported by the core module. + table_idx: u32, + }, } /// Indicator for which module is being used for a lowering or where options @@ -2204,7 +2273,7 @@ impl<'a> Shims<'a> { | Import::ExportedTaskCancel | Import::ErrorContextDrop | Import::BackpressureSet - | Import::Yield { .. } + | Import::ThreadYield { .. } | Import::SubtaskDrop | Import::SubtaskCancel { .. } | Import::FutureNew(..) @@ -2221,7 +2290,12 @@ impl<'a> Shims<'a> { | Import::WaitableSetDrop | Import::WaitableJoin | Import::ContextGet(_) - | Import::ContextSet(_) => {} + | Import::ContextSet(_) + | Import::ThreadIndex + | Import::ThreadSwitchTo { .. } + | Import::ThreadSuspend { .. } + | Import::ThreadResumeLater + | Import::ThreadYieldTo { .. } => {} // If `task.return` needs to be indirect then generate a shim // for it, otherwise skip the shim and let it get materialized @@ -2306,13 +2380,15 @@ impl<'a> Shims<'a> { ); } - Import::WaitableSetWait { async_ } => { + Import::WaitableSetWait { cancellable } => { let name = self.shims.len().to_string(); self.push(Shim { name, debug_name: "waitable-set.wait".to_string(), options: RequiredOptions::empty(), - kind: ShimKind::WaitableSetWait { async_: *async_ }, + kind: ShimKind::WaitableSetWait { + cancellable: *cancellable, + }, sig: WasmSignature { params: vec![WasmType::I32; 2], results: vec![WasmType::I32], @@ -2322,13 +2398,15 @@ impl<'a> Shims<'a> { }); } - Import::WaitableSetPoll { async_ } => { + Import::WaitableSetPoll { cancellable } => { let name = self.shims.len().to_string(); self.push(Shim { name, debug_name: "waitable-set.poll".to_string(), options: RequiredOptions::empty(), - kind: ShimKind::WaitableSetPoll { async_: *async_ }, + kind: ShimKind::WaitableSetPoll { + cancellable: *cancellable, + }, sig: WasmSignature { params: vec![WasmType::I32; 2], results: vec![WasmType::I32], @@ -2377,6 +2455,26 @@ impl<'a> Shims<'a> { }); } + Import::ThreadNewIndirect { func_ty, table_idx } => { + let name = self.shims.len().to_string(); + self.push(Shim { + name, + debug_name: "thread.new_indirect".to_string(), + options: RequiredOptions::empty(), + kind: ShimKind::ThreadNewIndirect { + for_module, + func_ty: RoundtripReencoder.func_type(func_ty.clone())?, + table_idx: *table_idx, + }, + sig: WasmSignature { + params: vec![WasmType::I32; 2], + results: vec![WasmType::I32], + indirect_params: false, + retptr: false, + }, + }); + } + // Adapter imports into the main module must got through an // indirection, so that's registered here. Import::AdapterExport { adapter, func, ty } => { diff --git a/crates/wit-component/src/encoding/world.rs b/crates/wit-component/src/encoding/world.rs index fbfe7df842..81aa2684aa 100644 --- a/crates/wit-component/src/encoding/world.rs +++ b/crates/wit-component/src/encoding/world.rs @@ -421,13 +421,19 @@ impl<'a> ComponentWorld<'a> { | Import::WaitableSetPoll { .. } | Import::WaitableSetDrop | Import::WaitableJoin - | Import::Yield { .. } + | Import::ThreadYield { .. } | Import::SubtaskDrop | Import::SubtaskCancel { .. } | Import::ErrorContextNew { .. } | Import::ErrorContextDebugMessage { .. } | Import::ErrorContextDrop - | Import::ExportedTaskCancel => {} + | Import::ExportedTaskCancel + | Import::ThreadIndex + | Import::ThreadNewIndirect { .. } + | Import::ThreadSwitchTo { .. } + | Import::ThreadSuspend { .. } + | Import::ThreadResumeLater + | Import::ThreadYieldTo { .. } => {} } } } diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs index 0a990fd0db..ced254d281 100644 --- a/crates/wit-component/src/validation.rs +++ b/crates/wit-component/src/validation.rs @@ -5,6 +5,7 @@ use indexmap::{IndexMap, IndexSet, map::Entry}; use std::hash::{Hash, Hasher}; use std::mem; use wasm_encoder::ExportKind; +use wasmparser::CompositeInnerType; use wasmparser::names::{ComponentName, ComponentNameKind}; use wasmparser::{ Encoding, ExternalKind, FuncType, Parser, Payload, TypeRef, ValType, ValidPayload, Validator, @@ -286,14 +287,14 @@ pub enum Import { /// This allows the guest to wait for any pending calls to async-lowered /// imports and/or `stream` and `future` operations to complete without /// unwinding the current Wasm stack. - WaitableSetWait { async_: bool }, + WaitableSetWait { cancellable: bool }, /// A `canon waitable.poll` intrinsic. /// /// This allows the guest to check whether any pending calls to /// async-lowered imports and/or `stream` and `future` operations have /// completed without unwinding the current Wasm stack and without blocking. - WaitableSetPoll { async_: bool }, + WaitableSetPoll { cancellable: bool }, /// A `waitable-set.drop` intrinsic. WaitableSetDrop, @@ -301,11 +302,11 @@ pub enum Import { /// A `waitable.join` intrinsic. WaitableJoin, - /// A `canon yield` intrinsic. + /// A `canon thread.yield` intrinsic. /// /// This allows the guest to yield (e.g. during an computationally-intensive /// operation) and allow other subtasks to make progress. - Yield { async_: bool }, + ThreadYield { cancellable: bool }, /// A `canon subtask.drop` intrinsic. /// @@ -412,6 +413,37 @@ pub enum Import { /// This allows the guest to release its handle to the specified /// `error-context` instance. ErrorContextDrop, + + /// A `canon thread.index` intrinsic. + /// + /// This allows the guest to get the index of the current thread. + ThreadIndex, + + /// A `canon thread.new_indirect` intrinsic. + /// + /// This allows the guest to create a new thread running a specified function. + ThreadNewIndirect { func_ty: FuncType, table_idx: u32 }, + + /// A `canon thread.switch-to` intrinsic. + /// + /// This allows the guest to switch execution to another thread. + ThreadSwitchTo { cancellable: bool }, + + /// A `canon thread.suspend` intrinsic. + /// + /// This allows the guest to suspend the current thread, switching execution to + /// an unspecified thread. + ThreadSuspend { cancellable: bool }, + + /// A `canon thread.resume-later` intrinsic. + /// + /// This allows the guest to mark a suspended thread for later resumption. + ThreadResumeLater, + + /// A `canon thread.yield-to` intrinsic. + /// + /// This allows the guest to suspend, yielding execution to a specified thread. + ThreadYieldTo { cancellable: bool }, } impl ImportMap { @@ -536,7 +568,7 @@ impl ImportMap { None if encoder.reject_legacy_names => (import.module, STANDARD), None => (import.module, LEGACY), }; - self.classify_component_model_import(module, import.name, encoder, ty, names) + self.classify_component_model_import(module, import.name, encoder, ty, names, types) } /// Attempts to classify the import `{module}::{name}` with the rules @@ -548,6 +580,7 @@ impl ImportMap { encoder: &ComponentEncoder, ty: &FuncType, names: &dyn NameMangling, + types: TypesRef<'_>, ) -> Result { let resolve = &encoder.metadata.resolve; let world_id = encoder.metadata.world; @@ -558,6 +591,11 @@ impl ImportMap { } else { (false, name) }; + let (cancellable, name) = if let Some(name) = names.cancellable_name(name) { + (true, name) + } else { + (false, name) + }; let abi = if async_ { AbiVariant::GuestImportAsync } else { @@ -569,10 +607,17 @@ impl ImportMap { } Ok(()) }; + let validate_not_cancellable = || { + if cancellable { + bail!("`{name}` cannot be marked `cancellable`") + } + Ok(()) + }; if module == names.import_root() { if Some(name) == names.error_context_drop() { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::ErrorContextDrop); @@ -580,6 +625,7 @@ impl ImportMap { if Some(name) == names.backpressure_set() { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::BackpressureSet); @@ -587,29 +633,29 @@ impl ImportMap { if Some(name) == names.waitable_set_new() { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::WaitableSetNew); } if Some(name) == names.waitable_set_wait() { + validate_not_async()?; let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::WaitableSetWait { - async_: abi == AbiVariant::GuestImportAsync, - }); + return Ok(Import::WaitableSetWait { cancellable }); } if Some(name) == names.waitable_set_poll() { + validate_not_async()?; let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::WaitableSetPoll { - async_: abi == AbiVariant::GuestImportAsync, - }); + return Ok(Import::WaitableSetPoll { cancellable }); } if Some(name) == names.waitable_set_drop() { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::WaitableSetDrop); @@ -617,25 +663,29 @@ impl ImportMap { if Some(name) == names.waitable_join() { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32; 2], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::WaitableJoin); } - if Some(name) == names.yield_() { + if Some(name) == names.thread_yield() { + validate_not_async()?; let expected = FuncType::new([], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::Yield { async_ }); + return Ok(Import::ThreadYield { cancellable }); } if Some(name) == names.subtask_drop() { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::SubtaskDrop); } if Some(name) == names.subtask_cancel() { + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::SubtaskCancel { async_ }); @@ -643,6 +693,7 @@ impl ImportMap { if let Some(encoding) = names.error_context_new(name) { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::ErrorContextNew { encoding }); @@ -650,6 +701,7 @@ impl ImportMap { if let Some(encoding) = names.error_context_debug_message(name) { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32; 2], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::ErrorContextDebugMessage { encoding }); @@ -657,16 +709,86 @@ impl ImportMap { if let Some(i) = names.context_get(name) { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::ContextGet(i)); } if let Some(i) = names.context_set(name) { validate_not_async()?; + validate_not_cancellable()?; let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::ContextSet(i)); } + if Some(name) == names.thread_index() { + validate_not_async()?; + validate_not_cancellable()?; + let expected = FuncType::new([], [ValType::I32]); + validate_func_sig(name, &expected, ty)?; + return Ok(Import::ThreadIndex); + } + if let Some((func_ty_idx, table_idx)) = names.thread_new_indirect(name) { + validate_not_async()?; + validate_not_cancellable()?; + + let func_ty_id = types.core_type_at_in_module(func_ty_idx); + let func_ty = types + .get(func_ty_id) + .and_then(|ty| match &ty.composite_type.inner { + CompositeInnerType::Func(func) => Some(func), + _ => None, + }); + if func_ty.is_none() { + bail!("`{name}` references type {func_ty_idx}, which is not a function type"); + } + let expected_start_func = FuncType::new([ValType::I32], []); + if func_ty.unwrap() != &expected_start_func { + bail!( + "`{name}` references type {func_ty_idx}, which is not the type (i32) -> (); the only type currently supported for thread entrypoints" + ); + } + + // We can't validate the type of the table here, because the import must appear before + // the table definition in the module, so we can't look it up yet. We defer this validation + // to the shim module. + + let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); + validate_func_sig(name, &expected, ty)?; + // We store the function type itself and will simply ensure that such a type is available when + // (canon thread.new_indirect ..) is issued. We store the table index for now, and will ensure + // that it is exported from the main module when we generate the shim module, so that we can eventually + // generate an alias for it and reference the table from (canon thread.new_indirect ..). + return Ok(Import::ThreadNewIndirect { + func_ty: func_ty.unwrap().clone(), + table_idx, + }); + } + if Some(name) == names.thread_switch_to() { + validate_not_async()?; + let expected = FuncType::new([ValType::I32], [ValType::I32]); + validate_func_sig(name, &expected, ty)?; + return Ok(Import::ThreadSwitchTo { cancellable }); + } + if Some(name) == names.thread_suspend() { + validate_not_async()?; + let expected = FuncType::new([], [ValType::I32]); + validate_func_sig(name, &expected, ty)?; + return Ok(Import::ThreadSuspend { cancellable }); + } + if Some(name) == names.thread_resume_later() { + validate_not_async()?; + validate_not_cancellable()?; + let expected = FuncType::new([ValType::I32], []); + validate_func_sig(name, &expected, ty)?; + return Ok(Import::ThreadResumeLater); + } + if Some(name) == names.thread_yield_to() { + validate_not_async()?; + let expected = FuncType::new([ValType::I32], [ValType::I32]); + validate_func_sig(name, &expected, ty)?; + return Ok(Import::ThreadYieldTo { cancellable }); + } let key = WorldKey::Name(name.to_string()); if let Some(WorldItem::Function(func)) = world.imports.get(&key) { @@ -674,6 +796,11 @@ impl ImportMap { return Ok(Import::WorldFunc(key, func.name.clone(), abi)); } + // At this point, all cancellable imports have already been checked + if cancellable { + bail!("`{name}` cannot be marked `cancellable`"); + } + if let Some(import) = self.maybe_classify_wit_intrinsic(name, None, encoder, ty, async_, true, names)? { @@ -686,6 +813,11 @@ impl ImportMap { } } + // At this point, all cancellable imports have already been checked + if cancellable { + bail!("`{name}` cannot be marked `cancellable`"); + } + // Check for `[export]$root::[task-return]foo` or similar if matches!( module.strip_prefix(names.import_exported_intrinsic_prefix()), @@ -1085,6 +1217,9 @@ pub enum Export { WorldFuncCallback(WorldKey), InterfaceFuncCallback(WorldKey, String), + + /// Tables that store funcrefs, used for `thread.new_indirect` + FuncTable(u32), } impl ExportMap { @@ -1164,6 +1299,12 @@ impl ExportMap { } return Ok(None); } + ExternalKind::Table => { + if types.table_at(export.index).element_type.is_func_ref() { + return Ok(Some(Export::FuncTable(export.index))); + } + return Ok(None); + } _ => return Ok(None), } let ty = types[types.core_function_at(export.index)].unwrap_func(); @@ -1335,6 +1476,15 @@ impl ExportMap { self.find(|m| matches!(m, Export::Memory)) } + /// Returns the funcref table that matches the given index, + /// if exported, for this module. + pub fn func_table(&self, index: u32) -> Option<&str> { + self.find(|m| match m { + Export::FuncTable(i) => *i == index, + _ => false, + }) + } + /// Returns the `_initialize` intrinsic, if exported, for this module. pub fn initialize(&self) -> Option<&str> { self.find(|m| matches!(m, Export::Initialize)) @@ -1479,7 +1629,7 @@ trait NameMangling { fn waitable_set_poll(&self) -> Option<&str>; fn waitable_set_drop(&self) -> Option<&str>; fn waitable_join(&self) -> Option<&str>; - fn yield_(&self) -> Option<&str>; + fn thread_yield(&self) -> Option<&str>; fn subtask_drop(&self) -> Option<&str>; fn subtask_cancel(&self) -> Option<&str>; fn async_lift_callback_name<'a>(&self, s: &'a str) -> Option<&'a str>; @@ -1489,8 +1639,15 @@ trait NameMangling { fn error_context_new(&self, s: &str) -> Option; fn error_context_debug_message(&self, s: &str) -> Option; fn error_context_drop(&self) -> Option<&str>; + fn cancellable_name<'a>(&self, s: &'a str) -> Option<&'a str>; fn context_get(&self, name: &str) -> Option; fn context_set(&self, name: &str) -> Option; + fn thread_index(&self) -> Option<&str>; + fn thread_new_indirect(&self, name: &str) -> Option<(u32, u32)>; + fn thread_switch_to(&self) -> Option<&str>; + fn thread_suspend(&self) -> Option<&str>; + fn thread_resume_later(&self) -> Option<&str>; + fn thread_yield_to(&self) -> Option<&str>; fn module_to_interface( &self, module: &str, @@ -1573,7 +1730,7 @@ impl NameMangling for Standard { fn waitable_join(&self) -> Option<&str> { None } - fn yield_(&self) -> Option<&str> { + fn thread_yield(&self) -> Option<&str> { None } fn subtask_drop(&self) -> Option<&str> { @@ -1613,6 +1770,28 @@ impl NameMangling for Standard { fn context_set(&self, _: &str) -> Option { None } + fn thread_index(&self) -> Option<&str> { + None + } + fn thread_new_indirect(&self, _: &str) -> Option<(u32, u32)> { + None + } + fn thread_switch_to(&self) -> Option<&str> { + None + } + fn thread_suspend(&self) -> Option<&str> { + None + } + fn thread_resume_later(&self) -> Option<&str> { + None + } + fn thread_yield_to(&self) -> Option<&str> { + None + } + fn cancellable_name<'a>(&self, s: &'a str) -> Option<&'a str> { + _ = s; + None + } fn module_to_interface( &self, interface: &str, @@ -1772,8 +1951,8 @@ impl NameMangling for Legacy { fn waitable_join(&self) -> Option<&str> { Some("[waitable-join]") } - fn yield_(&self) -> Option<&str> { - Some("[yield]") + fn thread_yield(&self) -> Option<&str> { + Some("[thread-yield]") } fn subtask_drop(&self) -> Option<&str> { Some("[subtask-drop]") @@ -1820,6 +1999,32 @@ impl NameMangling for Legacy { let (n, rest) = prefixed_integer(name, "[context-set-")?; if rest.is_empty() { Some(n) } else { None } } + fn thread_index(&self) -> Option<&str> { + Some("[thread-index]") + } + fn thread_new_indirect(&self, name: &str) -> Option<(u32, u32)> { + let rest = name.strip_prefix("[thread-new-indirect-")?; + let func_ty_idx_end = rest.find('-')?; + let func_ty_idx = rest[..func_ty_idx_end].parse().ok()?; + let end_idx = rest.find(']')?; + let table_idx = rest[func_ty_idx_end + 1..end_idx].parse().ok()?; + Some((func_ty_idx, table_idx)) + } + fn thread_switch_to(&self) -> Option<&str> { + Some("[thread-switch-to]") + } + fn thread_suspend(&self) -> Option<&str> { + Some("[thread-suspend]") + } + fn thread_resume_later(&self) -> Option<&str> { + Some("[thread-resume-later]") + } + fn thread_yield_to(&self) -> Option<&str> { + Some("[thread-yield-to]") + } + fn cancellable_name<'a>(&self, s: &'a str) -> Option<&'a str> { + s.strip_prefix("[cancellable]") + } fn module_to_interface( &self, module: &str, diff --git a/crates/wit-component/tests/components/async-builtins/component.wat b/crates/wit-component/tests/components/threading/component.wat similarity index 59% rename from crates/wit-component/tests/components/async-builtins/component.wat rename to crates/wit-component/tests/components/threading/component.wat index e84346ac41..30f6b73830 100644 --- a/crates/wit-component/tests/components/async-builtins/component.wat +++ b/crates/wit-component/tests/components/threading/component.wat @@ -1,23 +1,23 @@ (component (core module (;0;) - (type (;0;) (func (param i32))) + (type $thread-start-func-ty (;0;) (func (param i32))) (type (;1;) (func)) (type (;2;) (func (param i32 i32))) (type (;3;) (func (result i32))) (type (;4;) (func (param i32 i32) (result i32))) (type (;5;) (func (param i32) (result i32))) (type (;6;) (func (param i32 i32 i32 i32) (result i32))) - (import "$root" "[backpressure-set]" (func (;0;) (type 0))) + (import "$root" "[backpressure-set]" (func (;0;) (type $thread-start-func-ty))) (import "[export]$root" "[task-cancel]" (func (;1;) (type 1))) (import "[export]$root" "[task-return]foo" (func (;2;) (type 2))) (import "[export]foo:foo/bar" "[task-return]foo" (func (;3;) (type 2))) (import "$root" "[waitable-set-new]" (func (;4;) (type 3))) (import "$root" "[waitable-set-wait]" (func (;5;) (type 4))) (import "$root" "[waitable-set-poll]" (func (;6;) (type 4))) - (import "$root" "[waitable-set-drop]" (func (;7;) (type 0))) + (import "$root" "[waitable-set-drop]" (func (;7;) (type $thread-start-func-ty))) (import "$root" "[waitable-join]" (func (;8;) (type 2))) - (import "$root" "[yield]" (func (;9;) (type 3))) - (import "$root" "[subtask-drop]" (func (;10;) (type 0))) + (import "$root" "[thread-yield]" (func (;9;) (type 3))) + (import "$root" "[subtask-drop]" (func (;10;) (type $thread-start-func-ty))) (import "$root" "[subtask-cancel]" (func (;11;) (type 5))) (import "$root" "[error-context-new-utf8]" (func (;12;) (type 4))) (import "$root" "[error-context-new-utf16]" (func (;13;) (type 4))) @@ -25,21 +25,36 @@ (import "$root" "[error-context-debug-message-utf8]" (func (;15;) (type 2))) (import "$root" "[error-context-debug-message-utf16]" (func (;16;) (type 2))) (import "$root" "[error-context-debug-message-latin1+utf16]" (func (;17;) (type 2))) - (import "$root" "[error-context-drop]" (func (;18;) (type 0))) + (import "$root" "[error-context-drop]" (func (;18;) (type $thread-start-func-ty))) (import "$root" "[context-get-0]" (func (;19;) (type 3))) - (import "$root" "[context-set-0]" (func (;20;) (type 0))) + (import "$root" "[context-set-0]" (func (;20;) (type $thread-start-func-ty))) + (import "$root" "[context-get-1]" (func (;21;) (type 3))) + (import "$root" "[context-set-1]" (func (;22;) (type $thread-start-func-ty))) + (import "$root" "[thread-index]" (func (;23;) (type 3))) + (import "$root" "[thread-new-indirect-0-0]" (func (;24;) (type 4))) + (import "$root" "[thread-switch-to]" (func (;25;) (type 5))) + (import "$root" "[thread-suspend]" (func (;26;) (type 3))) + (import "$root" "[thread-resume-later]" (func (;27;) (type $thread-start-func-ty))) + (import "$root" "[thread-yield-to]" (func (;28;) (type 5))) + (table (;0;) 1 1 funcref) (memory (;0;) 1) - (export "[async-lift-stackful]foo" (func 21)) - (export "[async-lift-stackful]foo:foo/bar#foo" (func 22)) + (export "thread_main" (func 29)) + (export "[async-lift-stackful]foo" (func 30)) + (export "[async-lift-stackful]foo:foo/bar#foo" (func 31)) (export "memory" (memory 0)) - (export "cabi_realloc" (func 23)) - (func (;21;) (type 2) (param i32 i32) + (export "indirect_function_table" (table 0)) + (export "cabi_realloc" (func 32)) + (elem (;0;) (i32.const 0) func 0) + (func (;29;) (type $thread-start-func-ty) (param i32) unreachable ) - (func (;22;) (type 2) (param i32 i32) + (func (;30;) (type 2) (param i32 i32) unreachable ) - (func (;23;) (type 6) (param i32 i32 i32 i32) (result i32) + (func (;31;) (type 2) (param i32 i32) + unreachable + ) + (func (;32;) (type 6) (param i32 i32 i32 i32) (result i32) unreachable ) (@producers @@ -51,7 +66,7 @@ (type (;0;) (func (param i32 i32) (result i32))) (type (;1;) (func (param i32 i32))) (type (;2;) (func (param i32 i32))) - (table (;0;) 10 10 funcref) + (table (;0;) 11 11 funcref) (export "0" (func $waitable-set.wait)) (export "1" (func $waitable-set.poll)) (export "2" (func $error-new)) @@ -60,8 +75,9 @@ (export "5" (func $error-debug-message)) (export "6" (func $"#func6 error-debug-message")) (export "7" (func $"#func7 error-debug-message")) - (export "8" (func $task-return-foo)) - (export "9" (func $"#func9 task-return-foo")) + (export "8" (func $thread.new_indirect)) + (export "9" (func $task-return-foo)) + (export "10" (func $"#func10 task-return-foo")) (export "$imports" (table 0)) (func $waitable-set.wait (;0;) (type 0) (param i32 i32) (result i32) local.get 0 @@ -111,18 +127,24 @@ i32.const 7 call_indirect (type 1) ) - (func $task-return-foo (;8;) (type 2) (param i32 i32) + (func $thread.new_indirect (;8;) (type 0) (param i32 i32) (result i32) local.get 0 local.get 1 i32.const 8 - call_indirect (type 2) + call_indirect (type 0) ) - (func $"#func9 task-return-foo" (@name "task-return-foo") (;9;) (type 2) (param i32 i32) + (func $task-return-foo (;9;) (type 2) (param i32 i32) local.get 0 local.get 1 i32.const 9 call_indirect (type 2) ) + (func $"#func10 task-return-foo" (@name "task-return-foo") (;10;) (type 2) (param i32 i32) + local.get 0 + local.get 1 + i32.const 10 + call_indirect (type 2) + ) (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) @@ -139,10 +161,11 @@ (import "" "5" (func (;5;) (type 1))) (import "" "6" (func (;6;) (type 1))) (import "" "7" (func (;7;) (type 1))) - (import "" "8" (func (;8;) (type 2))) + (import "" "8" (func (;8;) (type 0))) (import "" "9" (func (;9;) (type 2))) - (import "" "$imports" (table (;0;) 10 10 funcref)) - (elem (;0;) (i32.const 0) func 0 1 2 3 4 5 6 7 8 9) + (import "" "10" (func (;10;) (type 2))) + (import "" "$imports" (table (;0;) 11 11 funcref)) + (elem (;0;) (i32.const 0) func 0 1 2 3 4 5 6 7 8 9 10) (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) @@ -154,7 +177,7 @@ (alias core export 0 "1" (core func (;3;))) (core func (;4;) (canon waitable-set.drop)) (core func (;5;) (canon waitable.join)) - (core func (;6;) (canon yield)) + (core func (;6;) (canon thread.yield)) (core func (;7;) (canon subtask.drop)) (core func (;8;) (canon subtask.cancel)) (alias core export 0 "2" (core func (;9;))) @@ -166,6 +189,14 @@ (core func (;15;) (canon error-context.drop)) (core func (;16;) (canon context.get i32 0)) (core func (;17;) (canon context.set i32 0)) + (core func (;18;) (canon context.get i32 1)) + (core func (;19;) (canon context.set i32 1)) + (core func (;20;) (canon thread.index)) + (alias core export 0 "8" (core func (;21;))) + (core func (;22;) (canon thread.switch-to)) + (core func (;23;) (canon thread.suspend)) + (core func (;24;) (canon thread.resume-later)) + (core func (;25;) (canon thread.yield-to)) (core instance (;1;) (export "[backpressure-set]" (func 0)) (export "[waitable-set-new]" (func 1)) @@ -173,7 +204,7 @@ (export "[waitable-set-poll]" (func 3)) (export "[waitable-set-drop]" (func 4)) (export "[waitable-join]" (func 5)) - (export "[yield]" (func 6)) + (export "[thread-yield]" (func 6)) (export "[subtask-drop]" (func 7)) (export "[subtask-cancel]" (func 8)) (export "[error-context-new-utf8]" (func 9)) @@ -185,16 +216,24 @@ (export "[error-context-drop]" (func 15)) (export "[context-get-0]" (func 16)) (export "[context-set-0]" (func 17)) + (export "[context-get-1]" (func 18)) + (export "[context-set-1]" (func 19)) + (export "[thread-index]" (func 20)) + (export "[thread-new-indirect-0-0]" (func 21)) + (export "[thread-switch-to]" (func 22)) + (export "[thread-suspend]" (func 23)) + (export "[thread-resume-later]" (func 24)) + (export "[thread-yield-to]" (func 25)) ) - (core func (;18;) (canon task.cancel)) - (alias core export 0 "8" (core func (;19;))) + (core func (;26;) (canon task.cancel)) + (alias core export 0 "9" (core func (;27;))) (core instance (;2;) - (export "[task-cancel]" (func 18)) - (export "[task-return]foo" (func 19)) + (export "[task-cancel]" (func 26)) + (export "[task-return]foo" (func 27)) ) - (alias core export 0 "9" (core func (;20;))) + (alias core export 0 "10" (core func (;28;))) (core instance (;3;) - (export "[task-return]foo" (func 20)) + (export "[task-return]foo" (func 28)) ) (core instance (;4;) (instantiate 0 (with "$root" (instance 1)) @@ -204,41 +243,45 @@ ) (alias core export 4 "memory" (core memory (;0;))) (alias core export 0 "$imports" (core table (;0;))) - (core func (;21;) (canon waitable-set.wait (memory 0))) - (core func (;22;) (canon waitable-set.poll (memory 0))) - (core func (;23;) (canon error-context.new (memory 0) string-encoding=utf8)) - (core func (;24;) (canon error-context.new (memory 0) string-encoding=utf16)) - (core func (;25;) (canon error-context.new (memory 0) string-encoding=latin1+utf16)) - (alias core export 4 "cabi_realloc" (core func (;26;))) - (core func (;27;) (canon error-context.debug-message (memory 0) (realloc 26) string-encoding=utf8)) - (core func (;28;) (canon error-context.debug-message (memory 0) (realloc 26) string-encoding=utf16)) - (core func (;29;) (canon error-context.debug-message (memory 0) (realloc 26) string-encoding=latin1+utf16)) - (core func (;30;) (canon task.return (result string) (memory 0) string-encoding=utf8)) - (core func (;31;) (canon task.return (result string) (memory 0) string-encoding=utf8)) + (core func (;29;) (canon waitable-set.wait (memory 0))) + (core func (;30;) (canon waitable-set.poll (memory 0))) + (core func (;31;) (canon error-context.new (memory 0) string-encoding=utf8)) + (core func (;32;) (canon error-context.new (memory 0) string-encoding=utf16)) + (core func (;33;) (canon error-context.new (memory 0) string-encoding=latin1+utf16)) + (alias core export 4 "cabi_realloc" (core func (;34;))) + (core func (;35;) (canon error-context.debug-message (memory 0) (realloc 34) string-encoding=utf8)) + (core func (;36;) (canon error-context.debug-message (memory 0) (realloc 34) string-encoding=utf16)) + (core func (;37;) (canon error-context.debug-message (memory 0) (realloc 34) string-encoding=latin1+utf16)) + (core type (;0;) (func (param i32))) + (alias core export 4 "indirect_function_table" (core table (;1;))) + (core func (;38;) (canon thread.new_indirect 0 (table 1))) + (core func (;39;) (canon task.return (result string) (memory 0) string-encoding=utf8)) + (core func (;40;) (canon task.return (result string) (memory 0) string-encoding=utf8)) (core instance (;5;) (export "$imports" (table 0)) - (export "0" (func 21)) - (export "1" (func 22)) - (export "2" (func 23)) - (export "3" (func 24)) - (export "4" (func 25)) - (export "5" (func 27)) - (export "6" (func 28)) - (export "7" (func 29)) - (export "8" (func 30)) - (export "9" (func 31)) + (export "0" (func 29)) + (export "1" (func 30)) + (export "2" (func 31)) + (export "3" (func 32)) + (export "4" (func 33)) + (export "5" (func 35)) + (export "6" (func 36)) + (export "7" (func 37)) + (export "8" (func 38)) + (export "9" (func 39)) + (export "10" (func 40)) ) (core instance (;6;) (instantiate 2 (with "" (instance 5)) ) ) (type (;0;) (func (param "s" string) (result string))) - (alias core export 4 "[async-lift-stackful]foo" (core func (;32;))) - (func (;0;) (type 0) (canon lift (core func 32) (memory 0) (realloc 26) string-encoding=utf8 async)) + (alias core export 4 "[async-lift-stackful]foo" (core func (;41;))) + (func (;0;) (type 0) (canon lift (core func 41) (memory 0) (realloc 34) string-encoding=utf8 async)) (export (;1;) "foo" (func 0)) (type (;1;) (func (param "s" string) (result string))) - (alias core export 4 "[async-lift-stackful]foo:foo/bar#foo" (core func (;33;))) - (func (;2;) (type 1) (canon lift (core func 33) (memory 0) (realloc 26) string-encoding=utf8 async)) + (alias core export 4 "[async-lift-stackful]foo:foo/bar#foo" (core func (;42;))) + (func (;2;) (type 1) (canon lift (core func 42) (memory 0) (realloc 34) 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/component.wit.print b/crates/wit-component/tests/components/threading/component.wit.print similarity index 100% rename from crates/wit-component/tests/components/async-builtins/component.wit.print rename to crates/wit-component/tests/components/threading/component.wit.print diff --git a/crates/wit-component/tests/components/async-builtins/module.wat b/crates/wit-component/tests/components/threading/module.wat similarity index 66% rename from crates/wit-component/tests/components/async-builtins/module.wat rename to crates/wit-component/tests/components/threading/module.wat index adb7a582ff..5f04ce2feb 100644 --- a/crates/wit-component/tests/components/async-builtins/module.wat +++ b/crates/wit-component/tests/components/threading/module.wat @@ -1,4 +1,5 @@ (module + (type $thread-start-func-ty (func (param i32))) (import "$root" "[backpressure-set]" (func (param i32))) (import "[export]$root" "[task-cancel]" (func)) (import "[export]$root" "[task-return]foo" (func (param i32 i32))) @@ -8,7 +9,7 @@ (import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32))) (import "$root" "[waitable-set-drop]" (func (param i32))) (import "$root" "[waitable-join]" (func (param i32 i32))) - (import "$root" "[yield]" (func (result i32))) + (import "$root" "[thread-yield]" (func (result i32))) (import "$root" "[subtask-drop]" (func (param i32))) (import "$root" "[subtask-cancel]" (func (param i32) (result i32))) (import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32))) @@ -20,8 +21,21 @@ (import "$root" "[error-context-drop]" (func (param i32))) (import "$root" "[context-get-0]" (func (result i32))) (import "$root" "[context-set-0]" (func (param i32))) + (import "$root" "[context-get-1]" (func (result i32))) + (import "$root" "[context-set-1]" (func (param i32))) + (import "$root" "[thread-index]" (func (result i32))) + ;; 0-0 means the type 0 is the thread start function type, table 0 is the funcref table + (import "$root" "[thread-new-indirect-0-0]" (func (param i32 i32) (result i32))) + (import "$root" "[thread-switch-to]" (func (param i32) (result i32))) + (import "$root" "[thread-suspend]" (func (result i32))) + (import "$root" "[thread-resume-later]" (func (param i32))) + (import "$root" "[thread-yield-to]" (func (param i32) (result i32))) + (func (export "thread_main") (param i32) unreachable) (func (export "[async-lift-stackful]foo") (param i32 i32) unreachable) (func (export "[async-lift-stackful]foo:foo/bar#foo") (param i32 i32) unreachable) (memory (export "memory") 1) + (table (export "indirect_function_table") 1 1 funcref) + (elem (i32.const 0) func 0) + (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) ) diff --git a/crates/wit-component/tests/components/async-builtins/module.wit b/crates/wit-component/tests/components/threading/module.wit similarity index 100% rename from crates/wit-component/tests/components/async-builtins/module.wit rename to crates/wit-component/tests/components/threading/module.wit diff --git a/src/bin/wasm-tools/dump.rs b/src/bin/wasm-tools/dump.rs index 42f81c2e88..4d5ff800e5 100644 --- a/src/bin/wasm-tools/dump.rs +++ b/src/bin/wasm-tools/dump.rs @@ -432,7 +432,7 @@ impl<'a> Dump<'a> { | CanonicalFunction::WaitableSetPoll { .. } | CanonicalFunction::WaitableSetDrop | CanonicalFunction::WaitableJoin - | CanonicalFunction::Yield { .. } + | CanonicalFunction::ThreadYield { .. } | CanonicalFunction::SubtaskDrop | CanonicalFunction::SubtaskCancel { .. } | CanonicalFunction::StreamNew { .. } @@ -451,7 +451,13 @@ impl<'a> Dump<'a> { | CanonicalFunction::FutureDropWritable { .. } | CanonicalFunction::ErrorContextNew { .. } | CanonicalFunction::ErrorContextDebugMessage { .. } - | CanonicalFunction::ErrorContextDrop => { + | CanonicalFunction::ErrorContextDrop + | CanonicalFunction::ThreadIndex + | CanonicalFunction::ThreadNewIndirect { .. } + | CanonicalFunction::ThreadSwitchTo { .. } + | CanonicalFunction::ThreadSuspend { .. } + | CanonicalFunction::ThreadResumeLater { .. } + | CanonicalFunction::ThreadYieldTo { .. } => { ("core func", &mut i.core_funcs) } }; diff --git a/tests/cli/component-model-async/abi.wast b/tests/cli/component-model-async/abi.wast index e684da4c94..c1d3e95857 100644 --- a/tests/cli/component-model-async/abi.wast +++ b/tests/cli/component-model-async/abi.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-fixed-size-list,cm-async-stackful +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-fixed-size-list,cm-threading ;; async lower (component diff --git a/tests/cli/component-model-async/futures.wast b/tests/cli/component-model-async/futures.wast index f7370fafec..0445b05d52 100644 --- a/tests/cli/component-model-async/futures.wast +++ b/tests/cli/component-model-async/futures.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-builtins +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading ;; future.new (component diff --git a/tests/cli/component-model-async/lift.wast b/tests/cli/component-model-async/lift.wast index dbc08bed7d..2e14fd400e 100644 --- a/tests/cli/component-model-async/lift.wast +++ b/tests/cli/component-model-async/lift.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-stackful +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading ;; async lift; no callback (component diff --git a/tests/cli/component-model-async/resources.wast b/tests/cli/component-model-async/resources.wast index 8ce9370a1a..6b97d98571 100644 --- a/tests/cli/component-model-async/resources.wast +++ b/tests/cli/component-model-async/resources.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-builtins +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading (component (type $t (resource (rep i32))) diff --git a/tests/cli/component-model-async/streams.wast b/tests/cli/component-model-async/streams.wast index 19a111dd84..f99c45923b 100644 --- a/tests/cli/component-model-async/streams.wast +++ b/tests/cli/component-model-async/streams.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-builtins +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading ;; stream.new (component diff --git a/tests/cli/component-model-async/task-builtins.wast b/tests/cli/component-model-async/threading.wast similarity index 67% rename from tests/cli/component-model-async/task-builtins.wast rename to tests/cli/component-model-async/threading.wast index 47795fe36a..dda48ceaf3 100644 --- a/tests/cli/component-model-async/task-builtins.wast +++ b/tests/cli/component-model-async/threading.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-builtins,cm-async-stackful,cm-error-context +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading,cm-error-context ;; backpressure.set (component @@ -102,7 +102,7 @@ (core module $m (import "" "waitable-set.wait" (func $waitable-set-wait (param i32 i32) (result i32))) ) - (core func $waitable-set-wait (canon waitable-set.wait async (memory $libc "memory"))) + (core func $waitable-set-wait (canon waitable-set.wait cancellable (memory $libc "memory"))) (core instance $i (instantiate $m (with "" (instance (export "waitable-set.wait" (func $waitable-set-wait)))))) ) @@ -114,7 +114,7 @@ (core module $m (import "" "waitable-set.wait" (func $waitable-set-wait (param i32) (result i32))) ) - (core func $waitable-set-wait (canon waitable-set.wait async (memory $libc "memory"))) + (core func $waitable-set-wait (canon waitable-set.wait cancellable (memory $libc "memory"))) (core instance $i (instantiate $m (with "" (instance (export "waitable-set.wait" (func $waitable-set-wait)))))) ) "type mismatch for export `waitable-set.wait` of module instantiation argument ``" @@ -127,7 +127,7 @@ (core module $m (import "" "waitable-set.poll" (func $waitable-set-poll (param i32 i32) (result i32))) ) - (core func $waitable-set-poll (canon waitable-set.poll async (memory $libc "memory"))) + (core func $waitable-set-poll (canon waitable-set.poll cancellable (memory $libc "memory"))) (core instance $i (instantiate $m (with "" (instance (export "waitable-set.poll" (func $waitable-set-poll)))))) ) @@ -139,7 +139,7 @@ (core module $m (import "" "waitable-set.poll" (func $waitable-set-poll (param i32) (result i32))) ) - (core func $waitable-set-poll (canon waitable-set.poll async (memory $libc "memory"))) + (core func $waitable-set-poll (canon waitable-set.poll cancellable (memory $libc "memory"))) (core instance $i (instantiate $m (with "" (instance (export "waitable-set.poll" (func $waitable-set-poll)))))) ) "type mismatch for export `waitable-set.poll` of module instantiation argument ``" @@ -179,25 +179,25 @@ "type mismatch for export `waitable.join` of module instantiation argument ``" ) -;; yield +;; thread.yield (component (core module $m - (import "" "yield" (func $yield (result i32))) + (import "" "thread.yield" (func $thread.yield (result i32))) ) - (core func $yield (canon yield async)) - (core instance $i (instantiate $m (with "" (instance (export "yield" (func $yield)))))) + (core func $thread.yield (canon thread.yield cancellable)) + (core instance $i (instantiate $m (with "" (instance (export "thread.yield" (func $thread.yield)))))) ) -;; yield; incorrect type +;; thread.yield; incorrect type (assert_invalid (component (core module $m - (import "" "yield" (func $yield (param i32) (result i32))) + (import "" "thread.yield" (func $thread.yield (param i32) (result i32))) ) - (core func $yield (canon yield async)) - (core instance $i (instantiate $m (with "" (instance (export "yield" (func $yield)))))) + (core func $thread.yield (canon thread.yield cancellable)) + (core instance $i (instantiate $m (with "" (instance (export "thread.yield" (func $thread.yield)))))) ) - "type mismatch for export `yield` of module instantiation argument ``" + "type mismatch for export `thread.yield` of module instantiation argument ``" ) ;; subtask.drop @@ -246,15 +246,21 @@ (component (core func $get0 (canon context.get i32 0)) (core func $set0 (canon context.set i32 0)) + (core func $get1 (canon context.get i32 1)) + (core func $set1 (canon context.set i32 1)) (core module $m (import "" "get0" (func (result i32))) (import "" "set0" (func (param i32))) + (import "" "get1" (func (result i32))) + (import "" "set1" (func (param i32))) ) (core instance (instantiate $m (with "" (instance (export "get0" (func $get0)) (export "set0" (func $set0)) + (export "get1" (func $get1)) + (export "set1" (func $set1)) )) )) ) @@ -275,20 +281,34 @@ "found: (func (param i32))") (assert_invalid (component - (core func (canon context.get i32 1))) - "immediate must be zero: 1") + (core module $m (import "" "" (func (param i32) (result i32)))) + (core func $f (canon context.get i32 1)) + (core instance $i (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + "found: (func (result i32))") +(assert_invalid + (component + (core module $m (import "" "" (func (param i32) (result i32)))) + (core func $f (canon context.set i32 1)) + (core instance $i (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + "found: (func (param i32))") +(assert_invalid + (component + (core func (canon context.get i32 2))) + "immediate must be zero or one: 2") (assert_invalid (component - (core func (canon context.set i32 1))) - "immediate must be zero: 1") + (core func (canon context.set i32 2))) + "immediate must be zero or one: 2") (assert_invalid (component (core func (canon context.get i32 100))) - "immediate must be zero: 100") + "immediate must be zero or one: 100") (assert_invalid (component (core func (canon context.set i32 100))) - "immediate must be zero: 100") + "immediate must be zero or one: 100") (assert_malformed (component quote "(core func (canon context.get i64 100))") @@ -313,6 +333,94 @@ "\0b\7e\00") ;; context.set i64 0 "invalid leading byte (0x7e) for context.set") +;; thread.new_indirect +(component + (core type $start (func (param $context i32))) + (core module $libc (table (export "start-table") 1 (ref null func))) + (core instance $libc (instantiate $libc)) + (core func $new_indirect (canon thread.new_indirect $start (table $libc "start-table"))) +) + +(component + (core type $start (func (param $context i32))) + (core module $libc (table (export "start-table") 1 (ref null func))) + (core instance $libc (instantiate $libc)) + (core func $new_indirect (canon thread.new_indirect $start (table $libc "start-table"))) + + (core module $m + (type $new_indirect_ty (func (param i32) (param i32) (result i32))) + (import "" "thread.new_indirect" (func (type $new_indirect_ty))) + ) + + (core instance (instantiate $m + (with "" (instance + (export "thread.new_indirect" (func $new_indirect)) + )) + )) +) + +(assert_invalid + (component + (core type $start (func (param i32))) + ;; Refer to a non-existent table type (i.e., 0); validation + ;; for `thread.new_indirect` happens first. + (core func $new_indirect (canon thread.new_indirect $start (table 0))) + ) + "unknown table 0: table index out of bounds" +) + +(assert_invalid + (component + (core type $start (func)) + (core module $libc (table (export "start-table") 1 (ref null func))) + (core instance $libc (instantiate $libc)) + (core func $new_indirect (canon thread.new_indirect $start (table $libc "start-table"))) + ) + "start function must take a single `i32` argument" +) + +;; thead.index +(component + (core module $m + (import "" "thread.index" (func $thread.index (result i32))) + ) + (core func $thread.index (canon thread.index)) + (core instance $i (instantiate $m (with "" (instance (export "thread.index" (func $thread.index)))))) +) + +;; thread.index; incorrect type +(assert_invalid + (component + (core module $m + (import "" "thread.index" (func $thread.index (param i32) (result i32))) + ) + (core func $thread.index (canon thread.index)) + (core instance $i (instantiate $m (with "" (instance (export "thread.index" (func $thread.index)))))) + ) + "type mismatch for export `thread.index` of module instantiation argument ``" +) + +;; thread.switch-to +(component + (core module $m + (import "" "thread.switch-to" (func $thread.switch-to (param i32) (result i32))) + ) + (core func $thread.switch-to (canon thread.switch-to cancellable)) + (core instance $i (instantiate $m (with "" (instance (export "thread.switch-to" (func $thread.switch-to)))))) +) + +;; thread.switch-to; incorrect type +(assert_invalid + (component + (core module $m + (import "" "thread.switch-to" (func $thread.switch-to (param i32))) + ) + (core func $thread.switch-to (canon thread.switch-to cancellable)) + (core instance $i (instantiate $m (with "" (instance (export "thread.switch-to" (func $thread.switch-to)))))) + ) + "type mismatch for export `thread.switch-to` of module instantiation argument ``" +) + ;; different forms of canonical intrinsics (component @@ -332,10 +440,12 @@ (core module $m (memory (export "m") 1) (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) + (table (export "start-table") 1 (ref null func)) ) (core instance $i (instantiate $m)) (alias core export $i "m" (core memory $m)) (alias core export $i "r" (core func $r)) + (alias core export $i "start-table" (core table $start-table)) (type $r (resource (rep i32))) (core func (canon resource.drop $r async)) @@ -381,9 +491,34 @@ (core func (canon context.get i32 0)) (canon context.get i32 0 (core func)) - (core func (canon context.set i32 0)) (canon context.set i32 0 (core func)) + (core func (canon context.get i32 1)) + (canon context.get i32 1 (core func)) + (core func (canon context.set i32 1)) + (canon context.set i32 1 (core func)) + + (core func (canon thread.yield)) + (canon thread.yield (core func)) + (core func (canon thread.yield cancellable)) + (canon thread.yield cancellable (core func)) + (core type $start (func (param i32))) + (core func (canon thread.new_indirect $start (table $start-table))) + (canon thread.new_indirect $start (table $start-table) (core func)) + (core func (canon thread.switch-to)) + (canon thread.switch-to (core func)) + (core func (canon thread.switch-to cancellable)) + (canon thread.switch-to cancellable (core func)) + (core func (canon thread.suspend)) + (canon thread.suspend (core func)) + (core func (canon thread.suspend cancellable)) + (canon thread.suspend cancellable (core func)) + (core func (canon thread.resume-later)) + (canon thread.resume-later (core func)) + (core func (canon thread.yield-to)) + (canon thread.yield-to (core func)) + (core func (canon thread.yield-to cancellable)) + (canon thread.yield-to cancellable (core func)) ) (component diff --git a/tests/cli/missing-features/async-builtins.wast b/tests/cli/missing-features/async-builtins.wast deleted file mode 100644 index ec4d52b4c7..0000000000 --- a/tests/cli/missing-features/async-builtins.wast +++ /dev/null @@ -1,43 +0,0 @@ -;; RUN: wast % --assert default --snapshot tests/snapshots \ -;; -f=cm-async,-cm-async-builtins - -;; {future,stream}.cancel-{read,write} -(assert_invalid - (component - (type $t (future)) - (core func (canon future.cancel-read $t async))) - "requires the component model async builtins feature") -(assert_invalid - (component - (type $t (future)) - (core func (canon future.cancel-write $t async))) - "requires the component model async builtins feature") -(assert_invalid - (component - (type $t (stream)) - (core func (canon stream.cancel-read $t async))) - "requires the component model async builtins feature") -(assert_invalid - (component - (type $t (stream)) - (core func (canon stream.cancel-write $t async))) - "requires the component model async builtins feature") - -(component - (type $f (future)) - (type $s (stream)) - (core func (canon future.cancel-read $f)) - (core func (canon future.cancel-write $f)) - (core func (canon stream.cancel-read $s)) - (core func (canon stream.cancel-write $s)) -) - -;; async resource.drop -(assert_invalid - (component - (type $t (resource (rep i32))) - (core func (canon resource.drop $t async))) - "requires the component model async builtins feature") -(component - (type $t (resource (rep i32))) - (core func (canon resource.drop $t))) diff --git a/tests/cli/missing-features/async-stackful.wast b/tests/cli/missing-features/async-stackful.wast deleted file mode 100644 index cf800e4c14..0000000000 --- a/tests/cli/missing-features/async-stackful.wast +++ /dev/null @@ -1,51 +0,0 @@ -;; RUN: wast % --assert default --snapshot tests/snapshots \ -;; -f=cm-async,-cm-async-builtins - -(assert_invalid - (component - (core module $m (func (export "foo") (param i32))) - (core instance $i (instantiate $m)) - - (func (export "foo") (param "p1" u32) (result u32) - (canon lift (core func $i "foo") async) - ) - ) - "requires the async stackful feature") - -;; waitable-set.wait async -(assert_invalid - (component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func (canon waitable-set.wait async (memory $libc "memory"))) - ) - "requires the component model async stackful feature") - -(component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func (canon waitable-set.wait (memory $libc "memory"))) -) - -;; waitable-set.poll async -(assert_invalid - (component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func (canon waitable-set.poll async (memory $libc "memory"))) - ) - "requires the component model async stackful feature") - -(component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func (canon waitable-set.poll (memory $libc "memory"))) -) - -;; yield -(assert_invalid - (component (core func (canon yield async))) - "requires the component model async stackful feature") - -(component (core func (canon yield))) - diff --git a/tests/cli/missing-features/component-model/async.wast b/tests/cli/missing-features/component-model/async.wast index f12c644c0a..1c35538146 100644 --- a/tests/cli/missing-features/component-model/async.wast +++ b/tests/cli/missing-features/component-model/async.wast @@ -80,7 +80,7 @@ (core module $m (import "" "waitable-set.wait" (func $waitable-set-wait (param i32) (result i32))) ) - (core func $waitable-set-wait (canon waitable-set.wait async (memory $libc "memory"))) + (core func $waitable-set-wait (canon waitable-set.wait (memory $libc "memory"))) (core instance $i (instantiate $m (with "" (instance (export "waitable-set.wait" (func $waitable-set-wait)))))) ) "`waitable-set.wait` requires the component model async feature" @@ -94,7 +94,7 @@ (core module $m (import "" "waitable-set.poll" (func $waitable-set-poll (param i32) (result i32))) ) - (core func $waitable-set-poll (canon waitable-set.poll async (memory $libc "memory"))) + (core func $waitable-set-poll (canon waitable-set.poll (memory $libc "memory"))) (core instance $i (instantiate $m (with "" (instance (export "waitable-set.poll" (func $waitable-set-poll)))))) ) "`waitable-set.poll` requires the component model async feature" @@ -112,18 +112,6 @@ "`waitable.join` requires the component model async feature" ) -;; yield -(assert_invalid - (component - (core module $m - (import "" "yield" (func $yield)) - ) - (core func $yield (canon yield async)) - (core instance $i (instantiate $m (with "" (instance (export "yield" (func $yield)))))) - ) - "`yield` requires the component model async feature" -) - ;; subtask.drop (assert_invalid (component @@ -352,7 +340,7 @@ (type $t (resource (rep i32))) (core func $f (canon resource.drop $t async)) ) - "requires the component model async builtins feature" + "requires the component model threading feature" ) (assert_invalid diff --git a/tests/cli/missing-features/component-model/threading.wast b/tests/cli/missing-features/component-model/threading.wast new file mode 100644 index 0000000000..60e3e243a7 --- /dev/null +++ b/tests/cli/missing-features/component-model/threading.wast @@ -0,0 +1,101 @@ +;; RUN: wast % --assert default --snapshot tests/snapshots \ +;; -f=cm-async,-cm-threading + +(assert_invalid + (component + (core module $m (func (export "foo") (param i32))) + (core instance $i (instantiate $m)) + + (func (export "foo") (param "p1" u32) (result u32) + (canon lift (core func $i "foo") async) + ) + ) + "requires the component model threading feature") + +;; waitable-set.wait async +(assert_invalid + (component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func (canon waitable-set.wait cancellable (memory $libc "memory"))) + ) + "requires the component model threading feature") + +(component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func (canon waitable-set.wait (memory $libc "memory"))) +) + +;; waitable-set.poll cancellable +(assert_invalid + (component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func (canon waitable-set.poll cancellable (memory $libc "memory"))) + ) + "requires the component model threading feature") + +(component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func (canon waitable-set.poll (memory $libc "memory"))) +) + +;; thread.yield +(assert_invalid + (component (core func (canon thread.yield cancellable))) + "requires the component model threading feature") +(component (core func (canon thread.yield))) + +;; {future,stream}.cancel-{read,write} +(assert_invalid + (component + (type $t (future)) + (core func (canon future.cancel-read $t async))) + "requires the component model threading feature") +(assert_invalid + (component + (type $t (future)) + (core func (canon future.cancel-write $t async))) + "requires the component model threading feature") +(assert_invalid + (component + (type $t (stream)) + (core func (canon stream.cancel-read $t async))) + "requires the component model threading feature") +(assert_invalid + (component + (type $t (stream)) + (core func (canon stream.cancel-write $t async))) + "requires the component model threading feature") + +(component + (type $f (future)) + (type $s (stream)) + (core func (canon future.cancel-read $f)) + (core func (canon future.cancel-write $f)) + (core func (canon stream.cancel-read $s)) + (core func (canon stream.cancel-write $s)) +) + +;; async resource.drop +(assert_invalid + (component + (type $t (resource (rep i32))) + (core func (canon resource.drop $t async))) + "requires the component model threading feature") +(component + (type $t (resource (rep i32))) + (core func (canon resource.drop $t))) + +;; thread.* +(assert_invalid + (component + (core func (canon thread.index)) + (core func (canon thread.new_indirect 0 (table 0))) + (core func (canon thread.switch-to)) + (core func (canon thread.suspend)) + (core func (canon thread.resume-later)) + (core func (canon thread.yield-to))) + "requires the component model threading feature") \ No newline at end of file diff --git a/tests/cli/validate-unknown-features.wat.stderr b/tests/cli/validate-unknown-features.wat.stderr index 8b93bad803..56f34d94a2 100644 --- a/tests/cli/validate-unknown-features.wat.stderr +++ b/tests/cli/validate-unknown-features.wat.stderr @@ -1,4 +1,4 @@ error: invalid value 'unknown' for '--features ': unknown feature `unknown` -Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, legacy-exceptions, gc-types, stack-switching, wide-arithmetic, cm-values, cm-nested-names, cm-async, cm-async-stackful, cm-async-builtins, cm-error-context, cm-fixed-size-list, cm-gc, call-indirect-overlong, bulk-memory-opt, mvp, wasm1, wasm2, wasm3, lime1, all +Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, legacy-exceptions, gc-types, stack-switching, wide-arithmetic, cm-values, cm-nested-names, cm-async, cm-threading, cm-error-context, cm-fixed-size-list, cm-gc, call-indirect-overlong, bulk-memory-opt, mvp, wasm1, wasm2, wasm3, lime1, all For more information, try '--help'. diff --git a/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print b/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print index d99f410bf0..cc67534a58 100644 --- a/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print +++ b/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print @@ -1,9 +1,9 @@ (component (core module $m (;0;) (type (;0;) (func (result i32))) - (import "" "yield" (func $yield (;0;) (type 0))) + (import "" "thread.yield" (func $yield (;0;) (type 0))) ) - (core func $yield (;0;) (canon yield async)) + (core func $yield (;0;) (canon thread.yield async)) (core instance (;0;) (export "yield" (func $yield)) ) diff --git a/tests/snapshots/cli/component-model-async/threading.wast.json b/tests/snapshots/cli/component-model-async/threading.wast.json new file mode 100644 index 0000000000..552d8daf15 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast.json @@ -0,0 +1,322 @@ +{ + "source_filename": "tests/cli/component-model-async/threading.wast", + "commands": [ + { + "type": "module", + "line": 4, + "filename": "threading.0.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 14, + "filename": "threading.1.wasm", + "module_type": "binary", + "text": "type mismatch for export `backpressure.set` of module instantiation argument ``" + }, + { + "type": "module", + "line": 25, + "filename": "threading.2.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 34, + "filename": "threading.3.wasm", + "module_type": "binary", + "text": "cannot specify `async` option on `task.return`" + }, + { + "type": "assert_invalid", + "line": 38, + "filename": "threading.4.wasm", + "module_type": "binary", + "text": "cannot specify callback without async" + }, + { + "type": "assert_invalid", + "line": 45, + "filename": "threading.5.wasm", + "module_type": "binary", + "text": "cannot specify `post-return` option on `task.return`" + }, + { + "type": "assert_invalid", + "line": 52, + "filename": "threading.6.wasm", + "module_type": "binary", + "text": "cannot specify `realloc` option on `task.return`" + }, + { + "type": "module", + "line": 61, + "filename": "threading.7.wasm", + "module_type": "binary" + }, + { + "type": "module", + "line": 73, + "filename": "threading.8.wasm", + "module_type": "binary" + }, + { + "type": "module", + "line": 82, + "filename": "threading.9.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 90, + "filename": "threading.10.wasm", + "module_type": "binary", + "text": "type mismatch for export `waitable-set.new` of module instantiation argument ``" + }, + { + "type": "module", + "line": 99, + "filename": "threading.11.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 111, + "filename": "threading.12.wasm", + "module_type": "binary", + "text": "type mismatch for export `waitable-set.wait` of module instantiation argument ``" + }, + { + "type": "module", + "line": 124, + "filename": "threading.13.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 136, + "filename": "threading.14.wasm", + "module_type": "binary", + "text": "type mismatch for export `waitable-set.poll` of module instantiation argument ``" + }, + { + "type": "module", + "line": 149, + "filename": "threading.15.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 157, + "filename": "threading.16.wasm", + "module_type": "binary", + "text": "type mismatch for export `waitable-set.drop` of module instantiation argument ``" + }, + { + "type": "module", + "line": 166, + "filename": "threading.17.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 174, + "filename": "threading.18.wasm", + "module_type": "binary", + "text": "type mismatch for export `waitable.join` of module instantiation argument ``" + }, + { + "type": "module", + "line": 183, + "filename": "threading.19.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 193, + "filename": "threading.20.wasm", + "module_type": "binary", + "text": "type mismatch for export `thread.yield` of module instantiation argument ``" + }, + { + "type": "module", + "line": 204, + "filename": "threading.21.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 214, + "filename": "threading.22.wasm", + "module_type": "binary", + "text": "type mismatch for export `subtask.drop` of module instantiation argument ``" + }, + { + "type": "module", + "line": 225, + "filename": "threading.23.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 235, + "filename": "threading.24.wasm", + "module_type": "binary", + "text": "type mismatch for export `subtask.cancel` of module instantiation argument ``" + }, + { + "type": "module", + "line": 246, + "filename": "threading.25.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 269, + "filename": "threading.26.wasm", + "module_type": "binary", + "text": "found: (func (result i32))" + }, + { + "type": "assert_invalid", + "line": 276, + "filename": "threading.27.wasm", + "module_type": "binary", + "text": "found: (func (param i32))" + }, + { + "type": "assert_invalid", + "line": 283, + "filename": "threading.28.wasm", + "module_type": "binary", + "text": "found: (func (result i32))" + }, + { + "type": "assert_invalid", + "line": 290, + "filename": "threading.29.wasm", + "module_type": "binary", + "text": "found: (func (param i32))" + }, + { + "type": "assert_invalid", + "line": 297, + "filename": "threading.30.wasm", + "module_type": "binary", + "text": "immediate must be zero or one: 2" + }, + { + "type": "assert_invalid", + "line": 301, + "filename": "threading.31.wasm", + "module_type": "binary", + "text": "immediate must be zero or one: 2" + }, + { + "type": "assert_invalid", + "line": 305, + "filename": "threading.32.wasm", + "module_type": "binary", + "text": "immediate must be zero or one: 100" + }, + { + "type": "assert_invalid", + "line": 309, + "filename": "threading.33.wasm", + "module_type": "binary", + "text": "immediate must be zero or one: 100" + }, + { + "type": "assert_malformed", + "line": 313, + "filename": "threading.34.wat", + "module_type": "text", + "text": "expected keyword `i32`" + }, + { + "type": "assert_malformed", + "line": 317, + "filename": "threading.35.wat", + "module_type": "text", + "text": "expected keyword `i32`" + }, + { + "type": "assert_malformed", + "line": 322, + "filename": "threading.36.wasm", + "module_type": "binary", + "text": "invalid leading byte (0x7e) for context.get" + }, + { + "type": "assert_malformed", + "line": 329, + "filename": "threading.37.wasm", + "module_type": "binary", + "text": "invalid leading byte (0x7e) for context.set" + }, + { + "type": "module", + "line": 337, + "filename": "threading.38.wasm", + "module_type": "binary" + }, + { + "type": "module", + "line": 344, + "filename": "threading.39.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 363, + "filename": "threading.40.wasm", + "module_type": "binary", + "text": "unknown table 0: table index out of bounds" + }, + { + "type": "assert_invalid", + "line": 373, + "filename": "threading.41.wasm", + "module_type": "binary", + "text": "start function must take a single `i32` argument" + }, + { + "type": "module", + "line": 383, + "filename": "threading.42.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 393, + "filename": "threading.43.wasm", + "module_type": "binary", + "text": "type mismatch for export `thread.index` of module instantiation argument ``" + }, + { + "type": "module", + "line": 404, + "filename": "threading.44.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 414, + "filename": "threading.45.wasm", + "module_type": "binary", + "text": "type mismatch for export `thread.switch-to` of module instantiation argument ``" + }, + { + "type": "module", + "line": 426, + "filename": "threading.46.wasm", + "module_type": "binary" + }, + { + "type": "module", + "line": 524, + "filename": "threading.47.wasm", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/cli/component-model-async/threading.wast/0.print b/tests/snapshots/cli/component-model-async/threading.wast/0.print new file mode 100644 index 0000000000..686f8faf09 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/0.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32))) + (import "" "backpressure.set" (func $backpressure.set (;0;) (type 0))) + ) + (core func $backpressure.set (;0;) (canon backpressure.set)) + (core instance (;0;) + (export "backpressure.set" (func $backpressure.set)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/11.print b/tests/snapshots/cli/component-model-async/threading.wast/11.print new file mode 100644 index 0000000000..30cc2c0977 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/11.print @@ -0,0 +1,20 @@ +(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 i32) (result i32))) + (import "" "waitable-set.wait" (func $waitable-set-wait (;0;) (type 0))) + ) + (alias core export $libc "memory" (core memory (;0;))) + (core func $waitable-set-wait (;0;) (canon waitable-set.wait cancellable (memory 0))) + (core instance (;1;) + (export "waitable-set.wait" (func $waitable-set-wait)) + ) + (core instance $i (;2;) (instantiate $m + (with "" (instance 1)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/13.print b/tests/snapshots/cli/component-model-async/threading.wast/13.print new file mode 100644 index 0000000000..4690399a01 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/13.print @@ -0,0 +1,20 @@ +(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 i32) (result i32))) + (import "" "waitable-set.poll" (func $waitable-set-poll (;0;) (type 0))) + ) + (alias core export $libc "memory" (core memory (;0;))) + (core func $waitable-set-poll (;0;) (canon waitable-set.poll cancellable (memory 0))) + (core instance (;1;) + (export "waitable-set.poll" (func $waitable-set-poll)) + ) + (core instance $i (;2;) (instantiate $m + (with "" (instance 1)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/15.print b/tests/snapshots/cli/component-model-async/threading.wast/15.print new file mode 100644 index 0000000000..8470c01ee8 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/15.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32))) + (import "" "waitable-set.drop" (func (;0;) (type 0))) + ) + (core func $waitable-set-drop (;0;) (canon waitable-set.drop)) + (core instance (;0;) + (export "waitable-set.drop" (func $waitable-set-drop)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/17.print b/tests/snapshots/cli/component-model-async/threading.wast/17.print new file mode 100644 index 0000000000..3667f8c326 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/17.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32 i32))) + (import "" "waitable.join" (func (;0;) (type 0))) + ) + (core func $waitable.join (;0;) (canon waitable.join)) + (core instance (;0;) + (export "waitable.join" (func $waitable.join)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/19.print b/tests/snapshots/cli/component-model-async/threading.wast/19.print new file mode 100644 index 0000000000..f8845497a5 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/19.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (result i32))) + (import "" "thread.yield" (func $thread.yield (;0;) (type 0))) + ) + (core func $thread.yield (;0;) (canon thread.yield cancellable)) + (core instance (;0;) + (export "thread.yield" (func $thread.yield)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/2.print b/tests/snapshots/cli/component-model-async/threading.wast/2.print new file mode 100644 index 0000000000..84b3158da3 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/2.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32))) + (import "" "task.return" (func $task-return (;0;) (type 0))) + ) + (core func $task-return (;0;) (canon task.return (result u32))) + (core instance (;0;) + (export "task.return" (func $task-return)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/21.print b/tests/snapshots/cli/component-model-async/threading.wast/21.print new file mode 100644 index 0000000000..038cc25c37 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/21.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/cli/component-model-async/threading.wast/23.print b/tests/snapshots/cli/component-model-async/threading.wast/23.print new file mode 100644 index 0000000000..234b55d33f --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/23.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32) (result i32))) + (import "" "subtask.cancel" (func $subtask-cancel (;0;) (type 0))) + ) + (core func $subtask-cancel (;0;) (canon subtask.cancel)) + (core instance (;0;) + (export "subtask.cancel" (func $subtask-cancel)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/25.print b/tests/snapshots/cli/component-model-async/threading.wast/25.print new file mode 100644 index 0000000000..615e61f119 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/25.print @@ -0,0 +1,24 @@ +(component + (core func $get0 (;0;) (canon context.get i32 0)) + (core func $set0 (;1;) (canon context.set i32 0)) + (core func $get1 (;2;) (canon context.get i32 1)) + (core func $set1 (;3;) (canon context.set i32 1)) + (core module $m (;0;) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (import "" "get0" (func (;0;) (type 0))) + (import "" "set0" (func (;1;) (type 1))) + (import "" "get1" (func (;2;) (type 0))) + (import "" "set1" (func (;3;) (type 1))) + ) + (core instance (;0;) + (export "get0" (func $get0)) + (export "set0" (func $set0)) + (export "get1" (func $get1)) + (export "set1" (func $set1)) + ) + (core instance (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/36.print b/tests/snapshots/cli/component-model-async/threading.wast/36.print new file mode 100644 index 0000000000..60858a0d95 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/36.print @@ -0,0 +1,10 @@ +(component + (core type $start (;0;) (func (param i32))) + (core module $libc (;0;) + (table (;0;) 1 funcref) + (export "start-table" (table 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "start-table" (core table (;0;))) + (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/37.print b/tests/snapshots/cli/component-model-async/threading.wast/37.print new file mode 100644 index 0000000000..ee4c6537b9 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/37.print @@ -0,0 +1,21 @@ +(component + (core type $start (;0;) (func (param i32))) + (core module $libc (;0;) + (table (;0;) 1 funcref) + (export "start-table" (table 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "start-table" (core table (;0;))) + (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) + (core module $m (;1;) + (type $new_indirect_ty (;0;) (func (param i32 i32) (result i32))) + (import "" "new_indirect" (func (;0;) (type $new_indirect_ty))) + ) + (core instance (;1;) + (export "new_indirect" (func $new_indirect)) + ) + (core instance (;2;) (instantiate $m + (with "" (instance 1)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/38.print b/tests/snapshots/cli/component-model-async/threading.wast/38.print new file mode 100644 index 0000000000..60858a0d95 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/38.print @@ -0,0 +1,10 @@ +(component + (core type $start (;0;) (func (param i32))) + (core module $libc (;0;) + (table (;0;) 1 funcref) + (export "start-table" (table 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "start-table" (core table (;0;))) + (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/39.print b/tests/snapshots/cli/component-model-async/threading.wast/39.print new file mode 100644 index 0000000000..40cbf9610b --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/39.print @@ -0,0 +1,21 @@ +(component + (core type $start (;0;) (func (param i32))) + (core module $libc (;0;) + (table (;0;) 1 funcref) + (export "start-table" (table 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "start-table" (core table (;0;))) + (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) + (core module $m (;1;) + (type $new_indirect_ty (;0;) (func (param i32 i32) (result i32))) + (import "" "thread.new_indirect" (func (;0;) (type $new_indirect_ty))) + ) + (core instance (;1;) + (export "thread.new_indirect" (func $new_indirect)) + ) + (core instance (;2;) (instantiate $m + (with "" (instance 1)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/40.print b/tests/snapshots/cli/component-model-async/threading.wast/40.print new file mode 100644 index 0000000000..216e7af76f --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/40.print @@ -0,0 +1,69 @@ +(component + (core func (;0;) (canon backpressure.set)) + (core func (;1;) (canon backpressure.set)) + (core func (;2;) (canon task.return)) + (core func (;3;) (canon task.return)) + (core func (;4;) (canon task.cancel)) + (core func (;5;) (canon task.cancel)) + (core func (;6;) (canon subtask.drop)) + (core func (;7;) (canon subtask.drop)) + (core func (;8;) (canon subtask.cancel)) + (core func (;9;) (canon subtask.cancel)) + (core func (;10;) (canon subtask.cancel async)) + (core func (;11;) (canon subtask.cancel async)) + (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)) + (alias core export $i "m" (core memory $m (;0;))) + (alias core export $i "r" (core func $r (;12;))) + (type $r (;0;) (resource (rep i32))) + (core func (;13;) (canon resource.drop $r async)) + (core func (;14;) (canon resource.drop $r async)) + (type $s (;1;) (stream)) + (type $f (;2;) (future)) + (core func (;15;) (canon future.new $f)) + (core func (;16;) (canon future.new $f)) + (core func (;17;) (canon stream.new $s)) + (core func (;18;) (canon stream.new $s)) + (core func (;19;) (canon future.cancel-read $f)) + (core func (;20;) (canon future.cancel-read $f)) + (core func (;21;) (canon stream.cancel-read $s)) + (core func (;22;) (canon stream.cancel-read $s)) + (core func (;23;) (canon future.cancel-write $f)) + (core func (;24;) (canon future.cancel-write $f)) + (core func (;25;) (canon stream.cancel-write $s)) + (core func (;26;) (canon stream.cancel-write $s)) + (core func (;27;) (canon future.drop-readable $f)) + (core func (;28;) (canon future.drop-readable $f)) + (core func (;29;) (canon future.drop-writable $f)) + (core func (;30;) (canon future.drop-writable $f)) + (core func (;31;) (canon stream.drop-readable $s)) + (core func (;32;) (canon stream.drop-readable $s)) + (core func (;33;) (canon stream.drop-writable $s)) + (core func (;34;) (canon stream.drop-writable $s)) + (core func (;35;) (canon future.read $f (memory $m))) + (core func (;36;) (canon future.read $f (memory $m))) + (core func (;37;) (canon future.write $f (memory $m))) + (core func (;38;) (canon future.write $f (memory $m))) + (core func (;39;) (canon stream.read $s (memory $m))) + (core func (;40;) (canon stream.read $s (memory $m))) + (core func (;41;) (canon stream.write $s (memory $m))) + (core func (;42;) (canon stream.write $s (memory $m))) + (core func (;43;) (canon error-context.new (memory $m))) + (core func (;44;) (canon error-context.new (memory $m))) + (core func (;45;) (canon error-context.debug-message (memory $m) (realloc $r))) + (core func (;46;) (canon error-context.debug-message (memory $m) (realloc $r))) + (core func (;47;) (canon error-context.drop)) + (core func (;48;) (canon error-context.drop)) + (core func (;49;) (canon context.get i32 0)) + (core func (;50;) (canon context.get i32 0)) + (core func (;51;) (canon context.set i32 0)) + (core func (;52;) (canon context.set i32 0)) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/41.print b/tests/snapshots/cli/component-model-async/threading.wast/41.print new file mode 100644 index 0000000000..28dfb3b000 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/41.print @@ -0,0 +1,4 @@ +(component + (type (;0;) (stream u8)) + (core func (;0;) (canon task.return (result 0))) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/42.print b/tests/snapshots/cli/component-model-async/threading.wast/42.print new file mode 100644 index 0000000000..d36b57ffea --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/42.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (result i32))) + (import "" "thread.index" (func $thread.index (;0;) (type 0))) + ) + (core func $thread.index (;0;) (canon thread.index)) + (core instance (;0;) + (export "thread.index" (func $thread.index)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/43.print b/tests/snapshots/cli/component-model-async/threading.wast/43.print new file mode 100644 index 0000000000..28dfb3b000 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/43.print @@ -0,0 +1,4 @@ +(component + (type (;0;) (stream u8)) + (core func (;0;) (canon task.return (result 0))) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/44.print b/tests/snapshots/cli/component-model-async/threading.wast/44.print new file mode 100644 index 0000000000..6c92cb7183 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/44.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32) (result i32))) + (import "" "thread.switch-to" (func $thread.switch-to (;0;) (type 0))) + ) + (core func $thread.switch-to (;0;) (canon thread.switch-to cancellable)) + (core instance (;0;) + (export "thread.switch-to" (func $thread.switch-to)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/46.print b/tests/snapshots/cli/component-model-async/threading.wast/46.print new file mode 100644 index 0000000000..b79cfae234 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/46.print @@ -0,0 +1,97 @@ +(component + (core func (;0;) (canon backpressure.set)) + (core func (;1;) (canon backpressure.set)) + (core func (;2;) (canon task.return)) + (core func (;3;) (canon task.return)) + (core func (;4;) (canon task.cancel)) + (core func (;5;) (canon task.cancel)) + (core func (;6;) (canon subtask.drop)) + (core func (;7;) (canon subtask.drop)) + (core func (;8;) (canon subtask.cancel)) + (core func (;9;) (canon subtask.cancel)) + (core func (;10;) (canon subtask.cancel async)) + (core func (;11;) (canon subtask.cancel async)) + (core module $m (;0;) + (type (;0;) (func (param i32 i32 i32 i32) (result i32))) + (table (;0;) 1 funcref) + (memory (;0;) 1) + (export "m" (memory 0)) + (export "r" (func 0)) + (export "start-table" (table 0)) + (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) + unreachable + ) + ) + (core instance $i (;0;) (instantiate $m)) + (alias core export $i "m" (core memory $m (;0;))) + (alias core export $i "r" (core func $r (;12;))) + (alias core export $i "start-table" (core table $start-table (;0;))) + (type $r (;0;) (resource (rep i32))) + (core func (;13;) (canon resource.drop $r async)) + (core func (;14;) (canon resource.drop $r async)) + (type $s (;1;) (stream)) + (type $f (;2;) (future)) + (core func (;15;) (canon future.new $f)) + (core func (;16;) (canon future.new $f)) + (core func (;17;) (canon stream.new $s)) + (core func (;18;) (canon stream.new $s)) + (core func (;19;) (canon future.cancel-read $f)) + (core func (;20;) (canon future.cancel-read $f)) + (core func (;21;) (canon stream.cancel-read $s)) + (core func (;22;) (canon stream.cancel-read $s)) + (core func (;23;) (canon future.cancel-write $f)) + (core func (;24;) (canon future.cancel-write $f)) + (core func (;25;) (canon stream.cancel-write $s)) + (core func (;26;) (canon stream.cancel-write $s)) + (core func (;27;) (canon future.drop-readable $f)) + (core func (;28;) (canon future.drop-readable $f)) + (core func (;29;) (canon future.drop-writable $f)) + (core func (;30;) (canon future.drop-writable $f)) + (core func (;31;) (canon stream.drop-readable $s)) + (core func (;32;) (canon stream.drop-readable $s)) + (core func (;33;) (canon stream.drop-writable $s)) + (core func (;34;) (canon stream.drop-writable $s)) + (core func (;35;) (canon future.read $f (memory $m))) + (core func (;36;) (canon future.read $f (memory $m))) + (core func (;37;) (canon future.write $f (memory $m))) + (core func (;38;) (canon future.write $f (memory $m))) + (core func (;39;) (canon stream.read $s (memory $m))) + (core func (;40;) (canon stream.read $s (memory $m))) + (core func (;41;) (canon stream.write $s (memory $m))) + (core func (;42;) (canon stream.write $s (memory $m))) + (core func (;43;) (canon error-context.new (memory $m))) + (core func (;44;) (canon error-context.new (memory $m))) + (core func (;45;) (canon error-context.debug-message (memory $m) (realloc $r))) + (core func (;46;) (canon error-context.debug-message (memory $m) (realloc $r))) + (core func (;47;) (canon error-context.drop)) + (core func (;48;) (canon error-context.drop)) + (core func (;49;) (canon context.get i32 0)) + (core func (;50;) (canon context.get i32 0)) + (core func (;51;) (canon context.set i32 0)) + (core func (;52;) (canon context.set i32 0)) + (core func (;53;) (canon context.get i32 1)) + (core func (;54;) (canon context.get i32 1)) + (core func (;55;) (canon context.set i32 1)) + (core func (;56;) (canon context.set i32 1)) + (core func (;57;) (canon thread.yield)) + (core func (;58;) (canon thread.yield)) + (core func (;59;) (canon thread.yield cancellable)) + (core func (;60;) (canon thread.yield cancellable)) + (core type $start (;0;) (func (param i32))) + (core func (;61;) (canon thread.new_indirect $start (table $start-table))) + (core func (;62;) (canon thread.new_indirect $start (table $start-table))) + (core func (;63;) (canon thread.switch-to)) + (core func (;64;) (canon thread.switch-to)) + (core func (;65;) (canon thread.switch-to cancellable)) + (core func (;66;) (canon thread.switch-to cancellable)) + (core func (;67;) (canon thread.suspend)) + (core func (;68;) (canon thread.suspend)) + (core func (;69;) (canon thread.suspend cancellable)) + (core func (;70;) (canon thread.suspend cancellable)) + (core func (;71;) (canon thread.resume-later)) + (core func (;72;) (canon thread.resume-later)) + (core func (;73;) (canon thread.yield-to)) + (core func (;74;) (canon thread.yield-to)) + (core func (;75;) (canon thread.yield-to cancellable)) + (core func (;76;) (canon thread.yield-to cancellable)) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/47.print b/tests/snapshots/cli/component-model-async/threading.wast/47.print new file mode 100644 index 0000000000..28dfb3b000 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/47.print @@ -0,0 +1,4 @@ +(component + (type (;0;) (stream u8)) + (core func (;0;) (canon task.return (result 0))) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/7.print b/tests/snapshots/cli/component-model-async/threading.wast/7.print new file mode 100644 index 0000000000..48e7d0adab --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/7.print @@ -0,0 +1,12 @@ +(component + (core module $m (;0;) + (memory (;0;) 1) + (export "m" (memory 0)) + ) + (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))) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/8.print b/tests/snapshots/cli/component-model-async/threading.wast/8.print new file mode 100644 index 0000000000..0162fff210 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/8.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func)) + (import "" "task.cancel" (func $task-cancel (;0;) (type 0))) + ) + (core func $task-cancel (;0;) (canon task.cancel)) + (core instance (;0;) + (export "task.cancel" (func $task-cancel)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/9.print b/tests/snapshots/cli/component-model-async/threading.wast/9.print new file mode 100644 index 0000000000..967b3b8c79 --- /dev/null +++ b/tests/snapshots/cli/component-model-async/threading.wast/9.print @@ -0,0 +1,14 @@ +(component + (core module $m (;0;) + (type (;0;) (func (result i32))) + (import "" "waitable-set.new" (func (;0;) (type 0))) + ) + (core func $waitable-set-new (;0;) (canon waitable-set.new)) + (core instance (;0;) + (export "waitable-set.new" (func $waitable-set-new)) + ) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) + ) + ) +) diff --git a/tests/snapshots/cli/missing-features/async-builtins.wast.json b/tests/snapshots/cli/missing-features/async-builtins.wast.json deleted file mode 100644 index 92de6d7617..0000000000 --- a/tests/snapshots/cli/missing-features/async-builtins.wast.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "source_filename": "tests/cli/missing-features/async-builtins.wast", - "commands": [ - { - "type": "assert_invalid", - "line": 6, - "filename": "async-builtins.0.wasm", - "module_type": "binary", - "text": "requires the component model async builtins feature" - }, - { - "type": "assert_invalid", - "line": 11, - "filename": "async-builtins.1.wasm", - "module_type": "binary", - "text": "requires the component model async builtins feature" - }, - { - "type": "assert_invalid", - "line": 16, - "filename": "async-builtins.2.wasm", - "module_type": "binary", - "text": "requires the component model async builtins feature" - }, - { - "type": "assert_invalid", - "line": 21, - "filename": "async-builtins.3.wasm", - "module_type": "binary", - "text": "requires the component model async builtins feature" - }, - { - "type": "module", - "line": 26, - "filename": "async-builtins.4.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 37, - "filename": "async-builtins.5.wasm", - "module_type": "binary", - "text": "requires the component model async builtins feature" - }, - { - "type": "module", - "line": 41, - "filename": "async-builtins.6.wasm", - "module_type": "binary" - } - ] -} \ No newline at end of file diff --git a/tests/snapshots/cli/missing-features/async-stackful.wast.json b/tests/snapshots/cli/missing-features/async-stackful.wast.json deleted file mode 100644 index b12de4d023..0000000000 --- a/tests/snapshots/cli/missing-features/async-stackful.wast.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "source_filename": "tests/cli/missing-features/async-stackful.wast", - "commands": [ - { - "type": "assert_invalid", - "line": 5, - "filename": "async-stackful.0.wasm", - "module_type": "binary", - "text": "requires the async stackful feature" - }, - { - "type": "assert_invalid", - "line": 17, - "filename": "async-stackful.1.wasm", - "module_type": "binary", - "text": "requires the component model async stackful feature" - }, - { - "type": "module", - "line": 24, - "filename": "async-stackful.2.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 32, - "filename": "async-stackful.3.wasm", - "module_type": "binary", - "text": "requires the component model async stackful feature" - }, - { - "type": "module", - "line": 39, - "filename": "async-stackful.4.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 47, - "filename": "async-stackful.5.wasm", - "module_type": "binary", - "text": "requires the component model async stackful feature" - }, - { - "type": "module", - "line": 50, - "filename": "async-stackful.6.wasm", - "module_type": "binary" - } - ] -} \ No newline at end of file diff --git a/tests/snapshots/cli/missing-features/async-stackful.wast/6.print b/tests/snapshots/cli/missing-features/async-stackful.wast/6.print index ffbb762e32..a1d9c7a10c 100644 --- a/tests/snapshots/cli/missing-features/async-stackful.wast/6.print +++ b/tests/snapshots/cli/missing-features/async-stackful.wast/6.print @@ -1,3 +1,3 @@ (component - (core func (;0;) (canon yield)) + (core func (;0;) (canon thread.yield)) ) diff --git a/tests/snapshots/cli/missing-features/component-model/async.wast.json b/tests/snapshots/cli/missing-features/component-model/async.wast.json index d65dd165a8..278991db3e 100644 --- a/tests/snapshots/cli/missing-features/component-model/async.wast.json +++ b/tests/snapshots/cli/missing-features/component-model/async.wast.json @@ -76,161 +76,154 @@ "line": 117, "filename": "async.10.wasm", "module_type": "binary", - "text": "`yield` requires the component model async feature" + "text": "`subtask.drop` requires the component model async feature" }, { "type": "assert_invalid", "line": 129, "filename": "async.11.wasm", "module_type": "binary", - "text": "`subtask.drop` requires the component model async feature" + "text": "`subtask.cancel` requires the component model async feature" }, { "type": "assert_invalid", "line": 141, "filename": "async.12.wasm", "module_type": "binary", - "text": "`subtask.cancel` requires the component model async feature" + "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 153, + "line": 154, "filename": "async.13.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 166, + "line": 169, "filename": "async.14.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 181, + "line": 184, "filename": "async.15.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 196, + "line": 197, "filename": "async.16.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 209, + "line": 210, "filename": "async.17.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 222, + "line": 223, "filename": "async.18.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 235, + "line": 236, "filename": "async.19.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 248, + "line": 249, "filename": "async.20.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 261, + "line": 264, "filename": "async.21.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 276, + "line": 279, "filename": "async.22.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 291, + "line": 292, "filename": "async.23.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 304, + "line": 305, "filename": "async.24.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 317, + "line": 318, "filename": "async.25.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 330, + "line": 331, "filename": "async.26.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 343, + "line": 335, "filename": "async.27.wasm", "module_type": "binary", "text": "requires the component model async feature" }, { "type": "assert_invalid", - "line": 347, + "line": 339, "filename": "async.28.wasm", "module_type": "binary", - "text": "requires the component model async feature" + "text": "requires the component model threading feature" }, { "type": "assert_invalid", - "line": 351, + "line": 347, "filename": "async.29.wasm", "module_type": "binary", - "text": "requires the component model async builtins feature" + "text": "require the component model async feature" }, { "type": "assert_invalid", - "line": 359, + "line": 352, "filename": "async.30.wasm", "module_type": "binary", "text": "require the component model async feature" }, { "type": "assert_invalid", - "line": 364, + "line": 357, "filename": "async.31.wasm", "module_type": "binary", "text": "require the component model async feature" - }, - { - "type": "assert_invalid", - "line": 369, - "filename": "async.32.wasm", - "module_type": "binary", - "text": "require the component model async feature" } ] } \ No newline at end of file diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast.json b/tests/snapshots/cli/missing-features/component-model/threading.wast.json new file mode 100644 index 0000000000..461f3f4045 --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast.json @@ -0,0 +1,105 @@ +{ + "source_filename": "tests/cli/missing-features/component-model/threading.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 5, + "filename": "threading.0.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "assert_invalid", + "line": 17, + "filename": "threading.1.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "module", + "line": 24, + "filename": "threading.2.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 32, + "filename": "threading.3.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "module", + "line": 39, + "filename": "threading.4.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 47, + "filename": "threading.5.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "module", + "line": 49, + "filename": "threading.6.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 53, + "filename": "threading.7.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "assert_invalid", + "line": 58, + "filename": "threading.8.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "assert_invalid", + "line": 63, + "filename": "threading.9.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "assert_invalid", + "line": 68, + "filename": "threading.10.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "module", + "line": 73, + "filename": "threading.11.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 84, + "filename": "threading.12.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + }, + { + "type": "module", + "line": 88, + "filename": "threading.13.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 94, + "filename": "threading.14.wasm", + "module_type": "binary", + "text": "requires the component model threading feature" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/10.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/10.print new file mode 100644 index 0000000000..610a633cad --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast/10.print @@ -0,0 +1,8 @@ +(component + (type $f (;0;) (future)) + (type $s (;1;) (stream)) + (core func (;0;) (canon future.cancel-read $f)) + (core func (;1;) (canon future.cancel-write $f)) + (core func (;2;) (canon stream.cancel-read $s)) + (core func (;3;) (canon stream.cancel-write $s)) +) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/11.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/11.print new file mode 100644 index 0000000000..610a633cad --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast/11.print @@ -0,0 +1,8 @@ +(component + (type $f (;0;) (future)) + (type $s (;1;) (stream)) + (core func (;0;) (canon future.cancel-read $f)) + (core func (;1;) (canon future.cancel-write $f)) + (core func (;2;) (canon stream.cancel-read $s)) + (core func (;3;) (canon stream.cancel-write $s)) +) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/12.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/12.print new file mode 100644 index 0000000000..2c15950a33 --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast/12.print @@ -0,0 +1,4 @@ +(component + (type $t (;0;) (resource (rep i32))) + (core func (;0;) (canon resource.drop $t)) +) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/13.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/13.print new file mode 100644 index 0000000000..2c15950a33 --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast/13.print @@ -0,0 +1,4 @@ +(component + (type $t (;0;) (resource (rep i32))) + (core func (;0;) (canon resource.drop $t)) +) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/2.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/2.print new file mode 100644 index 0000000000..96c65f93d7 --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast/2.print @@ -0,0 +1,9 @@ +(component + (core module $libc (;0;) + (memory (;0;) 1) + (export "memory" (memory 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "memory" (core memory (;0;))) + (core func (;0;) (canon waitable-set.wait (memory 0))) +) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/4.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/4.print new file mode 100644 index 0000000000..a4322a5d8c --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast/4.print @@ -0,0 +1,9 @@ +(component + (core module $libc (;0;) + (memory (;0;) 1) + (export "memory" (memory 0)) + ) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "memory" (core memory (;0;))) + (core func (;0;) (canon waitable-set.poll (memory 0))) +) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/6.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/6.print new file mode 100644 index 0000000000..a1d9c7a10c --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast/6.print @@ -0,0 +1,3 @@ +(component + (core func (;0;) (canon thread.yield)) +) From 75ea65b41cc567bbb6f9c9a0170bd3a0fec369ee Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 5 Sep 2025 08:57:17 +0100 Subject: [PATCH 2/7] Change content.get/set validation --- crates/wasmparser/src/validator/component.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 9721a4f643..495b10c5a3 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -1476,8 +1476,10 @@ impl ComponentState { "`context.get` requires the component model async feature" ) } - if i > 1 { + if self.features.cm_threading() && i > 1 { bail!(offset, "`context.get` immediate must be zero or one: {i}") + } else if i > 0 { + bail!(offset, "`context.get` immediate must be zero: {i}") } self.core_funcs From 190e62a605babb1da6af5cb4ca047cc06cef2e91 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 5 Sep 2025 09:41:57 +0100 Subject: [PATCH 3/7] Change content.get/set validation --- crates/wasmparser/src/validator/component.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 495b10c5a3..8067484437 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -1494,8 +1494,10 @@ impl ComponentState { "`context.set` requires the component model async feature" ) } - if i > 1 { + if self.features.cm_threading() && i > 1 { bail!(offset, "`context.set` immediate must be zero or one: {i}") + } else if i > 0 { + bail!(offset, "`context.set` immediate must be zero: {i}") } self.core_funcs From 062113335c5d894c3806067c0a5d287a557321ac Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 5 Sep 2025 10:13:13 +0100 Subject: [PATCH 4/7] Improve context immediate validation --- crates/wasmparser/src/validator/component.rs | 29 +++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 8067484437..5e27bbe895 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -1469,6 +1469,23 @@ impl ComponentState { Ok(()) } + fn validate_context_immediate( + &self, + immediate: u32, + operation: &str, + offset: usize, + ) -> Result<()> { + if !self.features.cm_threading() && immediate > 0 { + bail!(offset, "`{operation}` immediate must be zero: {immediate}") + } else if immediate > 1 { + bail!( + offset, + "`{operation}` immediate must be zero or one: {immediate}" + ) + } + Ok(()) + } + fn context_get(&mut self, i: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> { if !self.features.cm_async() { bail!( @@ -1476,11 +1493,7 @@ impl ComponentState { "`context.get` requires the component model async feature" ) } - if self.features.cm_threading() && i > 1 { - bail!(offset, "`context.get` immediate must be zero or one: {i}") - } else if i > 0 { - bail!(offset, "`context.get` immediate must be zero: {i}") - } + self.validate_context_immediate(i, "context.get", offset)?; self.core_funcs .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset)); @@ -1494,11 +1507,7 @@ impl ComponentState { "`context.set` requires the component model async feature" ) } - if self.features.cm_threading() && i > 1 { - bail!(offset, "`context.set` immediate must be zero or one: {i}") - } else if i > 0 { - bail!(offset, "`context.set` immediate must be zero: {i}") - } + self.validate_context_immediate(i, "context.set", offset)?; self.core_funcs .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset)); From 011ba98e8b180aca8265d8ae124dd882203e859a Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 5 Sep 2025 10:36:22 +0100 Subject: [PATCH 5/7] Update thread.new_indirect approach --- crates/wit-component/src/encoding.rs | 26 +++---- crates/wit-component/src/validation.rs | 77 ++++++------------- .../tests/components/threading/component.wat | 8 +- .../tests/components/threading/module.wat | 5 +- 4 files changed, 39 insertions(+), 77 deletions(-) diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 2184e751c8..9c085e4756 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -80,7 +80,6 @@ use std::borrow::Cow; use std::collections::HashMap; use std::hash::Hash; use std::mem; -use wasm_encoder::reencode::{Reencode, RoundtripReencoder}; use wasm_encoder::*; use wasmparser::{Validator, WasmFeatures}; use wit_parser::{ @@ -673,7 +672,7 @@ impl<'a> EncodingState<'a> { | Export::GeneralPurposeImportRealloc | Export::Initialize | Export::ReallocForAdapter - | Export::FuncTable(_) => continue, + | Export::IndirectFunctionTable => continue, } } @@ -1379,22 +1378,20 @@ impl<'a> EncodingState<'a> { ShimKind::ThreadNewIndirect { for_module, func_ty, - table_idx, } => { // Encode the function type for the thread start function so we can reference it in the `canon` call. let (func_ty_idx, f) = self.component.core_type(); f.core().func_type(func_ty); // In order for the funcref table referenced by `thread.new_indirect` to be used, - // it must have been imported by the model. We check this here, which also validates - // that the table is indeed a funcref table, as we couldn't check this during initial validation. + // it must have been exported by the module. let exports = self.info.exports_for(*for_module); let instance_index = self.instance_for(*for_module); - let table_idx = exports.func_table(*table_idx).map(|table| { + let table_idx = exports.indirect_function_table().map(|table| { self.core_alias_export(instance_index, table, ExportKind::Table) }).ok_or_else(|| { anyhow!( - "table at index {table_idx} must be an exported funcref table for thread.new_indirect" + "table __indirect_function_table must be an exported funcref table for thread.new_indirect" ) })?; @@ -1873,12 +1870,12 @@ impl<'a> EncodingState<'a> { let index = self.component.thread_index(); Ok((ExportKind::Func, index)) } - Import::ThreadNewIndirect { func_ty, table_idx } => Ok(self.materialize_shim_import( + Import::ThreadNewIndirect => Ok(self.materialize_shim_import( shims, &ShimKind::ThreadNewIndirect { for_module, - func_ty: RoundtripReencoder.func_type(func_ty.clone())?, - table_idx: *table_idx, + // This is fixed for now + func_ty: FuncType::new([ValType::I32], []), }, )), Import::ThreadSwitchTo { cancellable } => { @@ -2220,9 +2217,6 @@ enum ShimKind<'a> { for_module: CustomModule<'a>, /// The function type to use when creating the thread. func_ty: FuncType, - /// The indirect function table to use when creating the thread. - /// This must be exported by the core module. - table_idx: u32, }, } @@ -2455,7 +2449,7 @@ impl<'a> Shims<'a> { }); } - Import::ThreadNewIndirect { func_ty, table_idx } => { + Import::ThreadNewIndirect => { let name = self.shims.len().to_string(); self.push(Shim { name, @@ -2463,8 +2457,8 @@ impl<'a> Shims<'a> { options: RequiredOptions::empty(), kind: ShimKind::ThreadNewIndirect { for_module, - func_ty: RoundtripReencoder.func_type(func_ty.clone())?, - table_idx: *table_idx, + // This is fixed for now + func_ty: FuncType::new([ValType::I32], vec![]), }, sig: WasmSignature { params: vec![WasmType::I32; 2], diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs index ced254d281..401242b2f5 100644 --- a/crates/wit-component/src/validation.rs +++ b/crates/wit-component/src/validation.rs @@ -5,7 +5,6 @@ use indexmap::{IndexMap, IndexSet, map::Entry}; use std::hash::{Hash, Hasher}; use std::mem; use wasm_encoder::ExportKind; -use wasmparser::CompositeInnerType; use wasmparser::names::{ComponentName, ComponentNameKind}; use wasmparser::{ Encoding, ExternalKind, FuncType, Parser, Payload, TypeRef, ValType, ValidPayload, Validator, @@ -422,7 +421,7 @@ pub enum Import { /// A `canon thread.new_indirect` intrinsic. /// /// This allows the guest to create a new thread running a specified function. - ThreadNewIndirect { func_ty: FuncType, table_idx: u32 }, + ThreadNewIndirect, /// A `canon thread.switch-to` intrinsic. /// @@ -568,7 +567,7 @@ impl ImportMap { None if encoder.reject_legacy_names => (import.module, STANDARD), None => (import.module, LEGACY), }; - self.classify_component_model_import(module, import.name, encoder, ty, names, types) + self.classify_component_model_import(module, import.name, encoder, ty, names) } /// Attempts to classify the import `{module}::{name}` with the rules @@ -580,7 +579,6 @@ impl ImportMap { encoder: &ComponentEncoder, ty: &FuncType, names: &dyn NameMangling, - types: TypesRef<'_>, ) -> Result { let resolve = &encoder.metadata.resolve; let world_id = encoder.metadata.world; @@ -728,41 +726,13 @@ impl ImportMap { validate_func_sig(name, &expected, ty)?; return Ok(Import::ThreadIndex); } - if let Some((func_ty_idx, table_idx)) = names.thread_new_indirect(name) { + if Some(name) == names.thread_new_indirect() { validate_not_async()?; validate_not_cancellable()?; - let func_ty_id = types.core_type_at_in_module(func_ty_idx); - let func_ty = types - .get(func_ty_id) - .and_then(|ty| match &ty.composite_type.inner { - CompositeInnerType::Func(func) => Some(func), - _ => None, - }); - if func_ty.is_none() { - bail!("`{name}` references type {func_ty_idx}, which is not a function type"); - } - let expected_start_func = FuncType::new([ValType::I32], []); - if func_ty.unwrap() != &expected_start_func { - bail!( - "`{name}` references type {func_ty_idx}, which is not the type (i32) -> (); the only type currently supported for thread entrypoints" - ); - } - - // We can't validate the type of the table here, because the import must appear before - // the table definition in the module, so we can't look it up yet. We defer this validation - // to the shim module. - let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - // We store the function type itself and will simply ensure that such a type is available when - // (canon thread.new_indirect ..) is issued. We store the table index for now, and will ensure - // that it is exported from the main module when we generate the shim module, so that we can eventually - // generate an alias for it and reference the table from (canon thread.new_indirect ..). - return Ok(Import::ThreadNewIndirect { - func_ty: func_ty.unwrap().clone(), - table_idx, - }); + return Ok(Import::ThreadNewIndirect); } if Some(name) == names.thread_switch_to() { validate_not_async()?; @@ -1218,8 +1188,8 @@ pub enum Export { InterfaceFuncCallback(WorldKey, String), - /// Tables that store funcrefs, used for `thread.new_indirect` - FuncTable(u32), + /// __indirect_function_table, used for `thread.new_indirect` + IndirectFunctionTable, } impl ExportMap { @@ -1300,8 +1270,8 @@ impl ExportMap { return Ok(None); } ExternalKind::Table => { - if types.table_at(export.index).element_type.is_func_ref() { - return Ok(Some(Export::FuncTable(export.index))); + if Some(name) == names.export_indirect_function_table() { + return Ok(Some(Export::IndirectFunctionTable)); } return Ok(None); } @@ -1476,13 +1446,9 @@ impl ExportMap { self.find(|m| matches!(m, Export::Memory)) } - /// Returns the funcref table that matches the given index, - /// if exported, for this module. - pub fn func_table(&self, index: u32) -> Option<&str> { - self.find(|m| match m { - Export::FuncTable(i) => *i == index, - _ => false, - }) + /// Returns the indirect function table, if exported, for this module. + pub fn indirect_function_table(&self) -> Option<&str> { + self.find(|t| matches!(t, Export::IndirectFunctionTable)) } /// Returns the `_initialize` intrinsic, if exported, for this module. @@ -1618,6 +1584,7 @@ trait NameMangling { fn export_memory(&self) -> &str; fn export_initialize(&self) -> &str; fn export_realloc(&self) -> &str; + fn export_indirect_function_table(&self) -> Option<&str>; fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str>; fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str>; fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str>; @@ -1643,7 +1610,7 @@ trait NameMangling { fn context_get(&self, name: &str) -> Option; fn context_set(&self, name: &str) -> Option; fn thread_index(&self) -> Option<&str>; - fn thread_new_indirect(&self, name: &str) -> Option<(u32, u32)>; + fn thread_new_indirect(&self) -> Option<&str>; fn thread_switch_to(&self) -> Option<&str>; fn thread_suspend(&self) -> Option<&str>; fn thread_resume_later(&self) -> Option<&str>; @@ -1696,6 +1663,9 @@ impl NameMangling for Standard { fn export_realloc(&self) -> &str { "_realloc" } + fn export_indirect_function_table(&self) -> Option<&str> { + None + } fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str> { s.strip_suffix("_drop") } @@ -1773,7 +1743,7 @@ impl NameMangling for Standard { fn thread_index(&self) -> Option<&str> { None } - fn thread_new_indirect(&self, _: &str) -> Option<(u32, u32)> { + fn thread_new_indirect(&self) -> Option<&str> { None } fn thread_switch_to(&self) -> Option<&str> { @@ -1918,6 +1888,9 @@ impl NameMangling for Legacy { fn export_realloc(&self) -> &str { "cabi_realloc" } + fn export_indirect_function_table(&self) -> Option<&str> { + Some("__indirect_function_table") + } fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str> { s.strip_prefix("[resource-drop]") } @@ -2002,13 +1975,9 @@ impl NameMangling for Legacy { fn thread_index(&self) -> Option<&str> { Some("[thread-index]") } - fn thread_new_indirect(&self, name: &str) -> Option<(u32, u32)> { - let rest = name.strip_prefix("[thread-new-indirect-")?; - let func_ty_idx_end = rest.find('-')?; - let func_ty_idx = rest[..func_ty_idx_end].parse().ok()?; - let end_idx = rest.find(']')?; - let table_idx = rest[func_ty_idx_end + 1..end_idx].parse().ok()?; - Some((func_ty_idx, table_idx)) + fn thread_new_indirect(&self) -> Option<&str> { + // For now, we'll fix the type of the start function and the table to extract it from + Some("[thread-new-indirect-v0]") } fn thread_switch_to(&self) -> Option<&str> { Some("[thread-switch-to]") diff --git a/crates/wit-component/tests/components/threading/component.wat b/crates/wit-component/tests/components/threading/component.wat index 30f6b73830..cde783a484 100644 --- a/crates/wit-component/tests/components/threading/component.wat +++ b/crates/wit-component/tests/components/threading/component.wat @@ -31,7 +31,7 @@ (import "$root" "[context-get-1]" (func (;21;) (type 3))) (import "$root" "[context-set-1]" (func (;22;) (type $thread-start-func-ty))) (import "$root" "[thread-index]" (func (;23;) (type 3))) - (import "$root" "[thread-new-indirect-0-0]" (func (;24;) (type 4))) + (import "$root" "[thread-new-indirect-v0]" (func (;24;) (type 4))) (import "$root" "[thread-switch-to]" (func (;25;) (type 5))) (import "$root" "[thread-suspend]" (func (;26;) (type 3))) (import "$root" "[thread-resume-later]" (func (;27;) (type $thread-start-func-ty))) @@ -42,7 +42,7 @@ (export "[async-lift-stackful]foo" (func 30)) (export "[async-lift-stackful]foo:foo/bar#foo" (func 31)) (export "memory" (memory 0)) - (export "indirect_function_table" (table 0)) + (export "__indirect_function_table" (table 0)) (export "cabi_realloc" (func 32)) (elem (;0;) (i32.const 0) func 0) (func (;29;) (type $thread-start-func-ty) (param i32) @@ -219,7 +219,7 @@ (export "[context-get-1]" (func 18)) (export "[context-set-1]" (func 19)) (export "[thread-index]" (func 20)) - (export "[thread-new-indirect-0-0]" (func 21)) + (export "[thread-new-indirect-v0]" (func 21)) (export "[thread-switch-to]" (func 22)) (export "[thread-suspend]" (func 23)) (export "[thread-resume-later]" (func 24)) @@ -253,7 +253,7 @@ (core func (;36;) (canon error-context.debug-message (memory 0) (realloc 34) string-encoding=utf16)) (core func (;37;) (canon error-context.debug-message (memory 0) (realloc 34) string-encoding=latin1+utf16)) (core type (;0;) (func (param i32))) - (alias core export 4 "indirect_function_table" (core table (;1;))) + (alias core export 4 "__indirect_function_table" (core table (;1;))) (core func (;38;) (canon thread.new_indirect 0 (table 1))) (core func (;39;) (canon task.return (result string) (memory 0) string-encoding=utf8)) (core func (;40;) (canon task.return (result string) (memory 0) string-encoding=utf8)) diff --git a/crates/wit-component/tests/components/threading/module.wat b/crates/wit-component/tests/components/threading/module.wat index 5f04ce2feb..0d5a13aa6d 100644 --- a/crates/wit-component/tests/components/threading/module.wat +++ b/crates/wit-component/tests/components/threading/module.wat @@ -24,8 +24,7 @@ (import "$root" "[context-get-1]" (func (result i32))) (import "$root" "[context-set-1]" (func (param i32))) (import "$root" "[thread-index]" (func (result i32))) - ;; 0-0 means the type 0 is the thread start function type, table 0 is the funcref table - (import "$root" "[thread-new-indirect-0-0]" (func (param i32 i32) (result i32))) + (import "$root" "[thread-new-indirect-v0]" (func (param i32 i32) (result i32))) (import "$root" "[thread-switch-to]" (func (param i32) (result i32))) (import "$root" "[thread-suspend]" (func (result i32))) (import "$root" "[thread-resume-later]" (func (param i32))) @@ -34,7 +33,7 @@ (func (export "[async-lift-stackful]foo") (param i32 i32) unreachable) (func (export "[async-lift-stackful]foo:foo/bar#foo") (param i32 i32) unreachable) (memory (export "memory") 1) - (table (export "indirect_function_table") 1 1 funcref) + (table (export "__indirect_function_table") 1 1 funcref) (elem (i32.const 0) func 0) (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) From e2a58ecdfd08f353ef892e41f20c7345711292b3 Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Fri, 5 Sep 2025 17:47:50 +0100 Subject: [PATCH 6/7] Refactor import name validation and extraction --- crates/wit-component/src/validation.rs | 934 ++++++++++++++++--------- 1 file changed, 613 insertions(+), 321 deletions(-) diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs index 401242b2f5..3d20c3e5c9 100644 --- a/crates/wit-component/src/validation.rs +++ b/crates/wit-component/src/validation.rs @@ -584,195 +584,143 @@ impl ImportMap { let world_id = encoder.metadata.world; let world = &resolve.worlds[world_id]; - let (async_, name) = if let Some(name) = names.async_lower_name(name) { - (true, name) - } else { - (false, name) - }; - let (cancellable, name) = if let Some(name) = names.cancellable_name(name) { - (true, name) - } else { - (false, name) - }; - let abi = if async_ { - AbiVariant::GuestImportAsync - } else { - AbiVariant::GuestImport - }; - let validate_not_async = || { - if async_ { - bail!("`{name}` cannot be marked `async`") - } - Ok(()) - }; - let validate_not_cancellable = || { - if cancellable { - bail!("`{name}` cannot be marked `cancellable`") - } - Ok(()) - }; - if module == names.import_root() { - if Some(name) == names.error_context_drop() { - validate_not_async()?; - validate_not_cancellable()?; + if names.error_context_drop(name) { let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::ErrorContextDrop); } - if Some(name) == names.backpressure_set() { - validate_not_async()?; - validate_not_cancellable()?; + if names.backpressure_set(name) { let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::BackpressureSet); } - if Some(name) == names.waitable_set_new() { - validate_not_async()?; - validate_not_cancellable()?; + if names.waitable_set_new(name) { let expected = FuncType::new([], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::WaitableSetNew); } - if Some(name) == names.waitable_set_wait() { - validate_not_async()?; + if let Some(info) = names.waitable_set_wait(name) { let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::WaitableSetWait { cancellable }); + return Ok(Import::WaitableSetWait { + cancellable: info.cancellable, + }); } - if Some(name) == names.waitable_set_poll() { - validate_not_async()?; + if let Some(info) = names.waitable_set_poll(name) { let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::WaitableSetPoll { cancellable }); + return Ok(Import::WaitableSetPoll { + cancellable: info.cancellable, + }); } - if Some(name) == names.waitable_set_drop() { - validate_not_async()?; - validate_not_cancellable()?; + if names.waitable_set_drop(name) { let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::WaitableSetDrop); } - if Some(name) == names.waitable_join() { - validate_not_async()?; - validate_not_cancellable()?; + if names.waitable_join(name) { let expected = FuncType::new([ValType::I32; 2], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::WaitableJoin); } - if Some(name) == names.thread_yield() { - validate_not_async()?; + if let Some(info) = names.thread_yield(name) { let expected = FuncType::new([], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::ThreadYield { cancellable }); + return Ok(Import::ThreadYield { + cancellable: info.cancellable, + }); } - if Some(name) == names.subtask_drop() { - validate_not_async()?; - validate_not_cancellable()?; + if names.subtask_drop(name) { let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::SubtaskDrop); } - if Some(name) == names.subtask_cancel() { - validate_not_cancellable()?; + if let Some(info) = names.subtask_cancel(name) { let expected = FuncType::new([ValType::I32], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::SubtaskCancel { async_ }); + return Ok(Import::SubtaskCancel { + async_: info.async_lowered, + }); } if let Some(encoding) = names.error_context_new(name) { - validate_not_async()?; - validate_not_cancellable()?; let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::ErrorContextNew { encoding }); } if let Some(encoding) = names.error_context_debug_message(name) { - validate_not_async()?; - validate_not_cancellable()?; let expected = FuncType::new([ValType::I32; 2], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::ErrorContextDebugMessage { encoding }); } if let Some(i) = names.context_get(name) { - validate_not_async()?; - validate_not_cancellable()?; let expected = FuncType::new([], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::ContextGet(i)); } if let Some(i) = names.context_set(name) { - validate_not_async()?; - validate_not_cancellable()?; let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::ContextSet(i)); } - if Some(name) == names.thread_index() { - validate_not_async()?; - validate_not_cancellable()?; + if names.thread_index(name) { let expected = FuncType::new([], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::ThreadIndex); } - if Some(name) == names.thread_new_indirect() { - validate_not_async()?; - validate_not_cancellable()?; - + if names.thread_new_indirect(name) { let expected = FuncType::new([ValType::I32; 2], [ValType::I32]); validate_func_sig(name, &expected, ty)?; return Ok(Import::ThreadNewIndirect); } - if Some(name) == names.thread_switch_to() { - validate_not_async()?; + if let Some(info) = names.thread_switch_to(name) { let expected = FuncType::new([ValType::I32], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::ThreadSwitchTo { cancellable }); + return Ok(Import::ThreadSwitchTo { + cancellable: info.cancellable, + }); } - if Some(name) == names.thread_suspend() { - validate_not_async()?; + if let Some(info) = names.thread_suspend(name) { let expected = FuncType::new([], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::ThreadSuspend { cancellable }); + return Ok(Import::ThreadSuspend { + cancellable: info.cancellable, + }); } - if Some(name) == names.thread_resume_later() { - validate_not_async()?; - validate_not_cancellable()?; + if names.thread_resume_later(name) { let expected = FuncType::new([ValType::I32], []); validate_func_sig(name, &expected, ty)?; return Ok(Import::ThreadResumeLater); } - if Some(name) == names.thread_yield_to() { - validate_not_async()?; + if let Some(info) = names.thread_yield_to(name) { let expected = FuncType::new([ValType::I32], [ValType::I32]); validate_func_sig(name, &expected, ty)?; - return Ok(Import::ThreadYieldTo { cancellable }); + return Ok(Import::ThreadYieldTo { + cancellable: info.cancellable, + }); } - let key = WorldKey::Name(name.to_string()); + let (key_name, abi) = names.world_key_name_and_abi(name); + let key = WorldKey::Name(key_name.to_string()); if let Some(WorldItem::Function(func)) = world.imports.get(&key) { validate_func(resolve, ty, func, abi)?; return Ok(Import::WorldFunc(key, func.name.clone(), abi)); } - // At this point, all cancellable imports have already been checked - if cancellable { - bail!("`{name}` cannot be marked `cancellable`"); - } - if let Some(import) = - self.maybe_classify_wit_intrinsic(name, None, encoder, ty, async_, true, names)? + self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)? { return Ok(import); } @@ -783,18 +731,13 @@ impl ImportMap { } } - // At this point, all cancellable imports have already been checked - if cancellable { - bail!("`{name}` cannot be marked `cancellable`"); - } - // Check for `[export]$root::[task-return]foo` or similar if matches!( module.strip_prefix(names.import_exported_intrinsic_prefix()), Some(module) if module == names.import_root() ) { if let Some(import) = - self.maybe_classify_wit_intrinsic(name, None, encoder, ty, async_, false, names)? + self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)? { return Ok(import); } @@ -808,15 +751,9 @@ impl ImportMap { if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) { let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?; - if let Some(import) = self.maybe_classify_wit_intrinsic( - name, - Some((key, id)), - encoder, - ty, - async_, - false, - names, - )? { + if let Some(import) = + self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)? + { return Ok(import); } bail!("unknown function `{name}`") @@ -824,7 +761,8 @@ impl ImportMap { let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?; let interface = &resolve.interfaces[id]; - if let Some(f) = interface.functions.get(name) { + let (function_name, abi) = names.interface_function_name_and_abi(name); + if let Some(f) = interface.functions.get(function_name) { validate_func(resolve, ty, f, abi).with_context(|| { let name = resolve.name_world_key(&key); format!("failed to validate import interface `{name}`") @@ -832,15 +770,9 @@ impl ImportMap { return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi)); } - if let Some(import) = self.maybe_classify_wit_intrinsic( - name, - Some((key, id)), - encoder, - ty, - async_, - true, - names, - )? { + if let Some(import) = + self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)? + { return Ok(import); } bail!( @@ -860,8 +792,8 @@ impl ImportMap { /// ## Parameters /// /// * `name` - the core module name which is being pattern-matched. This - /// should be the "field" of the import. This should have the - /// "[async-lift]" prefix stripped out already. + /// should be the "field" of the import. This may include the "[async-lower]" + /// or "[cancellable]" prefixes. /// * `key_and_id` - this is the inferred "container" for the function /// being described which is inferred from the module portion of the core /// wasm import field. This is `None` for root-level function/type @@ -872,8 +804,6 @@ impl ImportMap { /// * `encoder` - this is the encoder state that contains /// `Resolve`/metadata information. /// * `ty` - the core wasm type of this import. - /// * `async_` - whether or not this import had the `[async-lift]` import. - /// Note that such prefix is not present in `name`. /// * `import` - whether or not this core wasm import is operating on a WIT /// level import or export. An example of this being an export is when a /// core module imports a destructor for an exported resource. @@ -884,7 +814,6 @@ impl ImportMap { key_and_id: Option<(WorldKey, InterfaceId)>, encoder: &ComponentEncoder, ty: &FuncType, - async_: bool, import: bool, names: &dyn NameMangling, ) -> Result> { @@ -909,9 +838,6 @@ impl ImportMap { // Test whether this is a `resource.drop` intrinsic. if let Some(resource) = names.resource_drop_name(name) { - if async_ { - bail!("async `resource.drop` calls not supported"); - } if let Some(resource_id) = resource_test(resource) { let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string())); let expected = FuncType::new([ValType::I32], []); @@ -955,108 +881,88 @@ impl ImportMap { func.result, ))); } - if Some(name) == names.task_cancel() { - if async_ { - bail!("async `task.cancel` calls not supported"); - } + if names.task_cancel(name) { let expected = FuncType::new([], []); validate_func_sig(name, &expected, ty)?; return Ok(Some(Import::ExportedTaskCancel)); } } - // Looks for `[$prefix-N]foo` within `name`. If found then `foo` is - // used to find a function within `id` and `world` above. Once found - // then `N` is used to index within that function to extract a - // future/stream type. If that's all found then a `PayloadInfo` is - // returned to get attached to an intrinsic. - let prefixed_payload = |prefix: &str| { - // parse the `prefix` into `func_name` and `type_index`, bailing out - // with `None` if anything doesn't match. - let (type_index, func_name) = prefixed_integer(name, prefix)?; - let type_index = type_index as usize; - - // Double-check that `func_name` is indeed a function name within - // this interface/world. Then additionally double-check that - // `type_index` is indeed a valid index for this function's type - // signature. - let function = get_function(resolve, world, func_name, id, import).ok()?; - let ty = *function.find_futures_and_streams(resolve).get(type_index)?; - - // And if all that passes wrap up everything in a `PayloadInfo`. - Some(PayloadInfo { - name: name.to_string(), - ty, - function: function.name.clone(), - key: key - .clone() - .unwrap_or_else(|| WorldKey::Name(name.to_string())), - interface: id, - imported: import, - }) + let lookup_context = PayloadLookupContext { + resolve, + world, + key, + id, + import, }; // Test for a number of async-related intrinsics. All intrinsics are // prefixed with `[...-N]` where `...` is the name of the intrinsic and // the `N` is the indexed future/stream that is being referred to. - let import = if let Some(info) = prefixed_payload("[future-new-") { - if async_ { - bail!("async `future.new` calls not supported"); - } + let import = if let Some(info) = names.future_new(&lookup_context, name) { validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?; Import::FutureNew(info) - } else if let Some(info) = prefixed_payload("[future-write-") { + } else if let Some(info) = names.future_write(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?; - Import::FutureWrite { async_, info } - } else if let Some(info) = prefixed_payload("[future-read-") { + Import::FutureWrite { + async_: info.async_lowered, + info: info.inner, + } + } else if let Some(info) = names.future_read(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?; - Import::FutureRead { async_, info } - } else if let Some(info) = prefixed_payload("[future-cancel-write-") { + Import::FutureRead { + async_: info.async_lowered, + info: info.inner, + } + } else if let Some(info) = names.future_cancel_write(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?; - Import::FutureCancelWrite { async_, info } - } else if let Some(info) = prefixed_payload("[future-cancel-read-") { + Import::FutureCancelWrite { + async_: info.async_lowered, + info: info.inner, + } + } else if let Some(info) = names.future_cancel_read(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?; - Import::FutureCancelRead { async_, info } - } else if let Some(info) = prefixed_payload("[future-drop-writable-") { - if async_ { - bail!("async `future.drop-writable` calls not supported"); + Import::FutureCancelRead { + async_: info.async_lowered, + info: info.inner, } + } else if let Some(info) = names.future_drop_writable(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?; Import::FutureDropWritable(info) - } else if let Some(info) = prefixed_payload("[future-drop-readable-") { - if async_ { - bail!("async `future.drop-readable` calls not supported"); - } + } else if let Some(info) = names.future_drop_readable(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?; Import::FutureDropReadable(info) - } else if let Some(info) = prefixed_payload("[stream-new-") { - if async_ { - bail!("async `stream.new` calls not supported"); - } + } else if let Some(info) = names.stream_new(&lookup_context, name) { validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?; Import::StreamNew(info) - } else if let Some(info) = prefixed_payload("[stream-write-") { + } else if let Some(info) = names.stream_write(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?; - Import::StreamWrite { async_, info } - } else if let Some(info) = prefixed_payload("[stream-read-") { + Import::StreamWrite { + async_: info.async_lowered, + info: info.inner, + } + } else if let Some(info) = names.stream_read(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?; - Import::StreamRead { async_, info } - } else if let Some(info) = prefixed_payload("[stream-cancel-write-") { + Import::StreamRead { + async_: info.async_lowered, + info: info.inner, + } + } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?; - Import::StreamCancelWrite { async_, info } - } else if let Some(info) = prefixed_payload("[stream-cancel-read-") { + Import::StreamCancelWrite { + async_: info.async_lowered, + info: info.inner, + } + } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?; - Import::StreamCancelRead { async_, info } - } else if let Some(info) = prefixed_payload("[stream-drop-writable-") { - if async_ { - bail!("async `stream.drop-writable` calls not supported"); + Import::StreamCancelRead { + async_: info.async_lowered, + info: info.inner, } + } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?; Import::StreamDropWritable(info) - } else if let Some(info) = prefixed_payload("[stream-drop-readable-") { - if async_ { - bail!("async `stream.drop-readable` calls not supported"); - } + } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) { validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?; Import::StreamDropReadable(info) } else { @@ -1556,6 +1462,29 @@ impl ExportMap { } } +/// A builtin that may be declared as cancellable. +struct MaybeCancellable { + #[allow(unused)] + inner: T, + cancellable: bool, +} + +/// A builtin that may be declared as async-lowered. +struct MaybeAsyncLowered { + inner: T, + async_lowered: bool, +} + +/// Context passed to `NameMangling` implementations of stream and future functions +/// to help with looking up payload information. +struct PayloadLookupContext<'a> { + resolve: &'a Resolve, + world: &'a World, + id: Option, + import: bool, + key: Option, +} + /// Trait dispatch and definition for parsing and interpreting "mangled names" /// which show up in imports and exports of the component model. /// @@ -1585,43 +1514,103 @@ trait NameMangling { fn export_initialize(&self) -> &str; fn export_realloc(&self) -> &str; fn export_indirect_function_table(&self) -> Option<&str>; - fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str>; - 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_cancel(&self) -> Option<&str>; - fn backpressure_set(&self) -> Option<&str>; - fn waitable_set_new(&self) -> Option<&str>; - fn waitable_set_wait(&self) -> Option<&str>; - fn waitable_set_poll(&self) -> Option<&str>; - fn waitable_set_drop(&self) -> Option<&str>; - fn waitable_join(&self) -> Option<&str>; - fn thread_yield(&self) -> Option<&str>; - fn subtask_drop(&self) -> Option<&str>; - fn subtask_cancel(&self) -> Option<&str>; - fn async_lift_callback_name<'a>(&self, s: &'a str) -> Option<&'a str>; - fn async_lower_name<'a>(&self, s: &'a str) -> Option<&'a str>; - fn async_lift_name<'a>(&self, s: &'a str) -> Option<&'a str>; - fn async_lift_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str>; - fn error_context_new(&self, s: &str) -> Option; - fn error_context_debug_message(&self, s: &str) -> Option; - fn error_context_drop(&self) -> Option<&str>; - fn cancellable_name<'a>(&self, s: &'a str) -> Option<&'a 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>; + fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>; + fn task_cancel(&self, name: &str) -> bool; + fn backpressure_set(&self, name: &str) -> bool; + fn waitable_set_new(&self, name: &str) -> bool; + fn waitable_set_wait(&self, name: &str) -> Option>; + fn waitable_set_poll(&self, name: &str) -> Option>; + fn waitable_set_drop(&self, name: &str) -> bool; + fn waitable_join(&self, name: &str) -> bool; + fn thread_yield(&self, name: &str) -> Option>; + fn subtask_drop(&self, name: &str) -> bool; + fn subtask_cancel(&self, name: &str) -> Option>; + fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>; + fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>; + fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>; + fn error_context_new(&self, name: &str) -> Option; + fn error_context_debug_message(&self, name: &str) -> Option; + fn error_context_drop(&self, name: &str) -> bool; fn context_get(&self, name: &str) -> Option; fn context_set(&self, name: &str) -> Option; - fn thread_index(&self) -> Option<&str>; - fn thread_new_indirect(&self) -> Option<&str>; - fn thread_switch_to(&self) -> Option<&str>; - fn thread_suspend(&self) -> Option<&str>; - fn thread_resume_later(&self) -> Option<&str>; - fn thread_yield_to(&self) -> Option<&str>; + fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option; + fn future_write( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option>; + fn future_read( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option>; + fn future_cancel_write( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option>; + fn future_cancel_read( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option>; + fn future_drop_writable( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option; + fn future_drop_readable( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option; + fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option; + fn stream_write( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option>; + fn stream_read( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option>; + fn stream_cancel_write( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option>; + fn stream_cancel_read( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option>; + fn stream_drop_writable( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option; + fn stream_drop_readable( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option; + fn thread_index(&self, name: &str) -> bool; + fn thread_new_indirect(&self, name: &str) -> bool; + fn thread_switch_to(&self, name: &str) -> Option>; + fn thread_suspend(&self, name: &str) -> Option>; + fn thread_resume_later(&self, name: &str) -> bool; + fn thread_yield_to(&self, name: &str) -> Option>; fn module_to_interface( &self, module: &str, resolve: &Resolve, items: &IndexMap, ) -> Result<(WorldKey, InterfaceId)>; - fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str>; + fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>; fn match_wit_export<'a>( &self, export_name: &str, @@ -1636,6 +1625,8 @@ trait NameMangling { world: WorldId, exports: &'a IndexSet, ) -> Option; + fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant); + fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant); } /// Definition of the "standard" naming scheme which currently starts with @@ -1666,100 +1657,186 @@ impl NameMangling for Standard { fn export_indirect_function_table(&self) -> Option<&str> { None } - fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_suffix("_drop") + fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_suffix("_drop") } - fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_suffix("_new") + fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_suffix("_new") } - fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_suffix("_rep") + fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_suffix("_rep") } - fn task_return_name<'a>(&self, s: &'a str) -> Option<&'a str> { - _ = s; + fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> { None } - fn task_cancel(&self) -> Option<&str> { + fn task_cancel(&self, _name: &str) -> bool { + false + } + fn backpressure_set(&self, _name: &str) -> bool { + false + } + fn waitable_set_new(&self, _name: &str) -> bool { + false + } + fn waitable_set_wait(&self, _name: &str) -> Option> { None } - fn backpressure_set(&self) -> Option<&str> { + fn waitable_set_poll(&self, _name: &str) -> Option> { None } - fn waitable_set_new(&self) -> Option<&str> { + fn waitable_set_drop(&self, _name: &str) -> bool { + false + } + fn waitable_join(&self, _name: &str) -> bool { + false + } + fn thread_yield(&self, _name: &str) -> Option> { None } - fn waitable_set_wait(&self) -> Option<&str> { + fn subtask_drop(&self, _name: &str) -> bool { + false + } + fn subtask_cancel(&self, _name: &str) -> Option> { None } - fn waitable_set_poll(&self) -> Option<&str> { + fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> { None } - fn waitable_set_drop(&self) -> Option<&str> { + fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> { None } - fn waitable_join(&self) -> Option<&str> { + fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> { None } - fn thread_yield(&self) -> Option<&str> { + fn error_context_new(&self, _name: &str) -> Option { None } - fn subtask_drop(&self) -> Option<&str> { + fn error_context_debug_message(&self, _name: &str) -> Option { None } - fn subtask_cancel(&self) -> Option<&str> { + fn error_context_drop(&self, _name: &str) -> bool { + false + } + fn context_get(&self, _name: &str) -> Option { None } - fn async_lift_callback_name<'a>(&self, s: &'a str) -> Option<&'a str> { - _ = s; + fn context_set(&self, _name: &str) -> Option { None } - fn async_lower_name<'a>(&self, s: &'a str) -> Option<&'a str> { - _ = s; + fn thread_index(&self, _name: &str) -> bool { + false + } + fn thread_new_indirect(&self, _name: &str) -> bool { + false + } + fn thread_switch_to(&self, _name: &str) -> Option> { None } - fn async_lift_name<'a>(&self, s: &'a str) -> Option<&'a str> { - _ = s; + fn thread_suspend(&self, _name: &str) -> Option> { None } - fn async_lift_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str> { - _ = s; + fn thread_resume_later(&self, _name: &str) -> bool { + false + } + fn thread_yield_to(&self, _name: &str) -> Option> { None } - fn error_context_new(&self, _: &str) -> Option { + fn future_new( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option { None } - fn error_context_debug_message(&self, _: &str) -> Option { + fn future_write( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option> { None } - fn error_context_drop(&self) -> Option<&str> { + fn future_read( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option> { None } - fn context_get(&self, _: &str) -> Option { + fn future_cancel_write( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option> { None } - fn context_set(&self, _: &str) -> Option { + fn future_cancel_read( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option> { None } - fn thread_index(&self) -> Option<&str> { + fn future_drop_writable( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option { None } - fn thread_new_indirect(&self) -> Option<&str> { + fn future_drop_readable( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option { None } - fn thread_switch_to(&self) -> Option<&str> { + fn stream_new( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option { None } - fn thread_suspend(&self) -> Option<&str> { + fn stream_write( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option> { None } - fn thread_resume_later(&self) -> Option<&str> { + fn stream_read( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option> { + None + } + fn stream_cancel_write( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option> { + None + } + fn stream_cancel_read( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option> { None } - fn thread_yield_to(&self) -> Option<&str> { + fn stream_drop_writable( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option { None } - fn cancellable_name<'a>(&self, s: &'a str) -> Option<&'a str> { - _ = s; + fn stream_drop_readable( + &self, + _lookup_context: &PayloadLookupContext, + _name: &str, + ) -> Option { None } fn module_to_interface( @@ -1787,8 +1864,8 @@ impl NameMangling for Standard { } bail!("failed to find world item corresponding to interface `{interface}`") } - fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_suffix("_post") + fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_suffix("_post") } fn match_wit_export<'a>( &self, @@ -1826,6 +1903,13 @@ impl NameMangling for Standard { _ => None, } } + + fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) { + (name, AbiVariant::GuestImport) + } + fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) { + (name, AbiVariant::GuestImport) + } } impl Standard { @@ -1869,6 +1953,107 @@ struct Legacy; const LEGACY: &'static dyn NameMangling = &Legacy; +impl Legacy { + // Looks for `[$prefix-N]foo` within `name`. If found then `foo` is + // used to find a function within `id` and `world` above. Once found + // then `N` is used to index within that function to extract a + // future/stream type. If that's all found then a `PayloadInfo` is + // returned to get attached to an intrinsic. + fn prefixed_payload( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + prefix: &str, + ) -> Option { + // parse the `prefix` into `func_name` and `type_index`, bailing out + // with `None` if anything doesn't match. + let (type_index, func_name) = prefixed_integer(name, prefix)?; + let type_index = type_index as usize; + + // Double-check that `func_name` is indeed a function name within + // this interface/world. Then additionally double-check that + // `type_index` is indeed a valid index for this function's type + // signature. + let function = get_function( + lookup_context.resolve, + lookup_context.world, + func_name, + lookup_context.id, + lookup_context.import, + ) + .ok()?; + let ty = *function + .find_futures_and_streams(lookup_context.resolve) + .get(type_index)?; + + // And if all that passes wrap up everything in a `PayloadInfo`. + Some(PayloadInfo { + name: name.to_string(), + ty, + function: function.name.clone(), + key: lookup_context + .key + .clone() + .unwrap_or_else(|| WorldKey::Name(name.to_string())), + interface: lookup_context.id, + imported: lookup_context.import, + }) + } + + fn maybe_async_lowered_payload( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + prefix: &str, + ) -> Option> { + let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name); + let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?; + Some(MaybeAsyncLowered { + inner: payload, + async_lowered, + }) + } + + fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) { + name.strip_prefix("[async-lower]") + .map_or((false, name), |s| (true, s)) + } + fn match_with_async_lowered_prefix( + &self, + name: &str, + expected: &str, + ) -> Option> { + let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name); + if clean_name == expected { + Some(MaybeAsyncLowered { + inner: (), + async_lowered, + }) + } else { + None + } + } + fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) { + name.strip_prefix("[cancellable]") + .map_or((false, name), |s| (true, s)) + } + fn match_with_cancellable_prefix( + &self, + name: &str, + expected: &str, + ) -> Option> { + let (cancellable, clean_name) = self.strip_cancellable_prefix(name); + if clean_name == expected { + Some(MaybeCancellable { + inner: (), + cancellable, + }) + } else { + None + } + } +} + impl NameMangling for Legacy { fn import_root(&self) -> &str { "$root" @@ -1891,59 +2076,56 @@ impl NameMangling for Legacy { fn export_indirect_function_table(&self) -> Option<&str> { Some("__indirect_function_table") } - fn resource_drop_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[resource-drop]") - } - fn resource_new_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[resource-new]") + fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_prefix("[resource-drop]") } - fn resource_rep_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[resource-rep]") + fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_prefix("[resource-new]") } - fn task_return_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[task-return]") + fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_prefix("[resource-rep]") } - fn task_cancel(&self) -> Option<&str> { - Some("[task-cancel]") + fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_prefix("[task-return]") } - fn backpressure_set(&self) -> Option<&str> { - Some("[backpressure-set]") + fn task_cancel(&self, name: &str) -> bool { + name == "[task-cancel]" } - fn waitable_set_new(&self) -> Option<&str> { - Some("[waitable-set-new]") + fn backpressure_set(&self, name: &str) -> bool { + name == "[backpressure-set]" } - fn waitable_set_wait(&self) -> Option<&str> { - Some("[waitable-set-wait]") + fn waitable_set_new(&self, name: &str) -> bool { + name == "[waitable-set-new]" } - fn waitable_set_poll(&self) -> Option<&str> { - Some("[waitable-set-poll]") + fn waitable_set_wait(&self, name: &str) -> Option> { + self.match_with_cancellable_prefix(name, "[waitable-set-wait]") } - fn waitable_set_drop(&self) -> Option<&str> { - Some("[waitable-set-drop]") + fn waitable_set_poll(&self, name: &str) -> Option> { + self.match_with_cancellable_prefix(name, "[waitable-set-poll]") } - fn waitable_join(&self) -> Option<&str> { - Some("[waitable-join]") + fn waitable_set_drop(&self, name: &str) -> bool { + name == "[waitable-set-drop]" } - fn thread_yield(&self) -> Option<&str> { - Some("[thread-yield]") + fn waitable_join(&self, name: &str) -> bool { + name == "[waitable-join]" } - fn subtask_drop(&self) -> Option<&str> { - Some("[subtask-drop]") + fn thread_yield(&self, name: &str) -> Option> { + self.match_with_cancellable_prefix(name, "[thread-yield]") } - fn subtask_cancel(&self) -> Option<&str> { - Some("[subtask-cancel]") + fn subtask_drop(&self, name: &str) -> bool { + name == "[subtask-drop]" } - fn async_lift_callback_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[callback][async-lift]") + fn subtask_cancel(&self, name: &str) -> Option> { + self.match_with_async_lowered_prefix(name, "[subtask-cancel]") } - fn async_lower_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[async-lower]") + fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_prefix("[callback][async-lift]") } - fn async_lift_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[async-lift]") + fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_prefix("[async-lift]") } - fn async_lift_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[async-lift-stackful]") + fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_prefix("[async-lift-stackful]") } fn error_context_new(&self, name: &str) -> Option { match name { @@ -1961,8 +2143,8 @@ impl NameMangling for Legacy { _ => None, } } - fn error_context_drop(&self) -> Option<&str> { - Some("[error-context-drop]") + fn error_context_drop(&self, name: &str) -> bool { + name == "[error-context-drop]" } fn context_get(&self, name: &str) -> Option { let (n, rest) = prefixed_integer(name, "[context-get-")?; @@ -1972,27 +2154,114 @@ impl NameMangling for Legacy { let (n, rest) = prefixed_integer(name, "[context-set-")?; if rest.is_empty() { Some(n) } else { None } } - fn thread_index(&self) -> Option<&str> { - Some("[thread-index]") + fn thread_index(&self, name: &str) -> bool { + name == "[thread-index]" } - fn thread_new_indirect(&self) -> Option<&str> { + fn thread_new_indirect(&self, name: &str) -> bool { // For now, we'll fix the type of the start function and the table to extract it from - Some("[thread-new-indirect-v0]") + name == "[thread-new-indirect-v0]" + } + fn thread_switch_to(&self, name: &str) -> Option> { + self.match_with_cancellable_prefix(name, "[thread-switch-to]") } - fn thread_switch_to(&self) -> Option<&str> { - Some("[thread-switch-to]") + fn thread_suspend(&self, name: &str) -> Option> { + self.match_with_cancellable_prefix(name, "[thread-suspend]") } - fn thread_suspend(&self) -> Option<&str> { - Some("[thread-suspend]") + fn thread_resume_later(&self, name: &str) -> bool { + name == "[thread-resume-later]" } - fn thread_resume_later(&self) -> Option<&str> { - Some("[thread-resume-later]") + fn thread_yield_to(&self, name: &str) -> Option> { + self.match_with_cancellable_prefix(name, "[thread-yield-to]") } - fn thread_yield_to(&self) -> Option<&str> { - Some("[thread-yield-to]") + fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option { + self.prefixed_payload(lookup_context, name, "[future-new-") } - fn cancellable_name<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("[cancellable]") + fn future_write( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option> { + self.maybe_async_lowered_payload(lookup_context, name, "[future-write-") + } + fn future_read( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option> { + self.maybe_async_lowered_payload(lookup_context, name, "[future-read-") + } + fn future_cancel_write( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option> { + self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-") + } + fn future_cancel_read( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option> { + self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-") + } + fn future_drop_writable( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option { + self.prefixed_payload(lookup_context, name, "[future-drop-writable-") + } + fn future_drop_readable( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option { + self.prefixed_payload(lookup_context, name, "[future-drop-readable-") + } + fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option { + self.prefixed_payload(lookup_context, name, "[stream-new-") + } + fn stream_write( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option> { + self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-") + } + fn stream_read( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option> { + self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-") + } + fn stream_cancel_write( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option> { + self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-") + } + fn stream_cancel_read( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option> { + self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-") + } + fn stream_drop_writable( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option { + self.prefixed_payload(lookup_context, name, "[stream-drop-writable-") + } + fn stream_drop_readable( + &self, + lookup_context: &PayloadLookupContext, + name: &str, + ) -> Option { + self.prefixed_payload(lookup_context, name, "[stream-drop-readable-") } fn module_to_interface( &self, @@ -2075,8 +2344,8 @@ impl NameMangling for Legacy { bail!("module requires an import interface named `{module}`") } - fn strip_post_return<'a>(&self, s: &'a str) -> Option<&'a str> { - s.strip_prefix("cabi_post_") + fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> { + name.strip_prefix("cabi_post_") } fn match_wit_export<'a>( &self, @@ -2143,6 +2412,29 @@ impl NameMangling for Legacy { None } + + fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) { + let (async_abi, name) = self.strip_async_lowered_prefix(name); + ( + name, + if async_abi { + AbiVariant::GuestImportAsync + } else { + AbiVariant::GuestImport + }, + ) + } + fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) { + let (async_abi, name) = self.strip_async_lowered_prefix(name); + ( + name, + if async_abi { + AbiVariant::GuestImportAsync + } else { + AbiVariant::GuestImport + }, + ) + } } /// This function validates the following: From 6ed91609ea350f18c7b69430796102327951ac4a Mon Sep 17 00:00:00 2001 From: Sy Brand Date: Mon, 8 Sep 2025 10:03:39 +0100 Subject: [PATCH 7/7] Split features --- crates/wasmparser/src/features.rs | 23 +- crates/wasmparser/src/validator/component.rs | 43 +- .../components/async-builtins/component.wat | 256 ++++++++++++ .../async-builtins/component.wit.print | 6 + .../components/async-builtins/module.wat | 27 ++ .../components/async-builtins/module.wit | 10 + .../tests/components/threading/component.wat | 274 +++--------- .../tests/components/threading/module.wat | 18 - tests/cli/component-model-async/abi.wast | 2 +- tests/cli/component-model-async/futures.wast | 2 +- tests/cli/component-model-async/lift.wast | 2 +- .../cli/component-model-async/resources.wast | 2 +- tests/cli/component-model-async/streams.wast | 2 +- .../component-model-async/task-builtins.wast | 393 ++++++++++++++++++ .../cli/component-model-async/threading.wast | 379 +---------------- .../component-model/async-builtins.wast | 44 ++ .../component-model/async-stackful.wast | 50 +++ .../component-model/async.wast | 2 +- .../component-model/threading.wast | 88 ---- .../cli/validate-unknown-features.wat.stderr | 2 +- .../task-builtins.wast.json | 4 +- .../task-builtins.wast/11.print | 2 +- .../task-builtins.wast/13.print | 2 +- .../task-builtins.wast/19.print | 6 +- .../task-builtins.wast/36.print | 2 + .../component-model-async/threading.wast.json | 263 ++---------- .../threading.wast/0.print | 14 +- .../threading.wast/11.print | 22 +- .../threading.wast/13.print | 22 +- .../threading.wast/15.print | 35 +- .../threading.wast/{41.print => 16.print} | 0 .../threading.wast/17.print | 14 - .../threading.wast/19.print | 14 - .../threading.wast/2.print | 14 - .../threading.wast/21.print | 14 - .../threading.wast/23.print | 14 - .../threading.wast/25.print | 24 -- .../threading.wast/36.print | 10 - .../threading.wast/37.print | 21 - .../threading.wast/38.print | 10 - .../threading.wast/39.print | 21 - .../threading.wast/40.print | 69 --- .../threading.wast/42.print | 14 - .../threading.wast/43.print | 4 - .../threading.wast/44.print | 14 - .../threading.wast/46.print | 97 ----- .../threading.wast/47.print | 4 - .../threading.wast/7.print | 16 +- .../threading.wast/8.print | 23 +- .../threading.wast/9.print | 14 - .../component-model/async-builtins.wast.json | 52 +++ .../async-builtins.wast/4.print | 0 .../async-builtins.wast/6.print | 0 .../component-model/async-stackful.wast.json | 51 +++ .../async-stackful.wast/2.print | 0 .../async-stackful.wast/4.print | 0 .../async-stackful.wast/6.print | 0 .../component-model/async.wast.json | 2 +- .../component-model/threading.wast.json | 95 +---- .../component-model/threading.wast/10.print | 8 - .../component-model/threading.wast/11.print | 8 - .../component-model/threading.wast/12.print | 4 - .../component-model/threading.wast/13.print | 4 - .../component-model/threading.wast/2.print | 9 - .../component-model/threading.wast/4.print | 9 - .../component-model/threading.wast/6.print | 3 - 66 files changed, 1131 insertions(+), 1522 deletions(-) create mode 100644 crates/wit-component/tests/components/async-builtins/component.wat create mode 100644 crates/wit-component/tests/components/async-builtins/component.wit.print create mode 100644 crates/wit-component/tests/components/async-builtins/module.wat create mode 100644 crates/wit-component/tests/components/async-builtins/module.wit create mode 100644 tests/cli/component-model-async/task-builtins.wast create mode 100644 tests/cli/missing-features/component-model/async-builtins.wast create mode 100644 tests/cli/missing-features/component-model/async-stackful.wast rename tests/snapshots/cli/component-model-async/threading.wast/{41.print => 16.print} (100%) delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/17.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/19.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/2.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/21.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/23.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/25.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/36.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/37.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/38.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/39.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/40.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/42.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/43.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/44.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/46.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/47.print delete mode 100644 tests/snapshots/cli/component-model-async/threading.wast/9.print create mode 100644 tests/snapshots/cli/missing-features/component-model/async-builtins.wast.json rename tests/snapshots/cli/missing-features/{ => component-model}/async-builtins.wast/4.print (100%) rename tests/snapshots/cli/missing-features/{ => component-model}/async-builtins.wast/6.print (100%) create mode 100644 tests/snapshots/cli/missing-features/component-model/async-stackful.wast.json rename tests/snapshots/cli/missing-features/{ => component-model}/async-stackful.wast/2.print (100%) rename tests/snapshots/cli/missing-features/{ => component-model}/async-stackful.wast/4.print (100%) rename tests/snapshots/cli/missing-features/{ => component-model}/async-stackful.wast/6.print (100%) delete mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/10.print delete mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/11.print delete mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/12.print delete mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/13.print delete mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/2.print delete mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/4.print delete mode 100644 tests/snapshots/cli/missing-features/component-model/threading.wast/6.print diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index 416ddfd9f3..6072bb44c0 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -254,27 +254,38 @@ define_wasm_features! { /// Corresponds to the ๐Ÿ”€ character in /// . pub cm_async: CM_ASYNC(1 << 27) = false; + /// Gates the "stackful ABI" in the component model async proposal. + /// + /// Corresponds to the ๐ŸšŸ character in + /// . + pub cm_async_stackful: CM_ASYNC_STACKFUL(1 << 28) = false; + /// Gates some intrinsics being marked with `async` in the component + /// model async proposal. + /// + /// Corresponds to the ๐Ÿš character in + /// . + pub cm_async_builtins: CM_ASYNC_BUILTINS(1 << 29) = false; /// Support for threading in the component model proposal. /// /// Corresponds to the ๐Ÿงต character in /// . - pub cm_threading: CM_THREADING(1 << 28) = false; + pub cm_threading: CM_THREADING(1 << 30) = false; /// Gates some intrinsics being marked with `error-context` in the component /// model async proposal. /// /// Corresponds to the ๐Ÿ“ character in /// . - pub cm_error_context: CM_ERROR_CONTEXT(1 << 29) = false; + pub cm_error_context: CM_ERROR_CONTEXT(1 << 31) = false; /// Support for fixed size lists /// /// Corresponds to the ๐Ÿ”ง character in /// . - pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 30) = false; + pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 32) = false; /// Support for Wasm GC in the component model proposal. /// /// Corresponds to the ๐Ÿ›ธ character in /// . - pub cm_gc: CM_GC(1 << 31) = false; + pub cm_gc: CM_GC(1 << 33) = false; /// Subset of the reference-types WebAssembly proposal which only /// encompasses the leb-encoding of the table immediate to the @@ -282,13 +293,13 @@ define_wasm_features! { /// integer for example. /// /// This is a subcomponent of the "lime1" feature. - pub call_indirect_overlong: CALL_INDIRECT_OVERLONG(1 << 32) = true; + pub call_indirect_overlong: CALL_INDIRECT_OVERLONG(1 << 34) = true; /// Subset of the bulk-memory proposal covering just the `memory.copy` /// and `memory.fill` instructions. /// /// This is a subcomponent of the "lime1" feature. - pub bulk_memory_opt: BULK_MEMORY_OPT(1 << 33) = true; + pub bulk_memory_opt: BULK_MEMORY_OPT(1 << 35) = true; } } diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 5e27bbe895..b1948dc150 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -363,8 +363,11 @@ impl CanonicalOptions { match self.concurrency { Concurrency::Sync => {} - Concurrency::Async { callback: None } if !state.features.cm_threading() => { - bail!(offset, "requires the component model threading feature") + Concurrency::Async { callback: None } if !state.features.cm_async_stackful() => { + bail!( + offset, + "requires the component model async stackful feature" + ) } Concurrency::Async { callback: None } => {} @@ -1369,10 +1372,10 @@ impl ComponentState { types: &mut TypeAlloc, offset: usize, ) -> Result<()> { - if !self.features.cm_threading() { + if !self.features.cm_async_builtins() { bail!( offset, - "`resource.drop` as `async` requires the component model threading feature" + "`resource.drop` as `async` requires the component model async builtins feature" ) } self.resource_at(resource, types, offset)?; @@ -1526,10 +1529,10 @@ impl ComponentState { "`thread.yield` requires the component model async feature" ) } - if cancellable && !self.features.cm_threading() { + if cancellable && !self.features.cm_async_stackful() { bail!( offset, - "cancellable `thread.yield` requires the component model threading feature" + "cancellable `thread.yield` requires the component model async stackful feature" ) } @@ -1558,10 +1561,10 @@ impl ComponentState { "`subtask.cancel` requires the component model async feature" ) } - if async_ && !self.features.cm_threading() { + if async_ && !self.features.cm_async_builtins() { bail!( offset, - "async `subtask.cancel` requires the component model threading feature" + "async `subtask.cancel` requires the component model async builtins feature" ) } @@ -1668,10 +1671,10 @@ impl ComponentState { "`stream.cancel-read` requires the component model async feature" ) } - if cancellable && !self.features.cm_threading() { + if cancellable && !self.features.cm_async_builtins() { bail!( offset, - "async `stream.cancel-read` requires the component model threading feature" + "async `stream.cancel-read` requires the component model async builtins feature" ) } @@ -1698,10 +1701,10 @@ impl ComponentState { "`stream.cancel-write` requires the component model async feature" ) } - if cancellable && !self.features.cm_threading() { + if cancellable && !self.features.cm_async_builtins() { bail!( offset, - "async `stream.cancel-write` requires the component model threading feature" + "async `stream.cancel-write` requires the component model async builtins feature" ) } @@ -1858,10 +1861,10 @@ impl ComponentState { "`future.cancel-read` requires the component model async feature" ) } - if cancellable && !self.features.cm_threading() { + if cancellable && !self.features.cm_async_builtins() { bail!( offset, - "async `future.cancel-read` requires the component model threading feature" + "async `future.cancel-read` requires the component model async builtins feature" ) } @@ -1888,10 +1891,10 @@ impl ComponentState { "`future.cancel-write` requires the component model async feature" ) } - if cancellable && !self.features.cm_threading() { + if cancellable && !self.features.cm_async_builtins() { bail!( offset, - "async `future.cancel-write` requires the component model threading feature" + "async `future.cancel-write` requires the component model async builtins feature" ) } @@ -2043,10 +2046,10 @@ impl ComponentState { "`waitable-set.wait` requires the component model async feature" ) } - if cancellable && !self.features.cm_threading() { + if cancellable && !self.features.cm_async_stackful() { bail!( offset, - "cancellable `waitable-set.wait` requires the component model threading feature" + "cancellable `waitable-set.wait` requires the component model async stackful feature" ) } @@ -2070,10 +2073,10 @@ impl ComponentState { "`waitable-set.poll` requires the component model async feature" ) } - if cancellable && !self.features.cm_threading() { + if cancellable && !self.features.cm_async_stackful() { bail!( offset, - "cancellable `waitable-set.poll` requires the component model threading feature" + "cancellable `waitable-set.poll` requires the component model async stackful feature" ) } diff --git a/crates/wit-component/tests/components/async-builtins/component.wat b/crates/wit-component/tests/components/async-builtins/component.wat new file mode 100644 index 0000000000..e5c37d5217 --- /dev/null +++ b/crates/wit-component/tests/components/async-builtins/component.wat @@ -0,0 +1,256 @@ +(component + (core module (;0;) + (type (;0;) (func (param i32))) + (type (;1;) (func)) + (type (;2;) (func (param i32 i32))) + (type (;3;) (func (result i32))) + (type (;4;) (func (param i32 i32) (result i32))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i32 i32 i32 i32) (result i32))) + (import "$root" "[backpressure-set]" (func (;0;) (type 0))) + (import "[export]$root" "[task-cancel]" (func (;1;) (type 1))) + (import "[export]$root" "[task-return]foo" (func (;2;) (type 2))) + (import "[export]foo:foo/bar" "[task-return]foo" (func (;3;) (type 2))) + (import "$root" "[waitable-set-new]" (func (;4;) (type 3))) + (import "$root" "[waitable-set-wait]" (func (;5;) (type 4))) + (import "$root" "[waitable-set-poll]" (func (;6;) (type 4))) + (import "$root" "[waitable-set-drop]" (func (;7;) (type 0))) + (import "$root" "[waitable-join]" (func (;8;) (type 2))) + (import "$root" "[thread-yield]" (func (;9;) (type 3))) + (import "$root" "[subtask-drop]" (func (;10;) (type 0))) + (import "$root" "[subtask-cancel]" (func (;11;) (type 5))) + (import "$root" "[error-context-new-utf8]" (func (;12;) (type 4))) + (import "$root" "[error-context-new-utf16]" (func (;13;) (type 4))) + (import "$root" "[error-context-new-latin1+utf16]" (func (;14;) (type 4))) + (import "$root" "[error-context-debug-message-utf8]" (func (;15;) (type 2))) + (import "$root" "[error-context-debug-message-utf16]" (func (;16;) (type 2))) + (import "$root" "[error-context-debug-message-latin1+utf16]" (func (;17;) (type 2))) + (import "$root" "[error-context-drop]" (func (;18;) (type 0))) + (import "$root" "[context-get-0]" (func (;19;) (type 3))) + (import "$root" "[context-set-0]" (func (;20;) (type 0))) + (memory (;0;) 1) + (export "[async-lift-stackful]foo" (func 21)) + (export "[async-lift-stackful]foo:foo/bar#foo" (func 22)) + (export "memory" (memory 0)) + (export "cabi_realloc" (func 23)) + (func (;21;) (type 2) (param i32 i32) + unreachable + ) + (func (;22;) (type 2) (param i32 i32) + unreachable + ) + (func (;23;) (type 6) (param i32 i32 i32 i32) (result i32) + unreachable + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + (processed-by "my-fake-bindgen" "123.45") + ) + ) + (core module (;1;) + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (type (;2;) (func (param i32 i32))) + (table (;0;) 10 10 funcref) + (export "0" (func $waitable-set.wait)) + (export "1" (func $waitable-set.poll)) + (export "2" (func $error-new)) + (export "3" (func $"#func3 error-new")) + (export "4" (func $"#func4 error-new")) + (export "5" (func $error-debug-message)) + (export "6" (func $"#func6 error-debug-message")) + (export "7" (func $"#func7 error-debug-message")) + (export "8" (func $task-return-foo)) + (export "9" (func $"#func9 task-return-foo")) + (export "$imports" (table 0)) + (func $waitable-set.wait (;0;) (type 0) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.const 0 + call_indirect (type 0) + ) + (func $waitable-set.poll (;1;) (type 0) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.const 1 + call_indirect (type 0) + ) + (func $error-new (;2;) (type 0) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.const 2 + call_indirect (type 0) + ) + (func $"#func3 error-new" (@name "error-new") (;3;) (type 0) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.const 3 + call_indirect (type 0) + ) + (func $"#func4 error-new" (@name "error-new") (;4;) (type 0) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.const 4 + call_indirect (type 0) + ) + (func $error-debug-message (;5;) (type 1) (param i32 i32) + local.get 0 + local.get 1 + i32.const 5 + call_indirect (type 1) + ) + (func $"#func6 error-debug-message" (@name "error-debug-message") (;6;) (type 1) (param i32 i32) + local.get 0 + local.get 1 + i32.const 6 + call_indirect (type 1) + ) + (func $"#func7 error-debug-message" (@name "error-debug-message") (;7;) (type 1) (param i32 i32) + local.get 0 + local.get 1 + i32.const 7 + call_indirect (type 1) + ) + (func $task-return-foo (;8;) (type 2) (param i32 i32) + local.get 0 + local.get 1 + i32.const 8 + call_indirect (type 2) + ) + (func $"#func9 task-return-foo" (@name "task-return-foo") (;9;) (type 2) (param i32 i32) + local.get 0 + local.get 1 + i32.const 9 + call_indirect (type 2) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core module (;2;) + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (param i32 i32))) + (type (;2;) (func (param i32 i32))) + (import "" "0" (func (;0;) (type 0))) + (import "" "1" (func (;1;) (type 0))) + (import "" "2" (func (;2;) (type 0))) + (import "" "3" (func (;3;) (type 0))) + (import "" "4" (func (;4;) (type 0))) + (import "" "5" (func (;5;) (type 1))) + (import "" "6" (func (;6;) (type 1))) + (import "" "7" (func (;7;) (type 1))) + (import "" "8" (func (;8;) (type 2))) + (import "" "9" (func (;9;) (type 2))) + (import "" "$imports" (table (;0;) 10 10 funcref)) + (elem (;0;) (i32.const 0) func 0 1 2 3 4 5 6 7 8 9) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) + ) + (core instance (;0;) (instantiate 1)) + (core func (;0;) (canon backpressure.set)) + (core func (;1;) (canon waitable-set.new)) + (alias core export 0 "0" (core func (;2;))) + (alias core export 0 "1" (core func (;3;))) + (core func (;4;) (canon waitable-set.drop)) + (core func (;5;) (canon waitable.join)) + (core func (;6;) (canon thread.yield)) + (core func (;7;) (canon subtask.drop)) + (core func (;8;) (canon subtask.cancel)) + (alias core export 0 "2" (core func (;9;))) + (alias core export 0 "3" (core func (;10;))) + (alias core export 0 "4" (core func (;11;))) + (alias core export 0 "5" (core func (;12;))) + (alias core export 0 "6" (core func (;13;))) + (alias core export 0 "7" (core func (;14;))) + (core func (;15;) (canon error-context.drop)) + (core func (;16;) (canon context.get i32 0)) + (core func (;17;) (canon context.set i32 0)) + (core instance (;1;) + (export "[backpressure-set]" (func 0)) + (export "[waitable-set-new]" (func 1)) + (export "[waitable-set-wait]" (func 2)) + (export "[waitable-set-poll]" (func 3)) + (export "[waitable-set-drop]" (func 4)) + (export "[waitable-join]" (func 5)) + (export "[thread-yield]" (func 6)) + (export "[subtask-drop]" (func 7)) + (export "[subtask-cancel]" (func 8)) + (export "[error-context-new-utf8]" (func 9)) + (export "[error-context-new-utf16]" (func 10)) + (export "[error-context-new-latin1+utf16]" (func 11)) + (export "[error-context-debug-message-utf8]" (func 12)) + (export "[error-context-debug-message-utf16]" (func 13)) + (export "[error-context-debug-message-latin1+utf16]" (func 14)) + (export "[error-context-drop]" (func 15)) + (export "[context-get-0]" (func 16)) + (export "[context-set-0]" (func 17)) + ) + (core func (;18;) (canon task.cancel)) + (alias core export 0 "8" (core func (;19;))) + (core instance (;2;) + (export "[task-cancel]" (func 18)) + (export "[task-return]foo" (func 19)) + ) + (alias core export 0 "9" (core func (;20;))) + (core instance (;3;) + (export "[task-return]foo" (func 20)) + ) + (core instance (;4;) (instantiate 0 + (with "$root" (instance 1)) + (with "[export]$root" (instance 2)) + (with "[export]foo:foo/bar" (instance 3)) + ) + ) + (alias core export 4 "memory" (core memory (;0;))) + (alias core export 0 "$imports" (core table (;0;))) + (core func (;21;) (canon waitable-set.wait (memory 0))) + (core func (;22;) (canon waitable-set.poll (memory 0))) + (core func (;23;) (canon error-context.new (memory 0) string-encoding=utf8)) + (core func (;24;) (canon error-context.new (memory 0) string-encoding=utf16)) + (core func (;25;) (canon error-context.new (memory 0) string-encoding=latin1+utf16)) + (alias core export 4 "cabi_realloc" (core func (;26;))) + (core func (;27;) (canon error-context.debug-message (memory 0) (realloc 26) string-encoding=utf8)) + (core func (;28;) (canon error-context.debug-message (memory 0) (realloc 26) string-encoding=utf16)) + (core func (;29;) (canon error-context.debug-message (memory 0) (realloc 26) string-encoding=latin1+utf16)) + (core func (;30;) (canon task.return (result string) (memory 0) string-encoding=utf8)) + (core func (;31;) (canon task.return (result string) (memory 0) string-encoding=utf8)) + (core instance (;5;) + (export "$imports" (table 0)) + (export "0" (func 21)) + (export "1" (func 22)) + (export "2" (func 23)) + (export "3" (func 24)) + (export "4" (func 25)) + (export "5" (func 27)) + (export "6" (func 28)) + (export "7" (func 29)) + (export "8" (func 30)) + (export "9" (func 31)) + ) + (core instance (;6;) (instantiate 2 + (with "" (instance 5)) + ) + ) + (type (;0;) (func (param "s" string) (result string))) + (alias core export 4 "[async-lift-stackful]foo" (core func (;32;))) + (func (;0;) (type 0) (canon lift (core func 32) (memory 0) (realloc 26) string-encoding=utf8 async)) + (export (;1;) "foo" (func 0)) + (type (;1;) (func (param "s" string) (result string))) + (alias core export 4 "[async-lift-stackful]foo:foo/bar#foo" (core func (;33;))) + (func (;2;) (type 1) (canon lift (core func 33) (memory 0) (realloc 26) string-encoding=utf8 async)) + (component (;0;) + (type (;0;) (func (param "s" string) (result string))) + (import "import-func-foo" (func (;0;) (type 0))) + (type (;1;) (func (param "s" string) (result string))) + (export (;1;) "foo" (func 0) (func (type 1))) + ) + (instance (;0;) (instantiate 0 + (with "import-func-foo" (func 2)) + ) + ) + (export (;1;) "foo:foo/bar" (instance 0)) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) diff --git a/crates/wit-component/tests/components/async-builtins/component.wit.print b/crates/wit-component/tests/components/async-builtins/component.wit.print new file mode 100644 index 0000000000..8c6e69aa82 --- /dev/null +++ b/crates/wit-component/tests/components/async-builtins/component.wit.print @@ -0,0 +1,6 @@ +package root:component; + +world root { + export foo: func(s: string) -> string; + export foo:foo/bar; +} diff --git a/crates/wit-component/tests/components/async-builtins/module.wat b/crates/wit-component/tests/components/async-builtins/module.wat new file mode 100644 index 0000000000..9b0ee257d1 --- /dev/null +++ b/crates/wit-component/tests/components/async-builtins/module.wat @@ -0,0 +1,27 @@ +(module + (import "$root" "[backpressure-set]" (func (param i32))) + (import "[export]$root" "[task-cancel]" (func)) + (import "[export]$root" "[task-return]foo" (func (param i32 i32))) + (import "[export]foo:foo/bar" "[task-return]foo" (func (param i32 i32))) + (import "$root" "[waitable-set-new]" (func (result i32))) + (import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32))) + (import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32))) + (import "$root" "[waitable-set-drop]" (func (param i32))) + (import "$root" "[waitable-join]" (func (param i32 i32))) + (import "$root" "[thread-yield]" (func (result i32))) + (import "$root" "[subtask-drop]" (func (param i32))) + (import "$root" "[subtask-cancel]" (func (param i32) (result i32))) + (import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32))) + (import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32))) + (import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32))) + (import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32))) + (import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32))) + (import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32))) + (import "$root" "[error-context-drop]" (func (param i32))) + (import "$root" "[context-get-0]" (func (result i32))) + (import "$root" "[context-set-0]" (func (param i32))) + (func (export "[async-lift-stackful]foo") (param i32 i32) unreachable) + (func (export "[async-lift-stackful]foo:foo/bar#foo") (param i32 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/async-builtins/module.wit b/crates/wit-component/tests/components/async-builtins/module.wit new file mode 100644 index 0000000000..f0629ae1d2 --- /dev/null +++ b/crates/wit-component/tests/components/async-builtins/module.wit @@ -0,0 +1,10 @@ +package foo:foo; + +interface bar { + foo: func(s: string) -> string; +} + +world module { + export bar; + export foo: func(s: string) -> string; +} diff --git a/crates/wit-component/tests/components/threading/component.wat b/crates/wit-component/tests/components/threading/component.wat index cde783a484..6287883974 100644 --- a/crates/wit-component/tests/components/threading/component.wat +++ b/crates/wit-component/tests/components/threading/component.wat @@ -7,54 +7,36 @@ (type (;4;) (func (param i32 i32) (result i32))) (type (;5;) (func (param i32) (result i32))) (type (;6;) (func (param i32 i32 i32 i32) (result i32))) - (import "$root" "[backpressure-set]" (func (;0;) (type $thread-start-func-ty))) - (import "[export]$root" "[task-cancel]" (func (;1;) (type 1))) - (import "[export]$root" "[task-return]foo" (func (;2;) (type 2))) - (import "[export]foo:foo/bar" "[task-return]foo" (func (;3;) (type 2))) - (import "$root" "[waitable-set-new]" (func (;4;) (type 3))) - (import "$root" "[waitable-set-wait]" (func (;5;) (type 4))) - (import "$root" "[waitable-set-poll]" (func (;6;) (type 4))) - (import "$root" "[waitable-set-drop]" (func (;7;) (type $thread-start-func-ty))) - (import "$root" "[waitable-join]" (func (;8;) (type 2))) - (import "$root" "[thread-yield]" (func (;9;) (type 3))) - (import "$root" "[subtask-drop]" (func (;10;) (type $thread-start-func-ty))) - (import "$root" "[subtask-cancel]" (func (;11;) (type 5))) - (import "$root" "[error-context-new-utf8]" (func (;12;) (type 4))) - (import "$root" "[error-context-new-utf16]" (func (;13;) (type 4))) - (import "$root" "[error-context-new-latin1+utf16]" (func (;14;) (type 4))) - (import "$root" "[error-context-debug-message-utf8]" (func (;15;) (type 2))) - (import "$root" "[error-context-debug-message-utf16]" (func (;16;) (type 2))) - (import "$root" "[error-context-debug-message-latin1+utf16]" (func (;17;) (type 2))) - (import "$root" "[error-context-drop]" (func (;18;) (type $thread-start-func-ty))) - (import "$root" "[context-get-0]" (func (;19;) (type 3))) - (import "$root" "[context-set-0]" (func (;20;) (type $thread-start-func-ty))) - (import "$root" "[context-get-1]" (func (;21;) (type 3))) - (import "$root" "[context-set-1]" (func (;22;) (type $thread-start-func-ty))) - (import "$root" "[thread-index]" (func (;23;) (type 3))) - (import "$root" "[thread-new-indirect-v0]" (func (;24;) (type 4))) - (import "$root" "[thread-switch-to]" (func (;25;) (type 5))) - (import "$root" "[thread-suspend]" (func (;26;) (type 3))) - (import "$root" "[thread-resume-later]" (func (;27;) (type $thread-start-func-ty))) - (import "$root" "[thread-yield-to]" (func (;28;) (type 5))) + (import "[export]$root" "[task-cancel]" (func (;0;) (type 1))) + (import "[export]$root" "[task-return]foo" (func (;1;) (type 2))) + (import "[export]foo:foo/bar" "[task-return]foo" (func (;2;) (type 2))) + (import "$root" "[context-get-1]" (func (;3;) (type 3))) + (import "$root" "[context-set-1]" (func (;4;) (type $thread-start-func-ty))) + (import "$root" "[thread-index]" (func (;5;) (type 3))) + (import "$root" "[thread-new-indirect-v0]" (func (;6;) (type 4))) + (import "$root" "[thread-switch-to]" (func (;7;) (type 5))) + (import "$root" "[thread-suspend]" (func (;8;) (type 3))) + (import "$root" "[thread-resume-later]" (func (;9;) (type $thread-start-func-ty))) + (import "$root" "[thread-yield-to]" (func (;10;) (type 5))) (table (;0;) 1 1 funcref) (memory (;0;) 1) - (export "thread_main" (func 29)) - (export "[async-lift-stackful]foo" (func 30)) - (export "[async-lift-stackful]foo:foo/bar#foo" (func 31)) + (export "thread_main" (func 11)) + (export "[async-lift-stackful]foo" (func 12)) + (export "[async-lift-stackful]foo:foo/bar#foo" (func 13)) (export "memory" (memory 0)) (export "__indirect_function_table" (table 0)) - (export "cabi_realloc" (func 32)) + (export "cabi_realloc" (func 14)) (elem (;0;) (i32.const 0) func 0) - (func (;29;) (type $thread-start-func-ty) (param i32) + (func (;11;) (type $thread-start-func-ty) (param i32) unreachable ) - (func (;30;) (type 2) (param i32 i32) + (func (;12;) (type 2) (param i32 i32) unreachable ) - (func (;31;) (type 2) (param i32 i32) + (func (;13;) (type 2) (param i32 i32) unreachable ) - (func (;32;) (type 6) (param i32 i32 i32 i32) (result i32) + (func (;14;) (type 6) (param i32 i32 i32 i32) (result i32) unreachable ) (@producers @@ -63,225 +45,107 @@ ) ) (core module (;1;) - (type (;0;) (func (param i32 i32) (result i32))) - (type (;1;) (func (param i32 i32))) - (type (;2;) (func (param i32 i32))) - (table (;0;) 11 11 funcref) - (export "0" (func $waitable-set.wait)) - (export "1" (func $waitable-set.poll)) - (export "2" (func $error-new)) - (export "3" (func $"#func3 error-new")) - (export "4" (func $"#func4 error-new")) - (export "5" (func $error-debug-message)) - (export "6" (func $"#func6 error-debug-message")) - (export "7" (func $"#func7 error-debug-message")) - (export "8" (func $thread.new_indirect)) - (export "9" (func $task-return-foo)) - (export "10" (func $"#func10 task-return-foo")) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32) (result i32))) + (table (;0;) 3 3 funcref) + (export "0" (func $task-return-foo)) + (export "1" (func $"#func1 task-return-foo")) + (export "2" (func $thread.new_indirect)) (export "$imports" (table 0)) - (func $waitable-set.wait (;0;) (type 0) (param i32 i32) (result i32) + (func $task-return-foo (;0;) (type 0) (param i32 i32) local.get 0 local.get 1 i32.const 0 call_indirect (type 0) ) - (func $waitable-set.poll (;1;) (type 0) (param i32 i32) (result i32) + (func $"#func1 task-return-foo" (@name "task-return-foo") (;1;) (type 0) (param i32 i32) local.get 0 local.get 1 i32.const 1 call_indirect (type 0) ) - (func $error-new (;2;) (type 0) (param i32 i32) (result i32) + (func $thread.new_indirect (;2;) (type 1) (param i32 i32) (result i32) local.get 0 local.get 1 i32.const 2 - call_indirect (type 0) - ) - (func $"#func3 error-new" (@name "error-new") (;3;) (type 0) (param i32 i32) (result i32) - local.get 0 - local.get 1 - i32.const 3 - call_indirect (type 0) - ) - (func $"#func4 error-new" (@name "error-new") (;4;) (type 0) (param i32 i32) (result i32) - local.get 0 - local.get 1 - i32.const 4 - call_indirect (type 0) - ) - (func $error-debug-message (;5;) (type 1) (param i32 i32) - local.get 0 - local.get 1 - i32.const 5 - call_indirect (type 1) - ) - (func $"#func6 error-debug-message" (@name "error-debug-message") (;6;) (type 1) (param i32 i32) - local.get 0 - local.get 1 - i32.const 6 - call_indirect (type 1) - ) - (func $"#func7 error-debug-message" (@name "error-debug-message") (;7;) (type 1) (param i32 i32) - local.get 0 - local.get 1 - i32.const 7 call_indirect (type 1) ) - (func $thread.new_indirect (;8;) (type 0) (param i32 i32) (result i32) - local.get 0 - local.get 1 - i32.const 8 - call_indirect (type 0) - ) - (func $task-return-foo (;9;) (type 2) (param i32 i32) - local.get 0 - local.get 1 - i32.const 9 - call_indirect (type 2) - ) - (func $"#func10 task-return-foo" (@name "task-return-foo") (;10;) (type 2) (param i32 i32) - local.get 0 - local.get 1 - i32.const 10 - call_indirect (type 2) - ) (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) ) (core module (;2;) - (type (;0;) (func (param i32 i32) (result i32))) - (type (;1;) (func (param i32 i32))) - (type (;2;) (func (param i32 i32))) + (type (;0;) (func (param i32 i32))) + (type (;1;) (func (param i32 i32) (result i32))) (import "" "0" (func (;0;) (type 0))) (import "" "1" (func (;1;) (type 0))) - (import "" "2" (func (;2;) (type 0))) - (import "" "3" (func (;3;) (type 0))) - (import "" "4" (func (;4;) (type 0))) - (import "" "5" (func (;5;) (type 1))) - (import "" "6" (func (;6;) (type 1))) - (import "" "7" (func (;7;) (type 1))) - (import "" "8" (func (;8;) (type 0))) - (import "" "9" (func (;9;) (type 2))) - (import "" "10" (func (;10;) (type 2))) - (import "" "$imports" (table (;0;) 11 11 funcref)) - (elem (;0;) (i32.const 0) func 0 1 2 3 4 5 6 7 8 9 10) + (import "" "2" (func (;2;) (type 1))) + (import "" "$imports" (table (;0;) 3 3 funcref)) + (elem (;0;) (i32.const 0) func 0 1 2) (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) ) (core instance (;0;) (instantiate 1)) - (core func (;0;) (canon backpressure.set)) - (core func (;1;) (canon waitable-set.new)) - (alias core export 0 "0" (core func (;2;))) - (alias core export 0 "1" (core func (;3;))) - (core func (;4;) (canon waitable-set.drop)) - (core func (;5;) (canon waitable.join)) - (core func (;6;) (canon thread.yield)) - (core func (;7;) (canon subtask.drop)) - (core func (;8;) (canon subtask.cancel)) - (alias core export 0 "2" (core func (;9;))) - (alias core export 0 "3" (core func (;10;))) - (alias core export 0 "4" (core func (;11;))) - (alias core export 0 "5" (core func (;12;))) - (alias core export 0 "6" (core func (;13;))) - (alias core export 0 "7" (core func (;14;))) - (core func (;15;) (canon error-context.drop)) - (core func (;16;) (canon context.get i32 0)) - (core func (;17;) (canon context.set i32 0)) - (core func (;18;) (canon context.get i32 1)) - (core func (;19;) (canon context.set i32 1)) - (core func (;20;) (canon thread.index)) - (alias core export 0 "8" (core func (;21;))) - (core func (;22;) (canon thread.switch-to)) - (core func (;23;) (canon thread.suspend)) - (core func (;24;) (canon thread.resume-later)) - (core func (;25;) (canon thread.yield-to)) + (core func (;0;) (canon task.cancel)) + (alias core export 0 "0" (core func (;1;))) (core instance (;1;) - (export "[backpressure-set]" (func 0)) - (export "[waitable-set-new]" (func 1)) - (export "[waitable-set-wait]" (func 2)) - (export "[waitable-set-poll]" (func 3)) - (export "[waitable-set-drop]" (func 4)) - (export "[waitable-join]" (func 5)) - (export "[thread-yield]" (func 6)) - (export "[subtask-drop]" (func 7)) - (export "[subtask-cancel]" (func 8)) - (export "[error-context-new-utf8]" (func 9)) - (export "[error-context-new-utf16]" (func 10)) - (export "[error-context-new-latin1+utf16]" (func 11)) - (export "[error-context-debug-message-utf8]" (func 12)) - (export "[error-context-debug-message-utf16]" (func 13)) - (export "[error-context-debug-message-latin1+utf16]" (func 14)) - (export "[error-context-drop]" (func 15)) - (export "[context-get-0]" (func 16)) - (export "[context-set-0]" (func 17)) - (export "[context-get-1]" (func 18)) - (export "[context-set-1]" (func 19)) - (export "[thread-index]" (func 20)) - (export "[thread-new-indirect-v0]" (func 21)) - (export "[thread-switch-to]" (func 22)) - (export "[thread-suspend]" (func 23)) - (export "[thread-resume-later]" (func 24)) - (export "[thread-yield-to]" (func 25)) + (export "[task-cancel]" (func 0)) + (export "[task-return]foo" (func 1)) ) - (core func (;26;) (canon task.cancel)) - (alias core export 0 "9" (core func (;27;))) + (alias core export 0 "1" (core func (;2;))) (core instance (;2;) - (export "[task-cancel]" (func 26)) - (export "[task-return]foo" (func 27)) + (export "[task-return]foo" (func 2)) ) - (alias core export 0 "10" (core func (;28;))) + (core func (;3;) (canon context.get i32 1)) + (core func (;4;) (canon context.set i32 1)) + (core func (;5;) (canon thread.index)) + (alias core export 0 "2" (core func (;6;))) + (core func (;7;) (canon thread.switch-to)) + (core func (;8;) (canon thread.suspend)) + (core func (;9;) (canon thread.resume-later)) + (core func (;10;) (canon thread.yield-to)) (core instance (;3;) - (export "[task-return]foo" (func 28)) + (export "[context-get-1]" (func 3)) + (export "[context-set-1]" (func 4)) + (export "[thread-index]" (func 5)) + (export "[thread-new-indirect-v0]" (func 6)) + (export "[thread-switch-to]" (func 7)) + (export "[thread-suspend]" (func 8)) + (export "[thread-resume-later]" (func 9)) + (export "[thread-yield-to]" (func 10)) ) (core instance (;4;) (instantiate 0 - (with "$root" (instance 1)) - (with "[export]$root" (instance 2)) - (with "[export]foo:foo/bar" (instance 3)) + (with "[export]$root" (instance 1)) + (with "[export]foo:foo/bar" (instance 2)) + (with "$root" (instance 3)) ) ) (alias core export 4 "memory" (core memory (;0;))) (alias core export 0 "$imports" (core table (;0;))) - (core func (;29;) (canon waitable-set.wait (memory 0))) - (core func (;30;) (canon waitable-set.poll (memory 0))) - (core func (;31;) (canon error-context.new (memory 0) string-encoding=utf8)) - (core func (;32;) (canon error-context.new (memory 0) string-encoding=utf16)) - (core func (;33;) (canon error-context.new (memory 0) string-encoding=latin1+utf16)) - (alias core export 4 "cabi_realloc" (core func (;34;))) - (core func (;35;) (canon error-context.debug-message (memory 0) (realloc 34) string-encoding=utf8)) - (core func (;36;) (canon error-context.debug-message (memory 0) (realloc 34) string-encoding=utf16)) - (core func (;37;) (canon error-context.debug-message (memory 0) (realloc 34) string-encoding=latin1+utf16)) + (alias core export 4 "cabi_realloc" (core func (;11;))) + (core func (;12;) (canon task.return (result string) (memory 0) string-encoding=utf8)) + (core func (;13;) (canon task.return (result string) (memory 0) string-encoding=utf8)) (core type (;0;) (func (param i32))) (alias core export 4 "__indirect_function_table" (core table (;1;))) - (core func (;38;) (canon thread.new_indirect 0 (table 1))) - (core func (;39;) (canon task.return (result string) (memory 0) string-encoding=utf8)) - (core func (;40;) (canon task.return (result string) (memory 0) string-encoding=utf8)) + (core func (;14;) (canon thread.new_indirect 0 (table 1))) (core instance (;5;) (export "$imports" (table 0)) - (export "0" (func 29)) - (export "1" (func 30)) - (export "2" (func 31)) - (export "3" (func 32)) - (export "4" (func 33)) - (export "5" (func 35)) - (export "6" (func 36)) - (export "7" (func 37)) - (export "8" (func 38)) - (export "9" (func 39)) - (export "10" (func 40)) + (export "0" (func 12)) + (export "1" (func 13)) + (export "2" (func 14)) ) (core instance (;6;) (instantiate 2 (with "" (instance 5)) ) ) (type (;0;) (func (param "s" string) (result string))) - (alias core export 4 "[async-lift-stackful]foo" (core func (;41;))) - (func (;0;) (type 0) (canon lift (core func 41) (memory 0) (realloc 34) string-encoding=utf8 async)) + (alias core export 4 "[async-lift-stackful]foo" (core func (;15;))) + (func (;0;) (type 0) (canon lift (core func 15) (memory 0) (realloc 11) string-encoding=utf8 async)) (export (;1;) "foo" (func 0)) (type (;1;) (func (param "s" string) (result string))) - (alias core export 4 "[async-lift-stackful]foo:foo/bar#foo" (core func (;42;))) - (func (;2;) (type 1) (canon lift (core func 42) (memory 0) (realloc 34) string-encoding=utf8 async)) + (alias core export 4 "[async-lift-stackful]foo:foo/bar#foo" (core func (;16;))) + (func (;2;) (type 1) (canon lift (core func 16) (memory 0) (realloc 11) 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/threading/module.wat b/crates/wit-component/tests/components/threading/module.wat index 0d5a13aa6d..4b4099ed48 100644 --- a/crates/wit-component/tests/components/threading/module.wat +++ b/crates/wit-component/tests/components/threading/module.wat @@ -1,26 +1,8 @@ (module (type $thread-start-func-ty (func (param i32))) - (import "$root" "[backpressure-set]" (func (param i32))) (import "[export]$root" "[task-cancel]" (func)) (import "[export]$root" "[task-return]foo" (func (param i32 i32))) (import "[export]foo:foo/bar" "[task-return]foo" (func (param i32 i32))) - (import "$root" "[waitable-set-new]" (func (result i32))) - (import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32))) - (import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32))) - (import "$root" "[waitable-set-drop]" (func (param i32))) - (import "$root" "[waitable-join]" (func (param i32 i32))) - (import "$root" "[thread-yield]" (func (result i32))) - (import "$root" "[subtask-drop]" (func (param i32))) - (import "$root" "[subtask-cancel]" (func (param i32) (result i32))) - (import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32))) - (import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32))) - (import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32))) - (import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32))) - (import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32))) - (import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32))) - (import "$root" "[error-context-drop]" (func (param i32))) - (import "$root" "[context-get-0]" (func (result i32))) - (import "$root" "[context-set-0]" (func (param i32))) (import "$root" "[context-get-1]" (func (result i32))) (import "$root" "[context-set-1]" (func (param i32))) (import "$root" "[thread-index]" (func (result i32))) diff --git a/tests/cli/component-model-async/abi.wast b/tests/cli/component-model-async/abi.wast index c1d3e95857..e684da4c94 100644 --- a/tests/cli/component-model-async/abi.wast +++ b/tests/cli/component-model-async/abi.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-fixed-size-list,cm-threading +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-fixed-size-list,cm-async-stackful ;; async lower (component diff --git a/tests/cli/component-model-async/futures.wast b/tests/cli/component-model-async/futures.wast index 0445b05d52..f7370fafec 100644 --- a/tests/cli/component-model-async/futures.wast +++ b/tests/cli/component-model-async/futures.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-builtins ;; future.new (component diff --git a/tests/cli/component-model-async/lift.wast b/tests/cli/component-model-async/lift.wast index 2e14fd400e..dbc08bed7d 100644 --- a/tests/cli/component-model-async/lift.wast +++ b/tests/cli/component-model-async/lift.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-stackful ;; async lift; no callback (component diff --git a/tests/cli/component-model-async/resources.wast b/tests/cli/component-model-async/resources.wast index 6b97d98571..8ce9370a1a 100644 --- a/tests/cli/component-model-async/resources.wast +++ b/tests/cli/component-model-async/resources.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-builtins (component (type $t (resource (rep i32))) diff --git a/tests/cli/component-model-async/streams.wast b/tests/cli/component-model-async/streams.wast index f99c45923b..19a111dd84 100644 --- a/tests/cli/component-model-async/streams.wast +++ b/tests/cli/component-model-async/streams.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-builtins ;; stream.new (component diff --git a/tests/cli/component-model-async/task-builtins.wast b/tests/cli/component-model-async/task-builtins.wast new file mode 100644 index 0000000000..28fb3a99fe --- /dev/null +++ b/tests/cli/component-model-async/task-builtins.wast @@ -0,0 +1,393 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-async-builtins,cm-async-stackful,cm-error-context + +;; backpressure.set +(component + (core module $m + (import "" "backpressure.set" (func $backpressure.set (param i32))) + ) + (core func $backpressure.set (canon backpressure.set)) + (core instance $i (instantiate $m (with "" (instance (export "backpressure.set" (func $backpressure.set)))))) +) + +;; backpressure.set; incorrect type +(assert_invalid + (component + (core module $m + (import "" "backpressure.set" (func $backpressure.set (param i32 i32))) + ) + (core func $backpressure.set (canon backpressure.set)) + (core instance $i (instantiate $m (with "" (instance (export "backpressure.set" (func $backpressure.set)))))) + ) + "type mismatch for export `backpressure.set` of module instantiation argument ``" +) + +;; task.return +(component + (core module $m + (import "" "task.return" (func $task-return (param i32))) + ) + (core func $task-return (canon task.return (result u32))) + (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 without async") + +(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`") + +(assert_invalid + (component + (core module $m + (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $m (instantiate $m)) + (core func $task-return (canon task.return (result u32) (realloc (func $m "r")))) + ) + "cannot specify `realloc` option on `task.return`") + +(component + (core module $m + (memory (export "m") 1) + ) + (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"))) +) + +;; task.cancel +(component + (core module $m + (import "" "task.cancel" (func $task-cancel)) + ) + (core func $task-cancel (canon task.cancel)) + (core instance $i (instantiate $m (with "" (instance (export "task.cancel" (func $task-cancel)))))) +) + +;; waitable-set.new +(component + (core module $m (import "" "waitable-set.new" (func (result i32)))) + (core func $waitable-set-new (canon waitable-set.new)) + (core instance $i (instantiate $m (with "" (instance (export "waitable-set.new" (func $waitable-set-new)))))) +) + +;; waitable-set.new; incorrect type +(assert_invalid + (component + (core module $m (import "" "waitable-set.new" (func (result i64)))) + (core func $waitable-set-new (canon waitable-set.new)) + (core instance $i (instantiate $m (with "" (instance (export "waitable-set.new" (func $waitable-set-new)))))) + ) + "type mismatch for export `waitable-set.new` of module instantiation argument ``" +) + +;; waitable-set.wait +(component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "waitable-set.wait" (func $waitable-set-wait (param i32 i32) (result i32))) + ) + (core func $waitable-set-wait (canon waitable-set.wait cancellable (memory $libc "memory"))) + (core instance $i (instantiate $m (with "" (instance (export "waitable-set.wait" (func $waitable-set-wait)))))) +) + +;; waitable-set.wait; incorrect type +(assert_invalid + (component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "waitable-set.wait" (func $waitable-set-wait (param i32) (result i32))) + ) + (core func $waitable-set-wait (canon waitable-set.wait cancellable (memory $libc "memory"))) + (core instance $i (instantiate $m (with "" (instance (export "waitable-set.wait" (func $waitable-set-wait)))))) + ) + "type mismatch for export `waitable-set.wait` of module instantiation argument ``" +) + +;; waitable-set.poll +(component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "waitable-set.poll" (func $waitable-set-poll (param i32 i32) (result i32))) + ) + (core func $waitable-set-poll (canon waitable-set.poll cancellable (memory $libc "memory"))) + (core instance $i (instantiate $m (with "" (instance (export "waitable-set.poll" (func $waitable-set-poll)))))) +) + +;; waitable-set.poll; incorrect type +(assert_invalid + (component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "waitable-set.poll" (func $waitable-set-poll (param i32) (result i32))) + ) + (core func $waitable-set-poll (canon waitable-set.poll cancellable (memory $libc "memory"))) + (core instance $i (instantiate $m (with "" (instance (export "waitable-set.poll" (func $waitable-set-poll)))))) + ) + "type mismatch for export `waitable-set.poll` of module instantiation argument ``" +) + +;; waitable-set.drop +(component + (core module $m (import "" "waitable-set.drop" (func (param i32)))) + (core func $waitable-set-drop (canon waitable-set.drop)) + (core instance $i (instantiate $m (with "" (instance (export "waitable-set.drop" (func $waitable-set-drop)))))) +) + +;; waitable-set.drop; incorrect type +(assert_invalid + (component + (core module $m (import "" "waitable-set.drop" (func (param i64)))) + (core func $waitable-set-drop (canon waitable-set.drop)) + (core instance $i (instantiate $m (with "" (instance (export "waitable-set.drop" (func $waitable-set-drop)))))) + ) + "type mismatch for export `waitable-set.drop` of module instantiation argument ``" +) + +;; waitable.join +(component + (core module $m (import "" "waitable.join" (func (param i32 i32)))) + (core func $waitable.join (canon waitable.join)) + (core instance $i (instantiate $m (with "" (instance (export "waitable.join" (func $waitable.join)))))) +) + +;; waitable.join; incorrect type +(assert_invalid + (component + (core module $m (import "" "waitable.join" (func (param i64)))) + (core func $waitable.join (canon waitable.join)) + (core instance $i (instantiate $m (with "" (instance (export "waitable.join" (func $waitable.join)))))) + ) + "type mismatch for export `waitable.join` of module instantiation argument ``" +) + +;; thread.yield +(component + (core module $m + (import "" "thread.yield" (func $thread.yield (result i32))) + ) + (core func $thread.yield (canon thread.yield cancellable)) + (core instance $i (instantiate $m (with "" (instance (export "thread.yield" (func $thread.yield)))))) +) + +;; thread.yield; incorrect type +(assert_invalid + (component + (core module $m + (import "" "thread.yield" (func $thread.yield (param i32) (result i32))) + ) + (core func $thread.yield (canon thread.yield cancellable)) + (core instance $i (instantiate $m (with "" (instance (export "thread.yield" (func $thread.yield)))))) + ) + "type mismatch for export `thread.yield` of module instantiation argument ``" +) + +;; subtask.drop +(component + (core module $m + (import "" "subtask.drop" (func $subtask-drop (param i32))) + ) + (core func $subtask-drop (canon subtask.drop)) + (core instance $i (instantiate $m (with "" (instance (export "subtask.drop" (func $subtask-drop)))))) +) + +;; subtask.drop; incorrect type +(assert_invalid + (component + (core module $m + (import "" "subtask.drop" (func $subtask-drop (param i32) (result i32))) + ) + (core func $subtask-drop (canon subtask.drop)) + (core instance $i (instantiate $m (with "" (instance (export "subtask.drop" (func $subtask-drop)))))) + ) + "type mismatch for export `subtask.drop` of module instantiation argument ``" +) + +;; subtask.cancel +(component + (core module $m + (import "" "subtask.cancel" (func $subtask-cancel (param i32) (result i32))) + ) + (core func $subtask-cancel (canon subtask.cancel)) + (core instance $i (instantiate $m (with "" (instance (export "subtask.cancel" (func $subtask-cancel)))))) +) + +;; subtask.cancel; incorrect type +(assert_invalid + (component + (core module $m + (import "" "subtask.cancel" (func $subtask-cancel (param i32 i32) (result i32))) + ) + (core func $subtask-cancel (canon subtask.cancel)) + (core instance $i (instantiate $m (with "" (instance (export "subtask.cancel" (func $subtask-cancel)))))) + ) + "type mismatch for export `subtask.cancel` of module instantiation argument ``" +) + +;; context.{get,set} +(component + (core func $get0 (canon context.get i32 0)) + (core func $set0 (canon context.set i32 0)) + + (core module $m + (import "" "get0" (func (result i32))) + (import "" "set0" (func (param i32))) + ) + (core instance (instantiate $m + (with "" (instance + (export "get0" (func $get0)) + (export "set0" (func $set0)) + )) + )) +) + +(assert_invalid + (component + (core module $m (import "" "" (func (param i32) (result i32)))) + (core func $f (canon context.get i32 0)) + (core instance $i (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + "found: (func (result i32))") +(assert_invalid + (component + (core module $m (import "" "" (func (param i32) (result i32)))) + (core func $f (canon context.set i32 0)) + (core instance $i (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + "found: (func (param i32))") +(assert_invalid + (component + (core func (canon context.get i32 1))) + "immediate must be zero: 1") +(assert_invalid + (component + (core func (canon context.set i32 1))) + "immediate must be zero: 1") +(assert_invalid + (component + (core func (canon context.get i32 100))) + "immediate must be zero: 100") +(assert_invalid + (component + (core func (canon context.set i32 100))) + "immediate must be zero: 100") +(assert_malformed + (component quote + "(core func (canon context.get i64 100))") + "expected keyword `i32`") +(assert_malformed + (component quote + "(core func (canon context.set i64 100))") + "expected keyword `i32`") + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\08\04" ;; canonicals section, 4 bytes + "\01" ;; 1 count + "\0a\7e\00") ;; context.get i64 0 + "invalid leading byte (0x7e) for context.get") +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\08\04" ;; canonicals section, 4 bytes + "\01" ;; 1 count + "\0b\7e\00") ;; context.set i64 0 + "invalid leading byte (0x7e) for context.set") + +;; different forms of canonical intrinsics + +(component + (core func (canon backpressure.set)) + (canon backpressure.set (core func)) + (core func (canon task.return)) + (canon task.return (core func)) + (core func (canon task.cancel)) + (canon task.cancel (core func)) + (core func (canon subtask.drop)) + (canon subtask.drop (core func)) + (core func (canon subtask.cancel)) + (canon subtask.cancel (core func)) + (core func (canon subtask.cancel async)) + (canon subtask.cancel async (core func)) + + (core module $m + (memory (export "m") 1) + (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + (alias core export $i "m" (core memory $m)) + (alias core export $i "r" (core func $r)) + + (type $r (resource (rep i32))) + (core func (canon resource.drop $r async)) + (canon resource.drop $r async (core func)) + + (type $s (stream)) + (type $f (future)) + (core func (canon future.new $f)) + (canon future.new $f (core func)) + (core func (canon stream.new $s)) + (canon stream.new $s (core func)) + (core func (canon future.cancel-read $f)) + (canon future.cancel-read $f (core func)) + (core func (canon stream.cancel-read $s)) + (canon stream.cancel-read $s (core func)) + (core func (canon future.cancel-write $f)) + (canon future.cancel-write $f (core func)) + (core func (canon stream.cancel-write $s)) + (canon stream.cancel-write $s (core func)) + (core func (canon future.drop-readable $f)) + (canon future.drop-readable $f (core func)) + (core func (canon future.drop-writable $f)) + (canon future.drop-writable $f (core func)) + (core func (canon stream.drop-readable $s)) + (canon stream.drop-readable $s (core func)) + (core func (canon stream.drop-writable $s)) + (canon stream.drop-writable $s (core func)) + (core func (canon future.read $f (memory $m))) + (canon future.read $f (memory $m) (core func)) + (core func (canon future.write $f (memory $m))) + (canon future.write $f (memory $m) (core func)) + (core func (canon stream.read $s (memory $m))) + (canon stream.read $s (memory $m) (core func)) + (core func (canon stream.write $s (memory $m))) + (canon stream.write $s (memory $m) (core func)) + + (core func (canon error-context.new (memory $m))) + (canon error-context.new (memory $m) (core func)) + (core func (canon error-context.debug-message (memory $m) (realloc $r))) + (canon error-context.debug-message (memory $m) (realloc $r) (core func)) + (core func (canon error-context.drop)) + (canon error-context.drop (core func)) + + (core func (canon context.get i32 0)) + (canon context.get i32 0 (core func)) + (core func (canon context.set i32 0)) + (canon context.set i32 0 (core func)) + + (core func (canon thread.yield)) + (canon thread.yield (core func)) +) + +(component + (canon task.return (result (stream u8)) (core func)) +) diff --git a/tests/cli/component-model-async/threading.wast b/tests/cli/component-model-async/threading.wast index dda48ceaf3..744f513755 100644 --- a/tests/cli/component-model-async/threading.wast +++ b/tests/cli/component-model-async/threading.wast @@ -1,264 +1,16 @@ ;; RUN: wast --assert default --snapshot tests/snapshots % -f cm-async,cm-threading,cm-error-context -;; backpressure.set +;; context.{get,set} 1 (component - (core module $m - (import "" "backpressure.set" (func $backpressure.set (param i32))) - ) - (core func $backpressure.set (canon backpressure.set)) - (core instance $i (instantiate $m (with "" (instance (export "backpressure.set" (func $backpressure.set)))))) -) - -;; backpressure.set; incorrect type -(assert_invalid - (component - (core module $m - (import "" "backpressure.set" (func $backpressure.set (param i32 i32))) - ) - (core func $backpressure.set (canon backpressure.set)) - (core instance $i (instantiate $m (with "" (instance (export "backpressure.set" (func $backpressure.set)))))) - ) - "type mismatch for export `backpressure.set` of module instantiation argument ``" -) - -;; task.return -(component - (core module $m - (import "" "task.return" (func $task-return (param i32))) - ) - (core func $task-return (canon task.return (result u32))) - (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 without async") - -(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`") - -(assert_invalid - (component - (core module $m - (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) - ) - (core instance $m (instantiate $m)) - (core func $task-return (canon task.return (result u32) (realloc (func $m "r")))) - ) - "cannot specify `realloc` option on `task.return`") - -(component - (core module $m - (memory (export "m") 1) - ) - (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"))) -) - -;; task.cancel -(component - (core module $m - (import "" "task.cancel" (func $task-cancel)) - ) - (core func $task-cancel (canon task.cancel)) - (core instance $i (instantiate $m (with "" (instance (export "task.cancel" (func $task-cancel)))))) -) - -;; waitable-set.new -(component - (core module $m (import "" "waitable-set.new" (func (result i32)))) - (core func $waitable-set-new (canon waitable-set.new)) - (core instance $i (instantiate $m (with "" (instance (export "waitable-set.new" (func $waitable-set-new)))))) -) - -;; waitable-set.new; incorrect type -(assert_invalid - (component - (core module $m (import "" "waitable-set.new" (func (result i64)))) - (core func $waitable-set-new (canon waitable-set.new)) - (core instance $i (instantiate $m (with "" (instance (export "waitable-set.new" (func $waitable-set-new)))))) - ) - "type mismatch for export `waitable-set.new` of module instantiation argument ``" -) - -;; waitable-set.wait -(component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core module $m - (import "" "waitable-set.wait" (func $waitable-set-wait (param i32 i32) (result i32))) - ) - (core func $waitable-set-wait (canon waitable-set.wait cancellable (memory $libc "memory"))) - (core instance $i (instantiate $m (with "" (instance (export "waitable-set.wait" (func $waitable-set-wait)))))) -) - -;; waitable-set.wait; incorrect type -(assert_invalid - (component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core module $m - (import "" "waitable-set.wait" (func $waitable-set-wait (param i32) (result i32))) - ) - (core func $waitable-set-wait (canon waitable-set.wait cancellable (memory $libc "memory"))) - (core instance $i (instantiate $m (with "" (instance (export "waitable-set.wait" (func $waitable-set-wait)))))) - ) - "type mismatch for export `waitable-set.wait` of module instantiation argument ``" -) - -;; waitable-set.poll -(component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core module $m - (import "" "waitable-set.poll" (func $waitable-set-poll (param i32 i32) (result i32))) - ) - (core func $waitable-set-poll (canon waitable-set.poll cancellable (memory $libc "memory"))) - (core instance $i (instantiate $m (with "" (instance (export "waitable-set.poll" (func $waitable-set-poll)))))) -) - -;; waitable-set.poll; incorrect type -(assert_invalid - (component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core module $m - (import "" "waitable-set.poll" (func $waitable-set-poll (param i32) (result i32))) - ) - (core func $waitable-set-poll (canon waitable-set.poll cancellable (memory $libc "memory"))) - (core instance $i (instantiate $m (with "" (instance (export "waitable-set.poll" (func $waitable-set-poll)))))) - ) - "type mismatch for export `waitable-set.poll` of module instantiation argument ``" -) - -;; waitable-set.drop -(component - (core module $m (import "" "waitable-set.drop" (func (param i32)))) - (core func $waitable-set-drop (canon waitable-set.drop)) - (core instance $i (instantiate $m (with "" (instance (export "waitable-set.drop" (func $waitable-set-drop)))))) -) - -;; waitable-set.drop; incorrect type -(assert_invalid - (component - (core module $m (import "" "waitable-set.drop" (func (param i64)))) - (core func $waitable-set-drop (canon waitable-set.drop)) - (core instance $i (instantiate $m (with "" (instance (export "waitable-set.drop" (func $waitable-set-drop)))))) - ) - "type mismatch for export `waitable-set.drop` of module instantiation argument ``" -) - -;; waitable.join -(component - (core module $m (import "" "waitable.join" (func (param i32 i32)))) - (core func $waitable.join (canon waitable.join)) - (core instance $i (instantiate $m (with "" (instance (export "waitable.join" (func $waitable.join)))))) -) - -;; waitable.join; incorrect type -(assert_invalid - (component - (core module $m (import "" "waitable.join" (func (param i64)))) - (core func $waitable.join (canon waitable.join)) - (core instance $i (instantiate $m (with "" (instance (export "waitable.join" (func $waitable.join)))))) - ) - "type mismatch for export `waitable.join` of module instantiation argument ``" -) - -;; thread.yield -(component - (core module $m - (import "" "thread.yield" (func $thread.yield (result i32))) - ) - (core func $thread.yield (canon thread.yield cancellable)) - (core instance $i (instantiate $m (with "" (instance (export "thread.yield" (func $thread.yield)))))) -) - -;; thread.yield; incorrect type -(assert_invalid - (component - (core module $m - (import "" "thread.yield" (func $thread.yield (param i32) (result i32))) - ) - (core func $thread.yield (canon thread.yield cancellable)) - (core instance $i (instantiate $m (with "" (instance (export "thread.yield" (func $thread.yield)))))) - ) - "type mismatch for export `thread.yield` of module instantiation argument ``" -) - -;; subtask.drop -(component - (core module $m - (import "" "subtask.drop" (func $subtask-drop (param i32))) - ) - (core func $subtask-drop (canon subtask.drop)) - (core instance $i (instantiate $m (with "" (instance (export "subtask.drop" (func $subtask-drop)))))) -) - -;; subtask.drop; incorrect type -(assert_invalid - (component - (core module $m - (import "" "subtask.drop" (func $subtask-drop (param i32) (result i32))) - ) - (core func $subtask-drop (canon subtask.drop)) - (core instance $i (instantiate $m (with "" (instance (export "subtask.drop" (func $subtask-drop)))))) - ) - "type mismatch for export `subtask.drop` of module instantiation argument ``" -) - -;; subtask.cancel -(component - (core module $m - (import "" "subtask.cancel" (func $subtask-cancel (param i32) (result i32))) - ) - (core func $subtask-cancel (canon subtask.cancel)) - (core instance $i (instantiate $m (with "" (instance (export "subtask.cancel" (func $subtask-cancel)))))) -) - -;; subtask.cancel; incorrect type -(assert_invalid - (component - (core module $m - (import "" "subtask.cancel" (func $subtask-cancel (param i32 i32) (result i32))) - ) - (core func $subtask-cancel (canon subtask.cancel)) - (core instance $i (instantiate $m (with "" (instance (export "subtask.cancel" (func $subtask-cancel)))))) - ) - "type mismatch for export `subtask.cancel` of module instantiation argument ``" -) - -;; context.{get,set} -(component - (core func $get0 (canon context.get i32 0)) - (core func $set0 (canon context.set i32 0)) (core func $get1 (canon context.get i32 1)) (core func $set1 (canon context.set i32 1)) (core module $m - (import "" "get0" (func (result i32))) - (import "" "set0" (func (param i32))) (import "" "get1" (func (result i32))) (import "" "set1" (func (param i32))) ) (core instance (instantiate $m (with "" (instance - (export "get0" (func $get0)) - (export "set0" (func $set0)) (export "get1" (func $get1)) (export "set1" (func $set1)) )) @@ -267,18 +19,21 @@ (assert_invalid (component - (core module $m (import "" "" (func (param i32) (result i32)))) - (core func $f (canon context.get i32 0)) - (core instance $i (instantiate $m (with "" (instance (export "" (func $f)))))) - ) - "found: (func (result i32))") + (core func (canon context.get i32 2))) + "immediate must be zero or one: 2") (assert_invalid (component - (core module $m (import "" "" (func (param i32) (result i32)))) - (core func $f (canon context.set i32 0)) - (core instance $i (instantiate $m (with "" (instance (export "" (func $f)))))) - ) - "found: (func (param i32))") + (core func (canon context.set i32 2))) + "immediate must be zero or one: 2") +(assert_invalid + (component + (core func (canon context.get i32 100))) + "immediate must be zero or one: 100") +(assert_invalid + (component + (core func (canon context.set i32 100))) + "immediate must be zero or one: 100") + (assert_invalid (component (core module $m (import "" "" (func (param i32) (result i32)))) @@ -293,45 +48,6 @@ (core instance $i (instantiate $m (with "" (instance (export "" (func $f)))))) ) "found: (func (param i32))") -(assert_invalid - (component - (core func (canon context.get i32 2))) - "immediate must be zero or one: 2") -(assert_invalid - (component - (core func (canon context.set i32 2))) - "immediate must be zero or one: 2") -(assert_invalid - (component - (core func (canon context.get i32 100))) - "immediate must be zero or one: 100") -(assert_invalid - (component - (core func (canon context.set i32 100))) - "immediate must be zero or one: 100") -(assert_malformed - (component quote - "(core func (canon context.get i64 100))") - "expected keyword `i32`") -(assert_malformed - (component quote - "(core func (canon context.set i64 100))") - "expected keyword `i32`") - -(assert_malformed - (component binary - "\00asm" "\0d\00\01\00" ;; component header - "\08\04" ;; canonicals section, 4 bytes - "\01" ;; 1 count - "\0a\7e\00") ;; context.get i64 0 - "invalid leading byte (0x7e) for context.get") -(assert_malformed - (component binary - "\00asm" "\0d\00\01\00" ;; component header - "\08\04" ;; canonicals section, 4 bytes - "\01" ;; 1 count - "\0b\7e\00") ;; context.set i64 0 - "invalid leading byte (0x7e) for context.set") ;; thread.new_indirect (component @@ -424,84 +140,17 @@ ;; different forms of canonical intrinsics (component - (core func (canon backpressure.set)) - (canon backpressure.set (core func)) - (core func (canon task.return)) - (canon task.return (core func)) - (core func (canon task.cancel)) - (canon task.cancel (core func)) - (core func (canon subtask.drop)) - (canon subtask.drop (core func)) - (core func (canon subtask.cancel)) - (canon subtask.cancel (core func)) - (core func (canon subtask.cancel async)) - (canon subtask.cancel async (core func)) - (core module $m - (memory (export "m") 1) - (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) (table (export "start-table") 1 (ref null func)) ) (core instance $i (instantiate $m)) - (alias core export $i "m" (core memory $m)) - (alias core export $i "r" (core func $r)) (alias core export $i "start-table" (core table $start-table)) - (type $r (resource (rep i32))) - (core func (canon resource.drop $r async)) - (canon resource.drop $r async (core func)) - - (type $s (stream)) - (type $f (future)) - (core func (canon future.new $f)) - (canon future.new $f (core func)) - (core func (canon stream.new $s)) - (canon stream.new $s (core func)) - (core func (canon future.cancel-read $f)) - (canon future.cancel-read $f (core func)) - (core func (canon stream.cancel-read $s)) - (canon stream.cancel-read $s (core func)) - (core func (canon future.cancel-write $f)) - (canon future.cancel-write $f (core func)) - (core func (canon stream.cancel-write $s)) - (canon stream.cancel-write $s (core func)) - (core func (canon future.drop-readable $f)) - (canon future.drop-readable $f (core func)) - (core func (canon future.drop-writable $f)) - (canon future.drop-writable $f (core func)) - (core func (canon stream.drop-readable $s)) - (canon stream.drop-readable $s (core func)) - (core func (canon stream.drop-writable $s)) - (canon stream.drop-writable $s (core func)) - (core func (canon future.read $f (memory $m))) - (canon future.read $f (memory $m) (core func)) - (core func (canon future.write $f (memory $m))) - (canon future.write $f (memory $m) (core func)) - (core func (canon stream.read $s (memory $m))) - (canon stream.read $s (memory $m) (core func)) - (core func (canon stream.write $s (memory $m))) - (canon stream.write $s (memory $m) (core func)) - - (core func (canon error-context.new (memory $m))) - (canon error-context.new (memory $m) (core func)) - (core func (canon error-context.debug-message (memory $m) (realloc $r))) - (canon error-context.debug-message (memory $m) (realloc $r) (core func)) - (core func (canon error-context.drop)) - (canon error-context.drop (core func)) - - (core func (canon context.get i32 0)) - (canon context.get i32 0 (core func)) - (core func (canon context.set i32 0)) - (canon context.set i32 0 (core func)) (core func (canon context.get i32 1)) (canon context.get i32 1 (core func)) (core func (canon context.set i32 1)) (canon context.set i32 1 (core func)) - (core func (canon thread.yield)) - (canon thread.yield (core func)) - (core func (canon thread.yield cancellable)) - (canon thread.yield cancellable (core func)) (core type $start (func (param i32))) (core func (canon thread.new_indirect $start (table $start-table))) (canon thread.new_indirect $start (table $start-table) (core func)) diff --git a/tests/cli/missing-features/component-model/async-builtins.wast b/tests/cli/missing-features/component-model/async-builtins.wast new file mode 100644 index 0000000000..e39c9855ef --- /dev/null +++ b/tests/cli/missing-features/component-model/async-builtins.wast @@ -0,0 +1,44 @@ +;; RUN: wast % --assert default --snapshot tests/snapshots \ +;; -f=cm-async,-cm-async-builtins + +;; {future,stream}.cancel-{read,write} +(assert_invalid + (component + (type $t (future)) + (core func (canon future.cancel-read $t async))) + "requires the component model async builtins feature") +(assert_invalid + (component + (type $t (future)) + (core func (canon future.cancel-write $t async))) + "requires the component model async builtins feature") +(assert_invalid + (component + (type $t (stream)) + (core func (canon stream.cancel-read $t async))) + "requires the component model async builtins feature") +(assert_invalid + (component + (type $t (stream)) + (core func (canon stream.cancel-write $t async))) + "requires the component model async builtins feature") + +(component + (type $f (future)) + (type $s (stream)) + (core func (canon future.cancel-read $f)) + (core func (canon future.cancel-write $f)) + (core func (canon stream.cancel-read $s)) + (core func (canon stream.cancel-write $s)) +) + +;; async resource.drop +(assert_invalid + (component + (type $t (resource (rep i32))) + (core func (canon resource.drop $t async))) + "requires the component model async builtins feature") +(component + (type $t (resource (rep i32))) + (core func (canon resource.drop $t))) + \ No newline at end of file diff --git a/tests/cli/missing-features/component-model/async-stackful.wast b/tests/cli/missing-features/component-model/async-stackful.wast new file mode 100644 index 0000000000..df9f1ae2e8 --- /dev/null +++ b/tests/cli/missing-features/component-model/async-stackful.wast @@ -0,0 +1,50 @@ +;; RUN: wast % --assert default --snapshot tests/snapshots \ +;; -f=cm-async,-cm-async-builtins + +(assert_invalid + (component + (core module $m (func (export "foo") (param i32))) + (core instance $i (instantiate $m)) + + (func (export "foo") (param "p1" u32) (result u32) + (canon lift (core func $i "foo") async) + ) + ) + "requires the component model async stackful feature") + +;; waitable-set.wait cancellable +(assert_invalid + (component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func (canon waitable-set.wait cancellable (memory $libc "memory"))) + ) + "requires the component model async stackful feature") + +(component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func (canon waitable-set.wait (memory $libc "memory"))) +) + +;; waitable-set.poll cancellable +(assert_invalid + (component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func (canon waitable-set.poll cancellable (memory $libc "memory"))) + ) + "requires the component model async stackful feature") + +(component + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func (canon waitable-set.poll (memory $libc "memory"))) +) + +;; thread.yield +(assert_invalid + (component (core func (canon thread.yield cancellable))) + "requires the component model async stackful feature") + +(component (core func (canon thread.yield))) \ No newline at end of file diff --git a/tests/cli/missing-features/component-model/async.wast b/tests/cli/missing-features/component-model/async.wast index 1c35538146..538694646b 100644 --- a/tests/cli/missing-features/component-model/async.wast +++ b/tests/cli/missing-features/component-model/async.wast @@ -340,7 +340,7 @@ (type $t (resource (rep i32))) (core func $f (canon resource.drop $t async)) ) - "requires the component model threading feature" + "requires the component model async builtins feature" ) (assert_invalid diff --git a/tests/cli/missing-features/component-model/threading.wast b/tests/cli/missing-features/component-model/threading.wast index 60e3e243a7..0d0562fdc5 100644 --- a/tests/cli/missing-features/component-model/threading.wast +++ b/tests/cli/missing-features/component-model/threading.wast @@ -1,94 +1,6 @@ ;; RUN: wast % --assert default --snapshot tests/snapshots \ ;; -f=cm-async,-cm-threading -(assert_invalid - (component - (core module $m (func (export "foo") (param i32))) - (core instance $i (instantiate $m)) - - (func (export "foo") (param "p1" u32) (result u32) - (canon lift (core func $i "foo") async) - ) - ) - "requires the component model threading feature") - -;; waitable-set.wait async -(assert_invalid - (component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func (canon waitable-set.wait cancellable (memory $libc "memory"))) - ) - "requires the component model threading feature") - -(component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func (canon waitable-set.wait (memory $libc "memory"))) -) - -;; waitable-set.poll cancellable -(assert_invalid - (component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func (canon waitable-set.poll cancellable (memory $libc "memory"))) - ) - "requires the component model threading feature") - -(component - (core module $libc (memory (export "memory") 1)) - (core instance $libc (instantiate $libc)) - (core func (canon waitable-set.poll (memory $libc "memory"))) -) - -;; thread.yield -(assert_invalid - (component (core func (canon thread.yield cancellable))) - "requires the component model threading feature") -(component (core func (canon thread.yield))) - -;; {future,stream}.cancel-{read,write} -(assert_invalid - (component - (type $t (future)) - (core func (canon future.cancel-read $t async))) - "requires the component model threading feature") -(assert_invalid - (component - (type $t (future)) - (core func (canon future.cancel-write $t async))) - "requires the component model threading feature") -(assert_invalid - (component - (type $t (stream)) - (core func (canon stream.cancel-read $t async))) - "requires the component model threading feature") -(assert_invalid - (component - (type $t (stream)) - (core func (canon stream.cancel-write $t async))) - "requires the component model threading feature") - -(component - (type $f (future)) - (type $s (stream)) - (core func (canon future.cancel-read $f)) - (core func (canon future.cancel-write $f)) - (core func (canon stream.cancel-read $s)) - (core func (canon stream.cancel-write $s)) -) - -;; async resource.drop -(assert_invalid - (component - (type $t (resource (rep i32))) - (core func (canon resource.drop $t async))) - "requires the component model threading feature") -(component - (type $t (resource (rep i32))) - (core func (canon resource.drop $t))) - ;; thread.* (assert_invalid (component diff --git a/tests/cli/validate-unknown-features.wat.stderr b/tests/cli/validate-unknown-features.wat.stderr index 56f34d94a2..a07287ad9f 100644 --- a/tests/cli/validate-unknown-features.wat.stderr +++ b/tests/cli/validate-unknown-features.wat.stderr @@ -1,4 +1,4 @@ error: invalid value 'unknown' for '--features ': unknown feature `unknown` -Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, legacy-exceptions, gc-types, stack-switching, wide-arithmetic, cm-values, cm-nested-names, cm-async, cm-threading, cm-error-context, cm-fixed-size-list, cm-gc, call-indirect-overlong, bulk-memory-opt, mvp, wasm1, wasm2, wasm3, lime1, all +Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, legacy-exceptions, gc-types, stack-switching, wide-arithmetic, cm-values, cm-nested-names, cm-async, cm-async-stackful, cm-async-builtins, cm-threading, cm-error-context, cm-fixed-size-list, cm-gc, call-indirect-overlong, bulk-memory-opt, mvp, wasm1, wasm2, wasm3, lime1, all For more information, try '--help'. diff --git a/tests/snapshots/cli/component-model-async/task-builtins.wast.json b/tests/snapshots/cli/component-model-async/task-builtins.wast.json index 50464cc6dc..b3e68812da 100644 --- a/tests/snapshots/cli/component-model-async/task-builtins.wast.json +++ b/tests/snapshots/cli/component-model-async/task-builtins.wast.json @@ -136,7 +136,7 @@ "line": 193, "filename": "task-builtins.20.wasm", "module_type": "binary", - "text": "type mismatch for export `yield` of module instantiation argument ``" + "text": "type mismatch for export `thread.yield` of module instantiation argument ``" }, { "type": "module", @@ -248,7 +248,7 @@ }, { "type": "module", - "line": 389, + "line": 391, "filename": "task-builtins.37.wasm", "module_type": "binary" } diff --git a/tests/snapshots/cli/component-model-async/task-builtins.wast/11.print b/tests/snapshots/cli/component-model-async/task-builtins.wast/11.print index 8835e4a135..30cc2c0977 100644 --- a/tests/snapshots/cli/component-model-async/task-builtins.wast/11.print +++ b/tests/snapshots/cli/component-model-async/task-builtins.wast/11.print @@ -9,7 +9,7 @@ (import "" "waitable-set.wait" (func $waitable-set-wait (;0;) (type 0))) ) (alias core export $libc "memory" (core memory (;0;))) - (core func $waitable-set-wait (;0;) (canon waitable-set.wait async (memory 0))) + (core func $waitable-set-wait (;0;) (canon waitable-set.wait cancellable (memory 0))) (core instance (;1;) (export "waitable-set.wait" (func $waitable-set-wait)) ) diff --git a/tests/snapshots/cli/component-model-async/task-builtins.wast/13.print b/tests/snapshots/cli/component-model-async/task-builtins.wast/13.print index 98bca2b0c0..4690399a01 100644 --- a/tests/snapshots/cli/component-model-async/task-builtins.wast/13.print +++ b/tests/snapshots/cli/component-model-async/task-builtins.wast/13.print @@ -9,7 +9,7 @@ (import "" "waitable-set.poll" (func $waitable-set-poll (;0;) (type 0))) ) (alias core export $libc "memory" (core memory (;0;))) - (core func $waitable-set-poll (;0;) (canon waitable-set.poll async (memory 0))) + (core func $waitable-set-poll (;0;) (canon waitable-set.poll cancellable (memory 0))) (core instance (;1;) (export "waitable-set.poll" (func $waitable-set-poll)) ) diff --git a/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print b/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print index cc67534a58..f8845497a5 100644 --- a/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print +++ b/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print @@ -1,11 +1,11 @@ (component (core module $m (;0;) (type (;0;) (func (result i32))) - (import "" "thread.yield" (func $yield (;0;) (type 0))) + (import "" "thread.yield" (func $thread.yield (;0;) (type 0))) ) - (core func $yield (;0;) (canon thread.yield async)) + (core func $thread.yield (;0;) (canon thread.yield cancellable)) (core instance (;0;) - (export "yield" (func $yield)) + (export "thread.yield" (func $thread.yield)) ) (core instance $i (;1;) (instantiate $m (with "" (instance 0)) diff --git a/tests/snapshots/cli/component-model-async/task-builtins.wast/36.print b/tests/snapshots/cli/component-model-async/task-builtins.wast/36.print index 216e7af76f..3ffca107b6 100644 --- a/tests/snapshots/cli/component-model-async/task-builtins.wast/36.print +++ b/tests/snapshots/cli/component-model-async/task-builtins.wast/36.print @@ -66,4 +66,6 @@ (core func (;50;) (canon context.get i32 0)) (core func (;51;) (canon context.set i32 0)) (core func (;52;) (canon context.set i32 0)) + (core func (;53;) (canon thread.yield)) + (core func (;54;) (canon thread.yield)) ) diff --git a/tests/snapshots/cli/component-model-async/threading.wast.json b/tests/snapshots/cli/component-model-async/threading.wast.json index 552d8daf15..90307605ad 100644 --- a/tests/snapshots/cli/component-model-async/threading.wast.json +++ b/tests/snapshots/cli/component-model-async/threading.wast.json @@ -9,69 +9,71 @@ }, { "type": "assert_invalid", - "line": 14, + "line": 21, "filename": "threading.1.wasm", "module_type": "binary", - "text": "type mismatch for export `backpressure.set` of module instantiation argument ``" + "text": "immediate must be zero or one: 2" }, { - "type": "module", + "type": "assert_invalid", "line": 25, "filename": "threading.2.wasm", - "module_type": "binary" + "module_type": "binary", + "text": "immediate must be zero or one: 2" }, { "type": "assert_invalid", - "line": 34, + "line": 29, "filename": "threading.3.wasm", "module_type": "binary", - "text": "cannot specify `async` option on `task.return`" + "text": "immediate must be zero or one: 100" }, { "type": "assert_invalid", - "line": 38, + "line": 33, "filename": "threading.4.wasm", "module_type": "binary", - "text": "cannot specify callback without async" + "text": "immediate must be zero or one: 100" }, { "type": "assert_invalid", - "line": 45, + "line": 38, "filename": "threading.5.wasm", "module_type": "binary", - "text": "cannot specify `post-return` option on `task.return`" + "text": "found: (func (result i32))" }, { "type": "assert_invalid", - "line": 52, + "line": 45, "filename": "threading.6.wasm", "module_type": "binary", - "text": "cannot specify `realloc` option on `task.return`" + "text": "found: (func (param i32))" }, { "type": "module", - "line": 61, + "line": 53, "filename": "threading.7.wasm", "module_type": "binary" }, { "type": "module", - "line": 73, + "line": 60, "filename": "threading.8.wasm", "module_type": "binary" }, { - "type": "module", - "line": 82, + "type": "assert_invalid", + "line": 79, "filename": "threading.9.wasm", - "module_type": "binary" + "module_type": "binary", + "text": "unknown table 0: table index out of bounds" }, { "type": "assert_invalid", - "line": 90, + "line": 89, "filename": "threading.10.wasm", "module_type": "binary", - "text": "type mismatch for export `waitable-set.new` of module instantiation argument ``" + "text": "start function must take a single `i32` argument" }, { "type": "module", @@ -81,241 +83,34 @@ }, { "type": "assert_invalid", - "line": 111, + "line": 109, "filename": "threading.12.wasm", "module_type": "binary", - "text": "type mismatch for export `waitable-set.wait` of module instantiation argument ``" + "text": "type mismatch for export `thread.index` of module instantiation argument ``" }, { "type": "module", - "line": 124, + "line": 120, "filename": "threading.13.wasm", "module_type": "binary" }, { "type": "assert_invalid", - "line": 136, + "line": 130, "filename": "threading.14.wasm", "module_type": "binary", - "text": "type mismatch for export `waitable-set.poll` of module instantiation argument ``" - }, - { - "type": "module", - "line": 149, - "filename": "threading.15.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 157, - "filename": "threading.16.wasm", - "module_type": "binary", - "text": "type mismatch for export `waitable-set.drop` of module instantiation argument ``" - }, - { - "type": "module", - "line": 166, - "filename": "threading.17.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 174, - "filename": "threading.18.wasm", - "module_type": "binary", - "text": "type mismatch for export `waitable.join` of module instantiation argument ``" - }, - { - "type": "module", - "line": 183, - "filename": "threading.19.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 193, - "filename": "threading.20.wasm", - "module_type": "binary", - "text": "type mismatch for export `thread.yield` of module instantiation argument ``" - }, - { - "type": "module", - "line": 204, - "filename": "threading.21.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 214, - "filename": "threading.22.wasm", - "module_type": "binary", - "text": "type mismatch for export `subtask.drop` of module instantiation argument ``" - }, - { - "type": "module", - "line": 225, - "filename": "threading.23.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 235, - "filename": "threading.24.wasm", - "module_type": "binary", - "text": "type mismatch for export `subtask.cancel` of module instantiation argument ``" - }, - { - "type": "module", - "line": 246, - "filename": "threading.25.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 269, - "filename": "threading.26.wasm", - "module_type": "binary", - "text": "found: (func (result i32))" - }, - { - "type": "assert_invalid", - "line": 276, - "filename": "threading.27.wasm", - "module_type": "binary", - "text": "found: (func (param i32))" - }, - { - "type": "assert_invalid", - "line": 283, - "filename": "threading.28.wasm", - "module_type": "binary", - "text": "found: (func (result i32))" - }, - { - "type": "assert_invalid", - "line": 290, - "filename": "threading.29.wasm", - "module_type": "binary", - "text": "found: (func (param i32))" - }, - { - "type": "assert_invalid", - "line": 297, - "filename": "threading.30.wasm", - "module_type": "binary", - "text": "immediate must be zero or one: 2" - }, - { - "type": "assert_invalid", - "line": 301, - "filename": "threading.31.wasm", - "module_type": "binary", - "text": "immediate must be zero or one: 2" - }, - { - "type": "assert_invalid", - "line": 305, - "filename": "threading.32.wasm", - "module_type": "binary", - "text": "immediate must be zero or one: 100" - }, - { - "type": "assert_invalid", - "line": 309, - "filename": "threading.33.wasm", - "module_type": "binary", - "text": "immediate must be zero or one: 100" - }, - { - "type": "assert_malformed", - "line": 313, - "filename": "threading.34.wat", - "module_type": "text", - "text": "expected keyword `i32`" - }, - { - "type": "assert_malformed", - "line": 317, - "filename": "threading.35.wat", - "module_type": "text", - "text": "expected keyword `i32`" - }, - { - "type": "assert_malformed", - "line": 322, - "filename": "threading.36.wasm", - "module_type": "binary", - "text": "invalid leading byte (0x7e) for context.get" - }, - { - "type": "assert_malformed", - "line": 329, - "filename": "threading.37.wasm", - "module_type": "binary", - "text": "invalid leading byte (0x7e) for context.set" - }, - { - "type": "module", - "line": 337, - "filename": "threading.38.wasm", - "module_type": "binary" - }, - { - "type": "module", - "line": 344, - "filename": "threading.39.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 363, - "filename": "threading.40.wasm", - "module_type": "binary", - "text": "unknown table 0: table index out of bounds" - }, - { - "type": "assert_invalid", - "line": 373, - "filename": "threading.41.wasm", - "module_type": "binary", - "text": "start function must take a single `i32` argument" - }, - { - "type": "module", - "line": 383, - "filename": "threading.42.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 393, - "filename": "threading.43.wasm", - "module_type": "binary", - "text": "type mismatch for export `thread.index` of module instantiation argument ``" - }, - { - "type": "module", - "line": 404, - "filename": "threading.44.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 414, - "filename": "threading.45.wasm", - "module_type": "binary", "text": "type mismatch for export `thread.switch-to` of module instantiation argument ``" }, { "type": "module", - "line": 426, - "filename": "threading.46.wasm", + "line": 142, + "filename": "threading.15.wasm", "module_type": "binary" }, { "type": "module", - "line": 524, - "filename": "threading.47.wasm", + "line": 173, + "filename": "threading.16.wasm", "module_type": "binary" } ] diff --git a/tests/snapshots/cli/component-model-async/threading.wast/0.print b/tests/snapshots/cli/component-model-async/threading.wast/0.print index 686f8faf09..7f416aa032 100644 --- a/tests/snapshots/cli/component-model-async/threading.wast/0.print +++ b/tests/snapshots/cli/component-model-async/threading.wast/0.print @@ -1,13 +1,17 @@ (component + (core func $get1 (;0;) (canon context.get i32 1)) + (core func $set1 (;1;) (canon context.set i32 1)) (core module $m (;0;) - (type (;0;) (func (param i32))) - (import "" "backpressure.set" (func $backpressure.set (;0;) (type 0))) + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32))) + (import "" "get1" (func (;0;) (type 0))) + (import "" "set1" (func (;1;) (type 1))) ) - (core func $backpressure.set (;0;) (canon backpressure.set)) (core instance (;0;) - (export "backpressure.set" (func $backpressure.set)) + (export "get1" (func $get1)) + (export "set1" (func $set1)) ) - (core instance $i (;1;) (instantiate $m + (core instance (;1;) (instantiate $m (with "" (instance 0)) ) ) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/11.print b/tests/snapshots/cli/component-model-async/threading.wast/11.print index 30cc2c0977..d36b57ffea 100644 --- a/tests/snapshots/cli/component-model-async/threading.wast/11.print +++ b/tests/snapshots/cli/component-model-async/threading.wast/11.print @@ -1,20 +1,14 @@ (component - (core module $libc (;0;) - (memory (;0;) 1) - (export "memory" (memory 0)) + (core module $m (;0;) + (type (;0;) (func (result i32))) + (import "" "thread.index" (func $thread.index (;0;) (type 0))) ) - (core instance $libc (;0;) (instantiate $libc)) - (core module $m (;1;) - (type (;0;) (func (param i32 i32) (result i32))) - (import "" "waitable-set.wait" (func $waitable-set-wait (;0;) (type 0))) + (core func $thread.index (;0;) (canon thread.index)) + (core instance (;0;) + (export "thread.index" (func $thread.index)) ) - (alias core export $libc "memory" (core memory (;0;))) - (core func $waitable-set-wait (;0;) (canon waitable-set.wait cancellable (memory 0))) - (core instance (;1;) - (export "waitable-set.wait" (func $waitable-set-wait)) - ) - (core instance $i (;2;) (instantiate $m - (with "" (instance 1)) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) ) ) ) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/13.print b/tests/snapshots/cli/component-model-async/threading.wast/13.print index 4690399a01..6c92cb7183 100644 --- a/tests/snapshots/cli/component-model-async/threading.wast/13.print +++ b/tests/snapshots/cli/component-model-async/threading.wast/13.print @@ -1,20 +1,14 @@ (component - (core module $libc (;0;) - (memory (;0;) 1) - (export "memory" (memory 0)) + (core module $m (;0;) + (type (;0;) (func (param i32) (result i32))) + (import "" "thread.switch-to" (func $thread.switch-to (;0;) (type 0))) ) - (core instance $libc (;0;) (instantiate $libc)) - (core module $m (;1;) - (type (;0;) (func (param i32 i32) (result i32))) - (import "" "waitable-set.poll" (func $waitable-set-poll (;0;) (type 0))) + (core func $thread.switch-to (;0;) (canon thread.switch-to cancellable)) + (core instance (;0;) + (export "thread.switch-to" (func $thread.switch-to)) ) - (alias core export $libc "memory" (core memory (;0;))) - (core func $waitable-set-poll (;0;) (canon waitable-set.poll cancellable (memory 0))) - (core instance (;1;) - (export "waitable-set.poll" (func $waitable-set-poll)) - ) - (core instance $i (;2;) (instantiate $m - (with "" (instance 1)) + (core instance $i (;1;) (instantiate $m + (with "" (instance 0)) ) ) ) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/15.print b/tests/snapshots/cli/component-model-async/threading.wast/15.print index 8470c01ee8..59adde4fb6 100644 --- a/tests/snapshots/cli/component-model-async/threading.wast/15.print +++ b/tests/snapshots/cli/component-model-async/threading.wast/15.print @@ -1,14 +1,29 @@ (component (core module $m (;0;) - (type (;0;) (func (param i32))) - (import "" "waitable-set.drop" (func (;0;) (type 0))) - ) - (core func $waitable-set-drop (;0;) (canon waitable-set.drop)) - (core instance (;0;) - (export "waitable-set.drop" (func $waitable-set-drop)) - ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) - ) + (table (;0;) 1 funcref) + (export "start-table" (table 0)) ) + (core instance $i (;0;) (instantiate $m)) + (alias core export $i "start-table" (core table $start-table (;0;))) + (core func (;0;) (canon context.get i32 1)) + (core func (;1;) (canon context.get i32 1)) + (core func (;2;) (canon context.set i32 1)) + (core func (;3;) (canon context.set i32 1)) + (core type $start (;0;) (func (param i32))) + (core func (;4;) (canon thread.new_indirect $start (table $start-table))) + (core func (;5;) (canon thread.new_indirect $start (table $start-table))) + (core func (;6;) (canon thread.switch-to)) + (core func (;7;) (canon thread.switch-to)) + (core func (;8;) (canon thread.switch-to cancellable)) + (core func (;9;) (canon thread.switch-to cancellable)) + (core func (;10;) (canon thread.suspend)) + (core func (;11;) (canon thread.suspend)) + (core func (;12;) (canon thread.suspend cancellable)) + (core func (;13;) (canon thread.suspend cancellable)) + (core func (;14;) (canon thread.resume-later)) + (core func (;15;) (canon thread.resume-later)) + (core func (;16;) (canon thread.yield-to)) + (core func (;17;) (canon thread.yield-to)) + (core func (;18;) (canon thread.yield-to cancellable)) + (core func (;19;) (canon thread.yield-to cancellable)) ) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/41.print b/tests/snapshots/cli/component-model-async/threading.wast/16.print similarity index 100% rename from tests/snapshots/cli/component-model-async/threading.wast/41.print rename to tests/snapshots/cli/component-model-async/threading.wast/16.print diff --git a/tests/snapshots/cli/component-model-async/threading.wast/17.print b/tests/snapshots/cli/component-model-async/threading.wast/17.print deleted file mode 100644 index 3667f8c326..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/17.print +++ /dev/null @@ -1,14 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (param i32 i32))) - (import "" "waitable.join" (func (;0;) (type 0))) - ) - (core func $waitable.join (;0;) (canon waitable.join)) - (core instance (;0;) - (export "waitable.join" (func $waitable.join)) - ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/19.print b/tests/snapshots/cli/component-model-async/threading.wast/19.print deleted file mode 100644 index f8845497a5..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/19.print +++ /dev/null @@ -1,14 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (result i32))) - (import "" "thread.yield" (func $thread.yield (;0;) (type 0))) - ) - (core func $thread.yield (;0;) (canon thread.yield cancellable)) - (core instance (;0;) - (export "thread.yield" (func $thread.yield)) - ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/2.print b/tests/snapshots/cli/component-model-async/threading.wast/2.print deleted file mode 100644 index 84b3158da3..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/2.print +++ /dev/null @@ -1,14 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (param i32))) - (import "" "task.return" (func $task-return (;0;) (type 0))) - ) - (core func $task-return (;0;) (canon task.return (result u32))) - (core instance (;0;) - (export "task.return" (func $task-return)) - ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/21.print b/tests/snapshots/cli/component-model-async/threading.wast/21.print deleted file mode 100644 index 038cc25c37..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/21.print +++ /dev/null @@ -1,14 +0,0 @@ -(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/cli/component-model-async/threading.wast/23.print b/tests/snapshots/cli/component-model-async/threading.wast/23.print deleted file mode 100644 index 234b55d33f..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/23.print +++ /dev/null @@ -1,14 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (param i32) (result i32))) - (import "" "subtask.cancel" (func $subtask-cancel (;0;) (type 0))) - ) - (core func $subtask-cancel (;0;) (canon subtask.cancel)) - (core instance (;0;) - (export "subtask.cancel" (func $subtask-cancel)) - ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/25.print b/tests/snapshots/cli/component-model-async/threading.wast/25.print deleted file mode 100644 index 615e61f119..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/25.print +++ /dev/null @@ -1,24 +0,0 @@ -(component - (core func $get0 (;0;) (canon context.get i32 0)) - (core func $set0 (;1;) (canon context.set i32 0)) - (core func $get1 (;2;) (canon context.get i32 1)) - (core func $set1 (;3;) (canon context.set i32 1)) - (core module $m (;0;) - (type (;0;) (func (result i32))) - (type (;1;) (func (param i32))) - (import "" "get0" (func (;0;) (type 0))) - (import "" "set0" (func (;1;) (type 1))) - (import "" "get1" (func (;2;) (type 0))) - (import "" "set1" (func (;3;) (type 1))) - ) - (core instance (;0;) - (export "get0" (func $get0)) - (export "set0" (func $set0)) - (export "get1" (func $get1)) - (export "set1" (func $set1)) - ) - (core instance (;1;) (instantiate $m - (with "" (instance 0)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/36.print b/tests/snapshots/cli/component-model-async/threading.wast/36.print deleted file mode 100644 index 60858a0d95..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/36.print +++ /dev/null @@ -1,10 +0,0 @@ -(component - (core type $start (;0;) (func (param i32))) - (core module $libc (;0;) - (table (;0;) 1 funcref) - (export "start-table" (table 0)) - ) - (core instance $libc (;0;) (instantiate $libc)) - (alias core export $libc "start-table" (core table (;0;))) - (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/37.print b/tests/snapshots/cli/component-model-async/threading.wast/37.print deleted file mode 100644 index ee4c6537b9..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/37.print +++ /dev/null @@ -1,21 +0,0 @@ -(component - (core type $start (;0;) (func (param i32))) - (core module $libc (;0;) - (table (;0;) 1 funcref) - (export "start-table" (table 0)) - ) - (core instance $libc (;0;) (instantiate $libc)) - (alias core export $libc "start-table" (core table (;0;))) - (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) - (core module $m (;1;) - (type $new_indirect_ty (;0;) (func (param i32 i32) (result i32))) - (import "" "new_indirect" (func (;0;) (type $new_indirect_ty))) - ) - (core instance (;1;) - (export "new_indirect" (func $new_indirect)) - ) - (core instance (;2;) (instantiate $m - (with "" (instance 1)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/38.print b/tests/snapshots/cli/component-model-async/threading.wast/38.print deleted file mode 100644 index 60858a0d95..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/38.print +++ /dev/null @@ -1,10 +0,0 @@ -(component - (core type $start (;0;) (func (param i32))) - (core module $libc (;0;) - (table (;0;) 1 funcref) - (export "start-table" (table 0)) - ) - (core instance $libc (;0;) (instantiate $libc)) - (alias core export $libc "start-table" (core table (;0;))) - (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/39.print b/tests/snapshots/cli/component-model-async/threading.wast/39.print deleted file mode 100644 index 40cbf9610b..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/39.print +++ /dev/null @@ -1,21 +0,0 @@ -(component - (core type $start (;0;) (func (param i32))) - (core module $libc (;0;) - (table (;0;) 1 funcref) - (export "start-table" (table 0)) - ) - (core instance $libc (;0;) (instantiate $libc)) - (alias core export $libc "start-table" (core table (;0;))) - (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) - (core module $m (;1;) - (type $new_indirect_ty (;0;) (func (param i32 i32) (result i32))) - (import "" "thread.new_indirect" (func (;0;) (type $new_indirect_ty))) - ) - (core instance (;1;) - (export "thread.new_indirect" (func $new_indirect)) - ) - (core instance (;2;) (instantiate $m - (with "" (instance 1)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/40.print b/tests/snapshots/cli/component-model-async/threading.wast/40.print deleted file mode 100644 index 216e7af76f..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/40.print +++ /dev/null @@ -1,69 +0,0 @@ -(component - (core func (;0;) (canon backpressure.set)) - (core func (;1;) (canon backpressure.set)) - (core func (;2;) (canon task.return)) - (core func (;3;) (canon task.return)) - (core func (;4;) (canon task.cancel)) - (core func (;5;) (canon task.cancel)) - (core func (;6;) (canon subtask.drop)) - (core func (;7;) (canon subtask.drop)) - (core func (;8;) (canon subtask.cancel)) - (core func (;9;) (canon subtask.cancel)) - (core func (;10;) (canon subtask.cancel async)) - (core func (;11;) (canon subtask.cancel async)) - (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)) - (alias core export $i "m" (core memory $m (;0;))) - (alias core export $i "r" (core func $r (;12;))) - (type $r (;0;) (resource (rep i32))) - (core func (;13;) (canon resource.drop $r async)) - (core func (;14;) (canon resource.drop $r async)) - (type $s (;1;) (stream)) - (type $f (;2;) (future)) - (core func (;15;) (canon future.new $f)) - (core func (;16;) (canon future.new $f)) - (core func (;17;) (canon stream.new $s)) - (core func (;18;) (canon stream.new $s)) - (core func (;19;) (canon future.cancel-read $f)) - (core func (;20;) (canon future.cancel-read $f)) - (core func (;21;) (canon stream.cancel-read $s)) - (core func (;22;) (canon stream.cancel-read $s)) - (core func (;23;) (canon future.cancel-write $f)) - (core func (;24;) (canon future.cancel-write $f)) - (core func (;25;) (canon stream.cancel-write $s)) - (core func (;26;) (canon stream.cancel-write $s)) - (core func (;27;) (canon future.drop-readable $f)) - (core func (;28;) (canon future.drop-readable $f)) - (core func (;29;) (canon future.drop-writable $f)) - (core func (;30;) (canon future.drop-writable $f)) - (core func (;31;) (canon stream.drop-readable $s)) - (core func (;32;) (canon stream.drop-readable $s)) - (core func (;33;) (canon stream.drop-writable $s)) - (core func (;34;) (canon stream.drop-writable $s)) - (core func (;35;) (canon future.read $f (memory $m))) - (core func (;36;) (canon future.read $f (memory $m))) - (core func (;37;) (canon future.write $f (memory $m))) - (core func (;38;) (canon future.write $f (memory $m))) - (core func (;39;) (canon stream.read $s (memory $m))) - (core func (;40;) (canon stream.read $s (memory $m))) - (core func (;41;) (canon stream.write $s (memory $m))) - (core func (;42;) (canon stream.write $s (memory $m))) - (core func (;43;) (canon error-context.new (memory $m))) - (core func (;44;) (canon error-context.new (memory $m))) - (core func (;45;) (canon error-context.debug-message (memory $m) (realloc $r))) - (core func (;46;) (canon error-context.debug-message (memory $m) (realloc $r))) - (core func (;47;) (canon error-context.drop)) - (core func (;48;) (canon error-context.drop)) - (core func (;49;) (canon context.get i32 0)) - (core func (;50;) (canon context.get i32 0)) - (core func (;51;) (canon context.set i32 0)) - (core func (;52;) (canon context.set i32 0)) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/42.print b/tests/snapshots/cli/component-model-async/threading.wast/42.print deleted file mode 100644 index d36b57ffea..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/42.print +++ /dev/null @@ -1,14 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (result i32))) - (import "" "thread.index" (func $thread.index (;0;) (type 0))) - ) - (core func $thread.index (;0;) (canon thread.index)) - (core instance (;0;) - (export "thread.index" (func $thread.index)) - ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/43.print b/tests/snapshots/cli/component-model-async/threading.wast/43.print deleted file mode 100644 index 28dfb3b000..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/43.print +++ /dev/null @@ -1,4 +0,0 @@ -(component - (type (;0;) (stream u8)) - (core func (;0;) (canon task.return (result 0))) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/44.print b/tests/snapshots/cli/component-model-async/threading.wast/44.print deleted file mode 100644 index 6c92cb7183..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/44.print +++ /dev/null @@ -1,14 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (param i32) (result i32))) - (import "" "thread.switch-to" (func $thread.switch-to (;0;) (type 0))) - ) - (core func $thread.switch-to (;0;) (canon thread.switch-to cancellable)) - (core instance (;0;) - (export "thread.switch-to" (func $thread.switch-to)) - ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) - ) - ) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/46.print b/tests/snapshots/cli/component-model-async/threading.wast/46.print deleted file mode 100644 index b79cfae234..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/46.print +++ /dev/null @@ -1,97 +0,0 @@ -(component - (core func (;0;) (canon backpressure.set)) - (core func (;1;) (canon backpressure.set)) - (core func (;2;) (canon task.return)) - (core func (;3;) (canon task.return)) - (core func (;4;) (canon task.cancel)) - (core func (;5;) (canon task.cancel)) - (core func (;6;) (canon subtask.drop)) - (core func (;7;) (canon subtask.drop)) - (core func (;8;) (canon subtask.cancel)) - (core func (;9;) (canon subtask.cancel)) - (core func (;10;) (canon subtask.cancel async)) - (core func (;11;) (canon subtask.cancel async)) - (core module $m (;0;) - (type (;0;) (func (param i32 i32 i32 i32) (result i32))) - (table (;0;) 1 funcref) - (memory (;0;) 1) - (export "m" (memory 0)) - (export "r" (func 0)) - (export "start-table" (table 0)) - (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32) - unreachable - ) - ) - (core instance $i (;0;) (instantiate $m)) - (alias core export $i "m" (core memory $m (;0;))) - (alias core export $i "r" (core func $r (;12;))) - (alias core export $i "start-table" (core table $start-table (;0;))) - (type $r (;0;) (resource (rep i32))) - (core func (;13;) (canon resource.drop $r async)) - (core func (;14;) (canon resource.drop $r async)) - (type $s (;1;) (stream)) - (type $f (;2;) (future)) - (core func (;15;) (canon future.new $f)) - (core func (;16;) (canon future.new $f)) - (core func (;17;) (canon stream.new $s)) - (core func (;18;) (canon stream.new $s)) - (core func (;19;) (canon future.cancel-read $f)) - (core func (;20;) (canon future.cancel-read $f)) - (core func (;21;) (canon stream.cancel-read $s)) - (core func (;22;) (canon stream.cancel-read $s)) - (core func (;23;) (canon future.cancel-write $f)) - (core func (;24;) (canon future.cancel-write $f)) - (core func (;25;) (canon stream.cancel-write $s)) - (core func (;26;) (canon stream.cancel-write $s)) - (core func (;27;) (canon future.drop-readable $f)) - (core func (;28;) (canon future.drop-readable $f)) - (core func (;29;) (canon future.drop-writable $f)) - (core func (;30;) (canon future.drop-writable $f)) - (core func (;31;) (canon stream.drop-readable $s)) - (core func (;32;) (canon stream.drop-readable $s)) - (core func (;33;) (canon stream.drop-writable $s)) - (core func (;34;) (canon stream.drop-writable $s)) - (core func (;35;) (canon future.read $f (memory $m))) - (core func (;36;) (canon future.read $f (memory $m))) - (core func (;37;) (canon future.write $f (memory $m))) - (core func (;38;) (canon future.write $f (memory $m))) - (core func (;39;) (canon stream.read $s (memory $m))) - (core func (;40;) (canon stream.read $s (memory $m))) - (core func (;41;) (canon stream.write $s (memory $m))) - (core func (;42;) (canon stream.write $s (memory $m))) - (core func (;43;) (canon error-context.new (memory $m))) - (core func (;44;) (canon error-context.new (memory $m))) - (core func (;45;) (canon error-context.debug-message (memory $m) (realloc $r))) - (core func (;46;) (canon error-context.debug-message (memory $m) (realloc $r))) - (core func (;47;) (canon error-context.drop)) - (core func (;48;) (canon error-context.drop)) - (core func (;49;) (canon context.get i32 0)) - (core func (;50;) (canon context.get i32 0)) - (core func (;51;) (canon context.set i32 0)) - (core func (;52;) (canon context.set i32 0)) - (core func (;53;) (canon context.get i32 1)) - (core func (;54;) (canon context.get i32 1)) - (core func (;55;) (canon context.set i32 1)) - (core func (;56;) (canon context.set i32 1)) - (core func (;57;) (canon thread.yield)) - (core func (;58;) (canon thread.yield)) - (core func (;59;) (canon thread.yield cancellable)) - (core func (;60;) (canon thread.yield cancellable)) - (core type $start (;0;) (func (param i32))) - (core func (;61;) (canon thread.new_indirect $start (table $start-table))) - (core func (;62;) (canon thread.new_indirect $start (table $start-table))) - (core func (;63;) (canon thread.switch-to)) - (core func (;64;) (canon thread.switch-to)) - (core func (;65;) (canon thread.switch-to cancellable)) - (core func (;66;) (canon thread.switch-to cancellable)) - (core func (;67;) (canon thread.suspend)) - (core func (;68;) (canon thread.suspend)) - (core func (;69;) (canon thread.suspend cancellable)) - (core func (;70;) (canon thread.suspend cancellable)) - (core func (;71;) (canon thread.resume-later)) - (core func (;72;) (canon thread.resume-later)) - (core func (;73;) (canon thread.yield-to)) - (core func (;74;) (canon thread.yield-to)) - (core func (;75;) (canon thread.yield-to cancellable)) - (core func (;76;) (canon thread.yield-to cancellable)) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/47.print b/tests/snapshots/cli/component-model-async/threading.wast/47.print deleted file mode 100644 index 28dfb3b000..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/47.print +++ /dev/null @@ -1,4 +0,0 @@ -(component - (type (;0;) (stream u8)) - (core func (;0;) (canon task.return (result 0))) -) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/7.print b/tests/snapshots/cli/component-model-async/threading.wast/7.print index 48e7d0adab..60858a0d95 100644 --- a/tests/snapshots/cli/component-model-async/threading.wast/7.print +++ b/tests/snapshots/cli/component-model-async/threading.wast/7.print @@ -1,12 +1,10 @@ (component - (core module $m (;0;) - (memory (;0;) 1) - (export "m" (memory 0)) + (core type $start (;0;) (func (param i32))) + (core module $libc (;0;) + (table (;0;) 1 funcref) + (export "start-table" (table 0)) ) - (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))) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "start-table" (core table (;0;))) + (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) ) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/8.print b/tests/snapshots/cli/component-model-async/threading.wast/8.print index 0162fff210..40cbf9610b 100644 --- a/tests/snapshots/cli/component-model-async/threading.wast/8.print +++ b/tests/snapshots/cli/component-model-async/threading.wast/8.print @@ -1,14 +1,21 @@ (component - (core module $m (;0;) - (type (;0;) (func)) - (import "" "task.cancel" (func $task-cancel (;0;) (type 0))) + (core type $start (;0;) (func (param i32))) + (core module $libc (;0;) + (table (;0;) 1 funcref) + (export "start-table" (table 0)) ) - (core func $task-cancel (;0;) (canon task.cancel)) - (core instance (;0;) - (export "task.cancel" (func $task-cancel)) + (core instance $libc (;0;) (instantiate $libc)) + (alias core export $libc "start-table" (core table (;0;))) + (core func $new_indirect (;0;) (canon thread.new_indirect $start (table 0))) + (core module $m (;1;) + (type $new_indirect_ty (;0;) (func (param i32 i32) (result i32))) + (import "" "thread.new_indirect" (func (;0;) (type $new_indirect_ty))) ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) + (core instance (;1;) + (export "thread.new_indirect" (func $new_indirect)) + ) + (core instance (;2;) (instantiate $m + (with "" (instance 1)) ) ) ) diff --git a/tests/snapshots/cli/component-model-async/threading.wast/9.print b/tests/snapshots/cli/component-model-async/threading.wast/9.print deleted file mode 100644 index 967b3b8c79..0000000000 --- a/tests/snapshots/cli/component-model-async/threading.wast/9.print +++ /dev/null @@ -1,14 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (result i32))) - (import "" "waitable-set.new" (func (;0;) (type 0))) - ) - (core func $waitable-set-new (;0;) (canon waitable-set.new)) - (core instance (;0;) - (export "waitable-set.new" (func $waitable-set-new)) - ) - (core instance $i (;1;) (instantiate $m - (with "" (instance 0)) - ) - ) -) diff --git a/tests/snapshots/cli/missing-features/component-model/async-builtins.wast.json b/tests/snapshots/cli/missing-features/component-model/async-builtins.wast.json new file mode 100644 index 0000000000..e1105da089 --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/async-builtins.wast.json @@ -0,0 +1,52 @@ +{ + "source_filename": "tests/cli/missing-features/component-model/async-builtins.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 6, + "filename": "async-builtins.0.wasm", + "module_type": "binary", + "text": "requires the component model async builtins feature" + }, + { + "type": "assert_invalid", + "line": 11, + "filename": "async-builtins.1.wasm", + "module_type": "binary", + "text": "requires the component model async builtins feature" + }, + { + "type": "assert_invalid", + "line": 16, + "filename": "async-builtins.2.wasm", + "module_type": "binary", + "text": "requires the component model async builtins feature" + }, + { + "type": "assert_invalid", + "line": 21, + "filename": "async-builtins.3.wasm", + "module_type": "binary", + "text": "requires the component model async builtins feature" + }, + { + "type": "module", + "line": 26, + "filename": "async-builtins.4.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 37, + "filename": "async-builtins.5.wasm", + "module_type": "binary", + "text": "requires the component model async builtins feature" + }, + { + "type": "module", + "line": 41, + "filename": "async-builtins.6.wasm", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/cli/missing-features/async-builtins.wast/4.print b/tests/snapshots/cli/missing-features/component-model/async-builtins.wast/4.print similarity index 100% rename from tests/snapshots/cli/missing-features/async-builtins.wast/4.print rename to tests/snapshots/cli/missing-features/component-model/async-builtins.wast/4.print diff --git a/tests/snapshots/cli/missing-features/async-builtins.wast/6.print b/tests/snapshots/cli/missing-features/component-model/async-builtins.wast/6.print similarity index 100% rename from tests/snapshots/cli/missing-features/async-builtins.wast/6.print rename to tests/snapshots/cli/missing-features/component-model/async-builtins.wast/6.print diff --git a/tests/snapshots/cli/missing-features/component-model/async-stackful.wast.json b/tests/snapshots/cli/missing-features/component-model/async-stackful.wast.json new file mode 100644 index 0000000000..0bf14ba56b --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/async-stackful.wast.json @@ -0,0 +1,51 @@ +{ + "source_filename": "tests/cli/missing-features/component-model/async-stackful.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 5, + "filename": "async-stackful.0.wasm", + "module_type": "binary", + "text": "requires the component model async stackful feature" + }, + { + "type": "assert_invalid", + "line": 17, + "filename": "async-stackful.1.wasm", + "module_type": "binary", + "text": "requires the component model async stackful feature" + }, + { + "type": "module", + "line": 24, + "filename": "async-stackful.2.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 32, + "filename": "async-stackful.3.wasm", + "module_type": "binary", + "text": "requires the component model async stackful feature" + }, + { + "type": "module", + "line": 39, + "filename": "async-stackful.4.wasm", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 47, + "filename": "async-stackful.5.wasm", + "module_type": "binary", + "text": "requires the component model async stackful feature" + }, + { + "type": "module", + "line": 50, + "filename": "async-stackful.6.wasm", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/cli/missing-features/async-stackful.wast/2.print b/tests/snapshots/cli/missing-features/component-model/async-stackful.wast/2.print similarity index 100% rename from tests/snapshots/cli/missing-features/async-stackful.wast/2.print rename to tests/snapshots/cli/missing-features/component-model/async-stackful.wast/2.print diff --git a/tests/snapshots/cli/missing-features/async-stackful.wast/4.print b/tests/snapshots/cli/missing-features/component-model/async-stackful.wast/4.print similarity index 100% rename from tests/snapshots/cli/missing-features/async-stackful.wast/4.print rename to tests/snapshots/cli/missing-features/component-model/async-stackful.wast/4.print diff --git a/tests/snapshots/cli/missing-features/async-stackful.wast/6.print b/tests/snapshots/cli/missing-features/component-model/async-stackful.wast/6.print similarity index 100% rename from tests/snapshots/cli/missing-features/async-stackful.wast/6.print rename to tests/snapshots/cli/missing-features/component-model/async-stackful.wast/6.print diff --git a/tests/snapshots/cli/missing-features/component-model/async.wast.json b/tests/snapshots/cli/missing-features/component-model/async.wast.json index 278991db3e..16ddc9dbd6 100644 --- a/tests/snapshots/cli/missing-features/component-model/async.wast.json +++ b/tests/snapshots/cli/missing-features/component-model/async.wast.json @@ -202,7 +202,7 @@ "line": 339, "filename": "async.28.wasm", "module_type": "binary", - "text": "requires the component model threading feature" + "text": "requires the component model async builtins feature" }, { "type": "assert_invalid", diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast.json b/tests/snapshots/cli/missing-features/component-model/threading.wast.json index 461f3f4045..cf6e1c505c 100644 --- a/tests/snapshots/cli/missing-features/component-model/threading.wast.json +++ b/tests/snapshots/cli/missing-features/component-model/threading.wast.json @@ -3,103 +3,10 @@ "commands": [ { "type": "assert_invalid", - "line": 5, + "line": 6, "filename": "threading.0.wasm", "module_type": "binary", "text": "requires the component model threading feature" - }, - { - "type": "assert_invalid", - "line": 17, - "filename": "threading.1.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" - }, - { - "type": "module", - "line": 24, - "filename": "threading.2.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 32, - "filename": "threading.3.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" - }, - { - "type": "module", - "line": 39, - "filename": "threading.4.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 47, - "filename": "threading.5.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" - }, - { - "type": "module", - "line": 49, - "filename": "threading.6.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 53, - "filename": "threading.7.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" - }, - { - "type": "assert_invalid", - "line": 58, - "filename": "threading.8.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" - }, - { - "type": "assert_invalid", - "line": 63, - "filename": "threading.9.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" - }, - { - "type": "assert_invalid", - "line": 68, - "filename": "threading.10.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" - }, - { - "type": "module", - "line": 73, - "filename": "threading.11.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 84, - "filename": "threading.12.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" - }, - { - "type": "module", - "line": 88, - "filename": "threading.13.wasm", - "module_type": "binary" - }, - { - "type": "assert_invalid", - "line": 94, - "filename": "threading.14.wasm", - "module_type": "binary", - "text": "requires the component model threading feature" } ] } \ No newline at end of file diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/10.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/10.print deleted file mode 100644 index 610a633cad..0000000000 --- a/tests/snapshots/cli/missing-features/component-model/threading.wast/10.print +++ /dev/null @@ -1,8 +0,0 @@ -(component - (type $f (;0;) (future)) - (type $s (;1;) (stream)) - (core func (;0;) (canon future.cancel-read $f)) - (core func (;1;) (canon future.cancel-write $f)) - (core func (;2;) (canon stream.cancel-read $s)) - (core func (;3;) (canon stream.cancel-write $s)) -) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/11.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/11.print deleted file mode 100644 index 610a633cad..0000000000 --- a/tests/snapshots/cli/missing-features/component-model/threading.wast/11.print +++ /dev/null @@ -1,8 +0,0 @@ -(component - (type $f (;0;) (future)) - (type $s (;1;) (stream)) - (core func (;0;) (canon future.cancel-read $f)) - (core func (;1;) (canon future.cancel-write $f)) - (core func (;2;) (canon stream.cancel-read $s)) - (core func (;3;) (canon stream.cancel-write $s)) -) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/12.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/12.print deleted file mode 100644 index 2c15950a33..0000000000 --- a/tests/snapshots/cli/missing-features/component-model/threading.wast/12.print +++ /dev/null @@ -1,4 +0,0 @@ -(component - (type $t (;0;) (resource (rep i32))) - (core func (;0;) (canon resource.drop $t)) -) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/13.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/13.print deleted file mode 100644 index 2c15950a33..0000000000 --- a/tests/snapshots/cli/missing-features/component-model/threading.wast/13.print +++ /dev/null @@ -1,4 +0,0 @@ -(component - (type $t (;0;) (resource (rep i32))) - (core func (;0;) (canon resource.drop $t)) -) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/2.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/2.print deleted file mode 100644 index 96c65f93d7..0000000000 --- a/tests/snapshots/cli/missing-features/component-model/threading.wast/2.print +++ /dev/null @@ -1,9 +0,0 @@ -(component - (core module $libc (;0;) - (memory (;0;) 1) - (export "memory" (memory 0)) - ) - (core instance $libc (;0;) (instantiate $libc)) - (alias core export $libc "memory" (core memory (;0;))) - (core func (;0;) (canon waitable-set.wait (memory 0))) -) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/4.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/4.print deleted file mode 100644 index a4322a5d8c..0000000000 --- a/tests/snapshots/cli/missing-features/component-model/threading.wast/4.print +++ /dev/null @@ -1,9 +0,0 @@ -(component - (core module $libc (;0;) - (memory (;0;) 1) - (export "memory" (memory 0)) - ) - (core instance $libc (;0;) (instantiate $libc)) - (alias core export $libc "memory" (core memory (;0;))) - (core func (;0;) (canon waitable-set.poll (memory 0))) -) diff --git a/tests/snapshots/cli/missing-features/component-model/threading.wast/6.print b/tests/snapshots/cli/missing-features/component-model/threading.wast/6.print deleted file mode 100644 index a1d9c7a10c..0000000000 --- a/tests/snapshots/cli/missing-features/component-model/threading.wast/6.print +++ /dev/null @@ -1,3 +0,0 @@ -(component - (core func (;0;) (canon thread.yield)) -)