Skip to content

Commit 26b417f

Browse files
committed
Add resume_throw_ref to the explainer
Give it opcode 0xe5 to be adjacent to `resume_throw` at 0xe4, and as a result bump `switch` to 0xe6. Redefine the execution semantics of `resume_throw` in terms of `resume_throw_ref`. As a drive-by, fix the nullability of reference operands in the initial introduction of each other instruction.
1 parent 389f6cc commit 26b417f

1 file changed

Lines changed: 57 additions & 28 deletions

File tree

proposals/stack-switching/Explainer.md

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,8 @@ a task function would ordinarily return, it should instead switch to
483483
the next task. When doing so, it should pass a new flag to the target
484484
continuation to indicate that the source continuation should not be
485485
enqueued in the task list, but should instead be cancelled. Cancellation
486-
can be implemented using another instruction, `resume_throw`, which is
487-
described later in the document.
486+
can be implemented using two more instructions, `resume_throw` and
487+
`resume_throw_ref`, which are described later in the document.
488488

489489
Full versions of `$scheduler1` and `$scheduler2` can be found
490490
[here](examples/scheduler1.wast) and [here](examples/scheduler2.wast).
@@ -543,7 +543,7 @@ The following instruction creates a *suspended continuation* from a
543543
function.
544544

545545
```wast
546-
cont.new $ct : [(ref $ft)] -> [(ref $ct)]
546+
cont.new $ct : [(ref null $ft)] -> [(ref $ct)]
547547
where:
548548
- $ft = func [t1*] -> [t2*]
549549
- $ct = cont $ft
@@ -561,7 +561,7 @@ continuation under a *handler*. The handler specifies what to do when
561561
control is subsequently suspended again.
562562

563563
```wast
564-
resume $ct hdl* : [t1* (ref $ct)] -> [t2*]
564+
resume $ct hdl* : [t1* (ref null $ct)] -> [t2*]
565565
where:
566566
- $ct = cont [t1*] -> [t2*]
567567
```
@@ -581,7 +581,7 @@ The second way to invoke a continuation is to raise an exception at
581581
the control tag invocation site which causes the stack to be unwound.
582582

583583
```wast
584-
resume_throw $ct $exn hdl* : [te* (ref $ct)])] -> [t2*]
584+
resume_throw $ct $exn hdl* : [te* (ref null $ct)] -> [t2*]
585585
where:
586586
- $ct = cont [t1*] -> [t2*]
587587
- $exn : [te*] -> []
@@ -597,11 +597,24 @@ exception is being raised (the continuation is not actually being
597597
supplied a value) the parameter types for the continuation `t1*` are
598598
unconstrained.
599599

600+
Exceptions can also be raised at a suspension site using
601+
`resume_throw_ref`.
602+
603+
```wast
604+
resume_throw_ref $ct hdl* : [exnref (ref null $ct)] -> [t2*]
605+
where:
606+
- $ct = cont [t1*] -> [t2*]
607+
```
608+
609+
The `resume_throw_ref` instruction is identical to the `resume_throw`
610+
instruction except that the exception it raises is given by an exnref
611+
operand rather than by an exception tag immediate.
612+
600613
The third way to invoke a continuation is to perform a symmetric
601614
switch.
602615

603616
```wast
604-
switch $ct1 $e : [t1* (ref $ct1)] -> [t2*]
617+
switch $ct1 $e : [t1* (ref null $ct1)] -> [t2*]
605618
where:
606619
- $e : [] -> [t*]
607620
- $ct1 = cont [t1* (ref $ct2)] -> [t*]
@@ -614,8 +627,9 @@ continuation argument (`$ct1`) and a control tag
614627
performs a direct switch to the suspended peer continuation (of type
615628
`$ct1`), passing in the required parameters (including the just
616629
suspended current continuation, in order to allow the peer to switch
617-
back again). As with `resume` and `resume_throw`, the `switch`
618-
instruction fully consumes its suspended continuation argument.
630+
back again). As with `resume`, `resume_throw`, and `resume_throw_ref`,
631+
the `switch` instruction fully consumes its suspended continuation
632+
argument.
619633

620634
### Suspending continuations
621635

@@ -641,7 +655,7 @@ A suspended continuation can be partially applied to a prefix of its
641655
arguments yielding another suspended continuation.
642656

643657
```wast
644-
cont.bind $ct1 $ct2 : [t1* (ref $ct1)] -> [(ref $ct2)]
658+
cont.bind $ct1 $ct2 : [t1* (ref null $ct1)] -> [(ref $ct2)]
645659
where:
646660
- $ct1 = cont [t1* t3*] -> [t2*]
647661
- $ct2 = cont [t3*] -> [t2*]
@@ -672,21 +686,22 @@ preallocating one slot for each continuation argument.
672686

673687
#### Consuming continuations
674688

675-
There are four different ways in which suspended continuations are
676-
consumed (`resume,resume_throw,switch,cont.bind`). A suspended
677-
continuation may be resumed with a particular handler with `resume`;
678-
aborted with `resume_throw`; directly switched to via `switch`; or
679-
partially applied with `cont.bind`.
689+
There are five different ways in which suspended continuations are
690+
consumed (`resume,resume_throw,resume_throw_ref,switch,cont.bind`).
691+
A suspended continuation may be resumed with a particular handler with
692+
`resume`; aborted with `resume_throw` or `resume_throw_ref`; directly
693+
switched to via `switch`; or partially applied with `cont.bind`.
680694

681695
In order to ensure that continuations are one-shot, `resume`,
682-
`resume_throw`, `switch`, and `cont.bind` destructively modify the
683-
suspended continuation such that any subsequent use of the same
684-
suspended continuation will result in a trap.
696+
`resume_throw`, `resume_throw_ref`, `switch`, and `cont.bind`
697+
destructively modify the suspended continuation such that any
698+
subsequent use of the same suspended continuation will result in a
699+
trap.
685700

686701
## Further examples
687702

688703
We now illustrate the use of tags with result values and the
689-
instructions `cont.bind` and `resume.throw`, by adapting and extending
704+
instructions `cont.bind` and `resume_throw`, by adapting and extending
690705
the examples of [Section
691706
3](#introduction-to-continuation-based-stack-switching).
692707

@@ -977,6 +992,13 @@ This abbreviation will be formalised with an auxiliary function or other means i
977992
- and `C.types[$ft] ~~ func [te*] -> []`
978993
- and `(hdl : t2*)*`
979994

995+
- `resume_throw_ref <typeidx> hdl*`
996+
- Execute a given continuation, but force it to immediately throw the given exception.
997+
- Used to abort a continuation.
998+
- `resume_throw_ref $ct hdl* : [exnref (ref null $ct)] -> [t2*]`
999+
- iff `C.types[$ct] ~~ cont [t1*] -> [t2*]`
1000+
- and `(hdl : t2*)*`
1001+
9801002
- `hdl = (on <taguse> <labelidx>) | (on <taguse> switch)`
9811003
- Handlers attached to `resume` and `resume_throw`, handling control tags for `suspend` and `switch`, respectively.
9821004
- `(on tu $l) : t*`
@@ -1094,15 +1116,21 @@ H^ea ::=
10941116

10951117
* `S; F; (ref.null t) (resume_throw $ct $e hdl*) --> S; F; trap`
10961118

1097-
* `S; F; (ref.cont ca) (resume_throw $ct $e hdl*) --> S; F; trap`
1119+
* `S; F; v^m (ref.cont ca) (resume_throw $ct $e hdl*) --> S'; F; (ref.exn |S.exns|) (ref.const ca) (resume_throw_ref $ct hdl*)`
1120+
- iff `ta = F.module.tags[$e]`
1121+
- and `S.tags[ta].type ~~ [t1^m] -> [t2*]`
1122+
- and `S' = S with exns += {S.tags[ta], v^m}`
1123+
1124+
* `S; F; (ref.null t) (resume_throw_ref $ct hdl*) --> S; F; trap`
1125+
1126+
* `S; F; (ref.cont ca) (resume_throw_ref $ct hdl*) --> S; F; trap`
10981127
- iff `S.conts[ca] = epsilon`
10991128

1100-
* `S; F; v^m (ref.cont ca) (resume_throw $ct $e hdl*) --> S''; F; prompt{hdl'*} E[(ref.exn |S'.exns|) throw_ref] end`
1129+
* `S; F; (ref.null t) (ref.cont ca) (resume_throw_ref $ct hdl*) --> S; F; trap`
1130+
1131+
* `S; F; (ref.exn ea) (ref.cont ca) (resume_throw_ref $ct hdl*) --> S'; F; prompt{hdl'*} E[(ref.exn ea) throw_ref] end`
11011132
- iff `S.conts[ca] = (E : n)`
1102-
- and `ta = S.tags[F.module.tags[$e]]`
1103-
- and `ta.type ~~ [t1^m] -> [t2*]`
1104-
- and `S' = S with exns += {ta, v^m}`
1105-
- and `S'' = S' with conts[ca] = epsilon`
1133+
- and `S' = S with conts[ca] = epsilon`
11061134
- and `hdl'* = hdl*[F.module.tags / 0..|F.module.tags|-1]`
11071135

11081136
* `S; F; (prompt{hdl*} v* end) --> S; F; v*`
@@ -1157,7 +1185,7 @@ The opcode for heap types is encoded as an `s33`.
11571185

11581186
#### Instructions
11591187

1160-
We use the use the opcode space `0xe0-0xe5` for the six new instructions.
1188+
We use the use the opcode space `0xe0-0xe6` for the seven new instructions.
11611189

11621190
| Opcode | Instruction | Immediates |
11631191
| ------ | ------------------------ | ---------- |
@@ -1166,10 +1194,11 @@ We use the use the opcode space `0xe0-0xe5` for the six new instructions.
11661194
| 0xe2 | `suspend $t` | `$t : u32` |
11671195
| 0xe3 | `resume $ct hdl*` | `$ct : u32` (for hdl see below) |
11681196
| 0xe4 | `resume_throw $ct $e hdl*` | `$ct : u32`, `$e : u32` (for hdl see below) |
1169-
| 0xe5 | `switch $ct1 $e` | `$ct1 : u32`, `$e : u32` |
1197+
| 0xe5 | `resume_throw_ref $ct hdl*` | `$ct : u32` (for hdl see below) |
1198+
| 0xe6 | `switch $ct1 $t` | `$ct1 : u32`, `$t : u32` |
11701199

1171-
In the case of `resume` and `resume_throw` we use a leading byte to
1172-
indicate the shape of `hdl` as follows.
1200+
In the cases of `resume`, `resume_throw`, and `resume_throw_ref` we use a
1201+
leading byte to indicate the shape of `hdl` as follows.
11731202

11741203
| Opcode | On clause shape | Immediates |
11751204
| ------ | --------------- | ---------- |

0 commit comments

Comments
 (0)