@@ -38,6 +38,7 @@ module Generate (Target : Target_sig.S) = struct
3838 ; global_flow_info : Global_flow .info
3939 ; fun_info : Call_graph_analysis .t
4040 ; types : Typing .t
41+ ; raising_funcs : unit Var.Hashtbl .t
4142 ; blocks : block Addr.Map .t
4243 ; closures : Closure_conversion .closure Var.Map .t
4344 ; global_context : Code_generation .context
@@ -1342,6 +1343,19 @@ module Generate (Target : Target_sig.S) = struct
13421343 | Number (n , Boxed) as into -> convert ~from: (Number (n, Unboxed )) ~into e
13431344 | _ -> e
13441345
1346+ let exception_handler_pc = - 3
1347+
1348+ let direct_call ctx context f args closure =
1349+ let e = W. Call (f, args @ [ closure ]) in
1350+ let e =
1351+ if Var.Hashtbl. mem ctx.raising_funcs f
1352+ then
1353+ let label = label_index context exception_handler_pc in
1354+ W. Br_on_null (label, e)
1355+ else e
1356+ in
1357+ return e
1358+
13451359 let rec translate_expr ctx context x e =
13461360 match e with
13471361 | Apply { f; args; exact; _ } ->
@@ -1375,7 +1389,7 @@ module Generate (Target : Target_sig.S) = struct
13751389 convert
13761390 ~from: (Typing. return_type ctx.types g)
13771391 ~into: (Typing. var_type ctx.types x)
1378- (return ( W. Call (g, args @ [ cl ])) )
1392+ (direct_call ctx context g args cl )
13791393 | None -> (
13801394 let funct = Var. fresh () in
13811395 let * closure = tee funct (return closure) in
@@ -1387,7 +1401,7 @@ module Generate (Target : Target_sig.S) = struct
13871401 in
13881402 let * args = expression_list (fun x -> load_and_box ctx x) args in
13891403 match funct with
1390- | W. RefFunc g -> return ( W. Call (g, args @ [ closure ]))
1404+ | W. RefFunc g -> direct_call ctx context g args closure
13911405 | _ -> return (W. Call_ref (ty, funct, args @ [ closure ])))
13921406 else
13931407 let * apply =
@@ -1694,25 +1708,47 @@ module Generate (Target : Target_sig.S) = struct
16941708 instr W. Unreachable
16951709 else body ~result_typ ~fall_through ~context
16961710
1697- let wrap_with_handlers p pc ~result_typ ~fall_through ~context body =
1711+ let wrap_with_handlers ~ location p pc ~result_typ ~fall_through ~context body =
16981712 let need_zero_divide_handler, need_bound_error_handler = needed_handlers p pc in
16991713 wrap_with_handler
1700- need_bound_error_handler
1701- bound_error_pc
1702- (let * f =
1703- register_import ~name: " caml_bound_error" (Fun { params = [] ; result = [] })
1704- in
1705- instr (CallInstr (f, [] )))
1714+ true
1715+ exception_handler_pc
1716+ (match location with
1717+ | `Toplevel ->
1718+ let * exn =
1719+ register_import
1720+ ~import_module: " env"
1721+ ~name: " caml_exception"
1722+ (Global { mut = true ; typ = Type. value })
1723+ in
1724+ let * tag = register_import ~name: exception_name (Tag Type. value) in
1725+ instr (Throw (tag, GlobalGet exn ))
1726+ | `Exception_handler ->
1727+ let * exn =
1728+ register_import
1729+ ~import_module: " env"
1730+ ~name: " caml_exception"
1731+ (Global { mut = true ; typ = Type. value })
1732+ in
1733+ instr (Br (2 , Some (GlobalGet exn )))
1734+ | `Function -> instr (Return (Some (RefNull Any ))))
17061735 (wrap_with_handler
1707- need_zero_divide_handler
1708- zero_divide_pc
1736+ need_bound_error_handler
1737+ bound_error_pc
17091738 (let * f =
1710- register_import
1711- ~name: " caml_raise_zero_divide"
1712- (Fun { params = [] ; result = [] })
1739+ register_import ~name: " caml_bound_error" (Fun { params = [] ; result = [] })
17131740 in
17141741 instr (CallInstr (f, [] )))
1715- body)
1742+ (wrap_with_handler
1743+ need_zero_divide_handler
1744+ zero_divide_pc
1745+ (let * f =
1746+ register_import
1747+ ~name: " caml_raise_zero_divide"
1748+ (Fun { params = [] ; result = [] })
1749+ in
1750+ instr (CallInstr (f, [] )))
1751+ body))
17161752 ~result_typ
17171753 ~fall_through
17181754 ~context
@@ -1732,6 +1768,11 @@ module Generate (Target : Target_sig.S) = struct
17321768 | Some f -> Typing. return_type ctx.types f
17331769 | _ -> Typing. Top
17341770 in
1771+ let return_exn =
1772+ match name_opt with
1773+ | Some f -> Var.Hashtbl. mem ctx.raising_funcs f
1774+ | _ -> false
1775+ in
17351776 let g = Structure. build_graph ctx.blocks pc in
17361777 let dom = Structure. dominator_tree g in
17371778 let rec translate_tree result_typ fall_through pc context =
@@ -1830,19 +1871,34 @@ module Generate (Target : Target_sig.S) = struct
18301871 instr (Br_table (e, List. map ~f: dest l, dest a.(len - 1 )))
18311872 | Raise (x , _ ) -> (
18321873 let * e = load x in
1833- let * tag = register_import ~name: exception_name (Tag Type. value) in
18341874 match fall_through with
18351875 | `Catch -> instr (Push e)
18361876 | `Block _ | `Return | `Skip -> (
18371877 match catch_index context with
18381878 | Some i -> instr (Br (i, Some e))
1839- | None -> instr (Throw (tag, e))))
1879+ | None ->
1880+ if return_exn
1881+ then
1882+ let * exn =
1883+ register_import
1884+ ~import_module: " env"
1885+ ~name: " caml_exception"
1886+ (Global { mut = true ; typ = Type. value })
1887+ in
1888+ let * () = instr (GlobalSet (exn , e)) in
1889+ instr (Return (Some (RefNull Any )))
1890+ else
1891+ let * tag =
1892+ register_import ~name: exception_name (Tag Type. value)
1893+ in
1894+ instr (Throw (tag, e))))
18401895 | Pushtrap (cont , x , cont' ) ->
18411896 handle_exceptions
18421897 ~result_typ
18431898 ~fall_through
18441899 ~context: (extend_context fall_through context)
18451900 (wrap_with_handlers
1901+ ~location: `Exception_handler
18461902 p
18471903 (fst cont)
18481904 (fun ~result_typ ~fall_through ~context ->
@@ -1914,6 +1970,7 @@ module Generate (Target : Target_sig.S) = struct
19141970 let * () = build_initial_env in
19151971 let * () =
19161972 wrap_with_handlers
1973+ ~location: (if return_exn then `Function else `Toplevel )
19171974 p
19181975 pc
19191976 ~result_typ: [ Option. value ~default: Type. value (unboxed_type return_type) ]
@@ -1951,7 +2008,11 @@ module Generate (Target : Target_sig.S) = struct
19512008 (unboxed_type (Typing. var_type ctx.types x)))
19522009 params
19532010 @ [ Type. value ]
1954- ; result = [ Option. value ~default: Type. value (unboxed_type return_type) ]
2011+ ; result =
2012+ [ Option. value
2013+ ~default: (if return_exn then Type. value_or_exn else Type. value)
2014+ (unboxed_type return_type)
2015+ ]
19552016 }
19562017 else Type. func_type (param_count - 1 ))
19572018 ; param_names
@@ -2026,7 +2087,8 @@ module Generate (Target : Target_sig.S) = struct
20262087*)
20272088 ~global_flow_info
20282089 ~fun_info
2029- ~types =
2090+ ~types
2091+ ~raising_funcs =
20302092 global_context.unit_name < - unit_name;
20312093 let p, closures = Closure_conversion. f p in
20322094 (*
@@ -2038,6 +2100,7 @@ module Generate (Target : Target_sig.S) = struct
20382100 ; global_flow_info
20392101 ; fun_info
20402102 ; types
2103+ ; raising_funcs
20412104 ; blocks = p.blocks
20422105 ; closures
20432106 ; global_context
@@ -2150,11 +2213,26 @@ let f ~context ~unit_name p ~live_vars ~in_cps ~deadcode_sentinal ~global_flow_d
21502213 let types =
21512214 Typing. f ~global_flow_state ~global_flow_info ~fun_info ~deadcode_sentinal p
21522215 in
2216+ let raising_funcs =
2217+ Call_graph_analysis. raising_functions p global_flow_info fun_info (fun f ->
2218+ match Typing. return_type types f with
2219+ | Int (Normalized | Unnormalized ) | Number (_ , Unboxed) -> false
2220+ | Int Ref | Number (_ , Boxed ) | Top | Bot | Tuple _ | Bigarray _ -> true )
2221+ in
21532222 let t = Timer. make () in
21542223 let p = Structure. norm p in
21552224 let p = fix_switch_branches p in
21562225 let res =
2157- G. f ~context ~unit_name ~live_vars ~in_cps ~global_flow_info ~fun_info ~types p
2226+ G. f
2227+ ~context
2228+ ~unit_name
2229+ ~live_vars
2230+ ~in_cps
2231+ ~global_flow_info
2232+ ~fun_info
2233+ ~types
2234+ ~raising_funcs
2235+ p
21582236 in
21592237 if times () then Format. eprintf " code gen.: %a@." Timer. print t;
21602238 res
0 commit comments