Skip to content

Commit 78d108d

Browse files
committed
formal spec overview for the 3rd exception handling proposal
This is an attempt to formally describe @aheejin's 3rd proposal, which she presented to the Wasm CG, and which was voted to be the new EH proposal, on September 18, 2020. This is not formal spec that I have developed, but a formal description of this 3rd proposal. This is a reworked form of my [first attempt on this formal spec overview](WebAssembly#87 (comment)) edited with my new understanding of the spec based on the discussion below, and in other issues, and according to @aheejin 's [3rd proposal overview](https://github.com/WebAssembly/exception-handling/blob/f7a4f60d11fb6326fc13f84d3889b11d3873f08a/proposals/Exceptions.md) in PR WebAssembly#137. This is in the form of a document as @tlively [requested](WebAssembly#142 (comment)), to make discussion on specific points easier. I wrote this formal spec overview roughly in the style of the 2nd proposal's [formal spec overview](WebAssembly#87 (comment)) by @rossberg. Particular points of interest: - In this I assume `rethrow` does have an immediate, as it is now described in WebAssembly#137. - The instruction `unwind` now reduces to `catch_all ... rethrow` as specified in Heejin's overview. - Because unwind is much simpler in this MVP, there is no `throw_point` anymore and `caught_m` is much simpler. - The introduction of `caught_m` now also introduces a label around the catch instructions, which label a rethrow instruction can reference. - Added explanation of the peculiar side condition in try's execution rule - just trying to make the rules more compact. I would be happy if anyone could point out things that are wrong or that I misunderstood.
1 parent 176d5c3 commit 78d108d

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# 3rd proposal formal spec overview
2+
3+
This is an overview of the 3rd proposal's formal spec additions, to aid in discussions concerning the proposed semantics.
4+
5+
## Abstract Syntax
6+
7+
### Types
8+
9+
Exception Types
10+
11+
```
12+
exntype ::= [t*] -> []
13+
```
14+
15+
### Instructions
16+
17+
```
18+
instr ::= ... | throw x | rethrow l
19+
| try bt instr* (catch x instr*)+ end
20+
| try bt instr* (catch x instr*)* catch_all instr* end
21+
| try bt instr* delegate l
22+
| try bt instr* unwind instr* end
23+
```
24+
25+
### Modules
26+
27+
Exceptions (definitions)
28+
29+
```
30+
exn ::= export* exception exntype | export* exception exntype import
31+
```
32+
33+
Modules
34+
35+
36+
```
37+
mod ::= module ... exn*
38+
```
39+
40+
## Validation (Typing)
41+
42+
To verify that a `try...delegate l` instruction refers to a label introduced by a try block (I'll call this a try-label), introduce a type attribute to labels in the validation context, which type attribute is set to `try` when the label is a try-label. The original notation `label [t*]` will then be a shortcut for `label {result [t*], type ε}`.
43+
44+
Moreover, to verify that the `rethrow l` instruction refers to a label introduced by a catch block (call this a catch-label), we allow this type attribute of labels in the validation context to be set to `catch` when the label is a catch label. This addition is reflected in the execution rules, by the administrative instruction `caught` which introduces a label around the instructions of the catching try-block's catch instructions.
45+
46+
47+
### Instructions
48+
49+
50+
```
51+
C_exn(x) = [t*] -> []
52+
--------------------------------
53+
C |- throw x : [t1* t*] -> [t2*]
54+
55+
56+
C_label(l).type = catch
57+
-------------------------------
58+
C |- rethrow l : [t1*] -> [t2*]
59+
60+
61+
bt = [t1*] -> [t2*]
62+
C, label {result [t2*], type try} |- instr* : [t1*] -> [t2*]
63+
(C_exn(x_i) = [t'_i*] -> [])^n
64+
(C, label {result [t2*], type catch} |- instr_i* : [t'_i*] -> [t2*])^n
65+
(C, label {result [t2*], type catch} |- instr'* : [] -> [t2*])?
66+
----------------------------------------------------------------------
67+
try bt instr* (catch x_i instr_i*)^n (catch_all instr'*)? end : bt
68+
69+
70+
bt = [t1*] -> [t2*]
71+
C, label {result [t2*], type try} |- instr* : [t1*] -> [t2*]
72+
C_label(l).type = try
73+
------------------------------------------------------------
74+
try bt instr* delegate l : bt
75+
76+
77+
bt = [t1*] -> [t2*]
78+
C, label {result [t2*], type try} |- instr_1* : [t1*] -> [t2*]
79+
C, label {result [t2*], type catch} |- instr_2* : [] -> [t2*]
80+
--------------------------------------------------------------
81+
try bt instr_1* unwind instr_2* : bt
82+
```
83+
84+
## Execution (Reduction)
85+
86+
### Runtime structure
87+
88+
Stores
89+
90+
```
91+
S ::= {..., exn exninst*}
92+
```
93+
94+
Exception Instances
95+
96+
```
97+
exninst ::= {type exntype}
98+
```
99+
100+
Module Instances
101+
102+
```
103+
m ::= {..., (exn a)*}
104+
```
105+
106+
Administrative Instructions
107+
108+
```
109+
instr ::= ... | throw a | catch_n{a instr*}*{instr*} instr* end
110+
| delegate{l} instr* end | caught_m{a val^n} instr* end
111+
```
112+
113+
Throw Contexts
114+
115+
```
116+
T ::= v* [_] e* | label_n{e*} T end | caught_m{a val^n} T end | frame_n{F} T end
117+
```
118+
119+
### Instructions
120+
121+
In the following reduction rules, note that `caught_m` introduces a label around the catching instructions. This corresponds to the label a `rethrow l` would target.
122+
123+
124+
```
125+
F; throw x --> F; throw a (iff F_exn(x) = a)
126+
127+
caught_m{a val^n} label_m{} B^l[rethrow l] end end
128+
--> caught_m{a val^n} label_m{} B^l[val^n (throw a)] end end
129+
130+
caught_m{a val^n} val^m end --> val^m
131+
```
132+
133+
The requirements below involving `k` are to distinguish between a missing `catch_all` and an existing `catch_all` with no instructions (`nop` is added to the empty instruction set of an existing `catch_all`).
134+
135+
```
136+
F; val^n (try bt instr* (catch x_i instr_i*)* (catch_all instr'*)^k end)
137+
--> F; catch_m{a_i instr_i*}*{instr''*} (label_m{} val^n instr* end) end
138+
(iff bt = [t1^n] -> [t2^m] and (F_exn(x_i) = a_i)* and
139+
(if k=1 and instr'*=ε then instr''* = nop)
140+
and (if k=1 and inst'*=/=ε then instr''* = instr'*) and (if k=0 then instr''*=ε).
141+
142+
catch_m{a_i instr_i*}*{instr'*} val^m end --> val^m
143+
144+
S; F; catch_m{a_i instr_i*}*{instr'*} T[val^n (throw a)] end
145+
--> S; F; caught_m{a val^n} label_m{} val^n instr_i* end end
146+
(iff S_exn(a) = {type [t^n]->[]} and a_i = a)
147+
148+
S; F; catch_m{a_i instr_i*}*{instr*} T[val^n (throw a)] end
149+
--> S; F; caught_m{a val^n} label_m{} instr* end end
150+
(iff S_exn(a) = {type [t^n]->[]} and instr =/= ε and for every i, a_i =/= a)
151+
152+
S; F; catch_m{a_i instr_i*}*{ε} T[val^n (throw a)] end
153+
--> S; F; val^n (throw a)
154+
(iff for every i, a_i =/= a)
155+
156+
157+
val^n (try bt instr* delegate l) --> delegate{l} (label_m{} val^n instr* end) end
158+
(iff bt = [t^n] -> [t^m])
159+
160+
catch_m{a_i instr_i*}*{instr*} (label_m{} B^l[ delegate{l} (T[val^n (throw a)]) end ] end) end
161+
--> catch_m{a_i instr_i*}*{instr*} label_m{} val^n (throw a) end end
162+
163+
164+
try bt instr* unwind instr'* end --> try bt instr* catch_all instr'* rethrow 0 end
165+
```

0 commit comments

Comments
 (0)