Skip to content

Commit 39e7279

Browse files
committed
Do not store the code pointer in the closure if we know we don't need it
1 parent 3a653c7 commit 39e7279

File tree

3 files changed

+115
-90
lines changed

3 files changed

+115
-90
lines changed

compiler/lib-wasm/gc_target.ml

Lines changed: 70 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -240,18 +240,7 @@ module Type = struct
240240
then
241241
register_type
242242
(if cps then "cps_closure_0" else "closure_0")
243-
(fun () ->
244-
let* fun_ty' = function_type ~cps arity in
245-
return
246-
{ supertype = None
247-
; final = false
248-
; typ =
249-
W.Struct
250-
[ { mut = false
251-
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
252-
}
253-
]
254-
})
243+
(fun () -> return { supertype = None; final = false; typ = W.Struct [] })
255244
else
256245
register_type
257246
(if cps
@@ -287,30 +276,29 @@ module Type = struct
287276
then Printf.sprintf "cps_env_%d_%d" arity env_type_id
288277
else Printf.sprintf "env_%d_%d" arity env_type_id)
289278
(fun () ->
290-
let* cl_typ = closure_type ~usage:`Alloc ~cps arity in
291-
let* common = closure_common_fields ~cps in
292-
let* fun_ty' = function_type ~cps arity in
293-
return
294-
{ supertype = Some cl_typ
295-
; final = true
296-
; typ =
297-
W.Struct
298-
((if arity = 1
299-
then common
300-
else if arity = 0
301-
then
302-
[ { mut = false
303-
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
304-
}
305-
]
306-
else
307-
common
308-
@ [ { mut = false
309-
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
310-
}
311-
])
312-
@ make_env_type env_type)
313-
})
279+
if arity = 0
280+
then
281+
return
282+
{ supertype = None; final = true; typ = W.Struct (make_env_type env_type) }
283+
else
284+
let* common = closure_common_fields ~cps in
285+
let* cl_typ = closure_type ~usage:`Alloc ~cps arity in
286+
let* fun_ty' = function_type ~cps arity in
287+
return
288+
{ supertype = Some cl_typ
289+
; final = true
290+
; typ =
291+
W.Struct
292+
((if arity = 1
293+
then common
294+
else
295+
common
296+
@ [ { mut = false
297+
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
298+
}
299+
])
300+
@ make_env_type env_type)
301+
})
314302

315303
let rec_env_type ~function_count ~env_type_id ~env_type =
316304
register_type (Printf.sprintf "rec_env_%d_%d" function_count env_type_id) (fun () ->
@@ -334,28 +322,41 @@ module Type = struct
334322
then Printf.sprintf "cps_closure_rec_%d_%d_%d" arity function_count env_type_id
335323
else Printf.sprintf "closure_rec_%d_%d_%d" arity function_count env_type_id)
336324
(fun () ->
337-
let* cl_typ = closure_type ~usage:`Alloc ~cps arity in
338-
let* common = closure_common_fields ~cps in
339-
let* fun_ty' = function_type ~cps arity in
340325
let* env_ty = rec_env_type ~function_count ~env_type_id ~env_type in
341-
return
342-
{ supertype = Some cl_typ
343-
; final = true
344-
; typ =
345-
W.Struct
346-
((if arity = 1
347-
then common
348-
else
349-
common
350-
@ [ { mut = false
351-
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
352-
}
353-
])
354-
@ [ { W.mut = false
326+
if arity = 0
327+
then
328+
return
329+
{ supertype = None
330+
; final = true
331+
; typ =
332+
W.Struct
333+
[ { W.mut = false
355334
; typ = W.Value (Ref { nullable = false; typ = Type env_ty })
356335
}
357-
])
358-
})
336+
]
337+
}
338+
else
339+
let* cl_typ = closure_type ~usage:`Alloc ~cps arity in
340+
let* common = closure_common_fields ~cps in
341+
let* fun_ty' = function_type ~cps arity in
342+
return
343+
{ supertype = Some cl_typ
344+
; final = true
345+
; typ =
346+
W.Struct
347+
((if arity = 1
348+
then common
349+
else
350+
common
351+
@ [ { mut = false
352+
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
353+
}
354+
])
355+
@ [ { W.mut = false
356+
; typ = W.Value (Ref { nullable = false; typ = Type env_ty })
357+
}
358+
])
359+
})
359360

360361
let rec curry_type ~cps arity m =
361362
register_type
@@ -800,7 +801,8 @@ module Memory = struct
800801

801802
let env_start arity =
802803
match arity with
803-
| 0 | 1 -> 1
804+
| 0 -> 0
805+
| 1 -> 1
804806
| _ -> 2
805807

806808
let load_function_pointer ~cps ~arity ?(skip_cast = false) closure =
@@ -1053,7 +1055,7 @@ module Closure = struct
10531055
| [ (g, _) ] -> Code.Var.equal f g
10541056
| _ :: r -> is_last_fun r f
10551057

1056-
let translate ~context ~closures ~cps f =
1058+
let translate ~context ~closures ~cps ~need_pointer f =
10571059
let info = Code.Var.Map.find f closures in
10581060
let free_variables = get_free_variables ~context info in
10591061
assert (
@@ -1062,7 +1064,7 @@ module Closure = struct
10621064
~f:(fun x -> Code.Var.Set.mem x context.globalized_variables)
10631065
free_variables));
10641066
let _, arity = List.find ~f:(fun (f', _) -> Code.Var.equal f f') info.functions in
1065-
let arity = if cps then arity - 1 else arity in
1067+
let arity = if need_pointer then if cps then arity - 1 else arity else 0 in
10661068
let* curry_fun = if arity > 1 then need_curry_fun ~cps ~arity else return f in
10671069
if List.is_empty free_variables
10681070
then
@@ -1075,7 +1077,8 @@ module Closure = struct
10751077
(W.StructNew
10761078
( typ
10771079
, match arity with
1078-
| 0 | 1 -> [ W.RefFunc f ]
1080+
| 0 -> []
1081+
| 1 -> [ W.RefFunc f ]
10791082
| _ -> [ RefFunc curry_fun; RefFunc f ] ))
10801083
in
10811084
return (W.GlobalGet name)
@@ -1098,7 +1101,8 @@ module Closure = struct
10981101
(W.StructNew
10991102
( typ
11001103
, (match arity with
1101-
| 0 | 1 -> [ W.RefFunc f ]
1104+
| 0 -> []
1105+
| 1 -> [ W.RefFunc f ]
11021106
| _ -> [ RefFunc curry_fun; RefFunc f ])
11031107
@ l ))
11041108
| (g, _) :: _ as functions ->
@@ -1132,9 +1136,10 @@ module Closure = struct
11321136
return
11331137
(W.StructNew
11341138
( typ
1135-
, (if arity = 1
1136-
then [ W.RefFunc f ]
1137-
else [ RefFunc curry_fun; RefFunc f ])
1139+
, (match arity with
1140+
| 0 -> []
1141+
| 1 -> [ W.RefFunc f ]
1142+
| _ -> [ RefFunc curry_fun; RefFunc f ])
11381143
@ [ env ] ))
11391144
in
11401145
if is_last_fun functions f
@@ -1155,7 +1160,7 @@ module Closure = struct
11551160
(load f)
11561161
else res
11571162

1158-
let bind_environment ~context ~closures ~cps f =
1163+
let bind_environment ~context ~closures ~cps ~need_pointer f =
11591164
let info = Code.Var.Map.find f closures in
11601165
let free_variables = get_free_variables ~context info in
11611166
let free_variable_count = List.length free_variables in
@@ -1167,7 +1172,7 @@ module Closure = struct
11671172
else
11681173
let env_type_id = Option.value ~default:(-1) info.id in
11691174
let _, arity = List.find ~f:(fun (f', _) -> Code.Var.equal f f') info.functions in
1170-
let arity = if cps then arity - 1 else arity in
1175+
let arity = if need_pointer then if cps then arity - 1 else arity else 0 in
11711176
let offset = Memory.env_start arity in
11721177
match info.Closure_conversion.functions with
11731178
| [ _ ] ->

compiler/lib-wasm/generate.ml

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module Generate (Target : Target_sig.S) = struct
3737
; in_cps : Effects.in_cps
3838
; deadcode_sentinal : Var.t
3939
; global_flow_info : Global_flow.info
40+
; fun_info : Call_graph_analysis.t
4041
; types : Typing.typ Var.Tbl.t
4142
; blocks : block Addr.Map.t
4243
; closures : Closure_conversion.closure Var.Map.t
@@ -791,35 +792,40 @@ module Generate (Target : Target_sig.S) = struct
791792
let rec loop acc l =
792793
match l with
793794
| [] -> (
794-
let arity = List.length args in
795-
let funct = Var.fresh () in
796-
let* closure = tee funct (load f) in
797-
let* ty, funct =
798-
Memory.load_function_pointer
799-
~cps:(Var.Set.mem x ctx.in_cps)
800-
~arity
801-
(load funct)
802-
in
803795
let* b = is_closure f in
804796
if b
805-
then return (W.Call (f, List.rev (closure :: acc)))
797+
then
798+
let* closure = load f in
799+
return (W.Call (f, List.rev (closure :: acc)))
806800
else
807-
match funct with
808-
| W.RefFunc g ->
809-
(* Functions with constant closures ignore their
810-
environment. In case of partial application, we
811-
still need the closure. *)
812-
let* cl = if exact then Value.unit else return closure in
801+
match
802+
if exact
803+
then Global_flow.get_unique_closure ctx.global_flow_info f
804+
else None
805+
with
806+
| Some g ->
807+
let* closure = load f in
808+
let* cl =
809+
(* Functions with constant closures ignore their
810+
environment. *)
811+
match closure with
812+
| GlobalGet _ -> Value.unit
813+
| _ -> return closure
814+
in
813815
return (W.Call (g, List.rev (cl :: acc)))
814-
| _ -> (
815-
match
816-
if exact
817-
then Global_flow.get_unique_closure ctx.global_flow_info f
818-
else None
819-
with
820-
| Some g -> return (W.Call (g, List.rev (closure :: acc)))
821-
| None -> return (W.Call_ref (ty, funct, List.rev (closure :: acc)))
822-
))
816+
| None -> (
817+
let arity = List.length args in
818+
let funct = Var.fresh () in
819+
let* closure = tee funct (load f) in
820+
let* ty, funct =
821+
Memory.load_function_pointer
822+
~cps:(Var.Set.mem x ctx.in_cps)
823+
~arity
824+
(load funct)
825+
in
826+
match funct with
827+
| W.RefFunc g -> return (W.Call (g, List.rev (closure :: acc)))
828+
| _ -> return (W.Call_ref (ty, funct, List.rev (closure :: acc)))))
823829
| x :: r ->
824830
let* x = load_and_box ctx x in
825831
loop (x :: acc) r
@@ -848,6 +854,10 @@ module Generate (Target : Target_sig.S) = struct
848854
~context:ctx.global_context
849855
~closures:ctx.closures
850856
~cps:(Var.Set.mem x ctx.in_cps)
857+
~need_pointer:
858+
(not
859+
(Config.Flag.optcall ()
860+
&& Var.Hashtbl.mem ctx.fun_info.unambiguous_non_escaping x))
851861
x
852862
| Constant c -> Constant.translate c
853863
| Special (Alias_prim _) -> assert false
@@ -1272,6 +1282,10 @@ module Generate (Target : Target_sig.S) = struct
12721282
~context:ctx.global_context
12731283
~closures:ctx.closures
12741284
~cps:(Var.Set.mem f ctx.in_cps)
1285+
~need_pointer:
1286+
(not
1287+
(Config.Flag.optcall ()
1288+
&& Var.Hashtbl.mem ctx.fun_info.unambiguous_non_escaping f))
12751289
f
12761290
| None -> return ()
12771291
in
@@ -1401,6 +1415,7 @@ module Generate (Target : Target_sig.S) = struct
14011415
*)
14021416
~deadcode_sentinal
14031417
~global_flow_info
1418+
~fun_info
14041419
~types =
14051420
global_context.unit_name <- unit_name;
14061421
let p, closures = Closure_conversion.f p in
@@ -1412,6 +1427,7 @@ module Generate (Target : Target_sig.S) = struct
14121427
; in_cps
14131428
; deadcode_sentinal
14141429
; global_flow_info
1430+
; fun_info
14151431
; types
14161432
; blocks = p.blocks
14171433
; closures
@@ -1521,6 +1537,7 @@ let start () = make_context ~value_type:Gc_target.Type.value
15211537

15221538
let f ~context ~unit_name p ~live_vars ~in_cps ~deadcode_sentinal ~global_flow_data =
15231539
let state, info = global_flow_data in
1540+
let fun_info = Call_graph_analysis.f p info in
15241541
let types = Typing.f ~state ~info ~deadcode_sentinal p in
15251542
let t = Timer.make () in
15261543
let p = fix_switch_branches p in
@@ -1532,6 +1549,7 @@ let f ~context ~unit_name p ~live_vars ~in_cps ~deadcode_sentinal ~global_flow_d
15321549
~in_cps
15331550
~deadcode_sentinal
15341551
~global_flow_info:info
1552+
~fun_info
15351553
~types
15361554
p
15371555
in

compiler/lib-wasm/target_sig.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,15 @@ module type S = sig
174174
context:Code_generation.context
175175
-> closures:Closure_conversion.closure Code.Var.Map.t
176176
-> cps:bool
177+
-> need_pointer:bool
177178
-> Code.Var.t
178179
-> expression
179180

180181
val bind_environment :
181182
context:Code_generation.context
182183
-> closures:Closure_conversion.closure Code.Var.Map.t
183184
-> cps:bool
185+
-> need_pointer:bool
184186
-> Code.Var.t
185187
-> unit Code_generation.t
186188

0 commit comments

Comments
 (0)