Skip to content

Commit 82f929d

Browse files
committed
Do not store the code pointer in the closure if we know we don't need it
1 parent aa9def0 commit 82f929d

File tree

3 files changed

+170
-119
lines changed

3 files changed

+170
-119
lines changed

compiler/lib-wasm/gc_target.ml

Lines changed: 134 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -281,36 +281,41 @@ module Type = struct
281281
})
282282
env_type
283283

284-
let env_type ~cps ~arity ~env_type_id ~env_type =
284+
let env_type ~cps ~arity ~no_code_pointer ~env_type_id ~env_type =
285285
register_type
286286
(if cps
287287
then Printf.sprintf "cps_env_%d_%d" arity env_type_id
288288
else Printf.sprintf "env_%d_%d" arity env_type_id)
289289
(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
290+
if no_code_pointer
291+
then
292+
return
293+
{ supertype = None; final = true; typ = W.Struct (make_env_type env_type) }
294+
else
295+
let* cl_typ = closure_type ~usage:`Alloc ~cps arity in
296+
let* common = closure_common_fields ~cps in
297+
let* fun_ty' = function_type ~cps arity in
298+
return
299+
{ supertype = Some cl_typ
300+
; final = true
301+
; typ =
302+
W.Struct
303+
((if arity = 1
304+
then common
305+
else if arity = 0
306+
then
307+
[ { mut = false
309308
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
310309
}
311-
])
312-
@ make_env_type env_type)
313-
})
310+
]
311+
else
312+
common
313+
@ [ { mut = false
314+
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
315+
}
316+
])
317+
@ make_env_type env_type)
318+
})
314319

315320
let rec_env_type ~function_count ~env_type_id ~env_type =
316321
register_type (Printf.sprintf "rec_env_%d_%d" function_count env_type_id) (fun () ->
@@ -328,34 +333,48 @@ module Type = struct
328333
@ make_env_type env_type)
329334
})
330335

331-
let rec_closure_type ~cps ~arity ~function_count ~env_type_id ~env_type =
336+
let rec_closure_type ~cps ~arity ~no_code_pointer ~function_count ~env_type_id ~env_type
337+
=
332338
register_type
333339
(if cps
334340
then Printf.sprintf "cps_closure_rec_%d_%d_%d" arity function_count env_type_id
335341
else Printf.sprintf "closure_rec_%d_%d_%d" arity function_count env_type_id)
336342
(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
340343
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
344+
if no_code_pointer
345+
then
346+
return
347+
{ supertype = None
348+
; final = true
349+
; typ =
350+
W.Struct
351+
[ { W.mut = false
355352
; typ = W.Value (Ref { nullable = false; typ = Type env_ty })
356353
}
357-
])
358-
})
354+
]
355+
}
356+
else
357+
let* cl_typ = closure_type ~usage:`Alloc ~cps arity in
358+
let* common = closure_common_fields ~cps in
359+
let* fun_ty' = function_type ~cps arity in
360+
return
361+
{ supertype = Some cl_typ
362+
; final = true
363+
; typ =
364+
W.Struct
365+
((if arity = 1
366+
then common
367+
else
368+
common
369+
@ [ { mut = false
370+
; typ = Value (Ref { nullable = false; typ = Type fun_ty' })
371+
}
372+
])
373+
@ [ { W.mut = false
374+
; typ = W.Value (Ref { nullable = false; typ = Type env_ty })
375+
}
376+
])
377+
})
359378

360379
let rec curry_type ~cps arity m =
361380
register_type
@@ -798,25 +817,35 @@ module Memory = struct
798817

799818
let set_field e idx e' = wasm_array_set e (Arith.const (Int32.of_int (idx + 1))) e'
800819

801-
let env_start arity =
802-
match arity with
803-
| 0 | 1 -> 1
804-
| _ -> 2
820+
let env_start ~no_code_pointer arity =
821+
if no_code_pointer
822+
then 0
823+
else
824+
match arity with
825+
| 0 | 1 -> 1
826+
| _ -> 2
805827

806828
let load_function_pointer ~cps ~arity ?(skip_cast = false) closure =
807829
let arity = if cps then arity - 1 else arity in
808830
let* ty = Type.closure_type ~usage:`Access ~cps arity in
809831
let* fun_ty = Type.function_type ~cps arity in
810832
let casted_closure = if skip_cast then closure else wasm_cast ty closure in
811-
let* e = wasm_struct_get ty casted_closure (env_start arity - 1) in
833+
let* e =
834+
wasm_struct_get ty casted_closure (env_start ~no_code_pointer:false arity - 1)
835+
in
812836
return (fun_ty, e)
813837

814838
let load_real_closure ~cps ~arity closure =
815839
let arity = if cps then arity - 1 else arity in
816840
let* ty = Type.dummy_closure_type ~cps ~arity in
817841
let* cl_typ = Type.closure_type ~usage:`Access ~cps arity in
818842
let* e =
819-
wasm_cast cl_typ (wasm_struct_get ty (wasm_cast ty closure) (env_start arity))
843+
wasm_cast
844+
cl_typ
845+
(wasm_struct_get
846+
ty
847+
(wasm_cast ty closure)
848+
(env_start ~no_code_pointer:false arity))
820849
in
821850
return (cl_typ, e)
822851

@@ -1053,7 +1082,7 @@ module Closure = struct
10531082
| [ (g, _) ] -> Code.Var.equal f g
10541083
| _ :: r -> is_last_fun r f
10551084

1056-
let translate ~context ~closures ~cps f =
1085+
let translate ~context ~closures ~cps ~no_code_pointer f =
10571086
let info = Code.Var.Map.find f closures in
10581087
let free_variables = get_free_variables ~context info in
10591088
assert (
@@ -1062,23 +1091,29 @@ module Closure = struct
10621091
~f:(fun x -> Code.Var.Set.mem x context.globalized_variables)
10631092
free_variables));
10641093
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
1094+
let arity = if no_code_pointer then 0 else if cps then arity - 1 else arity in
10661095
let* curry_fun = if arity > 1 then need_curry_fun ~cps ~arity else return f in
10671096
if List.is_empty free_variables
10681097
then
1069-
let* typ = Type.closure_type ~usage:`Alloc ~cps arity in
1070-
let name = Code.Var.fork f in
1071-
let* () =
1072-
register_global
1073-
name
1074-
{ mut = false; typ = Type.value }
1075-
(W.StructNew
1076-
( typ
1077-
, match arity with
1078-
| 0 | 1 -> [ W.RefFunc f ]
1079-
| _ -> [ RefFunc curry_fun; RefFunc f ] ))
1080-
in
1081-
return (W.GlobalGet name)
1098+
if no_code_pointer
1099+
then Value.unit
1100+
else
1101+
let* typ = Type.closure_type ~usage:`Alloc ~cps arity in
1102+
let name = Code.Var.fork f in
1103+
let* () =
1104+
register_global
1105+
name
1106+
{ mut = false; typ = Type.value }
1107+
(W.StructNew
1108+
( typ
1109+
, if no_code_pointer
1110+
then []
1111+
else
1112+
match arity with
1113+
| 0 | 1 -> [ W.RefFunc f ]
1114+
| _ -> [ RefFunc curry_fun; RefFunc f ] ))
1115+
in
1116+
return (W.GlobalGet name)
10821117
else
10831118
let* env_type = expression_list variable_type free_variables in
10841119
let env_type_id =
@@ -1092,14 +1127,17 @@ module Closure = struct
10921127
match info.Closure_conversion.functions with
10931128
| [] -> assert false
10941129
| [ _ ] ->
1095-
let* typ = Type.env_type ~cps ~arity ~env_type_id ~env_type in
1130+
let* typ = Type.env_type ~cps ~arity ~no_code_pointer ~env_type_id ~env_type in
10961131
let* l = expression_list load free_variables in
10971132
return
10981133
(W.StructNew
10991134
( typ
1100-
, (match arity with
1101-
| 0 | 1 -> [ W.RefFunc f ]
1102-
| _ -> [ RefFunc curry_fun; RefFunc f ])
1135+
, (if no_code_pointer
1136+
then []
1137+
else
1138+
match arity with
1139+
| 0 | 1 -> [ W.RefFunc f ]
1140+
| _ -> [ RefFunc curry_fun; RefFunc f ])
11031141
@ l ))
11041142
| (g, _) :: _ as functions ->
11051143
let function_count = List.length functions in
@@ -1125,16 +1163,25 @@ module Closure = struct
11251163
load env
11261164
in
11271165
let* typ =
1128-
Type.rec_closure_type ~cps ~arity ~function_count ~env_type_id ~env_type
1166+
Type.rec_closure_type
1167+
~cps
1168+
~arity
1169+
~no_code_pointer
1170+
~function_count
1171+
~env_type_id
1172+
~env_type
11291173
in
11301174
let res =
11311175
let* env = env in
11321176
return
11331177
(W.StructNew
11341178
( typ
1135-
, (if arity = 1
1136-
then [ W.RefFunc f ]
1137-
else [ RefFunc curry_fun; RefFunc f ])
1179+
, (if no_code_pointer
1180+
then []
1181+
else
1182+
match arity with
1183+
| 0 | 1 -> [ W.RefFunc f ]
1184+
| _ -> [ RefFunc curry_fun; RefFunc f ])
11381185
@ [ env ] ))
11391186
in
11401187
if is_last_fun functions f
@@ -1155,23 +1202,24 @@ module Closure = struct
11551202
(load f)
11561203
else res
11571204

1158-
let bind_environment ~context ~closures ~cps f =
1205+
let bind_environment ~context ~closures ~cps ~no_code_pointer f =
11591206
let info = Code.Var.Map.find f closures in
11601207
let free_variables = get_free_variables ~context info in
1161-
let free_variable_count = List.length free_variables in
1162-
if free_variable_count = 0
1208+
if List.is_empty free_variables
11631209
then
11641210
(* The closures are all constants and the environment is empty. *)
11651211
let* _ = add_var (Code.Var.fresh ()) in
11661212
return ()
11671213
else
11681214
let env_type_id = Option.value ~default:(-1) info.id in
11691215
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
1171-
let offset = Memory.env_start arity in
1216+
let arity = if no_code_pointer then 0 else if cps then arity - 1 else arity in
1217+
let offset = Memory.env_start ~no_code_pointer arity in
11721218
match info.Closure_conversion.functions with
11731219
| [ _ ] ->
1174-
let* typ = Type.env_type ~cps ~arity ~env_type_id ~env_type:[] in
1220+
let* typ =
1221+
Type.env_type ~cps ~arity ~no_code_pointer ~env_type_id ~env_type:[]
1222+
in
11751223
let* _ = add_var f in
11761224
let env = Code.Var.fresh_n "env" in
11771225
let* () =
@@ -1191,7 +1239,13 @@ module Closure = struct
11911239
| functions ->
11921240
let function_count = List.length functions in
11931241
let* typ =
1194-
Type.rec_closure_type ~cps ~arity ~function_count ~env_type_id ~env_type:[]
1242+
Type.rec_closure_type
1243+
~cps
1244+
~arity
1245+
~no_code_pointer
1246+
~function_count
1247+
~env_type_id
1248+
~env_type:[]
11951249
in
11961250
let* _ = add_var f in
11971251
let env = Code.Var.fresh_n "env" in
@@ -1231,7 +1285,7 @@ module Closure = struct
12311285
else Type.curry_type ~cps arity (m + 1)
12321286
in
12331287
let cast e = if m = 2 then Memory.wasm_cast ty e else e in
1234-
let offset = Memory.env_start 1 in
1288+
let offset = Memory.env_start ~no_code_pointer:false 1 in
12351289
return
12361290
( Memory.wasm_struct_get ty (cast (load closure)) (offset + 1)
12371291
, Memory.wasm_struct_get ty (cast (load closure)) offset

0 commit comments

Comments
 (0)