Skip to content

Commit 6b0b593

Browse files
authored
Implement reduction and text format (WebAssembly#6)
2 parents 7704c23 + dfb8dad commit 6b0b593

File tree

18 files changed

+746
-86
lines changed

18 files changed

+746
-86
lines changed

interpreter/binary/decode.ml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ let global_type s =
225225
let def_type s =
226226
match peek s with
227227
| Some 0x60 -> FuncDefType (func_type s)
228-
| Some 0x61 -> ContDefType (cont_type s)
228+
| Some 0x5f -> ContDefType (cont_type s)
229229
| None -> ignore (vs7 s); assert false (* force error *)
230230
| _ -> error s (pos s) "malformed type definition"
231231

@@ -553,9 +553,14 @@ let rec instr s =
553553
| 0xd4 -> br_on_null (at var s)
554554

555555
| 0xe0 -> cont_new (at var s)
556-
| 0xe1 -> cont_suspend (at var s)
557-
| 0xe2 -> cont_throw (at var s)
558-
| 0xe3 -> cont_resume (vec var_pair s)
556+
| 0xe1 -> suspend (at var s)
557+
| 0xe2 -> resume (vec var_pair s)
558+
| 0xe3 -> resume_throw (at var s)
559+
| 0xe4 ->
560+
let bt = block_type s in
561+
let es' = instr_block s in
562+
end_ s;
563+
guard bt es'
559564

560565
| 0xfc as b ->
561566
(match vu32 s with
@@ -656,6 +661,7 @@ let import_desc s =
656661
| 0x01 -> TableImport (table_type s)
657662
| 0x02 -> MemoryImport (memory_type s)
658663
| 0x03 -> GlobalImport (global_type s)
664+
| 0x04 -> EventImport (event_type s)
659665
| _ -> error s (pos s - 1) "malformed import kind"
660666

661667
let import s =
@@ -723,6 +729,7 @@ let export_desc s =
723729
| 0x01 -> TableExport (at var s)
724730
| 0x02 -> MemoryExport (at var s)
725731
| 0x03 -> GlobalExport (at var s)
732+
| 0x04 -> EventExport (at var s)
726733
| _ -> error s (pos s - 1) "malformed export kind"
727734

728735
let export s =

interpreter/binary/encode.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,10 @@ let encode m =
215215
| FuncBind x -> op 0x16; var x
216216

217217
| ContNew x -> op 0xe0; var x
218-
| ContSuspend x -> op 0xe1; var x
219-
| ContThrow x -> op 0xe2; var x
220-
| ContResume xls -> op 0xe3; vec var_pair xls
218+
| Suspend x -> op 0xe1; var x
219+
| Resume xls -> op 0xe2; vec var_pair xls
220+
| ResumeThrow x -> op 0xe3; var x
221+
| Guard (bt, es) -> op 0xe4; block_type bt; list instr es; end_ ()
221222

222223
| Drop -> op 0x1a
223224
| Select None -> op 0x1b

interpreter/exec/eval.ml

Lines changed: 146 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ open Source
1010
module Link = Error.Make ()
1111
module Trap = Error.Make ()
1212
module Exception = Error.Make ()
13+
module Suspension = Error.Make ()
1314
module Exhaustion = Error.Make ()
1415
module Crash = Error.Make ()
1516

1617
exception Link = Link.Error
1718
exception Trap = Trap.Error
1819
exception Exception = Exception.Error
20+
exception Suspension = Suspension.Error
1921
exception Exhaustion = Exhaustion.Error
2022
exception Crash = Crash.Error (* failure that cannot happen in valid code *)
2123

@@ -44,7 +46,7 @@ let numeric_error at = function
4446
| exn -> raise exn
4547

4648

47-
(* Administrative Expressions & Configurations *)
49+
(* Administrative Expressions & Continuations *)
4850

4951
type 'a stack = 'a list
5052

@@ -61,15 +63,48 @@ and admin_instr' =
6163
| Plain of instr'
6264
| Refer of ref_
6365
| Invoke of func_inst
66+
| Label of int * instr list * code
67+
| Local of int * value list * code
68+
| Frame of int * frame * code
69+
| Catch of int * event_inst option * instr list * code
70+
| Handle of (event_inst * idx) list option * code
6471
| Trapping of string
6572
| Throwing of event_inst * value stack
73+
| Suspending of event_inst * value stack * ctxt
6674
| Returning of value stack
6775
| ReturningInvoke of value stack * func_inst
6876
| Breaking of int32 * value stack
69-
| Label of int * instr list * code
70-
| Local of int * value list * code
71-
| Frame of int * frame * code
72-
| Catch of int * event_inst option * instr list * code
77+
78+
and ctxt = code -> code
79+
80+
type cont = int * ctxt (* TODO: represent type properly *)
81+
type ref_ += ContRef of cont
82+
83+
let () =
84+
let type_of_ref' = !Value.type_of_ref' in
85+
Value.type_of_ref' := function
86+
| ContRef _ -> BotHeapType (* TODO *)
87+
| r -> type_of_ref' r
88+
89+
let () =
90+
let string_of_ref' = !Value.string_of_ref' in
91+
Value.string_of_ref' := function
92+
| ContRef _ -> "cont"
93+
| r -> string_of_ref' r
94+
95+
let plain e = Plain e.it @@ e.at
96+
97+
let is_jumping e =
98+
match e.it with
99+
| Trapping _ | Throwing _ | Suspending _
100+
| Returning _ | ReturningInvoke _ | Breaking _ ->
101+
true
102+
| _ -> false
103+
104+
let compose (vs1, es1) (vs2, es2) = vs1 @ vs2, es1 @ es2
105+
106+
107+
(* Configurations *)
73108

74109
type config =
75110
{
@@ -81,14 +116,6 @@ type config =
81116
let frame inst = {inst; locals = []}
82117
let config inst vs es = {frame = frame inst; code = vs, es; budget = 300}
83118

84-
let plain e = Plain e.it @@ e.at
85-
86-
let is_jumping e =
87-
match e.it with
88-
| Trapping _ | Throwing _ | Returning _ | ReturningInvoke _ | Breaking _ ->
89-
true
90-
| _ -> false
91-
92119
let lookup category list x =
93120
try Lib.List32.nth list x.it with Failure _ ->
94121
Crash.error x.at ("undefined " ^ category ^ " " ^ Int32.to_string x.it)
@@ -191,12 +218,12 @@ let rec step (c : config) : config =
191218
vs', [Plain (Block (bt, es1)) @@ e.at]
192219

193220
| Let (bt, locals, es'), vs ->
194-
let vs0, vs' = split (List.length locals) vs e.at in
221+
let locs, vs' = split (List.length locals) vs e.at in
195222
let FuncType (ts1, ts2) = block_type c.frame.inst bt e.at in
196-
let vs1, vs2 = split (List.length ts1) vs' e.at in
197-
vs2, [
198-
Local (List.length ts2, List.rev vs0,
199-
(vs1, [Plain (Block (bt, es')) @@ e.at])
223+
let args, vs'' = split (List.length ts1) vs' e.at in
224+
vs'', [
225+
Local (List.length ts2, List.rev locs,
226+
(args, [Plain (Block (bt, es')) @@ e.at])
200227
) @@ e.at
201228
]
202229

@@ -209,7 +236,10 @@ let rec step (c : config) : config =
209236
vs', [Catch (n2, exno, es2, ([], [Label (n2, [], (args, List.map plain es1)) @@ e.at])) @@ e.at]
210237

211238
| Throw x, vs ->
212-
[], [Throwing (event c.frame.inst x, vs) @@ e.at]
239+
let evt = event c.frame.inst x in
240+
let EventType (FuncType (ts, _), _) = Event.type_of evt in
241+
let vs0, vs' = split (List.length ts) vs e.at in
242+
vs', [Throwing (evt, vs0) @@ e.at]
213243

214244
| Br x, vs ->
215245
[], [Breaking (x.it, vs) @@ e.at]
@@ -278,6 +308,47 @@ let rec step (c : config) : config =
278308
let f' = Func.alloc_closure (type_ c.frame.inst x) f args in
279309
Ref (FuncRef f') :: vs', []
280310

311+
| ContNew x, Ref (NullRef _) :: vs ->
312+
vs, [Trapping "null function reference" @@ e.at]
313+
314+
| ContNew x, Ref (FuncRef f) :: vs ->
315+
let FuncType (ts, _) = Func.type_of f in
316+
let ctxt code = compose code ([], [Invoke f @@ e.at]) in
317+
Ref (ContRef (List.length ts, ctxt)) :: vs, []
318+
319+
| Suspend x, vs ->
320+
let evt = event c.frame.inst x in
321+
let EventType (FuncType (ts, _), _) = Event.type_of evt in
322+
let args, vs' = split (List.length ts) vs e.at in
323+
vs', [Suspending (evt, args, fun code -> code) @@ e.at]
324+
325+
| Resume xls, Ref (NullRef _) :: vs ->
326+
vs, [Trapping "null continuation reference" @@ e.at]
327+
328+
| Resume xls, Ref (ContRef (n, ctxt)) :: vs ->
329+
let hs = List.map (fun (x, l) -> event c.frame.inst x, l) xls in
330+
let args, vs' = split n vs e.at in
331+
vs', [Handle (Some hs, ctxt (args, [])) @@ e.at]
332+
333+
| ResumeThrow x, Ref (NullRef _) :: vs ->
334+
vs, [Trapping "null continuation reference" @@ e.at]
335+
336+
| ResumeThrow x, Ref (ContRef (n, ctxt)) :: vs ->
337+
let evt = event c.frame.inst x in
338+
let EventType (FuncType (ts, _), _) = Event.type_of evt in
339+
let args, vs' = split (List.length ts) vs e.at in
340+
let vs1', es1' = ctxt (args, [Plain (Throw x) @@ e.at]) in
341+
vs1' @ vs', es1'
342+
343+
| Guard (bt, es'), vs ->
344+
let FuncType (ts1, _) = block_type c.frame.inst bt e.at in
345+
let args, vs' = split (List.length ts1) vs e.at in
346+
vs', [
347+
Handle (None,
348+
(args, [Plain (Block (bt, es')) @@ e.at])
349+
) @@ e.at
350+
]
351+
281352
| Drop, v :: vs' ->
282353
vs', []
283354

@@ -557,6 +628,10 @@ let rec step (c : config) : config =
557628
| Label (n, es0, (vs', [])), vs ->
558629
vs' @ vs, []
559630

631+
| Label (n, es0, (vs', {it = Suspending (evt, vs1, ctxt); at} :: es')), vs ->
632+
let ctxt' code = [], [Label (n, es0, compose (ctxt code) (vs', es')) @@ e.at] in
633+
vs, [Suspending (evt, vs1, ctxt') @@ at]
634+
560635
| Label (n, es0, (vs', {it = Breaking (0l, vs0); at} :: es')), vs ->
561636
take n vs0 e.at @ vs, List.map plain es0
562637

@@ -573,6 +648,10 @@ let rec step (c : config) : config =
573648
| Local (n, vs0, (vs', [])), vs ->
574649
vs' @ vs, []
575650

651+
| Local (n, vs0, (vs', {it = Suspending (evt, vs1, ctxt); at} :: es')), vs ->
652+
let ctxt' code = [], [Local (n, vs0, compose (ctxt code) (vs', es')) @@ e.at] in
653+
vs, [Suspending (evt, vs1, ctxt') @@ at]
654+
576655
| Local (n, vs0, (vs', e' :: es')), vs when is_jumping e' ->
577656
vs, [e']
578657

@@ -585,6 +664,10 @@ let rec step (c : config) : config =
585664
| Frame (n, frame', (vs', [])), vs ->
586665
vs' @ vs, []
587666

667+
| Frame (n, frame', (vs', {it = Suspending (evt, vs1, ctxt); at} :: es')), vs ->
668+
let ctxt' code = [], [Frame (n, frame', compose (ctxt code) (vs', es')) @@ e.at] in
669+
vs, [Suspending (evt, vs1, ctxt') @@ at]
670+
588671
| Frame (n, frame', (vs', {it = Returning vs0; at} :: es')), vs ->
589672
take n vs0 e.at @ vs, []
590673

@@ -630,14 +713,16 @@ let rec step (c : config) : config =
630713
| Catch (n, exno, es0, (vs', [])), vs ->
631714
vs' @ vs, []
632715

716+
| Catch (n, exno, es0, (vs', {it = Suspending (evt, vs1, ctxt); at} :: es')), vs ->
717+
let ctxt' code = [], [Catch (n, exno, es0, compose (ctxt code) (vs', es')) @@ e.at] in
718+
vs, [Suspending (evt, vs1, ctxt') @@ at]
719+
633720
| Catch (n, None, es0, (vs', {it = Throwing (exn, vs0); at} :: _)), vs ->
634721
vs, [Label (n, [], ([], List.map plain es0)) @@ e.at]
635722

636723
| Catch (n, Some exn, es0, (vs', {it = Throwing (exn0, vs0); at} :: _)), vs
637724
when exn0 == exn ->
638-
let EventType (FuncType (ts, _), _) = Event.type_of exn in
639-
let n' = List.length ts in
640-
vs, [Label (n, [], (take n' vs0 at, List.map plain es0)) @@ e.at]
725+
vs, [Label (n, [], (vs0, List.map plain es0)) @@ e.at]
641726

642727
| Catch (n, exno, es0, (vs', e' :: es')), vs when is_jumping e' ->
643728
vs, [e']
@@ -646,15 +731,36 @@ let rec step (c : config) : config =
646731
let c' = step {c with code = code'} in
647732
vs, [Catch (n, exno, es0, c'.code) @@ e.at]
648733

649-
| Returning _, vs
650-
| ReturningInvoke _, vs ->
651-
Crash.error e.at "undefined frame"
734+
| Handle (hso, (vs', [])), vs ->
735+
vs' @ vs, []
736+
737+
| Handle (None, (vs', {it = Suspending _; at} :: es')), vs ->
738+
vs, [Trapping "guard suspended" @@ at]
739+
740+
| Handle (Some hs, (vs', {it = Suspending (evt, vs1, ctxt); at} :: es')), vs
741+
when List.mem_assq evt hs ->
742+
let EventType (FuncType (_, ts), _) = Event.type_of evt in
743+
let ctxt' code = compose (ctxt code) (vs', es') in
744+
[Ref (ContRef (List.length ts, ctxt'))] @ vs1 @ vs,
745+
[Plain (Br (List.assq evt hs)) @@ e.at]
652746

653-
| Breaking (k, vs'), vs ->
654-
Crash.error e.at "undefined label"
747+
| Handle (hso, (vs', {it = Suspending (evt, vs1, ctxt); at} :: es')), vs ->
748+
let ctxt' code = [], [Handle (hso, compose (ctxt code) (vs', es')) @@ e.at] in
749+
vs, [Suspending (evt, vs1, ctxt') @@ at]
655750

656-
| Trapping _, vs
657-
| Throwing _, vs ->
751+
| Handle (hso, (vs', e' :: es')), vs when is_jumping e' ->
752+
vs, [e']
753+
754+
| Handle (hso, code'), vs ->
755+
let c' = step {c with code = code'} in
756+
vs, [Handle (hso, c'.code) @@ e.at]
757+
758+
| Trapping _, _
759+
| Throwing _, _
760+
| Suspending _, _
761+
| Returning _, _
762+
| ReturningInvoke _, _
763+
| Breaking _, _ ->
658764
assert false
659765

660766
in {c with code = vs', es' @ List.tl es}
@@ -665,13 +771,17 @@ let rec eval (c : config) : value stack =
665771
| vs, [] ->
666772
vs
667773

668-
| vs, {it = Trapping msg; at} :: _ ->
669-
Trap.error at msg
670-
671-
| vs, {it = Throwing _; at} :: _ ->
672-
Exception.error at "uncaught exception"
673-
674-
| vs, es ->
774+
| vs, e::_ when is_jumping e ->
775+
(match e.it with
776+
| Trapping msg -> Trap.error e.at msg
777+
| Throwing _ -> Exception.error e.at "unhandled exception"
778+
| Suspending _ -> Suspension.error e.at "unhandled event"
779+
| Returning _ | ReturningInvoke _ -> Crash.error e.at "undefined frame"
780+
| Breaking _ -> Crash.error e.at "undefined label"
781+
| _ -> assert false
782+
)
783+
784+
| _ ->
675785
eval (step c)
676786

677787

interpreter/exec/eval.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ open Instance
44
exception Link of Source.region * string
55
exception Trap of Source.region * string
66
exception Exception of Source.region * string
7+
exception Suspension of Source.region * string
78
exception Exhaustion of Source.region * string
89
exception Crash of Source.region * string
910

interpreter/script/js.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ function assert_exception(action) {
143143
throw new Error("Wasm exception expected");
144144
}
145145

146+
function assert_suspension(action) {
147+
try { action() } catch (e) {
148+
/* TODO: Not clear how to observe form JS */
149+
return;
150+
}
151+
throw new Error("Wasm exception expected");
152+
}
153+
146154
let StackOverflow;
147155
try { (function f() { 1 + f() })() } catch (e) { StackOverflow = e.constructor }
148156

@@ -536,6 +544,8 @@ let of_assertion mods ass =
536544
of_assertion' mods act "assert_trap" [] None
537545
| AssertException (act, _) ->
538546
of_assertion' mods act "assert_exception" [] None
547+
| AssertSuspension (act, _) ->
548+
of_assertion' mods act "assert_suspension" [] None
539549
| AssertExhaustion (act, _) ->
540550
of_assertion' mods act "assert_exhaustion" [] None
541551

interpreter/script/run.ml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,13 @@ let run_assertion ass =
446446
| _ -> Assert.error ass.at "expected exception"
447447
)
448448

449+
| AssertSuspension (act, re) ->
450+
trace ("Asserting suspension...");
451+
(match run_action act with
452+
| exception Eval.Suspension (_, msg) -> assert_message ass.at "runtime" msg re
453+
| _ -> Assert.error ass.at "expected suspension"
454+
)
455+
449456
| AssertExhaustion (act, re) ->
450457
trace ("Asserting exhaustion...");
451458
(match run_action act with

0 commit comments

Comments
 (0)