Skip to content

Commit e4d6706

Browse files
committed
[input] read related consecutive cmti files only once
When reading files in a directory, because we sort the content by filenames, often the`.cmt` is read after its correspnding `.cmi` without any other `.cmt` or `.cmi` in between. When reading the `.cmi`, the `.cmt` is also read to gether as many infos as possible. Now, when we reach the `.cmt`, rather than reading it again, we update the information stored in the state using pre-loaded data.
1 parent 124a90b commit e4d6706

File tree

2 files changed

+62
-17
lines changed

2 files changed

+62
-17
lines changed

src/deadCode.ml

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -420,19 +420,23 @@ let eom loc_dep =
420420

421421

422422
(* Starting point *)
423-
let rec load_file fn =
424-
let init_and_continue fn f =
425-
match State.init fn with
426-
| Error msg -> Printf.eprintf "%s\n!" msg
423+
let rec load_file state fn =
424+
let init_and_continue state fn f =
425+
match State.change_file state fn with
426+
| Error msg ->
427+
Printf.eprintf "%s\n!" msg;
428+
state
427429
| Ok state ->
428430
State.update state;
429-
f state
431+
f state;
432+
(* TODO: stateful computations should take and return the state when possible *)
433+
state
430434
in
431435
match kind fn with
432436
| `Cmi when !DeadCommon.declarations ->
433437
last_loc := Lexing.dummy_pos;
434438
if !DeadFlag.verbose then Printf.eprintf "Scanning %s\n%!" fn;
435-
init_and_continue fn (fun state ->
439+
init_and_continue state fn (fun state ->
436440
match state.file_infos.cmi_infos with
437441
| None -> () (* TODO error handling ? *)
438442
| Some cmi_infos -> read_interface fn cmi_infos state
@@ -442,7 +446,7 @@ let rec load_file fn =
442446
let open Cmt_format in
443447
last_loc := Lexing.dummy_pos;
444448
if !DeadFlag.verbose then Printf.eprintf "Scanning %s\n%!" fn;
445-
init_and_continue fn (fun state ->
449+
init_and_continue state fn (fun state ->
446450
regabs state;
447451
match state.file_infos.cmt_infos with
448452
| None -> bad_files := fn :: !bad_files
@@ -474,12 +478,13 @@ let rec load_file fn =
474478
| `Dir ->
475479
let next = Sys.readdir fn in
476480
Array.sort compare next;
477-
Array.iter
478-
(fun s -> load_file (fn ^ "/" ^ s))
481+
Array.fold_left
482+
(fun state s -> load_file state (fn ^ "/" ^ s))
483+
state
479484
next
480485
(* else Printf.eprintf "skipping directory %s\n" fn *)
481486

482-
| _ -> ()
487+
| _ -> state
483488

484489

485490
(******** REPORTING ********)
@@ -614,6 +619,12 @@ let parse () =
614619
update_opt optn print)
615620
in
616621

622+
let load_file filename =
623+
let state = State.get_current () in
624+
let state = load_file state filename in
625+
State.update state
626+
in
627+
617628
(* any extra argument can be accepted by any option using some
618629
* although it doesn't necessary affects the results (e.g. -O 3+4) *)
619630
Arg.(parse
@@ -682,19 +693,22 @@ let parse () =
682693

683694
]
684695
(Printf.eprintf "Scanning files...\n%!";
685-
load_file)
696+
load_file)
686697
("Usage: " ^ Sys.argv.(0) ^ " <options> <path>\nOptions are:"))
687698

688699

689700
let () =
690701
try
691702
parse ();
692-
DeadCommon.declarations := false;
693-
694-
let oldstyle = !DeadFlag.style in
695-
DeadFlag.update_style "-all";
696-
List.iter load_file !DeadFlag.directories;
697-
DeadFlag.style := oldstyle;
703+
let run_on_references_only state =
704+
DeadCommon.declarations := false;
705+
let oldstyle = !DeadFlag.style in
706+
DeadFlag.update_style "-all";
707+
List.fold_left load_file state !DeadFlag.directories
708+
|> ignore;
709+
DeadFlag.style := oldstyle
710+
in
711+
run_on_references_only (State.get_current ());
698712

699713
Printf.eprintf " [DONE]\n\n%!";
700714

src/state.ml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,21 @@ module File_infos = struct
103103
init_from_cmt cmti_file |> Result.map with_cmi_infos
104104
| _ -> Result.error (cmti_file ^ ": not a .cmi or .cmt file")
105105

106+
let change_file file_infos cmti_file =
107+
let no_ext = Filename.remove_extension cmti_file in
108+
assert(no_ext = Filename.remove_extension file_infos.cmti_file);
109+
match Filename.extension cmti_file, file_infos with
110+
| ".cmi", {cmi_infos=Some cmi_infos; _} ->
111+
let res = init_from_cmi_infos ~with_cmt:file_infos cmi_infos cmti_file in
112+
Result.ok res
113+
| ".cmt", {cmt_infos = Some cmt_infos; cmi_infos; _} ->
114+
let res = init_from_cmt_infos cmt_infos cmti_file in
115+
Result.ok {res with cmi_infos}
116+
| ".cmi", _
117+
| ".cmt", _ -> (* corresponding info is None *)
118+
init cmti_file
119+
| _ -> Result.error (cmti_file ^ ": not a .cmi or .cmt file")
120+
106121
let get_builddir t = t.builddir
107122

108123
let get_sourcepath t = t.sourcepath
@@ -127,6 +142,22 @@ let init cmti_file =
127142
let file_infos = File_infos.init cmti_file in
128143
Result.map (fun file_infos -> {file_infos}) file_infos
129144

145+
let change_file state cmti_file =
146+
let file_infos = state.file_infos in
147+
let equal_no_ext filename1 filename2 =
148+
let no_ext1 = Filename.remove_extension filename1 in
149+
let no_ext2 = Filename.remove_extension filename2 in
150+
no_ext1 = no_ext2
151+
in
152+
if file_infos.cmti_file = cmti_file then
153+
Result.ok state
154+
else if equal_no_ext file_infos.cmti_file cmti_file then
155+
let file_infos = File_infos.change_file file_infos cmti_file in
156+
Result.map (fun file_infos -> {file_infos}) file_infos
157+
else
158+
init cmti_file
159+
160+
130161
let current = ref empty
131162

132163
let get_current () = !current

0 commit comments

Comments
 (0)