Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 7799129

Browse files
[interpreter] Parse and convert EH opcodes (#160)
Add support for EH opcodes in the parser, AST, encoder, decoder and formatter, and add spec tests. This can already be used to convert the tests to JS, but not run them with the interpreter yet since validation and execution are still missing.
1 parent 0c0adbe commit 7799129

File tree

17 files changed

+652
-7
lines changed

17 files changed

+652
-7
lines changed

interpreter/binary/decode.ml

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,30 @@ let rec instr s =
246246
end
247247

248248
| 0x05 -> error s pos "misplaced ELSE opcode"
249-
| 0x06| 0x07 | 0x08 | 0x09 | 0x0a as b -> illegal s pos b
249+
| 0x06 ->
250+
let bt = block_type s in
251+
let es = instr_block s in
252+
let ct = catch_list s in
253+
let ca =
254+
if peek s = Some 0x19 then begin
255+
ignore (u8 s);
256+
Some (instr_block s)
257+
end else
258+
None
259+
in
260+
if ct <> [] || ca <> None then begin
261+
end_ s;
262+
try_catch bt es ct ca
263+
end else begin
264+
match op s with
265+
| 0x0b -> try_catch bt es [] None
266+
| 0x18 -> try_delegate bt es (at var s)
267+
| b -> illegal s pos b
268+
end
269+
| 0x07 -> error s pos "misplaced CATCH opcode"
270+
| 0x08 -> throw (at var s)
271+
| 0x09 -> rethrow (at var s)
272+
| 0x0a as b -> illegal s pos b
250273
| 0x0b -> error s pos "misplaced END opcode"
251274

252275
| 0x0c -> br (at var s)
@@ -263,7 +286,10 @@ let rec instr s =
263286
let x = at var s in
264287
call_indirect x y
265288

266-
| 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b
289+
| 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 as b -> illegal s pos b
290+
291+
| 0x18 -> error s pos "misplaced DELEGATE opcode"
292+
| 0x19 -> error s pos "misplaced CATCH_ALL opcode"
267293

268294
| 0x1a -> drop
269295
| 0x1b -> select None
@@ -499,11 +525,19 @@ let rec instr s =
499525
and instr_block s = List.rev (instr_block' s [])
500526
and instr_block' s es =
501527
match peek s with
502-
| None | Some (0x05 | 0x0b) -> es
528+
| None | Some (0x05 | 0x07 | 0x0a | 0x0b | 0x18 | 0x19) -> es
503529
| _ ->
504530
let pos = pos s in
505531
let e' = instr s in
506532
instr_block' s (Source.(e' @@ region s pos pos) :: es)
533+
and catch_list s =
534+
if peek s = Some 0x07 then begin
535+
ignore (u8 s);
536+
let tag = at var s in
537+
let instrs = instr_block s in
538+
(tag, instrs) :: catch_list s
539+
end else
540+
[]
507541

508542
let const s =
509543
let c = at instr_block s in

interpreter/binary/encode.ml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,28 @@ let encode m =
156156
op 0x04; block_type bt; list instr es1;
157157
if es2 <> [] then op 0x05;
158158
list instr es2; end_ ()
159-
159+
| TryCatch (bt, es, ct, ca) ->
160+
op 0x06; block_type bt; list instr es;
161+
let catch (tag, es) =
162+
op 0x07; var tag; list instr es
163+
in
164+
list catch ct;
165+
begin match ca with
166+
| None -> ()
167+
| Some es -> op 0x19; list instr es
168+
end;
169+
end_ ()
170+
| TryDelegate (bt, es, x) ->
171+
op 0x06; block_type bt; list instr es;
172+
op 0x18; var x
160173
| Br x -> op 0x0c; var x
161174
| BrIf x -> op 0x0d; var x
162175
| BrTable (xs, x) -> op 0x0e; vec var xs; var x
163176
| Return -> op 0x0f
164177
| Call x -> op 0x10; var x
165178
| CallIndirect (x, y) -> op 0x11; var y; var x
179+
| Throw x -> op 0x08; var x
180+
| Rethrow x -> op 0x09; var x
166181

167182
| Drop -> op 0x1a
168183
| Select None -> op 0x1b

interpreter/script/js.ml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ function assert_trap(action) {
135135
throw new Error("Wasm trap expected");
136136
}
137137

138+
function assert_exception(action) {
139+
try { action() } catch (e) { return; }
140+
throw new Error("exception expected");
141+
}
142+
138143
let StackOverflow;
139144
try { (function f() { 1 + f() })() } catch (e) { StackOverflow = e.constructor }
140145

@@ -508,6 +513,8 @@ let of_assertion mods ass =
508513
of_assertion' mods act "assert_trap" [] None
509514
| AssertExhaustion (act, _) ->
510515
of_assertion' mods act "assert_exhaustion" [] None
516+
| AssertUncaughtException act ->
517+
of_assertion' mods act "assert_exception" [] None
511518

512519
let of_command mods cmd =
513520
"\n// " ^ Filename.basename cmd.at.left.file ^

interpreter/script/run.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ let run_assertion ass =
458458
| _ -> Assert.error ass.at "expected runtime error"
459459
)
460460

461+
| AssertUncaughtException act -> () (* TODO *)
462+
461463
| AssertExhaustion (act, re) ->
462464
trace ("Asserting exhaustion...");
463465
(match run_action act with

interpreter/script/script.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ and assertion' =
3232
| AssertUninstantiable of definition * string
3333
| AssertReturn of action * result list
3434
| AssertTrap of action * string
35+
| AssertUncaughtException of action
3536
| AssertExhaustion of action * string
3637

3738
type command = command' Source.phrase

interpreter/syntax/ast.ml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ and instr' =
114114
| Unary of unop (* unary numeric operator *)
115115
| Binary of binop (* binary numeric operator *)
116116
| Convert of cvtop (* conversion *)
117+
| TryCatch of block_type * instr list * (* try *)
118+
(var * instr list) list * (* catch exception with tag *)
119+
instr list option (* catch_all *)
120+
| TryDelegate of block_type * instr list * (* try *)
121+
var (* delegate to outer handler *)
122+
| Throw of var (* throw exception *)
123+
| Rethrow of var (* rethrow exception *)
117124

118125

119126
(* Globals & Functions *)

interpreter/syntax/free.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ let rec instr (e : instr) =
8787
memories zero
8888
| MemoryInit x -> memories zero ++ datas (var x)
8989
| DataDrop x -> datas (var x)
90+
| TryCatch (bt, es, ct, ca) ->
91+
let catch (tag, es) = events (var tag) ++ block es in
92+
let catch_all = function
93+
| None -> empty
94+
| Some es -> block es in
95+
block es ++ (list catch ct) ++ catch_all ca
96+
| TryDelegate (bt, es, x) -> block es ++ events (var x)
97+
| Throw x -> events (var x)
98+
| Rethrow x -> labels (var x)
9099

91100
and block (es : instr list) =
92101
let free = list instr es in {free with labels = shift free.labels}

interpreter/syntax/operators.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@ let select t = Select t
1919
let block bt es = Block (bt, es)
2020
let loop bt es = Loop (bt, es)
2121
let if_ bt es1 es2 = If (bt, es1, es2)
22+
let try_catch bt es ct ca = TryCatch (bt, es, ct, ca)
23+
let try_delegate bt es x = TryDelegate (bt, es, x)
2224
let br x = Br x
2325
let br_if x = BrIf x
2426
let br_table xs x = BrTable (xs, x)
2527

2628
let return = Return
2729
let call x = Call x
2830
let call_indirect x y = CallIndirect (x, y)
31+
let throw x = Throw x
32+
let rethrow x = Rethrow x
2933

3034
let local_get x = LocalGet x
3135
let local_set x = LocalSet x

interpreter/text/arrange.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,18 @@ let rec instr e =
279279
| Unary op -> unop op, []
280280
| Binary op -> binop op, []
281281
| Convert op -> cvtop op, []
282+
| TryCatch (bt, es, ct, ca) ->
283+
let catch (tag, es) = Node ("catch " ^ var tag, list instr es) in
284+
let catch_all = match ca with
285+
| Some es -> [Node ("catch_all", list instr es)]
286+
| None -> [] in
287+
let handler = list catch ct @ catch_all in
288+
"try", block_type bt @ [Node ("do", list instr es)] @ handler
289+
| TryDelegate (bt, es, x) ->
290+
let delegate = [Node ("delegate " ^ var x, [])] in
291+
"try", block_type bt @ [Node ("do", list instr es)] @ delegate
292+
| Throw x -> "throw " ^ var x, []
293+
| Rethrow x -> "rethrow " ^ var x, []
282294
in Node (head, inner)
283295

284296
let const head c =
@@ -538,6 +550,8 @@ let assertion mode ass =
538550
[Node ("assert_return", action mode act :: List.map (result mode) results)]
539551
| AssertTrap (act, re) ->
540552
[Node ("assert_trap", [action mode act; Atom (string re)])]
553+
| AssertUncaughtException act ->
554+
[Node ("assert_exception", [action mode act])]
541555
| AssertExhaustion (act, re) ->
542556
[Node ("assert_exhaustion", [action mode act; Atom (string re)])]
543557

interpreter/text/lexer.mll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,14 @@ rule token = parse
348348
| "i32.reinterpret_f32" { CONVERT i32_reinterpret_f32 }
349349
| "i64.reinterpret_f64" { CONVERT i64_reinterpret_f64 }
350350

351+
| "try" { TRY }
352+
| "do" { DO }
353+
| "catch" { CATCH }
354+
| "catch_all" { CATCH_ALL }
355+
| "delegate" { DELEGATE }
356+
| "throw" { THROW }
357+
| "rethrow" { RETHROW }
358+
351359
| "type" { TYPE }
352360
| "func" { FUNC }
353361
| "start" { START }
@@ -379,6 +387,7 @@ rule token = parse
379387
| "assert_unlinkable" { ASSERT_UNLINKABLE }
380388
| "assert_return" { ASSERT_RETURN }
381389
| "assert_trap" { ASSERT_TRAP }
390+
| "assert_exception" { ASSERT_EXCEPTION }
382391
| "assert_exhaustion" { ASSERT_EXHAUSTION }
383392
| "nan:canonical" { NAN Script.CanonicalNan }
384393
| "nan:arithmetic" { NAN Script.ArithmeticNan }

0 commit comments

Comments
 (0)