From fdeba12544d0b47e4566117db7f4b41ba80a3fa5 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 7 Feb 2025 10:20:18 -0800 Subject: [PATCH 01/21] Add `thread.spawn_indirect` This change codifies the conclusions we arrived to in [#89]. It adds a new way to spawn threads, `thread.spawn_indirect`, which retrieves the thread start function from a table. This prompted me to rename `thread.spawn` to `thread.spawn_ref`. [#89]: https://github.com/WebAssembly/shared-everything-threads/issues/89 --- design/mvp/Async.md | 27 +++++++++++---------- design/mvp/Binary.md | 5 ++-- design/mvp/CanonicalABI.md | 48 +++++++++++++++++++++++++++++++++++--- design/mvp/Explainer.md | 33 +++++++++++++++++++------- 4 files changed, 86 insertions(+), 27 deletions(-) diff --git a/design/mvp/Async.md b/design/mvp/Async.md index f80fb4ca..db456cba 100644 --- a/design/mvp/Async.md +++ b/design/mvp/Async.md @@ -78,12 +78,11 @@ these languages' concurrency features are already bound (making the Component Model "just another OS" from the language toolchains' perspective). Moreover, this async ABI does not require components to use preemptive -multi-threading ([`thread.spawn`]) in order to achieve concurrency. Instead, -concurrency can be achieved by cooperatively switching between different -logical tasks running on a single thread. This switching may require the use of -[fibers] or a [CPS transform], but may also be avoided entirely when a -component's producer toolchain is engineered to always return to an -[event loop]. +multi-threading ([`thread.spawn*`]) in order to achieve concurrency. Instead, +concurrency can be achieved by cooperatively switching between different logical +tasks running on a single thread. This switching may require the use of [fibers] +or a [CPS transform], but may also be avoided entirely when a component's +producer toolchain is engineered to always return to an [event loop]. To avoid partitioning the world along sync/async lines as mentioned in the Goals section, the Component Model allows *every* component-level function type @@ -672,11 +671,11 @@ by declarative instantiation and `start` above. ## Interaction with multi-threading -For now, the integration between multi-threading (via [`thread.spawn`]) and -native async is limited. In particular, because all [lift and lower -definitions] produce non-`shared` functions, any threads spawned by a component -via `thread.spawn` will not be able to directly call imports (synchronously -*or* asynchronously) and will thus have to use Core WebAssembly `atomics.*` +For now, the integration between multi-threading (via [`thread.spawn*`]) and +native async is limited. In particular, because all [lift and lower definitions] +produce non-`shared` functions, any threads spawned by a component via +`thread.spawn*` will not be able to directly call imports (synchronously *or* +asynchronously) and will thus have to use Core WebAssembly `atomics.*` instructions to switch back to a non-`shared` function running on the "main" thread (i.e., whichever thread was used to call the component's exports). @@ -693,8 +692,8 @@ composition story described above could naturally be extended to a sync+async+shared composition story, continuing to avoid the "what color is your function" problem (where `shared` is the [color]). -Even without any use of `thread.new`, native async provides an opportunity to -achieve some automatic parallelism "for free". In particular, due to the +Even without any use of [`thread.spawn*`], native async provides an opportunity +to achieve some automatic parallelism "for free". In particular, due to the shared-nothing nature of components, each component instance could be given a separate thread on which to interleave all tasks executing in that instance. Thus, in a cross-component call from `C1` to `C2`, `C2`'s task can run in a @@ -750,7 +749,7 @@ comes after: [`yield`]: Explainer.md#-yield [`waitable-set.wait`]: Explainer.md#-waitable-setwait [`waitable-set.poll`]: Explainer.md#-waitable-setpoll -[`thread.spawn`]: Explainer.md#-threadspawn +[`thread.spawn*`]: Explainer.md#-threadspawnref [ESM-integration]: Explainer.md#ESM-integration [Canonical ABI Explainer]: CanonicalABI.md diff --git a/design/mvp/Binary.md b/design/mvp/Binary.md index 915afcc3..35c8ded0 100644 --- a/design/mvp/Binary.md +++ b/design/mvp/Binary.md @@ -286,9 +286,10 @@ canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> => (canon lift | 0x01 0x00 f:<funcidx> opts:<opts> => (canon lower f opts (core func)) | 0x02 rt:<typeidx> => (canon resource.new rt (core func)) | 0x03 rt:<typeidx> => (canon resource.drop rt (core func)) - | 0x07 rt:<typdidx> => (canon resource.drop rt async (core func)) ๐ + | 0x07 rt:<typeidx> => (canon resource.drop rt async (core func)) ๐ | 0x04 rt:<typeidx> => (canon resource.rep rt (core func)) - | 0x05 ft:<typeidx> => (canon thread.spawn ft (core func)) ๐งต + | 0x05 ft:<typeidx> => (canon thread.spawn_ref ft (core func)) ๐งต + | 0x24 ft:<typeidx> t:<core:tabidx> => (canon thread.spawn_indirect ft (table t) (core func)) ๐งต | 0x06 => (canon thread.available_parallelism (core func)) ๐งต | 0x08 => (canon backpressure.set (core func)) ๐ | 0x09 rs:<resultlist> opts:<opts> => (canon task.return rs opts (core func)) ๐ diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index 27bd1f95..c7be3dcf 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3773,11 +3773,11 @@ async def canon_error_context_drop(task, i): ``` -### ๐งต `canon thread.spawn` +### ๐งต `canon thread.spawn_ref` For a canonical definition: ```wat -(canon thread.spawn (type $ft) (core func $st)) +(canon thread.spawn_ref (type $ft) (core func $st)) ``` validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type `(func @@ -3802,7 +3802,7 @@ thread which: In pseudocode, `$st` looks like: ```python -def canon_thread_spawn(f, c): +def canon_thread_spawn_ref(f, c): trap_if(f is None) if DETERMINISTIC_PROFILE: return [-1] @@ -3820,6 +3820,48 @@ def canon_thread_spawn(f, c): ``` +### ๐งต `canon thread.spawn_indirect` + +For a canonical definition: +```wat +(canon thread.spawn_indirect (type $ft) (table $t) (core func $st)) +``` +validation specifies: +* `$ft` must refer to a `shared` function type; initially, only the type `(func + shared (param $c i32))` is allowed (see explanation in `thread.spawn_ref` + above) +* `$t` must refer to a table containing `ft`-typed items +* `$st` is given type `(func (param $i i32) (param $c i32) (result $e + i32))`. + +Calling `$st` retrieves a function `$f` of type `$ft` from table `$t`. If that +succeeds, it spawns a thread which: + - invokes `$f` with `$c` + - executes `$f` until completion or trap in a `shared` context as described by + the [shared-everything threads] proposal. + +In pseudocode, `$st` looks like: + +```python +def canon_thread_spawn_indirect(t, i, c): + trap_if(t[i] is None) + f = t[i] + if DETERMINISTIC_PROFILE: + return [-1] + + def thread_start(): + try: + f(c) + except CoreWebAssemblyException: + trap() + + if spawn(thread_start): + return [0] + else: + return [-1] +``` + + ### ๐งต `canon thread.available_parallelism` For a canonical definition: diff --git a/design/mvp/Explainer.md b/design/mvp/Explainer.md index b34146b8..bd2b174e 100644 --- a/design/mvp/Explainer.md +++ b/design/mvp/Explainer.md @@ -1438,7 +1438,8 @@ canon ::= ... | (canon error-context.new <canonopt>* (core func <id>?)) | (canon error-context.debug-message <canonopt>* (core func <id>?)) | (canon error-context.drop (core func <id>?)) - | (canon thread.spawn <typeidx> (core func <id>?)) ๐งต + | (canon thread.spawn_ref <typeidx> (core func <id>?)) ๐งต + | (canon thread.spawn_indirect <typeidx> <core:tableidx> (core func <id>?)) ๐งต | (canon thread.available_parallelism (core func <id>?)) ๐งต ``` @@ -1945,19 +1946,34 @@ thread management. These are specified as built-ins and not core WebAssembly instructions because browsers expect this functionality to come from existing Web/JS APIs. -###### ๐งต `thread.spawn` +###### ๐งต `thread.spawn_ref` | Synopsis | | | -------------------------- | --------------------------------------------------------- | | Approximate WIT signature | `func<FuncT>(f: FuncT, c: FuncT.params[0]) -> bool` | | Canonical ABI signature | `[f:(ref null (func shared (param i32))) c:i32] -> [i32]` | -The `thread.spawn` built-in spawns a new thread by invoking the shared function -`f` while passing `c` to it, returning whether a thread was successfully -spawned. While it's designed to allow different types in the future, the type -of `c` is currently hard-coded to always be `i32`. +The `thread.spawn_ref` built-in spawns a new thread by invoking the shared +function `f` while passing `c` to it, returning whether a thread was +successfully spawned. While it's designed to allow different types in the +future, the type of `c` is currently hard-coded to always be `i32`. -(See also [`canon_thread_spawn`] in the Canonical ABI explainer.) +(See also [`canon_thread_spawn_ref`] in the Canonical ABI explainer.) + + +###### ๐งต `thread.spawn_indirect` + +| Synopsis | | +| -------------------------- | ------------------------------------------------- | +| Approximate WIT signature | `func<FuncT>(i: i32, c: FuncT.params[0]) -> bool` | +| Canonical ABI signature | `[i:i32 c:i32] -> [i32]` | + +The `thread.spawn_indirect` built-in spawns a new thread by retrieving the +shared function `f` from a table using index `i` (much like the `call_indirect` +core instruction). Once `f` is retrieved, this built-in operates like +`thread.spawn_ref` above, including the limitations on `f`'s parameters. + +(See also [`canon_thread_spawn_indirect`] in the Canonical ABI explainer.) ###### ๐งต `thread.available_parallelism` @@ -2806,7 +2822,8 @@ For some use-case-focused, worked examples, see: [`canon_error_context_new`]: CanonicalABI.md#-canon-error-contextnew [`canon_error_context_debug_message`]: CanonicalABI.md#-canon-error-contextdebug-message [`canon_error_context_drop`]: CanonicalABI.md#-canon-error-contextdrop -[`canon_thread_spawn`]: CanonicalABI.md#-canon-theadspawn +[`canon_thread_spawn_ref`]: CanonicalABI.md#-canon-threadspawnref +[`canon_thread_spawn_indirect`]: CanonicalABI.md#-canon-threadspawnindirect [`canon_thread_available_parallelism`]: CanonicalABI.md#-canon-threadavailable_parallelism [`pack_async_copy_result`]: CanonicalABI.md#-canon-streamfuturereadwrite [the `close` built-ins]: CanonicalABI.md#-canon-streamfutureclose-readablewritable From dc325958637a6f5df2fc194dc15289e5e2547b86 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Thu, 27 Feb 2025 14:59:06 -0800 Subject: [PATCH 02/21] Fix `shared` syntax for `` --- design/mvp/CanonicalABI.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index c7be3dcf..ca240493 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3780,16 +3780,16 @@ For a canonical definition: (canon thread.spawn_ref (type $ft) (core func $st)) ``` validation specifies: -* `$ft` must refer to a `shared` function type; initially, only the type `(func - shared (param $c i32))` is allowed (see explanation below) +* `$ft` must refer to a `shared` function type; initially, only the type + `(shared (func (param $c i32)))` is allowed (see explanation below) * `$st` is given type `(func (param $f (ref null $ft)) (param $c i32) (result $e i32))`. > Note: ideally, a thread could be spawned with [arbitrary thread parameters]. > Currently, that would require additional work in the toolchain to support so, -> for simplicity, the current proposal simply fixes a single `i32` parameter type. -> However, `thread.spawn` could be extended to allow arbitrary thread parameters -> in the future, once it's concretely beneficial to the toolchain. +> for simplicity, the current proposal simply fixes a single `i32` parameter +> type. However, `thread.spawn_ref` could be extended to allow arbitrary thread +> parameters in the future, once it's concretely beneficial to the toolchain. > The inclusion of `$ft` ensures backwards compatibility for when arbitrary > parameters are allowed. @@ -3827,9 +3827,9 @@ For a canonical definition: (canon thread.spawn_indirect (type $ft) (table $t) (core func $st)) ``` validation specifies: -* `$ft` must refer to a `shared` function type; initially, only the type `(func - shared (param $c i32))` is allowed (see explanation in `thread.spawn_ref` - above) +* `$ft` must refer to a `shared` function type; initially, only the type + `(shared (func shared (param $c i32)))` is allowed (see explanation in + `thread.spawn_ref` above) * `$t` must refer to a table containing `ft`-typed items * `$st` is given type `(func (param $i i32) (param $c i32) (result $e i32))`. From 903cdb10c9218238966c0a0761cb3ec29a39562f Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Thu, 27 Feb 2025 15:02:32 -0800 Subject: [PATCH 03/21] Fix table type: it contains shared `funcref`s --- design/mvp/CanonicalABI.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index ca240493..53daacb8 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3830,12 +3830,12 @@ validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type `(shared (func shared (param $c i32)))` is allowed (see explanation in `thread.spawn_ref` above) -* `$t` must refer to a table containing `ft`-typed items +* `$t` must refer to a table with type `(table (ref null (shared func)) shared)` * `$st` is given type `(func (param $i i32) (param $c i32) (result $e i32))`. -Calling `$st` retrieves a function `$f` of type `$ft` from table `$t`. If that -succeeds, it spawns a thread which: +Calling `$st` retrieves a reference to function `$f` from table `$t` and checks +that `$f` is of type `$ft`. If that succeeds, it spawns a thread which: - invokes `$f` with `$c` - executes `$f` until completion or trap in a `shared` context as described by the [shared-everything threads] proposal. From 03d166d099edbc7157a5544d1272ec728ad5fccb Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:50:01 -0800 Subject: [PATCH 04/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index 53daacb8..91250c96 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3834,7 +3834,7 @@ validation specifies: * `$st` is given type `(func (param $i i32) (param $c i32) (result $e i32))`. -Calling `$st` retrieves a reference to function `$f` from table `$t` and checks +Calling `$spawn_indirect` retrieves a reference to function `$f` from table `$tbl` and checks that `$f` is of type `$ft`. If that succeeds, it spawns a thread which: - invokes `$f` with `$c` - executes `$f` until completion or trap in a `shared` context as described by From d394e76d84511e0aae21d48936b7dd3ba5d9c807 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:50:14 -0800 Subject: [PATCH 05/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index 91250c96..5192b192 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3830,7 +3830,7 @@ validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type `(shared (func shared (param $c i32)))` is allowed (see explanation in `thread.spawn_ref` above) -* `$t` must refer to a table with type `(table (ref null (shared func)) shared)` +* `$tbl` must refer to a table with type `(table (ref null (shared func)) shared)` * `$st` is given type `(func (param $i i32) (param $c i32) (result $e i32))`. From 90ac9d4a7a32b95a5d22832c3420050dd800aa81 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:52:08 -0800 Subject: [PATCH 06/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index 5192b192..d961afe6 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3828,7 +3828,7 @@ For a canonical definition: ``` validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type - `(shared (func shared (param $c i32)))` is allowed (see explanation in + `(shared (func (param $c i32)))` is allowed (see explanation in `thread.spawn_ref` above) * `$tbl` must refer to a table with type `(table (ref null (shared func)) shared)` * `$st` is given type `(func (param $i i32) (param $c i32) (result $e From 0e4defbbe26b9a13adbc22542f21b4101902018e Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:52:17 -0800 Subject: [PATCH 07/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index d961afe6..f083545d 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3840,7 +3840,7 @@ that `$f` is of type `$ft`. If that succeeds, it spawns a thread which: - executes `$f` until completion or trap in a `shared` context as described by the [shared-everything threads] proposal. -In pseudocode, `$st` looks like: +In pseudocode, `$spawn_indirect` looks like: ```python def canon_thread_spawn_indirect(t, i, c): From 7b9a6ba3181dfbea28ab0eebb15464cfd2a0712a Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:52:38 -0800 Subject: [PATCH 08/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index f083545d..ede8daad 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3843,9 +3843,10 @@ that `$f` is of type `$ft`. If that succeeds, it spawns a thread which: In pseudocode, `$spawn_indirect` looks like: ```python -def canon_thread_spawn_indirect(t, i, c): - trap_if(t[i] is None) - f = t[i] +def canon_thread_spawn_indirect(ft, tbl, i, c): + f = tbl[i] + trap_if(f is None) + trap_if(f.type != ft) if DETERMINISTIC_PROFILE: return [-1] From 1c5f3c9457bc7ad72458d7f46d269b5db761256b Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:52:51 -0800 Subject: [PATCH 09/21] Update design/mvp/Explainer.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/Explainer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/Explainer.md b/design/mvp/Explainer.md index bd2b174e..eff0834f 100644 --- a/design/mvp/Explainer.md +++ b/design/mvp/Explainer.md @@ -1951,7 +1951,7 @@ Web/JS APIs. | Synopsis | | | -------------------------- | --------------------------------------------------------- | | Approximate WIT signature | `func<FuncT>(f: FuncT, c: FuncT.params[0]) -> bool` | -| Canonical ABI signature | `[f:(ref null (func shared (param i32))) c:i32] -> [i32]` | +| Canonical ABI signature | `[f:(ref null (shared (func (param i32))) c:i32] -> [i32]` | The `thread.spawn_ref` built-in spawns a new thread by invoking the shared function `f` while passing `c` to it, returning whether a thread was From 4ac8c1cb84b94164e29818ead896fd1fdb78db82 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:53:20 -0800 Subject: [PATCH 10/21] Update design/mvp/Binary.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/Binary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/Binary.md b/design/mvp/Binary.md index 35c8ded0..beb1b419 100644 --- a/design/mvp/Binary.md +++ b/design/mvp/Binary.md @@ -289,7 +289,7 @@ canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> => (canon lift | 0x07 rt:<typeidx> => (canon resource.drop rt async (core func)) ๐ | 0x04 rt:<typeidx> => (canon resource.rep rt (core func)) | 0x05 ft:<typeidx> => (canon thread.spawn_ref ft (core func)) ๐งต - | 0x24 ft:<typeidx> t:<core:tabidx> => (canon thread.spawn_indirect ft (table t) (core func)) ๐งต + | 0x24 ft:<typeidx> t:<core:tableidx> => (canon thread.spawn_indirect ft (table t) (core func)) ๐งต | 0x06 => (canon thread.available_parallelism (core func)) ๐งต | 0x08 => (canon backpressure.set (core func)) ๐ | 0x09 rs:<resultlist> opts:<opts> => (canon task.return rs opts (core func)) ๐ From 34a557974cbbc0c30a1f2e31754d5c27621ad627 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:53:42 -0800 Subject: [PATCH 11/21] Update design/mvp/Explainer.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/Explainer.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/design/mvp/Explainer.md b/design/mvp/Explainer.md index eff0834f..363def2f 100644 --- a/design/mvp/Explainer.md +++ b/design/mvp/Explainer.md @@ -1969,7 +1969,8 @@ future, the type of `c` is currently hard-coded to always be `i32`. | Canonical ABI signature | `[i:i32 c:i32] -> [i32]` | The `thread.spawn_indirect` built-in spawns a new thread by retrieving the -shared function `f` from a table using index `i` (much like the `call_indirect` +shared function `f` from a table using index `i` and traps if the type of `f` is +not equal to `FuncT` (much like the `call_indirect` core instruction). Once `f` is retrieved, this built-in operates like `thread.spawn_ref` above, including the limitations on `f`'s parameters. From 9e9087e0ff9059438716f8a642f14e7d64580da1 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:53:51 -0800 Subject: [PATCH 12/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index ede8daad..cb2ec8a3 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3777,7 +3777,7 @@ async def canon_error_context_drop(task, i): For a canonical definition: ```wat -(canon thread.spawn_ref (type $ft) (core func $st)) +(canon thread.spawn_ref (type $ft) (core func $spawn_ref)) ``` validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type From 1588a270a7929709ec7c521fae69bf244d9451e3 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:54:26 -0800 Subject: [PATCH 13/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index cb2ec8a3..48790ab5 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3782,7 +3782,7 @@ For a canonical definition: validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type `(shared (func (param $c i32)))` is allowed (see explanation below) -* `$st` is given type `(func (param $f (ref null $ft)) (param $c i32) (result $e +* `$spawn_ref` is given type `(func (param $f (ref null $ft)) (param $c i32) (result $e i32))`. > Note: ideally, a thread could be spawned with [arbitrary thread parameters]. From deadb369ec8d1c93e3071f11c1497798d8c74699 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:54:35 -0800 Subject: [PATCH 14/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index 48790ab5..fe186408 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3831,7 +3831,7 @@ validation specifies: `(shared (func (param $c i32)))` is allowed (see explanation in `thread.spawn_ref` above) * `$tbl` must refer to a table with type `(table (ref null (shared func)) shared)` -* `$st` is given type `(func (param $i i32) (param $c i32) (result $e +* `$spawn_indirect` is given type `(func (param $i i32) (param $c i32) (result $e i32))`. Calling `$spawn_indirect` retrieves a reference to function `$f` from table `$tbl` and checks From 83f20a741e8498565e5651c5beb15c2ea3042c4a Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 08:57:28 -0800 Subject: [PATCH 15/21] Move `thread.*` encodings to the 0x40+ space --- design/mvp/Binary.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/design/mvp/Binary.md b/design/mvp/Binary.md index beb1b419..394b78fa 100644 --- a/design/mvp/Binary.md +++ b/design/mvp/Binary.md @@ -288,9 +288,6 @@ canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> => (canon lift | 0x03 rt:<typeidx> => (canon resource.drop rt (core func)) | 0x07 rt:<typeidx> => (canon resource.drop rt async (core func)) ๐ | 0x04 rt:<typeidx> => (canon resource.rep rt (core func)) - | 0x05 ft:<typeidx> => (canon thread.spawn_ref ft (core func)) ๐งต - | 0x24 ft:<typeidx> t:<core:tableidx> => (canon thread.spawn_indirect ft (table t) (core func)) ๐งต - | 0x06 => (canon thread.available_parallelism (core func)) ๐งต | 0x08 => (canon backpressure.set (core func)) ๐ | 0x09 rs:<resultlist> opts:<opts> => (canon task.return rs opts (core func)) ๐ | 0x0a 0x7f i:<u32> => (canon context.get i32 i (core func)) ๐ @@ -319,6 +316,9 @@ canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> => (canon lift | 0x21 async?:<async>? m:<core:memidx> => (canon waitable-set.poll async? (memory m) (core func)) ๐ | 0x22 => (canon waitable-set.drop (core func)) ๐ | 0x23 => (canon waitable.join (core func)) ๐ + | 0x40 ft:<typeidx> => (canon thread.spawn_ref ft (core func)) ๐งต + | 0x41 ft:<typeidx> t:<core:tableidx> => (canon thread.spawn_indirect ft (table t) (core func)) ๐งต + | 0x42 => (canon thread.available_parallelism (core func)) ๐งต async? ::= 0x00 => | 0x01 => async opts ::= opt*:vec(<canonopt>) => opt* From fbbceb17141f3a30fd48f52b4002857c46480ea7 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 09:00:21 -0800 Subject: [PATCH 16/21] Fix Markdown links --- design/mvp/Async.md | 2 +- design/mvp/CanonicalABI.md | 3 ++- design/mvp/Explainer.md | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/design/mvp/Async.md b/design/mvp/Async.md index db456cba..ff33b48a 100644 --- a/design/mvp/Async.md +++ b/design/mvp/Async.md @@ -749,7 +749,7 @@ comes after: [`yield`]: Explainer.md#-yield [`waitable-set.wait`]: Explainer.md#-waitable-setwait [`waitable-set.poll`]: Explainer.md#-waitable-setpoll -[`thread.spawn*`]: Explainer.md#-threadspawnref +[`thread.spawn*`]: Explainer.md#-threadspawn_ref [ESM-integration]: Explainer.md#ESM-integration [Canonical ABI Explainer]: CanonicalABI.md diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index fe186408..f15d5542 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -54,7 +54,8 @@ being specified here. * [`canon error-context.new`](#-canon-error-contextnew) ๐ * [`canon error-context.debug-message`](#-canon-error-contextdebug-message) ๐ * [`canon error-context.drop`](#-canon-error-contextdrop) ๐ - * [`canon thread.spawn`](#-canon-threadspawn) ๐งต + * [`canon thread.spawn_ref`](#-canon-threadspawn_ref) ๐งต + * [`canon thread.spawn_indirect`](#-canon-threadspawn_indirect) ๐งต * [`canon thread.available_parallelism`](#-canon-threadavailable_parallelism) ๐งต ## Supporting definitions diff --git a/design/mvp/Explainer.md b/design/mvp/Explainer.md index 363def2f..980fe4e4 100644 --- a/design/mvp/Explainer.md +++ b/design/mvp/Explainer.md @@ -2823,8 +2823,8 @@ For some use-case-focused, worked examples, see: [`canon_error_context_new`]: CanonicalABI.md#-canon-error-contextnew [`canon_error_context_debug_message`]: CanonicalABI.md#-canon-error-contextdebug-message [`canon_error_context_drop`]: CanonicalABI.md#-canon-error-contextdrop -[`canon_thread_spawn_ref`]: CanonicalABI.md#-canon-threadspawnref -[`canon_thread_spawn_indirect`]: CanonicalABI.md#-canon-threadspawnindirect +[`canon_thread_spawn_ref`]: CanonicalABI.md#-canon-threadspawn_ref +[`canon_thread_spawn_indirect`]: CanonicalABI.md#-canon-threadspawn_indirect [`canon_thread_available_parallelism`]: CanonicalABI.md#-canon-threadavailable_parallelism [`pack_async_copy_result`]: CanonicalABI.md#-canon-streamfuturereadwrite [the `close` built-ins]: CanonicalABI.md#-canon-streamfutureclose-readablewritable From cb429113b42004abd5ca28b2c2632f62bcb29bdd Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 09:03:39 -0800 Subject: [PATCH 17/21] Fix line wrapping --- design/mvp/CanonicalABI.md | 16 +++++++++------- design/mvp/Explainer.md | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index f15d5542..6a16fda4 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3783,8 +3783,8 @@ For a canonical definition: validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type `(shared (func (param $c i32)))` is allowed (see explanation below) -* `$spawn_ref` is given type `(func (param $f (ref null $ft)) (param $c i32) (result $e - i32))`. +* `$spawn_ref` is given type `(func (param $f (ref null $ft)) (param $c i32) + (result $e i32))`. > Note: ideally, a thread could be spawned with [arbitrary thread parameters]. > Currently, that would require additional work in the toolchain to support so, @@ -3831,12 +3831,14 @@ validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type `(shared (func (param $c i32)))` is allowed (see explanation in `thread.spawn_ref` above) -* `$tbl` must refer to a table with type `(table (ref null (shared func)) shared)` -* `$spawn_indirect` is given type `(func (param $i i32) (param $c i32) (result $e - i32))`. +* `$tbl` must refer to a table with type `(table (ref null (shared func)) + shared)` +* `$spawn_indirect` is given type `(func (param $i i32) (param $c i32) (result + $e i32))`. -Calling `$spawn_indirect` retrieves a reference to function `$f` from table `$tbl` and checks -that `$f` is of type `$ft`. If that succeeds, it spawns a thread which: +Calling `$spawn_indirect` retrieves a reference to function `$f` from table +`$tbl` and checks that `$f` is of type `$ft`. If that succeeds, it spawns a +thread which: - invokes `$f` with `$c` - executes `$f` until completion or trap in a `shared` context as described by the [shared-everything threads] proposal. diff --git a/design/mvp/Explainer.md b/design/mvp/Explainer.md index 980fe4e4..ae6dc677 100644 --- a/design/mvp/Explainer.md +++ b/design/mvp/Explainer.md @@ -1948,9 +1948,9 @@ Web/JS APIs. ###### ๐งต `thread.spawn_ref` -| Synopsis | | -| -------------------------- | --------------------------------------------------------- | -| Approximate WIT signature | `func<FuncT>(f: FuncT, c: FuncT.params[0]) -> bool` | +| Synopsis | | +| -------------------------- | ---------------------------------------------------------- | +| Approximate WIT signature | `func<FuncT>(f: FuncT, c: FuncT.params[0]) -> bool` | | Canonical ABI signature | `[f:(ref null (shared (func (param i32))) c:i32] -> [i32]` | The `thread.spawn_ref` built-in spawns a new thread by invoking the shared @@ -1970,9 +1970,9 @@ future, the type of `c` is currently hard-coded to always be `i32`. The `thread.spawn_indirect` built-in spawns a new thread by retrieving the shared function `f` from a table using index `i` and traps if the type of `f` is -not equal to `FuncT` (much like the `call_indirect` -core instruction). Once `f` is retrieved, this built-in operates like -`thread.spawn_ref` above, including the limitations on `f`'s parameters. +not equal to `FuncT` (much like the `call_indirect` core instruction). Once `f` +is retrieved, this built-in operates like `thread.spawn_ref` above, including +the limitations on `f`'s parameters. (See also [`canon_thread_spawn_indirect`] in the Canonical ABI explainer.) @@ -1983,14 +1983,15 @@ core instruction). Once `f` is retrieved, this built-in operates like | Approximate WIT signature | `func() -> u32` | | Canonical ABI signature | `[] -> [i32]` | -The `thread.available_parallelism` built-in returns the number of threads that can be -expected to execute in parallel. +The `thread.available_parallelism` built-in returns the number of threads that +can be expected to execute in parallel. The concept of "available parallelism" corresponds is sometimes referred to as "hardware concurrency", such as in [`navigator.hardwareConcurrency`] in JavaScript. -(See also [`canon_thread_available_parallelism`] in the Canonical ABI explainer.) +(See also [`canon_thread_available_parallelism`] in the Canonical ABI +explainer.) ### ๐ช Value Definitions From 3189cccf8fffb19d75a42259b04316566f92409d Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 09:04:32 -0800 Subject: [PATCH 18/21] Update design/mvp/CanonicalABI.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/CanonicalABI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index 6a16fda4..4dde1217 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3825,7 +3825,7 @@ def canon_thread_spawn_ref(f, c): For a canonical definition: ```wat -(canon thread.spawn_indirect (type $ft) (table $t) (core func $st)) +(canon thread.spawn_indirect $ft $tbl (core func $spawn_indirect)) ``` validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type From 1c558c78a874c67bf919b2535c32d2fe94892cc3 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 09:35:03 -0800 Subject: [PATCH 19/21] Fix up `thread.spawn_ref` variables --- design/mvp/CanonicalABI.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/design/mvp/CanonicalABI.md b/design/mvp/CanonicalABI.md index 4dde1217..0d1291f6 100644 --- a/design/mvp/CanonicalABI.md +++ b/design/mvp/CanonicalABI.md @@ -3778,7 +3778,7 @@ async def canon_error_context_drop(task, i): For a canonical definition: ```wat -(canon thread.spawn_ref (type $ft) (core func $spawn_ref)) +(canon thread.spawn_ref $ft (core func $spawn_ref)) ``` validation specifies: * `$ft` must refer to a `shared` function type; initially, only the type @@ -3794,13 +3794,13 @@ validation specifies: > The inclusion of `$ft` ensures backwards compatibility for when arbitrary > parameters are allowed. -Calling `$st` checks that the reference `$f` is not null. Then, it spawns a -thread which: +Calling `$spawn_ref` checks that the reference `$f` is not null. Then, it spawns +a thread which: - invokes `$f` with `$c` - executes `$f` until completion or trap in a `shared` context as described by the [shared-everything threads] proposal. -In pseudocode, `$st` looks like: +In pseudocode, `$spawn_ref` looks like: ```python def canon_thread_spawn_ref(f, c): From e4ea201602e0160a96e5b327078ad9427cc3ca30 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 11:44:04 -0800 Subject: [PATCH 20/21] Update design/mvp/Explainer.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/Explainer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/Explainer.md b/design/mvp/Explainer.md index ae6dc677..b344cdfc 100644 --- a/design/mvp/Explainer.md +++ b/design/mvp/Explainer.md @@ -1965,7 +1965,7 @@ future, the type of `c` is currently hard-coded to always be `i32`. | Synopsis | | | -------------------------- | ------------------------------------------------- | -| Approximate WIT signature | `func<FuncT>(i: i32, c: FuncT.params[0]) -> bool` | +| Approximate WIT signature | `func<FuncT>(i: u32, c: FuncT.params[0]) -> bool` | | Canonical ABI signature | `[i:i32 c:i32] -> [i32]` | The `thread.spawn_indirect` built-in spawns a new thread by retrieving the From eb4f9c7555248e977aee8921de84e98d79e065f4 Mon Sep 17 00:00:00 2001 From: Andrew Brown <andrew.brown@intel.com> Date: Fri, 28 Feb 2025 11:44:13 -0800 Subject: [PATCH 21/21] Update design/mvp/Binary.md Co-authored-by: Luke Wagner <mail@lukewagner.name> --- design/mvp/Binary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/mvp/Binary.md b/design/mvp/Binary.md index 394b78fa..6501b450 100644 --- a/design/mvp/Binary.md +++ b/design/mvp/Binary.md @@ -317,7 +317,7 @@ canon ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> => (canon lift | 0x22 => (canon waitable-set.drop (core func)) ๐ | 0x23 => (canon waitable.join (core func)) ๐ | 0x40 ft:<typeidx> => (canon thread.spawn_ref ft (core func)) ๐งต - | 0x41 ft:<typeidx> t:<core:tableidx> => (canon thread.spawn_indirect ft (table t) (core func)) ๐งต + | 0x41 ft:<typeidx> tbl:<core:tableidx> => (canon thread.spawn_indirect ft tbl (core func)) ๐งต | 0x42 => (canon thread.available_parallelism (core func)) ๐งต async? ::= 0x00 => | 0x01 => async