Skip to content

Commit 9579cb9

Browse files
authored
Add resume_throw_ref to the explainer (#132)
Give it opcode 0xe5 to be adjacent to `resume_throw` at 0xe4, and as a result bump `switch` to 0xe6. Update `switch` in the interpreter as well. 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 9579cb9

File tree

3 files changed

+63
-30
lines changed

3 files changed

+63
-30
lines changed

interpreter/binary/decode.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,8 @@ let rec instr s =
646646
let tag = at var s in
647647
let xls = vec on_clause s in
648648
resume_throw x tag xls
649-
| 0xe5 ->
649+
(* TODO: resume_throw_ref *)
650+
| 0xe6 ->
650651
let x = at var s in
651652
let y = at var s in
652653
switch x y

interpreter/binary/encode.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ struct
303303
| Suspend x -> op 0xe2; var x
304304
| Resume (x, xls) -> op 0xe3; var x; resumetable xls
305305
| ResumeThrow (x, y, xls) -> op 0xe4; var x; var y; resumetable xls
306-
| Switch (x, y) -> op 0xe5; var x; var y
306+
(* TOOD: resume_throw_ref *)
307+
| Switch (x, y) -> op 0xe6; var x; var y
307308

308309
| Throw x -> op 0x08; var x
309310
| ThrowRef -> op 0x0a

proposals/stack-switching/Explainer.md

Lines changed: 59 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,23 @@ 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`,
691+
`cont.bind`). A suspended continuation may be resumed with a particular
692+
handler with `resume`; aborted with `resume_throw` or
693+
`resume_throw_ref`; directly switched to via `switch`; or partially
694+
applied with `cont.bind`.
680695

681696
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.
697+
`resume_throw`, `resume_throw_ref`, `switch`, and `cont.bind`
698+
destructively modify the suspended continuation such that any
699+
subsequent use of the same suspended continuation will result in a
700+
trap.
685701

686702
## Further examples
687703

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

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

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

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

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

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`
1130+
* `S; F; (ref.null t) (ref.cont ca) (resume_throw_ref $ct hdl*) --> S; F; trap`
1131+
- iff `S.conts[ca] = (E : n)`
1132+
1133+
* `S; F; (ref.exn ea) (ref.cont ca) (resume_throw_ref $ct hdl*) --> S'; F; prompt{hdl'*} E[(ref.exn ea) throw_ref] end`
11011134
- 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`
1135+
- and `S' = S with conts[ca] = epsilon`
11061136
- and `hdl'* = hdl*[F.module.tags / 0..|F.module.tags|-1]`
11071137

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

11581188
#### Instructions
11591189

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

11621192
| Opcode | Instruction | Immediates |
11631193
| ------ | ------------------------ | ---------- |
@@ -1166,10 +1196,11 @@ We use the use the opcode space `0xe0-0xe5` for the six new instructions.
11661196
| 0xe2 | `suspend $t` | `$t : u32` |
11671197
| 0xe3 | `resume $ct hdl*` | `$ct : u32` (for hdl see below) |
11681198
| 0xe4 | `resume_throw $ct $e hdl*` | `$ct : u32`, `$e : u32` (for hdl see below) |
1169-
| 0xe5 | `switch $ct1 $e` | `$ct1 : u32`, `$e : u32` |
1199+
| 0xe5 | `resume_throw_ref $ct hdl*` | `$ct : u32` (for hdl see below) |
1200+
| 0xe6 | `switch $ct1 $t` | `$ct1 : u32`, `$t : u32` |
11701201

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

11741205
| Opcode | On clause shape | Immediates |
11751206
| ------ | --------------- | ---------- |

0 commit comments

Comments
 (0)