Skip to content

Commit 9387946

Browse files
committed
Implement exceptions by returning null
1 parent 0d98aad commit 9387946

File tree

7 files changed

+174
-70
lines changed

7 files changed

+174
-70
lines changed

compiler/lib-wasm/curry.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,19 +228,24 @@ module Make (Target : Target_sig.S) = struct
228228
match l with
229229
| [] ->
230230
let* y = y in
231-
instr (Push y)
231+
instr (Return (Some y))
232232
| x :: rem ->
233233
let* x = load x in
234-
build_applies (call ~cps:false ~arity:1 y [ x ]) rem
234+
let* c = call ~cps:false ~arity:1 y [ x ] in
235+
build_applies (return (W.Br_on_null (0, c))) rem
235236
in
236237
build_applies (load f) l)
237238
in
239+
let body =
240+
let* () = block { params = []; result = [] } body in
241+
instr (Return (Some (RefNull Any)))
242+
in
238243
let param_names = l @ [ f ] in
239244
let locals, body = function_body ~context ~param_names ~body in
240245
W.Function
241246
{ name
242247
; exported_name = None
243-
; typ = Type.primitive_type (arity + 1)
248+
; typ = Type.func_type arity
244249
; param_names
245250
; locals
246251
; body

compiler/lib-wasm/gc_target.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ let include_closure_arity = false
2727
module Type = struct
2828
let value = W.Ref { nullable = false; typ = Eq }
2929

30+
let value_or_exn = W.Ref { nullable = true; typ = Eq }
31+
3032
let block_type =
3133
register_type "block" (fun () ->
3234
return
@@ -205,7 +207,8 @@ module Type = struct
205207
let primitive_type n =
206208
{ W.params = List.init ~len:n ~f:(fun _ -> value); result = [ value ] }
207209

208-
let func_type n = primitive_type (n + 1)
210+
let func_type n =
211+
{ W.params = List.init ~len:(n + 1) ~f:(fun _ -> value); result = [ value_or_exn ] }
209212

210213
let function_type ~cps n =
211214
let n = if cps then n + 1 else n in

compiler/lib-wasm/generate.ml

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ module Generate (Target : Target_sig.S) = struct
181181

182182
let zero_divide_pc = -2
183183

184+
let exception_handler_pc = -3
185+
184186
let rec translate_expr ctx context x e =
185187
match e with
186188
| Apply { f; args; exact }
@@ -198,17 +200,21 @@ module Generate (Target : Target_sig.S) = struct
198200
(load funct)
199201
in
200202
let* b = is_closure f in
203+
let label = label_index context exception_handler_pc in
201204
if b
202-
then return (W.Call (f, List.rev (closure :: acc)))
205+
then return (W.Br_on_null (label, W.Call (f, List.rev (closure :: acc))))
203206
else
204207
match funct with
205208
| W.RefFunc g ->
206209
(* Functions with constant closures ignore their
207210
environment. In case of partial application, we
208211
still need the closure. *)
209212
let* cl = if exact then Value.unit else return closure in
210-
return (W.Call (g, List.rev (cl :: acc)))
211-
| _ -> return (W.Call_ref (ty, funct, List.rev (closure :: acc))))
213+
return (W.Br_on_null (label, W.Call (g, List.rev (cl :: acc))))
214+
| _ ->
215+
return
216+
(W.Br_on_null
217+
(label, W.Call_ref (ty, funct, List.rev (closure :: acc)))))
212218
| x :: r ->
213219
let* x = load x in
214220
loop (x :: acc) r
@@ -220,7 +226,9 @@ module Generate (Target : Target_sig.S) = struct
220226
in
221227
let* args = expression_list load args in
222228
let* closure = load f in
223-
return (W.Call (apply, args @ [ closure ]))
229+
return
230+
(W.Br_on_null
231+
(label_index context exception_handler_pc, W.Call (apply, args @ [ closure ])))
224232
| Block (tag, a, _, _) ->
225233
Memory.allocate
226234
~deadcode_sentinal:ctx.deadcode_sentinal
@@ -822,32 +830,55 @@ module Generate (Target : Target_sig.S) = struct
822830
{ params = []; result = [] }
823831
(body ~result_typ:[] ~fall_through:(`Block pc) ~context:(`Block pc :: context))
824832
in
825-
if List.is_empty result_typ
833+
if true && List.is_empty result_typ
826834
then handler
827835
else
828836
let* () = handler in
829-
instr (W.Return (Some (RefI31 (Const (I32 0l)))))
837+
let* u = Value.unit in
838+
instr (W.Return (Some u))
830839
else body ~result_typ ~fall_through ~context
831840

832-
let wrap_with_handlers p pc ~result_typ ~fall_through ~context body =
841+
let wrap_with_handlers ~location p pc ~result_typ ~fall_through ~context body =
833842
let need_zero_divide_handler, need_bound_error_handler = needed_handlers p pc in
834843
wrap_with_handler
835-
need_bound_error_handler
836-
bound_error_pc
837-
(let* f =
838-
register_import ~name:"caml_bound_error" (Fun { params = []; result = [] })
839-
in
840-
instr (CallInstr (f, [])))
844+
true
845+
exception_handler_pc
846+
(match location with
847+
| `Toplevel ->
848+
let* exn =
849+
register_import
850+
~import_module:"env"
851+
~name:"caml_exception"
852+
(Global { mut = true; typ = Type.value })
853+
in
854+
let* tag = register_import ~name:exception_name (Tag Type.value) in
855+
instr (Throw (tag, GlobalGet exn))
856+
| `Exception_handler ->
857+
let* exn =
858+
register_import
859+
~import_module:"env"
860+
~name:"caml_exception"
861+
(Global { mut = true; typ = Type.value })
862+
in
863+
instr (Br (2, Some (GlobalGet exn)))
864+
| `Function -> instr (Return (Some (RefNull Any))))
841865
(wrap_with_handler
842-
need_zero_divide_handler
843-
zero_divide_pc
866+
need_bound_error_handler
867+
bound_error_pc
844868
(let* f =
845-
register_import
846-
~name:"caml_raise_zero_divide"
847-
(Fun { params = []; result = [] })
869+
register_import ~name:"caml_bound_error" (Fun { params = []; result = [] })
848870
in
849871
instr (CallInstr (f, [])))
850-
body)
872+
(wrap_with_handler
873+
need_zero_divide_handler
874+
zero_divide_pc
875+
(let* f =
876+
register_import
877+
~name:"caml_raise_zero_divide"
878+
(Fun { params = []; result = [] })
879+
in
880+
instr (CallInstr (f, [])))
881+
body))
851882
~result_typ
852883
~fall_through
853884
~context
@@ -948,19 +979,34 @@ module Generate (Target : Target_sig.S) = struct
948979
instr (Br_table (e, List.map ~f:dest l, dest a.(len - 1)))
949980
| Raise (x, _) -> (
950981
let* e = load x in
951-
let* tag = register_import ~name:exception_name (Tag Type.value) in
952982
match fall_through with
953983
| `Catch -> instr (Push e)
954984
| `Block _ | `Return | `Skip -> (
955985
match catch_index context with
956986
| Some i -> instr (Br (i, Some e))
957-
| None -> instr (Throw (tag, e))))
987+
| None ->
988+
if Option.is_some name_opt
989+
then
990+
let* exn =
991+
register_import
992+
~import_module:"env"
993+
~name:"caml_exception"
994+
(Global { mut = true; typ = Type.value })
995+
in
996+
let* () = instr (GlobalSet (exn, e)) in
997+
instr (Return (Some (RefNull Any)))
998+
else
999+
let* tag =
1000+
register_import ~name:exception_name (Tag Type.value)
1001+
in
1002+
instr (Throw (tag, e))))
9581003
| Pushtrap (cont, x, cont') ->
9591004
handle_exceptions
9601005
~result_typ
9611006
~fall_through
9621007
~context:(extend_context fall_through context)
9631008
(wrap_with_handlers
1009+
~location:`Exception_handler
9641010
p
9651011
(fst cont)
9661012
(fun ~result_typ ~fall_through ~context ->
@@ -1031,6 +1077,10 @@ module Generate (Target : Target_sig.S) = struct
10311077
let* () = build_initial_env in
10321078
let* () =
10331079
wrap_with_handlers
1080+
~location:
1081+
(match name_opt with
1082+
| None -> `Toplevel
1083+
| Some _ -> `Function)
10341084
p
10351085
pc
10361086
~result_typ:[ Type.value ]
@@ -1079,7 +1129,9 @@ module Generate (Target : Target_sig.S) = struct
10791129
in
10801130
let* () = instr (Drop (Call (f, []))) in
10811131
cont)
1082-
~init:(instr (Push (RefI31 (Const (I32 0l)))))
1132+
~init:
1133+
(let* u = Value.unit in
1134+
instr (Push u))
10831135
to_link)
10841136
in
10851137
context.other_fields <-

compiler/lib-wasm/tail_call.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ let rewrite_tail_call ~y i =
3030
Some (Wasm_ast.Return_call (symb, l))
3131
| LocalSet (x, Call_ref (ty, e, l)) when Code.Var.equal x y ->
3232
Some (Return_call_ref (ty, e, l))
33+
| LocalSet (x, Br_on_null (_, Call (symb, l))) when Code.Var.equal x y ->
34+
Some (Wasm_ast.Return_call (symb, l))
35+
| LocalSet (x, Br_on_null (_, Call_ref (ty, e, l))) when Code.Var.equal x y ->
36+
Some (Return_call_ref (ty, e, l))
3337
| _ -> None
3438

3539
let rec instruction ~tail i =
@@ -42,6 +46,11 @@ let rec instruction ~tail i =
4246
| Push (Call (symb, l)) when tail -> Return_call (symb, l)
4347
| Push (Call_ref (ty, e, l)) when tail -> Return_call_ref (ty, e, l)
4448
| Push (Call_ref _) -> i
49+
| Return (Some (Br_on_null (_, Call (symb, l)))) -> Return_call (symb, l)
50+
| Return (Some (Br_on_null (_, Call_ref (ty, e, l)))) -> Return_call_ref (ty, e, l)
51+
| Push (Br_on_null (_, Call (symb, l))) when tail -> Return_call (symb, l)
52+
| Push (Br_on_null (_, Call_ref (ty, e, l))) when tail -> Return_call_ref (ty, e, l)
53+
| Push (Br_on_null (_, Call_ref _)) -> i
4554
| Drop (BlockExpr (typ, l)) -> Drop (BlockExpr (typ, instructions ~tail:false l))
4655
| Drop _
4756
| LocalSet _

0 commit comments

Comments
 (0)