Skip to content

Commit 79e62a4

Browse files
committed
Compiler: propagate arity across unit boundary
- Propagate shape information through the flow analysis
1 parent b702347 commit 79e62a4

File tree

25 files changed

+901
-152
lines changed

25 files changed

+901
-152
lines changed

compiler/bin-js_of_ocaml/build_fs.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function jsoo_create_file_extern(name,content){
7575
let code = Code.prepend Code.empty instr in
7676
Filename.gen_file output_file (fun chan ->
7777
let pfs_fmt = Pretty_print.to_out_channel chan in
78-
let (_ : Source_map.info) =
78+
let (_ : Source_map.info * Shape.t StringMap.t) =
7979
Driver.f
8080
~standalone:true
8181
~wrap_with_fun:`Iife

compiler/bin-js_of_ocaml/cmd_arg.ml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ type t =
6464
; static_env : (string * string) list
6565
; wrap_with_fun : [ `Iife | `Named of string | `Anonymous ]
6666
; target_env : Target_env.t
67+
; shape_files : string list
68+
; write_shape : bool
6769
; (* toplevel *)
6870
dynlink : bool
6971
; linkall : bool
@@ -114,6 +116,14 @@ let options =
114116
let doc = "Set output file name to [$(docv)]." in
115117
Arg.(value & opt (some string) None & info [ "o" ] ~docv:"FILE" ~doc)
116118
in
119+
let shape_files =
120+
let doc = "load shape file [$(docv)]." in
121+
Arg.(value & opt_all string [] & info [ "load-shape" ] ~docv:"FILE" ~doc)
122+
in
123+
let write_shape =
124+
let doc = "Emit shape files" in
125+
Arg.(value & flag & info [ "write-shape" ] ~doc)
126+
in
117127
let input_file =
118128
let doc =
119129
"Compile the bytecode program [$(docv)]. "
@@ -309,7 +319,9 @@ let options =
309319
input_file
310320
js_files
311321
keep_unit_names
312-
effects =
322+
effects
323+
shape_files
324+
write_shape =
313325
let inline_source_content = not sourcemap_don't_inline_content in
314326
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
315327
let runtime_files = js_files in
@@ -380,6 +392,8 @@ let options =
380392
; source_map
381393
; keep_unit_names
382394
; effects
395+
; shape_files
396+
; write_shape
383397
}
384398
in
385399
let t =
@@ -412,7 +426,9 @@ let options =
412426
$ input_file
413427
$ js_files
414428
$ keep_unit_names
415-
$ effects)
429+
$ effects
430+
$ shape_files
431+
$ write_shape)
416432
in
417433
Term.ret t
418434

@@ -633,6 +649,8 @@ let options_runtime_only =
633649
; source_map
634650
; keep_unit_names = false
635651
; effects
652+
; shape_files = []
653+
; write_shape = false
636654
}
637655
in
638656
let t =

compiler/bin-js_of_ocaml/cmd_arg.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ type t =
3737
| `Anonymous
3838
]
3939
; target_env : Target_env.t
40+
; shape_files : string list
41+
; write_shape : bool
4042
; (* toplevel *)
4143
dynlink : bool
4244
; linkall : bool

compiler/bin-js_of_ocaml/compile.ml

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ let source_map_enabled : Source_map.Encoding_spec.t option -> bool = function
4242
| Some _ -> true
4343

4444
let output_gen
45+
~write_shape
4546
~standalone
4647
~custom_header
4748
~build_info
@@ -53,7 +54,15 @@ let output_gen
5354
Driver.configure fmt;
5455
if standalone then header ~custom_header fmt;
5556
if Config.Flag.header () then jsoo_header fmt build_info;
56-
let sm = f ~standalone ~source_map (k, fmt) in
57+
let sm, shapes = f ~standalone ~shapes:write_shape ~source_map (k, fmt) in
58+
(if write_shape
59+
then
60+
match output_file with
61+
| `Stdout -> ()
62+
| `Name name ->
63+
Shape.Store.save'
64+
(Filename.remove_extension name ^ Shape.Store.ext)
65+
(StringMap.bindings shapes));
5766
match source_map, sm with
5867
| None, _ | _, None -> ()
5968
| Some { output_file = output; source_map; keep_empty }, Some sm ->
@@ -71,7 +80,6 @@ let output_gen
7180
Pretty_print.newline fmt;
7281
Pretty_print.string fmt (Printf.sprintf "//# sourceMappingURL=%s\n" urlData)
7382
in
74-
7583
match output_file with
7684
| `Stdout -> f stdout `Stdout
7785
| `Name name -> Filename.gen_file name (fun chan -> f chan `File)
@@ -132,6 +140,11 @@ let sourcemap_of_infos ~base l =
132140

133141
let sourcemap_of_info ~base info = sourcemap_of_infos ~base [ info ]
134142

143+
let map_fst f (x, y) = f x, y
144+
145+
let merge_shape a b =
146+
StringMap.union (fun _name s1 s2 -> if Shape.equal s1 s2 then Some s1 else None) a b
147+
135148
let run
136149
{ Cmd_arg.common
137150
; profile
@@ -156,6 +169,8 @@ let run
156169
; keep_unit_names
157170
; include_runtime
158171
; effects
172+
; shape_files
173+
; write_shape
159174
} =
160175
let source_map_base =
161176
Option.map ~f:(fun spec -> spec.Source_map.Encoding_spec.source_map) source_map
@@ -172,6 +187,7 @@ let run
172187
| `Name _, _ -> ());
173188
List.iter params ~f:(fun (s, v) -> Config.Param.set s v);
174189
List.iter static_env ~f:(fun (s, v) -> Eval.set_static_env s v);
190+
List.iter shape_files ~f:(fun fn -> Shape.Store.load' fn);
175191
let t = Timer.make () in
176192
let include_dirs =
177193
List.filter_map (include_dirs @ [ "+stdlib/" ]) ~f:(fun d -> Findlib.find [] d)
@@ -251,6 +267,7 @@ let run
251267
(one : Parse_bytecode.one)
252268
~check_sourcemap
253269
~standalone
270+
~shapes
254271
~(source_map : Source_map.Encoding_spec.t option)
255272
~link
256273
output_file =
@@ -269,6 +286,7 @@ let run
269286
let code = Code.prepend one.code instr in
270287
Driver.f
271288
~standalone
289+
~shapes
272290
?profile
273291
~link
274292
~wrap_with_fun
@@ -292,6 +310,7 @@ let run
292310
let res =
293311
Driver.f
294312
~standalone
313+
~shapes
295314
?profile
296315
~link
297316
~wrap_with_fun
@@ -313,14 +332,22 @@ let run
313332
let output_partial
314333
(cmo : Cmo_format.compilation_unit)
315334
~standalone
335+
~shapes
316336
~source_map
317337
code
318338
((_, fmt) as output_file) =
319339
assert (not standalone);
320340
let uinfo = Unit_info.of_cmo cmo in
321341
Pretty_print.string fmt "\n";
322342
Pretty_print.string fmt (Unit_info.to_string uinfo);
323-
output code ~check_sourcemap:true ~source_map ~standalone ~link:`No output_file
343+
output
344+
code
345+
~check_sourcemap:true
346+
~source_map
347+
~standalone
348+
~shapes
349+
~link:`No
350+
output_file
324351
in
325352
let output_partial_runtime ~standalone ~source_map ((_, fmt) as output_file) =
326353
assert (not standalone);
@@ -371,22 +398,24 @@ let run
371398
{ code; cmis = StringSet.empty; debug = Parse_bytecode.Debug.default_summary }
372399
in
373400
output_gen
401+
~write_shape
374402
~standalone:true
375403
~custom_header
376404
~build_info:(Build_info.create `Runtime)
377405
~source_map
378406
(fst output_file)
379-
(fun ~standalone ~source_map ((_, fmt) as output_file) ->
407+
(fun ~standalone ~shapes ~source_map ((_, fmt) as output_file) ->
380408
Pretty_print.string fmt "\n";
381409
Pretty_print.string fmt (Unit_info.to_string uinfo);
382410
output
383411
code
384412
~check_sourcemap:false
385413
~source_map
386414
~standalone
415+
~shapes
387416
~link:`All
388417
output_file
389-
|> sourcemap_of_info ~base:source_map_base)
418+
|> map_fst (sourcemap_of_info ~base:source_map_base))
390419
| (`Stdin | `File _) as bytecode ->
391420
let kind, ic, close_ic, include_dirs =
392421
match bytecode with
@@ -419,20 +448,22 @@ let run
419448
in
420449
if times () then Format.eprintf " parsing: %a@." Timer.print t1;
421450
output_gen
451+
~write_shape
422452
~standalone:true
423453
~custom_header
424454
~build_info:(Build_info.create `Exe)
425455
~source_map
426456
(fst output_file)
427-
(fun ~standalone ~source_map output_file ->
457+
(fun ~standalone ~shapes ~source_map output_file ->
428458
output
429459
code
430460
~check_sourcemap:true
431461
~standalone
462+
~shapes
432463
~source_map
433464
~link:(if linkall then `All else `Needed)
434465
output_file
435-
|> sourcemap_of_info ~base:source_map_base)
466+
|> map_fst (sourcemap_of_info ~base:source_map_base))
436467
| `Cmo cmo ->
437468
let output_file =
438469
match output_file, keep_unit_names with
@@ -457,20 +488,26 @@ let run
457488
in
458489
if times () then Format.eprintf " parsing: %a@." Timer.print t1;
459490
output_gen
491+
~write_shape
460492
~standalone:false
461493
~custom_header
462494
~build_info:(Build_info.create `Cmo)
463495
~source_map
464496
output_file
465-
(fun ~standalone ~source_map output ->
497+
(fun ~standalone ~shapes ~source_map output ->
466498
match include_runtime with
467499
| true ->
468-
let sm1 = output_partial_runtime ~standalone ~source_map output in
469-
let sm2 = output_partial cmo code ~standalone ~source_map output in
470-
sourcemap_of_infos ~base:source_map_base [ sm1; sm2 ]
500+
let sm1, sh1 =
501+
output_partial_runtime ~standalone ~shapes ~source_map output
502+
in
503+
let sm2, sh2 =
504+
output_partial cmo code ~standalone ~shapes ~source_map output
505+
in
506+
( sourcemap_of_infos ~base:source_map_base [ sm1; sm2 ]
507+
, merge_shape sh1 sh2 )
471508
| false ->
472-
output_partial cmo code ~standalone ~source_map output
473-
|> sourcemap_of_info ~base:source_map_base)
509+
output_partial cmo code ~standalone ~shapes ~source_map output
510+
|> map_fst (sourcemap_of_info ~base:source_map_base))
474511
| `Cma cma when keep_unit_names ->
475512
(if include_runtime
476513
then
@@ -486,14 +523,15 @@ let run
486523
failwith "use [-o dirname/] or remove [--keep-unit-names]"
487524
in
488525
output_gen
526+
~write_shape
489527
~standalone:false
490528
~custom_header
491529
~build_info:(Build_info.create `Runtime)
492530
~source_map
493531
(`Name output_file)
494-
(fun ~standalone ~source_map output ->
495-
output_partial_runtime ~standalone ~source_map output
496-
|> sourcemap_of_info ~base:source_map_base));
532+
(fun ~standalone ~shapes ~source_map output ->
533+
output_partial_runtime ~standalone ~shapes ~source_map output
534+
|> map_fst (sourcemap_of_info ~base:source_map_base)));
497535
List.iter cma.lib_units ~f:(fun cmo ->
498536
let output_file =
499537
match output_file with
@@ -522,23 +560,26 @@ let run
522560
t1
523561
(Ocaml_compiler.Cmo_format.name cmo);
524562
output_gen
563+
~write_shape
525564
~standalone:false
526565
~custom_header
527566
~build_info:(Build_info.create `Cma)
528567
~source_map
529568
(`Name output_file)
530-
(fun ~standalone ~source_map output ->
531-
output_partial ~standalone ~source_map cmo code output
532-
|> sourcemap_of_info ~base:source_map_base))
569+
(fun ~standalone ~shapes ~source_map output ->
570+
output_partial ~standalone ~shapes ~source_map cmo code output
571+
|> map_fst (sourcemap_of_info ~base:source_map_base)))
533572
| `Cma cma ->
534-
let f ~standalone ~source_map output =
535-
let source_map_runtime =
573+
let f ~standalone ~shapes ~source_map output =
574+
(* Always compute shapes because it can be used by other units of the cma *)
575+
let shapes = shapes || true in
576+
let runtime =
536577
if not include_runtime
537578
then None
538-
else Some (output_partial_runtime ~standalone ~source_map output)
579+
else Some (output_partial_runtime ~standalone ~shapes ~source_map output)
539580
in
540581

541-
let source_map_units =
582+
let units =
542583
List.map cma.lib_units ~f:(fun cmo ->
543584
let t1 = Timer.make () in
544585
let code =
@@ -556,16 +597,22 @@ let run
556597
Timer.print
557598
t1
558599
(Ocaml_compiler.Cmo_format.name cmo);
559-
output_partial ~standalone ~source_map cmo code output)
600+
output_partial ~standalone ~shapes ~source_map cmo code output)
601+
in
602+
let sm_and_shapes =
603+
match runtime with
604+
| None -> units
605+
| Some x -> x :: units
560606
in
561-
let sm =
562-
match source_map_runtime with
563-
| None -> source_map_units
564-
| Some x -> x :: source_map_units
607+
let shapes =
608+
List.fold_left sm_and_shapes ~init:StringMap.empty ~f:(fun acc (_, s) ->
609+
merge_shape s acc)
565610
in
566-
sourcemap_of_infos ~base:source_map_base sm
611+
( sourcemap_of_infos ~base:source_map_base (List.map sm_and_shapes ~f:fst)
612+
, shapes )
567613
in
568614
output_gen
615+
~write_shape
569616
~standalone:false
570617
~custom_header
571618
~build_info:(Build_info.create `Cma)

compiler/bin-wasm_of_ocaml/compile.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ let generate_prelude ~out_file =
245245
let code, uinfo = Parse_bytecode.predefined_exceptions () in
246246
let profile = Profile.O1 in
247247
let Driver.{ program; variable_uses; in_cps; deadcode_sentinal; _ } =
248-
Driver.optimize ~profile code
248+
Driver.optimize ~profile ~shapes:false code
249249
in
250250
let context = Generate.start () in
251251
let _ =
@@ -397,7 +397,7 @@ let run
397397
let code = one.code in
398398
let standalone = Option.is_none unit_name in
399399
let Driver.{ program; variable_uses; in_cps; deadcode_sentinal; _ } =
400-
Driver.optimize ~profile code
400+
Driver.optimize ~profile ~shapes:false code
401401
in
402402
let context = Generate.start () in
403403
let toplevel_name, generated_js =

compiler/lib/config.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ module Flag = struct
106106
let auto_link = o ~name:"auto-link" ~default:true
107107

108108
let es6 = o ~name:"es6" ~default:false
109+
110+
let load_shapes_auto = o ~name:"load-shapes-auto" ~default:false
109111
end
110112

111113
module Param = struct

compiler/lib/config.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ module Flag : sig
7676

7777
val es6 : unit -> bool
7878

79+
val load_shapes_auto : unit -> bool
80+
7981
val enable : string -> unit
8082

8183
val disable : string -> unit

0 commit comments

Comments
 (0)