Skip to content

Commit a4bb357

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 ec4317f commit a4bb357

29 files changed

+2769
-2355
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)]. "
@@ -307,7 +317,9 @@ let options =
307317
input_file
308318
js_files
309319
keep_unit_names
310-
effects =
320+
effects
321+
shape_files
322+
write_shape =
311323
let inline_source_content = not sourcemap_don't_inline_content in
312324
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
313325
let runtime_files = js_files in
@@ -378,6 +390,8 @@ let options =
378390
; source_map
379391
; keep_unit_names
380392
; effects
393+
; shape_files
394+
; write_shape
381395
}
382396
in
383397
let t =
@@ -410,7 +424,9 @@ let options =
410424
$ input_file
411425
$ js_files
412426
$ keep_unit_names
413-
$ effects)
427+
$ effects
428+
$ shape_files
429+
$ write_shape)
414430
in
415431
Term.ret t
416432

@@ -631,6 +647,8 @@ let options_runtime_only =
631647
; source_map
632648
; keep_unit_names = false
633649
; effects
650+
; shape_files = []
651+
; write_shape = false
634652
}
635653
in
636654
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: 45 additions & 17 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 ~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)
@@ -371,6 +387,7 @@ let run
371387
{ code; cmis = StringSet.empty; debug = Parse_bytecode.Debug.default_summary }
372388
in
373389
output_gen
390+
~write_shape
374391
~standalone:true
375392
~custom_header
376393
~build_info:(Build_info.create `Runtime)
@@ -386,7 +403,7 @@ let run
386403
~standalone
387404
~link:`All
388405
output_file
389-
|> sourcemap_of_info ~base:source_map_base)
406+
|> map_fst (sourcemap_of_info ~base:source_map_base))
390407
| (`Stdin | `File _) as bytecode ->
391408
let kind, ic, close_ic, include_dirs =
392409
match bytecode with
@@ -419,6 +436,7 @@ let run
419436
in
420437
if times () then Format.eprintf " parsing: %a@." Timer.print t1;
421438
output_gen
439+
~write_shape
422440
~standalone:true
423441
~custom_header
424442
~build_info:(Build_info.create `Exe)
@@ -432,7 +450,7 @@ let run
432450
~source_map
433451
~link:(if linkall then `All else `Needed)
434452
output_file
435-
|> sourcemap_of_info ~base:source_map_base)
453+
|> map_fst (sourcemap_of_info ~base:source_map_base))
436454
| `Cmo cmo ->
437455
let output_file =
438456
match output_file, keep_unit_names with
@@ -457,6 +475,7 @@ let run
457475
in
458476
if times () then Format.eprintf " parsing: %a@." Timer.print t1;
459477
output_gen
478+
~write_shape
460479
~standalone:false
461480
~custom_header
462481
~build_info:(Build_info.create `Cmo)
@@ -465,12 +484,13 @@ let run
465484
(fun ~standalone ~source_map output ->
466485
match include_runtime with
467486
| 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 ]
487+
let sm1, sh1 = output_partial_runtime ~standalone ~source_map output in
488+
let sm2, sh2 = output_partial cmo code ~standalone ~source_map output in
489+
( sourcemap_of_infos ~base:source_map_base [ sm1; sm2 ]
490+
, merge_shape sh1 sh2 )
471491
| false ->
472492
output_partial cmo code ~standalone ~source_map output
473-
|> sourcemap_of_info ~base:source_map_base)
493+
|> map_fst (sourcemap_of_info ~base:source_map_base))
474494
| `Cma cma when keep_unit_names ->
475495
(if include_runtime
476496
then
@@ -486,14 +506,15 @@ let run
486506
failwith "use [-o dirname/] or remove [--keep-unit-names]"
487507
in
488508
output_gen
509+
~write_shape
489510
~standalone:false
490511
~custom_header
491512
~build_info:(Build_info.create `Runtime)
492513
~source_map
493514
(`Name output_file)
494515
(fun ~standalone ~source_map output ->
495516
output_partial_runtime ~standalone ~source_map output
496-
|> sourcemap_of_info ~base:source_map_base));
517+
|> map_fst (sourcemap_of_info ~base:source_map_base)));
497518
List.iter cma.lib_units ~f:(fun cmo ->
498519
let output_file =
499520
match output_file with
@@ -522,23 +543,24 @@ let run
522543
t1
523544
(Ocaml_compiler.Cmo_format.name cmo);
524545
output_gen
546+
~write_shape
525547
~standalone:false
526548
~custom_header
527549
~build_info:(Build_info.create `Cma)
528550
~source_map
529551
(`Name output_file)
530552
(fun ~standalone ~source_map output ->
531553
output_partial ~standalone ~source_map cmo code output
532-
|> sourcemap_of_info ~base:source_map_base))
554+
|> map_fst (sourcemap_of_info ~base:source_map_base)))
533555
| `Cma cma ->
534556
let f ~standalone ~source_map output =
535-
let source_map_runtime =
557+
let runtime =
536558
if not include_runtime
537559
then None
538560
else Some (output_partial_runtime ~standalone ~source_map output)
539561
in
540562

541-
let source_map_units =
563+
let units =
542564
List.map cma.lib_units ~f:(fun cmo ->
543565
let t1 = Timer.make () in
544566
let code =
@@ -558,14 +580,20 @@ let run
558580
(Ocaml_compiler.Cmo_format.name cmo);
559581
output_partial ~standalone ~source_map cmo code output)
560582
in
561-
let sm =
562-
match source_map_runtime with
563-
| None -> source_map_units
564-
| Some x -> x :: source_map_units
583+
let sm_and_shapes =
584+
match runtime with
585+
| None -> units
586+
| Some x -> x :: units
587+
in
588+
let shapes =
589+
List.fold_left sm_and_shapes ~init:StringMap.empty ~f:(fun acc (_, s) ->
590+
merge_shape s acc)
565591
in
566-
sourcemap_of_infos ~base:source_map_base sm
592+
( sourcemap_of_infos ~base:source_map_base (List.map sm_and_shapes ~f:fst)
593+
, shapes )
567594
in
568595
output_gen
596+
~write_shape
569597
~standalone:false
570598
~custom_header
571599
~build_info:(Build_info.create `Cma)

compiler/lib/code.ml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,13 +511,17 @@ module Print = struct
511511
if exact
512512
then Format.fprintf f "%a!(%a)" Var.print g var_list args
513513
else Format.fprintf f "%a(%a)" Var.print g var_list args
514-
| Block (t, a, _, mut) ->
514+
| Block (t, a, k, mut) ->
515515
Format.fprintf
516516
f
517-
"%s{tag=%d"
517+
"{%s%s:tag=%d"
518518
(match mut with
519519
| Immutable -> "imm"
520520
| Maybe_mutable -> "")
521+
(match k with
522+
| Array -> "A"
523+
| NotArray -> "NA"
524+
| Unknown -> "U")
521525
t;
522526
for i = 0 to Array.length a - 1 do
523527
Format.fprintf f "; %d = %a" i Var.print a.(i)
@@ -773,6 +777,30 @@ let fold_closures_outermost_first { start; blocks; _ } f accu =
773777
let accu = f None [] (start, []) None accu in
774778
visit blocks start f accu
775779

780+
(* Compute the list of variables containing the return values of each
781+
function *)
782+
let return_values p =
783+
fold_closures
784+
p
785+
(fun name_opt _ (pc, _) _ rets ->
786+
match name_opt with
787+
| None -> rets
788+
| Some name ->
789+
let s =
790+
traverse
791+
{ fold = fold_children }
792+
(fun pc s ->
793+
let block = Addr.Map.find pc p.blocks in
794+
match block.branch with
795+
| Return x -> Var.Set.add x s
796+
| _ -> s)
797+
pc
798+
p.blocks
799+
Var.Set.empty
800+
in
801+
Var.Map.add name s rets)
802+
Var.Map.empty
803+
776804
let equal p1 p2 =
777805
p1.start = p2.start
778806
&& Addr.Map.equal

compiler/lib/code.mli

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

296296
val poptraps : block Addr.Map.t -> Addr.t -> Addr.Set.t
297297

298+
val return_values : program -> Var.Set.t Var.Map.t
299+
298300
val traverse :
299301
fold_blocs_poly -> (Addr.t -> 'c -> 'c) -> Addr.t -> block Addr.Map.t -> 'c -> 'c
300302

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)