Skip to content

Commit 35b0d10

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 6907d32 commit 35b0d10

28 files changed

+2931
-2516
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: 21 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)]. "
@@ -302,7 +312,10 @@ let options =
302312
input_file
303313
js_files
304314
keep_unit_names
305-
effects =
315+
effects
316+
shape_files
317+
write_shape
318+
=
306319
let inline_source_content = not sourcemap_don't_inline_content in
307320
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
308321
let runtime_files = js_files in
@@ -366,6 +379,8 @@ let options =
366379
; source_map
367380
; keep_unit_names
368381
; effects
382+
; shape_files
383+
; write_shape
369384
}
370385
in
371386
let t =
@@ -397,7 +412,9 @@ let options =
397412
$ input_file
398413
$ js_files
399414
$ keep_unit_names
400-
$ effects)
415+
$ effects
416+
$ shape_files
417+
$ write_shape)
401418
in
402419
Term.ret t
403420

@@ -606,6 +623,8 @@ let options_runtime_only =
606623
; source_map
607624
; keep_unit_names = false
608625
; effects
626+
; shape_files = []
627+
; write_shape = false
609628
}
610629
in
611630
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: 52 additions & 18 deletions
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
@@ -154,6 +173,8 @@ let run
154173
; keep_unit_names
155174
; include_runtime
156175
; effects
176+
; shape_files
177+
; write_shape
157178
} =
158179
let source_map_base = Option.map ~f:snd source_map in
159180
let source_map =
@@ -174,6 +195,7 @@ let run
174195
| `Name _, _ -> ());
175196
List.iter params ~f:(fun (s, v) -> Config.Param.set s v);
176197
List.iter static_env ~f:(fun (s, v) -> Eval.set_static_env s v);
198+
List.iter shape_files ~f:(fun fn -> Shape.Store.load' fn);
177199
let t = Timer.make () in
178200
let include_dirs =
179201
List.filter_map (include_dirs @ [ "+stdlib/" ]) ~f:(fun d -> Findlib.find [] d)
@@ -368,6 +390,7 @@ let run
368390
}
369391
in
370392
output_gen
393+
~write_shape
371394
~standalone:true
372395
~custom_header
373396
~build_info:(Build_info.create `Runtime)
@@ -383,7 +406,7 @@ let run
383406
~standalone
384407
~link:`All
385408
output_file
386-
|> sourcemap_of_info ~base:source_map_base)
409+
|> map_fst (sourcemap_of_info ~base:source_map_base))
387410
| (`Stdin | `File _) as bytecode ->
388411
let kind, ic, close_ic, include_dirs =
389412
match bytecode with
@@ -416,6 +439,7 @@ let run
416439
in
417440
if times () then Format.eprintf " parsing: %a@." Timer.print t1;
418441
output_gen
442+
~write_shape
419443
~standalone:true
420444
~custom_header
421445
~build_info:(Build_info.create `Exe)
@@ -429,7 +453,7 @@ let run
429453
~source_map
430454
~link:(if linkall then `All else `Needed)
431455
output_file
432-
|> sourcemap_of_info ~base:source_map_base)
456+
|> map_fst (sourcemap_of_info ~base:source_map_base))
433457
| `Cmo cmo ->
434458
let output_file =
435459
match output_file, keep_unit_names with
@@ -454,6 +478,7 @@ let run
454478
in
455479
if times () then Format.eprintf " parsing: %a@." Timer.print t1;
456480
output_gen
481+
~write_shape
457482
~standalone:false
458483
~custom_header
459484
~build_info:(Build_info.create `Cmo)
@@ -462,12 +487,13 @@ let run
462487
(fun ~standalone ~source_map output ->
463488
match include_runtime with
464489
| true ->
465-
let sm1 = output_partial_runtime ~standalone ~source_map output in
466-
let sm2 = output_partial cmo code ~standalone ~source_map output in
467-
sourcemap_of_infos ~base:source_map_base [ sm1; sm2 ]
490+
let sm1, sh1 = output_partial_runtime ~standalone ~source_map output in
491+
let sm2, sh2 = output_partial cmo code ~standalone ~source_map output in
492+
( sourcemap_of_infos ~base:source_map_base [ sm1; sm2 ]
493+
, merge_shape sh1 sh2 )
468494
| false ->
469495
output_partial cmo code ~standalone ~source_map output
470-
|> sourcemap_of_info ~base:source_map_base)
496+
|> map_fst (sourcemap_of_info ~base:source_map_base))
471497
| `Cma cma when keep_unit_names ->
472498
(if include_runtime
473499
then
@@ -483,14 +509,15 @@ let run
483509
failwith "use [-o dirname/] or remove [--keep-unit-names]"
484510
in
485511
output_gen
512+
~write_shape
486513
~standalone:false
487514
~custom_header
488515
~build_info:(Build_info.create `Runtime)
489516
~source_map
490517
(`Name output_file)
491518
(fun ~standalone ~source_map output ->
492519
output_partial_runtime ~standalone ~source_map output
493-
|> sourcemap_of_info ~base:source_map_base));
520+
|> map_fst (sourcemap_of_info ~base:source_map_base)));
494521
List.iter cma.lib_units ~f:(fun cmo ->
495522
let output_file =
496523
match output_file with
@@ -519,23 +546,24 @@ let run
519546
t1
520547
(Ocaml_compiler.Cmo_format.name cmo);
521548
output_gen
549+
~write_shape
522550
~standalone:false
523551
~custom_header
524552
~build_info:(Build_info.create `Cma)
525553
~source_map
526554
(`Name output_file)
527555
(fun ~standalone ~source_map output ->
528556
output_partial ~standalone ~source_map cmo code output
529-
|> sourcemap_of_info ~base:source_map_base))
557+
|> map_fst (sourcemap_of_info ~base:source_map_base)))
530558
| `Cma cma ->
531559
let f ~standalone ~source_map output =
532-
let source_map_runtime =
560+
let runtime =
533561
if not include_runtime
534562
then None
535563
else Some (output_partial_runtime ~standalone ~source_map output)
536564
in
537565

538-
let source_map_units =
566+
let units =
539567
List.map cma.lib_units ~f:(fun cmo ->
540568
let t1 = Timer.make () in
541569
let code =
@@ -555,14 +583,20 @@ let run
555583
(Ocaml_compiler.Cmo_format.name cmo);
556584
output_partial ~standalone ~source_map cmo code output)
557585
in
558-
let sm =
559-
match source_map_runtime with
560-
| None -> source_map_units
561-
| Some x -> x :: source_map_units
586+
let sm_and_shapes =
587+
match runtime with
588+
| None -> units
589+
| Some x -> x :: units
590+
in
591+
let shapes =
592+
List.fold_left sm_and_shapes ~init:StringMap.empty ~f:(fun acc (_, s) ->
593+
merge_shape s acc)
562594
in
563-
sourcemap_of_infos ~base:source_map_base sm
595+
( sourcemap_of_infos ~base:source_map_base (List.map sm_and_shapes ~f:fst)
596+
, shapes )
564597
in
565598
output_gen
599+
~write_shape
566600
~standalone:false
567601
~custom_header
568602
~build_info:(Build_info.create `Cma)

compiler/lib/code.ml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -560,13 +560,17 @@ module Print = struct
560560
if exact
561561
then Format.fprintf f "%a!(%a)" Var.print g var_list args
562562
else Format.fprintf f "%a(%a)" Var.print g var_list args
563-
| Block (t, a, _, mut) ->
563+
| Block (t, a, k, mut) ->
564564
Format.fprintf
565565
f
566-
"%s{tag=%d"
566+
"{%s%s:tag=%d"
567567
(match mut with
568568
| Immutable -> "imm"
569569
| Maybe_mutable -> "")
570+
(match k with
571+
| Array -> "A"
572+
| NotArray -> "NA"
573+
| Unknown -> "U")
570574
t;
571575
for i = 0 to Array.length a - 1 do
572576
Format.fprintf f "; %d = %a" i Var.print a.(i)
@@ -822,6 +826,30 @@ let fold_closures_outermost_first { start; blocks; _ } f accu =
822826
let accu = f None [] (start, []) accu in
823827
visit blocks start f accu
824828

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

compiler/lib/code.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ val fold_children_skip_try_body : 'c fold_blocs
306306

307307
val poptraps : block Addr.Map.t -> Addr.t -> Addr.Set.t
308308

309+
val return_values : program -> Var.Set.t Var.Map.t
310+
309311
val traverse :
310312
fold_blocs_poly -> (Addr.t -> 'c -> 'c) -> Addr.t -> block Addr.Map.t -> 'c -> 'c
311313

compiler/lib/config.ml

Lines changed: 2 additions & 0 deletions
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

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)