Skip to content

Commit 200fceb

Browse files
committed
Implement exceptions by returning null
1 parent b3671f0 commit 200fceb

File tree

7 files changed

+174
-69
lines changed

7 files changed

+174
-69
lines changed

compiler/lib-wasm/curry.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,20 +256,25 @@ module Make (Target : Target_sig.S) = struct
256256
match l with
257257
| [] ->
258258
let* y = y in
259-
instr (Push y)
259+
instr (Return (Some y))
260260
| x :: rem ->
261261
let* x = load x in
262-
build_applies (call ~cps:false ~arity:1 y [ x ]) rem
262+
let* c = call ~cps:false ~arity:1 y [ x ] in
263+
build_applies (return (W.Br_on_null (0, c))) rem
263264
in
264265
build_applies (load f) l)
265266
in
267+
let body =
268+
let* () = block { params = []; result = [] } body in
269+
instr (Return (Some (RefNull Any)))
270+
in
266271
let param_names = l @ [ f ] in
267272
let locals, body = function_body ~context ~param_names ~body in
268273
W.Function
269274
{ name
270275
; exported_name = None
271276
; typ = None
272-
; signature = Type.primitive_type (arity + 1)
277+
; signature = Type.func_type arity
273278
; param_names
274279
; locals
275280
; body

compiler/lib-wasm/gc_target.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ type expression = Wasm_ast.expression Code_generation.t
2525
module Type = struct
2626
let value = W.Ref { nullable = false; typ = Eq }
2727

28+
let value_or_exn = W.Ref { nullable = true; typ = Eq }
29+
2830
let block_type =
2931
register_type "block" (fun () ->
3032
return
@@ -203,7 +205,8 @@ module Type = struct
203205
let primitive_type n =
204206
{ W.params = List.init ~len:n ~f:(fun _ -> value); result = [ value ] }
205207

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

208211
let function_type ~cps n =
209212
let n = if cps then n + 1 else n in

compiler/lib-wasm/generate.ml

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -784,11 +784,14 @@ module Generate (Target : Target_sig.S) = struct
784784
in
785785
Memory.allocate ~tag:0 ~deadcode_sentinal:ctx.deadcode_sentinal ~load l)
786786

787+
let exception_handler_pc = -3
788+
787789
let rec translate_expr ctx context x e =
788790
match e with
789791
| Apply { f; args; exact; _ } ->
790792
let* closure = load f in
791793
let* args = expression_list (fun x -> load_and_box ctx x) args in
794+
let label = label_index context exception_handler_pc in
792795
if exact || List.length args = if Var.Set.mem x ctx.in_cps then 2 else 1
793796
then
794797
match
@@ -803,7 +806,7 @@ module Generate (Target : Target_sig.S) = struct
803806
if Option.is_some init then Value.unit else return closure
804807
| _ -> return closure
805808
in
806-
return (W.Call (g, args @ [ cl ]))
809+
return (W.Br_on_null (label, W.Call (g, args @ [ cl ])))
807810
| None -> (
808811
let funct = Var.fresh () in
809812
let* closure = tee funct (return closure) in
@@ -814,13 +817,16 @@ module Generate (Target : Target_sig.S) = struct
814817
(load funct)
815818
in
816819
match funct with
817-
| W.RefFunc g -> return (W.Call (g, args @ [ closure ]))
818-
| _ -> return (W.Call_ref (ty, funct, args @ [ closure ])))
820+
| W.RefFunc g ->
821+
return (W.Br_on_null (label, W.Call (g, args @ [ closure ])))
822+
| _ ->
823+
return
824+
(W.Br_on_null (label, W.Call_ref (ty, funct, args @ [ closure ]))))
819825
else
820826
let* apply =
821827
need_apply_fun ~cps:(Var.Set.mem x ctx.in_cps) ~arity:(List.length args)
822828
in
823-
return (W.Call (apply, args @ [ closure ]))
829+
return (W.Br_on_null (label, W.Call (apply, args @ [ closure ])))
824830
| Block (tag, a, _, _) ->
825831
Memory.allocate
826832
~deadcode_sentinal:ctx.deadcode_sentinal
@@ -1075,32 +1081,55 @@ module Generate (Target : Target_sig.S) = struct
10751081
{ params = []; result = [] }
10761082
(body ~result_typ:[] ~fall_through:(`Block pc) ~context:(`Block pc :: context))
10771083
in
1078-
if List.is_empty result_typ
1084+
if true && List.is_empty result_typ
10791085
then handler
10801086
else
10811087
let* () = handler in
1082-
instr (W.Return (Some (RefI31 (Const (I32 0l)))))
1088+
let* u = Value.unit in
1089+
instr (W.Return (Some u))
10831090
else body ~result_typ ~fall_through ~context
10841091

1085-
let wrap_with_handlers p pc ~result_typ ~fall_through ~context body =
1092+
let wrap_with_handlers ~location p pc ~result_typ ~fall_through ~context body =
10861093
let need_zero_divide_handler, need_bound_error_handler = needed_handlers p pc in
10871094
wrap_with_handler
1088-
need_bound_error_handler
1089-
bound_error_pc
1090-
(let* f =
1091-
register_import ~name:"caml_bound_error" (Fun { params = []; result = [] })
1092-
in
1093-
instr (CallInstr (f, [])))
1095+
true
1096+
exception_handler_pc
1097+
(match location with
1098+
| `Toplevel ->
1099+
let* exn =
1100+
register_import
1101+
~import_module:"env"
1102+
~name:"caml_exception"
1103+
(Global { mut = true; typ = Type.value })
1104+
in
1105+
let* tag = register_import ~name:exception_name (Tag Type.value) in
1106+
instr (Throw (tag, GlobalGet exn))
1107+
| `Exception_handler ->
1108+
let* exn =
1109+
register_import
1110+
~import_module:"env"
1111+
~name:"caml_exception"
1112+
(Global { mut = true; typ = Type.value })
1113+
in
1114+
instr (Br (2, Some (GlobalGet exn)))
1115+
| `Function -> instr (Return (Some (RefNull Any))))
10941116
(wrap_with_handler
1095-
need_zero_divide_handler
1096-
zero_divide_pc
1117+
need_bound_error_handler
1118+
bound_error_pc
10971119
(let* f =
1098-
register_import
1099-
~name:"caml_raise_zero_divide"
1100-
(Fun { params = []; result = [] })
1120+
register_import ~name:"caml_bound_error" (Fun { params = []; result = [] })
11011121
in
11021122
instr (CallInstr (f, [])))
1103-
body)
1123+
(wrap_with_handler
1124+
need_zero_divide_handler
1125+
zero_divide_pc
1126+
(let* f =
1127+
register_import
1128+
~name:"caml_raise_zero_divide"
1129+
(Fun { params = []; result = [] })
1130+
in
1131+
instr (CallInstr (f, [])))
1132+
body))
11041133
~result_typ
11051134
~fall_through
11061135
~context
@@ -1208,19 +1237,34 @@ module Generate (Target : Target_sig.S) = struct
12081237
instr (Br_table (e, List.map ~f:dest l, dest a.(len - 1)))
12091238
| Raise (x, _) -> (
12101239
let* e = load x in
1211-
let* tag = register_import ~name:exception_name (Tag Type.value) in
12121240
match fall_through with
12131241
| `Catch -> instr (Push e)
12141242
| `Block _ | `Return | `Skip -> (
12151243
match catch_index context with
12161244
| Some i -> instr (Br (i, Some e))
1217-
| None -> instr (Throw (tag, e))))
1245+
| None ->
1246+
if Option.is_some name_opt
1247+
then
1248+
let* exn =
1249+
register_import
1250+
~import_module:"env"
1251+
~name:"caml_exception"
1252+
(Global { mut = true; typ = Type.value })
1253+
in
1254+
let* () = instr (GlobalSet (exn, e)) in
1255+
instr (Return (Some (RefNull Any)))
1256+
else
1257+
let* tag =
1258+
register_import ~name:exception_name (Tag Type.value)
1259+
in
1260+
instr (Throw (tag, e))))
12181261
| Pushtrap (cont, x, cont') ->
12191262
handle_exceptions
12201263
~result_typ
12211264
~fall_through
12221265
~context:(extend_context fall_through context)
12231266
(wrap_with_handlers
1267+
~location:`Exception_handler
12241268
p
12251269
(fst cont)
12261270
(fun ~result_typ ~fall_through ~context ->
@@ -1292,6 +1336,10 @@ module Generate (Target : Target_sig.S) = struct
12921336
let* () = build_initial_env in
12931337
let* () =
12941338
wrap_with_handlers
1339+
~location:
1340+
(match name_opt with
1341+
| None -> `Toplevel
1342+
| Some _ -> `Function)
12951343
p
12961344
pc
12971345
~result_typ:[ Type.value ]
@@ -1343,7 +1391,9 @@ module Generate (Target : Target_sig.S) = struct
13431391
in
13441392
let* () = instr (Drop (Call (f, []))) in
13451393
cont)
1346-
~init:(instr (Push (RefI31 (Const (I32 0l)))))
1394+
~init:
1395+
(let* u = Value.unit in
1396+
instr (Push u))
13471397
to_link)
13481398
in
13491399
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)