Skip to content

Commit cdf9133

Browse files
committed
Compiler: propagate arity across unit boundary
Propagate shape information through the flow analysis Function arity from shapes: take advantage of flow analysis control write-shape
1 parent 9cfbfc4 commit cdf9133

28 files changed

+2907
-2477
lines changed

compiler/bin-js_of_ocaml/build_fs.ml

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

compiler/bin-js_of_ocaml/cmd_arg.ml

+18
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ type t =
5353
; static_env : (string * string) list
5454
; wrap_with_fun : [ `Iife | `Named of string | `Anonymous ]
5555
; target_env : Target_env.t
56+
; shape_files : string list
57+
; write_shape : bool
5658
; (* toplevel *)
5759
dynlink : bool
5860
; linkall : bool
@@ -102,6 +104,14 @@ let options =
102104
let doc = "Set output file name to [$(docv)]." in
103105
Arg.(value & opt (some string) None & info [ "o" ] ~docv:"FILE" ~doc)
104106
in
107+
let shape_files =
108+
let doc = "load shape file [$(docv)]." in
109+
Arg.(value & opt_all string [] & info [ "load-shape" ] ~docv:"FILE" ~doc)
110+
in
111+
let write_shape =
112+
let doc = "Emit shape files" in
113+
Arg.(value & flag & info [ "write-shape" ] ~doc)
114+
in
105115
let input_file =
106116
let doc =
107117
"Compile the bytecode program [$(docv)]. "
@@ -279,6 +289,8 @@ let options =
279289
output_file
280290
input_file
281291
js_files
292+
shape_files
293+
write_shape
282294
keep_unit_names =
283295
let inline_source_content = not sourcemap_don't_inline_content in
284296
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
@@ -341,6 +353,8 @@ let options =
341353
; bytecode
342354
; source_map
343355
; keep_unit_names
356+
; shape_files
357+
; write_shape
344358
}
345359
in
346360
let t =
@@ -371,6 +385,8 @@ let options =
371385
$ output_file
372386
$ input_file
373387
$ js_files
388+
$ shape_files
389+
$ write_shape
374390
$ keep_unit_names)
375391
in
376392
Term.ret t
@@ -567,6 +583,8 @@ let options_runtime_only =
567583
; bytecode = `None
568584
; source_map
569585
; keep_unit_names = false
586+
; shape_files = []
587+
; write_shape = false
570588
}
571589
in
572590
let t =

compiler/bin-js_of_ocaml/cmd_arg.mli

+2
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

+52-18
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,28 @@ let source_map_enabled = function
4646
| No_sourcemap -> false
4747
| Inline | File _ -> true
4848

49-
let output_gen ~standalone ~custom_header ~build_info ~source_map output_file f =
49+
let output_gen
50+
~write_shape
51+
~standalone
52+
~custom_header
53+
~build_info
54+
~source_map
55+
output_file
56+
f =
5057
let f chan k =
5158
let fmt = Pretty_print.to_out_channel chan in
5259
Driver.configure fmt;
5360
if standalone then header ~custom_header fmt;
5461
if Config.Flag.header () then jsoo_header fmt build_info;
55-
let sm = f ~standalone ~source_map (k, fmt) in
62+
let sm, shapes = f ~standalone ~source_map (k, fmt) in
63+
(if write_shape
64+
then
65+
match output_file with
66+
| `Stdout -> ()
67+
| `Name name ->
68+
Shape.Store.save'
69+
(Filename.remove_extension name ^ Shape.Store.ext)
70+
(StringMap.bindings shapes));
5671
match source_map, sm with
5772
| No_sourcemap, _ | _, None -> ()
5873
| ((Inline | File _) as output), Some sm ->
@@ -70,7 +85,6 @@ let output_gen ~standalone ~custom_header ~build_info ~source_map output_file f
7085
Pretty_print.newline fmt;
7186
Pretty_print.string fmt (Printf.sprintf "//# sourceMappingURL=%s\n" urlData)
7287
in
73-
7488
match output_file with
7589
| `Stdout -> f stdout `Stdout
7690
| `Name name -> Filename.gen_file name (fun chan -> f chan `File)
@@ -130,6 +144,11 @@ let sourcemap_of_infos ~base l =
130144

131145
let sourcemap_of_info ~base info = sourcemap_of_infos ~base [ info ]
132146

147+
let map_fst f (x, y) = f x, y
148+
149+
let merge_shape a b =
150+
StringMap.union (fun _name s1 s2 -> if Shape.equal s1 s2 then Some s1 else None) a b
151+
133152
let run
134153
{ Cmd_arg.common
135154
; profile
@@ -153,6 +172,8 @@ let run
153172
; export_file
154173
; keep_unit_names
155174
; include_runtime
175+
; shape_files
176+
; write_shape
156177
} =
157178
let source_map_base = Option.map ~f:snd source_map in
158179
let source_map =
@@ -172,6 +193,7 @@ let run
172193
| `Name _, _ -> ());
173194
List.iter params ~f:(fun (s, v) -> Config.Param.set s v);
174195
List.iter static_env ~f:(fun (s, v) -> Eval.set_static_env s v);
196+
List.iter shape_files ~f:(fun fn -> Shape.Store.load' fn);
175197
let t = Timer.make () in
176198
let include_dirs =
177199
List.filter_map (include_dirs @ [ "+stdlib/" ]) ~f:(fun d -> Findlib.find [] d)
@@ -366,6 +388,7 @@ let run
366388
}
367389
in
368390
output_gen
391+
~write_shape
369392
~standalone:true
370393
~custom_header
371394
~build_info:(Build_info.create `Runtime)
@@ -381,7 +404,7 @@ let run
381404
~standalone
382405
~link:`All
383406
output_file
384-
|> sourcemap_of_info ~base:source_map_base)
407+
|> map_fst (sourcemap_of_info ~base:source_map_base))
385408
| (`Stdin | `File _) as bytecode ->
386409
let kind, ic, close_ic, include_dirs =
387410
match bytecode with
@@ -414,6 +437,7 @@ let run
414437
in
415438
if times () then Format.eprintf " parsing: %a@." Timer.print t1;
416439
output_gen
440+
~write_shape
417441
~standalone:true
418442
~custom_header
419443
~build_info:(Build_info.create `Exe)
@@ -427,7 +451,7 @@ let run
427451
~source_map
428452
~link:(if linkall then `All else `Needed)
429453
output_file
430-
|> sourcemap_of_info ~base:source_map_base)
454+
|> map_fst (sourcemap_of_info ~base:source_map_base))
431455
| `Cmo cmo ->
432456
let output_file =
433457
match output_file, keep_unit_names with
@@ -452,6 +476,7 @@ let run
452476
in
453477
if times () then Format.eprintf " parsing: %a@." Timer.print t1;
454478
output_gen
479+
~write_shape
455480
~standalone:false
456481
~custom_header
457482
~build_info:(Build_info.create `Cmo)
@@ -460,12 +485,13 @@ let run
460485
(fun ~standalone ~source_map output ->
461486
match include_runtime with
462487
| true ->
463-
let sm1 = output_partial_runtime ~standalone ~source_map output in
464-
let sm2 = output_partial cmo code ~standalone ~source_map output in
465-
sourcemap_of_infos ~base:source_map_base [ sm1; sm2 ]
488+
let sm1, sh1 = output_partial_runtime ~standalone ~source_map output in
489+
let sm2, sh2 = output_partial cmo code ~standalone ~source_map output in
490+
( sourcemap_of_infos ~base:source_map_base [ sm1; sm2 ]
491+
, merge_shape sh1 sh2 )
466492
| false ->
467493
output_partial cmo code ~standalone ~source_map output
468-
|> sourcemap_of_info ~base:source_map_base)
494+
|> map_fst (sourcemap_of_info ~base:source_map_base))
469495
| `Cma cma when keep_unit_names ->
470496
(if include_runtime
471497
then
@@ -481,14 +507,15 @@ let run
481507
failwith "use [-o dirname/] or remove [--keep-unit-names]"
482508
in
483509
output_gen
510+
~write_shape
484511
~standalone:false
485512
~custom_header
486513
~build_info:(Build_info.create `Runtime)
487514
~source_map
488515
(`Name output_file)
489516
(fun ~standalone ~source_map output ->
490517
output_partial_runtime ~standalone ~source_map output
491-
|> sourcemap_of_info ~base:source_map_base));
518+
|> map_fst (sourcemap_of_info ~base:source_map_base)));
492519
List.iter cma.lib_units ~f:(fun cmo ->
493520
let output_file =
494521
match output_file with
@@ -517,23 +544,24 @@ let run
517544
t1
518545
(Ocaml_compiler.Cmo_format.name cmo);
519546
output_gen
547+
~write_shape
520548
~standalone:false
521549
~custom_header
522550
~build_info:(Build_info.create `Cma)
523551
~source_map
524552
(`Name output_file)
525553
(fun ~standalone ~source_map output ->
526554
output_partial ~standalone ~source_map cmo code output
527-
|> sourcemap_of_info ~base:source_map_base))
555+
|> map_fst (sourcemap_of_info ~base:source_map_base)))
528556
| `Cma cma ->
529557
let f ~standalone ~source_map output =
530-
let source_map_runtime =
558+
let runtime =
531559
if not include_runtime
532560
then None
533561
else Some (output_partial_runtime ~standalone ~source_map output)
534562
in
535563

536-
let source_map_units =
564+
let units =
537565
List.map cma.lib_units ~f:(fun cmo ->
538566
let t1 = Timer.make () in
539567
let code =
@@ -553,14 +581,20 @@ let run
553581
(Ocaml_compiler.Cmo_format.name cmo);
554582
output_partial ~standalone ~source_map cmo code output)
555583
in
556-
let sm =
557-
match source_map_runtime with
558-
| None -> source_map_units
559-
| Some x -> x :: source_map_units
584+
let sm_and_shapes =
585+
match runtime with
586+
| None -> units
587+
| Some x -> x :: units
588+
in
589+
let shapes =
590+
List.fold_left sm_and_shapes ~init:StringMap.empty ~f:(fun acc (_, s) ->
591+
merge_shape s acc)
560592
in
561-
sourcemap_of_infos ~base:source_map_base sm
593+
( sourcemap_of_infos ~base:source_map_base (List.map sm_and_shapes ~f:fst)
594+
, shapes )
562595
in
563596
output_gen
597+
~write_shape
564598
~standalone:false
565599
~custom_header
566600
~build_info:(Build_info.create `Cma)

compiler/lib/code.ml

+30-2
Original file line numberDiff line numberDiff line change
@@ -556,13 +556,17 @@ module Print = struct
556556
if exact
557557
then Format.fprintf f "%a!(%a)" Var.print g var_list args
558558
else Format.fprintf f "%a(%a)" Var.print g var_list args
559-
| Block (t, a, _, mut) ->
559+
| Block (t, a, k, mut) ->
560560
Format.fprintf
561561
f
562-
"%s{tag=%d"
562+
"{%s%s:tag=%d"
563563
(match mut with
564564
| Immutable -> "imm"
565565
| Maybe_mutable -> "")
566+
(match k with
567+
| Array -> "A"
568+
| NotArray -> "NA"
569+
| Unknown -> "U")
566570
t;
567571
for i = 0 to Array.length a - 1 do
568572
Format.fprintf f "; %d = %a" i Var.print a.(i)
@@ -818,6 +822,30 @@ let fold_closures_outermost_first { start; blocks; _ } f accu =
818822
let accu = f None [] (start, []) accu in
819823
visit blocks start f accu
820824

825+
(* Compute the list of variables containing the return values of each
826+
function *)
827+
let return_values p =
828+
fold_closures
829+
p
830+
(fun name_opt _ (pc, _) rets ->
831+
match name_opt with
832+
| None -> rets
833+
| Some name ->
834+
let s =
835+
traverse
836+
{ fold = fold_children }
837+
(fun pc s ->
838+
let block = Addr.Map.find pc p.blocks in
839+
match block.branch with
840+
| Return x -> Var.Set.add x s
841+
| _ -> s)
842+
pc
843+
p.blocks
844+
Var.Set.empty
845+
in
846+
Var.Map.add name s rets)
847+
Var.Map.empty
848+
821849
let eq p1 p2 =
822850
p1.start = p2.start
823851
&& Addr.Map.cardinal p1.blocks = Addr.Map.cardinal p2.blocks

compiler/lib/code.mli

+2
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ val fold_children_skip_try_body : 'c fold_blocs
304304

305305
val poptraps : block Addr.Map.t -> Addr.t -> Addr.Set.t
306306

307+
val return_values : program -> Var.Set.t Var.Map.t
308+
307309
val traverse :
308310
fold_blocs_poly -> (Addr.t -> 'c -> 'c) -> Addr.t -> block Addr.Map.t -> 'c -> 'c
309311

compiler/lib/config.ml

+2
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ module Flag = struct
101101
let auto_link = o ~name:"auto-link" ~default:true
102102

103103
let es6 = o ~name:"es6" ~default:false
104+
105+
let load_shapes_auto = o ~name:"load-shapes-auto" ~default:false
104106
end
105107

106108
module Param = struct

compiler/lib/config.mli

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ module Flag : sig
7575

7676
val es6 : unit -> bool
7777

78+
val load_shapes_auto : unit -> bool
79+
7880
val enable : string -> unit
7981

8082
val disable : string -> unit

0 commit comments

Comments
 (0)