Skip to content

Commit 6b01cc4

Browse files
committed
Fix typos and inconsistencies in CanonicalABI.md (no change)
1 parent 9fdc3cc commit 6b01cc4

2 files changed

Lines changed: 57 additions & 51 deletions

File tree

design/mvp/CanonicalABI.md

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -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
680680
hole check necessary. Upon initialization, table element `0` is allocated and
681681
set 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

719718
The `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`
726725
per `ResourceHandle`.
727726

728727
The `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
730729
functions). 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

733732
The `ResourceType` class represents a runtime instance of a resource type that
734733
has 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
```
865866
The `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

12731276
The `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
12751278
up 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
12771280
running 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
15721575
after *this* end has performed a `{stream,future}.{read,write}` followed by a
15731576
`{stream,future}.cancel-{read,write}`; `CANCELLED` notifies the wasm code
15741577
that 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

15781581
As with functions and buffers, native host code can be on either side of a
15791582
stream. 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
16981701
to rendezvous. If the writer was first to rendezvous, then there is already a
16991702
pending `ReadableBuffer` to read from, and so the reader copies as much as it
17001703
can (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
18241826
is in progress or in the process of being cancelled traps. This means that
18251827
client code must take care to wait for these operations to finish (potentially
18261828
cancelling 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

18301832
The 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

28312833
Flags 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
28332835
type definition and OR-ing all the bits together. Flag lifting/lowering can be
28342836
statically fused into array/integer operations (with a simple byte copy when
28352837
the case lists are the same) to avoid any string operations in a similar manner
@@ -2953,9 +2955,9 @@ def flatten_functype(opts, ft, context):
29532955
def 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

29602962
Presenting the definition of `flatten_type` piecewise, we start with the
29612963
top-level case analysis:
@@ -3108,7 +3110,7 @@ The contents of strings and variable-length lists are stored in memory so
31083110
lifting these types is essentially the same as loading them from memory; the
31093111
only difference is that the pointer and length come from ptr-sized values
31103112
instead 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
31133115
def 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
31393141
the definition of `flatten_variant` above, consuming the exact same core types
31403142
regardless of the dynamic case payload being lifted. Because of the `join`
31413143
performed 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
31453147
def 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):
32153217
Since component-level values are assumed in-range and, as previously stated,
32163218
core `i32` values are always internally represented as unsigned `int`s,
32173219
unsigned 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
32213223
def 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
32283230
can 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
32333234
def 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
36413642
only 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
36433644
as 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,
37323733
the index of a new `Subtask` is returned, bit-packed with the current state of
37333734
the `Subtask` (which will either be `STARTING` or `STARTED`). `STARTING` tells
37343735
the 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
37363737
thus any argument memory can be reused, but the result buffer has to be kept
37373738
reserved.
37383739
```python
@@ -3754,7 +3755,7 @@ reserved.
37543755
return [subtask.state | (subtaski << 4)]
37553756
```
37563757
When `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`)
37583759
will set a pending event on the `Subtask` (which derives `Waitable`) so that it
37593760
can be waited on via `waitable-set.{wait,poll}` or, if a `callback` is used, by
37603761
returning 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
40524053
synchronously-lifted functions (which must always return a value by returning
40534054
from 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

43944395
Then 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
43964397
restriction on futures/streams containing `borrow`s could be relaxed by
43974398
maintaining sufficient bookkeeping state to ensure that borrowed handles *or
43984399
streams/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

47114712
Calling `$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
47174719
class CoreFuncRef:
@@ -4953,7 +4955,7 @@ Calling `$f` calls the following function which uses the `$opts` immediate to
49534955
lowers the `ErrorContext`'s debug message. While *producing* an `error-context`
49544956
value may nondeterministically discard or transform the debug message, a
49554957
single `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
49584960
def 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
50195021
Calling `$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
50215023
thread-creation to skip the intermediate "suspended" state transition.
50225024
```python
50235025
def canon_thread_spawn_ref(shared, ft, f, c):

design/mvp/canonical-abi/definitions.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,7 @@ def resume_later(self):
493493

494494
def resume(self, cancelled = Cancelled.FALSE):
495495
assert(not self.running() and (self.cancellable or not cancelled))
496-
if self.waiting():
497-
assert(cancelled or self.ready())
498-
self.ready_func = None
499-
self.task.inst.store.waiting.remove(self)
496+
self.stop_waiting()
500497
thread = self
501498
while thread is not None:
502499
cont = thread.cont
@@ -505,9 +502,15 @@ def resume(self, cancelled = Cancelled.FALSE):
505502
thread = switch_to
506503
cancelled = Cancelled.FALSE
507504

505+
def stop_waiting(self):
506+
if self.waiting():
507+
self.ready_func = None
508+
self.task.inst.store.waiting.remove(self)
509+
508510
def suspend(self, cancellable) -> Cancelled:
509511
assert(self.running() and self.task.may_block())
510512
if self.task.deliver_pending_cancel(cancellable):
513+
self.stop_waiting()
511514
return Cancelled.TRUE
512515
self.cancellable = cancellable
513516
cancelled = block(switch_to = None)
@@ -538,6 +541,7 @@ def yield_(self, cancellable) -> Cancelled:
538541
def switch_to(self, cancellable, other: Thread) -> Cancelled:
539542
assert(self.running() and other.suspended())
540543
if self.task.deliver_pending_cancel(cancellable):
544+
self.stop_waiting()
541545
return Cancelled.TRUE
542546
self.cancellable = cancellable
543547
cancelled = block(switch_to = other)
@@ -1941,7 +1945,7 @@ def lower_flat(cx, v, t):
19411945
case F64Type() : return [maybe_scramble_nan64(v)]
19421946
case CharType() : return [char_to_i32(v)]
19431947
case StringType() : return lower_flat_string(cx, v)
1944-
case ErrorContextType() : return lower_error_context(cx, v)
1948+
case ErrorContextType() : return [lower_error_context(cx, v)]
19451949
case ListType(t, l) : return lower_flat_list(cx, v, t, l)
19461950
case RecordType(fields) : return lower_flat_record(cx, v, fields)
19471951
case VariantType(cases) : return lower_flat_variant(cx, v, cases)

0 commit comments

Comments
 (0)