@@ -675,7 +675,7 @@ class Table:
675675 return e
676676```
677677` Table ` maintains a dense array of elements that can contain holes created by
678- the ` remove ` method (defined below ). When table elements are accessed (e.g., by
678+ the ` remove ` method (defined above ). When table elements are accessed (e.g., by
679679` canon_lift ` and ` resource.rep ` , below), there are thus both a bounds check and
680680hole check necessary. Upon initialization, table element ` 0 ` is allocated and
681681set to ` None ` , effectively reserving index ` 0 ` which is both useful for
@@ -711,10 +711,9 @@ class ResourceHandle:
711711 self .borrow_scope = borrow_scope
712712 self .num_lends = 0
713713```
714- The ` rt ` and ` rep ` fields of ` ResourceHandle ` store the ` rt ` and ` rep `
715- parameters passed to the ` resource.new ` call that created this handle. The
716- ` rep ` field is currently fixed to be an ` i32 ` , but will be generalized in the
717- future to other types.
714+ The ` rt ` and ` rep ` fields of ` ResourceHandle ` store the resource type and
715+ representation of the resource. The ` rep ` field is currently fixed to be an
716+ ` i32 ` , but will be generalized in the future to other types.
718717
719718The ` own ` field indicates whether this element was created from an ` own ` type
720719(or, if false, a ` borrow ` type).
@@ -726,9 +725,9 @@ time and thus an optimizing implementation doesn't need to store the `Task`
726725per ` ResourceHandle ` .
727726
728727The ` num_lends ` field maintains a conservative approximation of the number of
729- live handles that were lent from this ` own ` handle (by calls to ` borrow ` -taking
728+ live handles that were lent from this handle (by calls to ` borrow ` -taking
730729functions). This count is maintained by the ` Subtask ` bookkeeping functions
731- (above ) and is ensured to be zero when an ` own ` handle is dropped.
730+ (below ) and is ensured to be zero when an ` own ` handle is dropped.
732731
733732The ` ResourceType ` class represents a runtime instance of a resource type that
734733has been created either by the host or a component instance (where multiple
@@ -850,17 +849,19 @@ thread to `switch_to`.
850849``` python
851850 def resume (self , cancelled = Cancelled.FALSE ):
852851 assert (not self .running() and (self .cancellable or not cancelled))
853- if self .waiting():
854- assert (cancelled or self .ready())
855- self .ready_func = None
856- self .task.inst.store.waiting.remove(self )
852+ self .stop_waiting()
857853 thread = self
858854 while thread is not None :
859855 cont = thread.cont
860856 thread.cont = None
861857 (thread.cont, switch_to) = resume(cont, cancelled, thread)
862858 thread = switch_to
863859 cancelled = Cancelled.FALSE
860+
861+ def stop_waiting (self ):
862+ if self .waiting():
863+ self .ready_func = None
864+ self .task.inst.store.waiting.remove(self )
864865```
865866The ` Thread.resume ` method propagates cancellation requests (from
866867` Task.request_cancellation ` ) to the first continuation that is resumed, allowing
@@ -881,6 +882,7 @@ here which transfers control flow back to `Thread.resume()` via `block()`. The
881882 def suspend (self , cancellable ) -> Cancelled:
882883 assert (self .running() and self .task.may_block())
883884 if self .task.deliver_pending_cancel(cancellable):
885+ self .stop_waiting()
884886 return Cancelled.TRUE
885887 self .cancellable = cancellable
886888 cancelled = block(switch_to = None )
@@ -948,6 +950,7 @@ caller is `cancellable`. Then the current thread transfers control flow back to
948950 def switch_to (self , cancellable , other : Thread) -> Cancelled:
949951 assert (self .running() and other.suspended())
950952 if self .task.deliver_pending_cancel(cancellable):
953+ self .stop_waiting()
951954 return Cancelled.TRUE
952955 self .cancellable = cancellable
953956 cancelled = block(switch_to = other)
@@ -1271,7 +1274,7 @@ and the task has not yet returned a value to its caller.
12711274```
12721275
12731276The ` Task.request_cancellation ` method is called by the host or wasm caller
1274- to signal that they don't need the return value and that the caller should hurry
1277+ to signal that they don't need the return value and that the callee should hurry
12751278up and call the ` OnResolve ` callback. If a task is waiting to start in
12761279` Task.enter ` due to backpressure, then it is immediately cancelled without
12771280running any guest code. Otherwise, if * any* of a cancelled ` Task ` 's ` Thread ` s
@@ -1572,8 +1575,8 @@ thus no more reads/writes are possible. The `CANCELLED` code is only possible
15721575after * this* end has performed a ` {stream,future}.{read,write} ` followed by a
15731576` {stream,future}.cancel-{read,write} ` ; ` CANCELLED ` notifies the wasm code
15741577that the cancellation finished and so ownership of the memory buffer has been
1575- returned to the wasm code. Lastly, ` COMPLETED ` indicates that at least one
1576- value has been copied and neither ` DROPPED ` nor ` CANCELLED ` apply.
1578+ returned to the wasm code. Lastly, ` COMPLETED ` indicates that the copy is done
1579+ and neither ` DROPPED ` nor ` CANCELLED ` apply.
15771580
15781581As with functions and buffers, native host code can be on either side of a
15791582stream. Thus, streams are defined in terms of abstract interfaces that can be
@@ -1698,9 +1701,8 @@ stored in the `pending_*` fields, requiring the reader to wait for the writer
16981701to rendezvous. If the writer was first to rendezvous, then there is already a
16991702pending ` ReadableBuffer ` to read from, and so the reader copies as much as it
17001703can (which may be less than a full buffer's worth) and eagerly completes the
1701- copy without blocking. In the final special case where both the reader and
1702- pending writer have zero-length buffers, the writer is notified, but the reader
1703- remains blocked:
1704+ copy without blocking. In the final special case where the pending writer has a
1705+ zero-length buffer, the writer is notified, but the reader remains blocked:
17041706``` python
17051707 def read (self , inst , dst_buffer , on_copy , on_copy_done ):
17061708 if self .dropped:
@@ -1824,8 +1826,8 @@ As shown in `drop`, attempting to drop a readable or writable end while a copy
18241826is in progress or in the process of being cancelled traps. This means that
18251827client code must take care to wait for these operations to finish (potentially
18261828cancelling them via ` stream.cancel-{read,write} ` ) before dropping. The
1827- ` SYNC_COPY ` vs. ` ASYNC_COPY ` distinction is tracked in the state to determine
1828- whether the copy operation can be cancelled.
1829+ ` SYNC_COPYING ` vs. ` ASYNC_COPYING ` distinction is tracked in the state to
1830+ determine whether the copy operation can be cancelled.
18291831
18301832The polymorphic ` copy ` method dispatches to either ` ReadableStream.read ` or
18311833` WritableStream.write ` and allows the implementations of ` stream.{read,write} `
@@ -2829,7 +2831,7 @@ def match_case(v, cases):
28292831```
28302832
28312833Flags are converted from a dictionary to a bit-vector by iterating
2832- through the case- labels of the variant in the order they were listed in the
2834+ through the labels of the flags type in the order they were listed in the
28332835type definition and OR-ing all the bits together. Flag lifting/lowering can be
28342836statically fused into array/integer operations (with a simple byte copy when
28352837the case lists are the same) to avoid any string operations in a similar manner
@@ -2953,9 +2955,9 @@ def flatten_functype(opts, ft, context):
29532955def flatten_types (ts , opts ):
29542956 return [ft for t in ts for ft in flatten_type(t, opts)]
29552957```
2956- As shown here, the core signatures ` async ` functions use a lower limit on the
2957- maximum number of parameters (4) and results (0) passed as scalars before
2958- falling back to passing through memory.
2958+ As shown here, the core signatures of ` async ` -lowered functions use a lower
2959+ limit on the maximum number of parameters (4) and results (0) passed as scalars
2960+ before falling back to passing through memory.
29592961
29602962Presenting the definition of ` flatten_type ` piecewise, we start with the
29612963top-level case analysis:
@@ -3108,7 +3110,7 @@ The contents of strings and variable-length lists are stored in memory so
31083110lifting these types is essentially the same as loading them from memory; the
31093111only difference is that the pointer and length come from ptr-sized values
31103112instead of from linear memory. Fixed-length lists are lifted the same way as a
3111- tuple (via ` lift_flat_record ` below) .
3113+ tuple.
31123114``` python
31133115def lift_flat_string (cx , vi ):
31143116 ptr = vi.next(cx.opts.memory.ptr_type())
@@ -3139,8 +3141,8 @@ Variants are also lifted recursively. Lifting a variant must carefully follow
31393141the definition of ` flatten_variant ` above, consuming the exact same core types
31403142regardless of the dynamic case payload being lifted. Because of the ` join `
31413143performed by ` flatten_variant ` , we need a more-permissive value iterator that
3142- reinterprets between the different types appropriately and also traps if the
3143- high bits of an ` i64 ` are set for a 32-bit type :
3144+ reinterprets between the different types appropriately and also wraps
3145+ ` i64 ` values to 32-bit when needed :
31443146``` python
31453147def lift_flat_variant (cx , vi , cases ):
31463148 flat_types = flatten_variant(cases, cx.opts)
@@ -3201,7 +3203,7 @@ def lower_flat(cx, v, t):
32013203 case F64Type() : return [maybe_scramble_nan64(v)]
32023204 case CharType() : return [char_to_i32(v)]
32033205 case StringType() : return lower_flat_string(cx, v)
3204- case ErrorContextType() : return lower_error_context(cx, v)
3206+ case ErrorContextType() : return [ lower_error_context(cx, v)]
32053207 case ListType(t, l) : return lower_flat_list(cx, v, t, l)
32063208 case RecordType(fields) : return lower_flat_record(cx, v, fields)
32073209 case VariantType(cases) : return lower_flat_variant(cx, v, cases)
@@ -3215,20 +3217,19 @@ def lower_flat(cx, v, t):
32153217Since component-level values are assumed in-range and, as previously stated,
32163218core ` i32 ` values are always internally represented as unsigned ` int ` s,
32173219unsigned integer values need no extra conversion. Signed integer values are
3218- converted to unsigned core ` i32 ` s by 2s complement arithmetic (which again
3219- would be a no-op in hardware):
3220+ converted to unsigned core ` i32 ` or ` i64 ` values by 2s complement arithmetic
3221+ (which again would be a no-op in hardware):
32203222``` python
32213223def lower_flat_signed (i , core_bits ):
32223224 if i < 0 :
32233225 i += (1 << core_bits)
32243226 return [i]
32253227```
32263228
3227- Since strings and variable-length lists are stored in linear memory, lifting
3229+ Since strings and variable-length lists are stored in linear memory, lowering
32283230can reuse the previous definitions; only the resulting pointers are returned
3229- differently (as ` i32 ` values instead of as a pair in linear memory).
3230- Fixed-length lists are lowered the same way as tuples (via ` lower_flat_record `
3231- below).
3231+ differently (as flat values instead of as a pair in linear memory).
3232+ Fixed-length lists are lowered the same way as tuples.
32323233``` python
32333234def lower_flat_string (cx , v ):
32343235 ptr, packed_length = store_string_into_range(cx, v)
@@ -3392,7 +3393,7 @@ validation is performed:
33923393
33933394* ` $callee ` must have type ` flatten_functype($opts, $ft, 'lift') `
33943395* ` $f ` is given type ` $ft `
3395- * if a ` post-return ` is present, it has type ` (func (param flatten_functype({} , $ft, 'lift').results)) `
3396+ * if a ` post-return ` is present, it has type ` (func (param flatten_functype($opts , $ft, 'lift').results)) `
33963397* requires options based on [ ` lift(param) ` ] ( #canonopt-validation ) for all parameters in ` ft `
33973398* requires options based on [ ` lower(result) ` ] ( #canonopt-validation ) if ` ft ` has a result
33983399* if ` len(flatten_types(ft.param_types())) > MAX_FLAT_PARAMS ` , ` realloc ` is required
@@ -3641,7 +3642,7 @@ Each call to `canon_lower` creates a new `Subtask`. However, this `Subtask` is
36413642only added to the current component instance's ` handles ` table (below) if
36423643` async ` is specified * and* ` callee ` blocks. In any case, this ` Subtask ` is used
36433644as the ` LiftLowerContext.borrow_scope ` for ` borrow ` arguments, ensuring that
3644- owned handles are not dropped before ` Subtask.deliver_return ` is called (below).
3645+ owned handles are not dropped before ` Subtask.deliver_resolve ` is called (below).
36453646``` python
36463647 subtask = Subtask()
36473648 cx = LiftLowerContext(opts, thread.task.inst, subtask)
@@ -3732,7 +3733,7 @@ add a `Subtask` to the current component instance's `handles` table. Otherwise,
37323733the index of a new ` Subtask ` is returned, bit-packed with the current state of
37333734the ` Subtask ` (which will either be ` STARTING ` or ` STARTED ` ). ` STARTING ` tells
37343735the caller that they need to keep the memory for both the arguments and results
3735- allocated; ` STARTED ` tells the caller that the arguments have been ready and
3736+ allocated; ` STARTED ` tells the caller that the arguments have been read and
37363737thus any argument memory can be reused, but the result buffer has to be kept
37373738reserved.
37383739``` python
@@ -3754,7 +3755,7 @@ reserved.
37543755 return [subtask.state | (subtaski << 4 )]
37553756```
37563757When ` on_start ` and ` on_resolve ` are called after this initial ` async ` -lowered
3757- call returns, the ` on_progress ` callback (called by ` on_start ` and ` on_return ` )
3758+ call returns, the ` on_progress ` callback (called by ` on_start ` and ` on_resolve ` )
37583759will set a pending event on the ` Subtask ` (which derives ` Waitable ` ) so that it
37593760can be waited on via ` waitable-set.{wait,poll} ` or, if a ` callback ` is used, by
37603761returning to the event loop. If ` on_start ` is called followed by ` on_resolve `
@@ -4052,9 +4053,9 @@ The `trap_if(not task.opts.async_)` prevents `task.cancel` from being called by
40524053synchronously-lifted functions (which must always return a value by returning
40534054from the lifted core function).
40544055
4055- ` Task.cancel ` also traps if there has been no cancellation request (in which
4056- case the callee expects to receive a return value ) or if the task has already
4057- returned a value or already called ` task.cancel ` .
4056+ ` Task.cancel ` also traps if the cancellation has not been delivered to the task
4057+ (in which case the callee should not yet know to cancel ) or if the task has
4058+ already returned a value or already called ` task.cancel ` .
40584059
40594060
40604061### 🔀 ` canon waitable-set.new `
@@ -4392,7 +4393,7 @@ condition could be relaxed to allow multiple pipelined reads or writes.)
43924393```
43934394
43944395Then a readable or writable buffer is created which (in ` Buffer ` 's constructor)
4395- eagerly checks the alignment and bounds of (` i ` , ` n ` ). (In the future, the
4396+ eagerly checks the alignment and bounds of (` ptr ` , ` n ` ). (In the future, the
43964397restriction on futures/streams containing ` borrow ` s could be relaxed by
43974398maintaining sufficient bookkeeping state to ensure that borrowed handles * or
43984399streams/futures of borrowed handles* could not outlive their originating call.
@@ -4709,9 +4710,10 @@ validation specifies
47094710 * 🐘 - ` U ` is ` i32 ` or ` i64 ` as determined by ` $ftbl ` 's address type
47104711
47114712Calling ` $new_indirect ` invokes the following function which reads a ` funcref `
4712- from ` $ftbl ` (trapping if out-of-bounds, null or the wrong type), calls the
4713- ` funcref ` passing the closure parameter ` $c ` , and returns the index of the new
4714- thread in the current component instance's ` threads ` table.
4713+ from ` $ftbl ` (trapping if out-of-bounds, null or the wrong type), creates a new
4714+ suspended thread that will call the ` funcref ` passing the closure parameter ` $c `
4715+ when resumed, and returns the index of the new thread in the current component
4716+ instance's ` threads ` table.
47154717``` python
47164718@dataclass
47174719class CoreFuncRef :
@@ -4953,7 +4955,7 @@ Calling `$f` calls the following function which uses the `$opts` immediate to
49534955lowers the ` ErrorContext ` 's debug message. While * producing* an ` error-context `
49544956value may nondeterministically discard or transform the debug message, a
49554957single ` error-context ` value must return the same debug message from
4956- ` error.debug-message ` over time.
4958+ ` error-context .debug-message ` over time.
49574959``` python
49584960def canon_error_context_debug_message (opts , i , ptr ):
49594961 inst = current_thread().task.inst
@@ -5017,7 +5019,7 @@ parallel with all other threads.
50175019> parameters are allowed.
50185020
50195021Calling ` $spawn_ref ` invokes the following function which simply fuses the
5020- ` thread.new_ref ` and ` thread.resume-later ` built-ins, allowing
5022+ ` thread.new-ref ` and ` thread.resume-later ` built-ins, allowing
50215023thread-creation to skip the intermediate "suspended" state transition.
50225024``` python
50235025def canon_thread_spawn_ref (shared , ft , f , c ):
0 commit comments