Skip to content

Commit 08b118c

Browse files
EnoumyOlivierNicole
authored andcommitted
Link: read files once and all at once
Js_of_ocaml's linker used to read line-per-line each file twice. This patch is a performance optimization that changes the js_of_ocaml linker to read each file once, and also read the files "all at once". This speeds up linking, at the cost of extra peak memory utilization.
1 parent b0b9951 commit 08b118c

File tree

1 file changed

+30
-36
lines changed

1 file changed

+30
-36
lines changed

compiler/lib/link_js.ml

+30-36
Original file line numberDiff line numberDiff line change
@@ -37,57 +37,52 @@ module Line_reader : sig
3737

3838
val drop : t -> unit
3939

40-
val close : t -> unit
40+
val reset : t -> unit
4141

4242
val lnum : t -> int
4343

4444
val fname : t -> string
4545
end = struct
4646
type t =
47-
{ ic : in_channel
48-
; fname : string
49-
; mutable next : string option
47+
{ fname : string
48+
; lines : string list
49+
; mutable current : string list
5050
; mutable lnum : int
5151
}
5252

53-
let close t = close_in t.ic
53+
let reset t =
54+
t.current <- t.lines;
55+
t.lnum <- 0
5456

5557
let open_ fname =
56-
let ic = open_in_bin fname in
57-
{ ic; lnum = 0; fname; next = None }
58+
let lines =
59+
In_channel.input_all (open_in_bin fname) |> String.split_on_char ~sep:'\n'
60+
in
61+
{ lines; lnum = 0; fname; current = lines }
5862

5963
let next t =
6064
let lnum = t.lnum in
6165
let s =
62-
match t.next with
63-
| None -> input_line t.ic
64-
| Some s ->
65-
t.next <- None;
66-
s
66+
match t.current with
67+
| [] -> raise End_of_file
68+
| x :: rem ->
69+
t.current <- rem;
70+
x
6771
in
6872
t.lnum <- lnum + 1;
6973
s
7074

7175
let peek t =
72-
match t.next with
73-
| Some x -> Some x
74-
| None -> (
75-
try
76-
let s = input_line t.ic in
77-
t.next <- Some s;
78-
Some s
79-
with End_of_file -> None)
76+
match t.current with
77+
| x :: _ -> Some x
78+
| [] -> None
8079

8180
let drop t =
82-
match t.next with
83-
| Some _ ->
84-
t.next <- None;
81+
match t.current with
82+
| [] -> ()
83+
| _ :: rem ->
84+
t.current <- rem;
8585
t.lnum <- t.lnum + 1
86-
| None -> (
87-
try
88-
let (_ : string) = input_line t.ic in
89-
t.lnum <- t.lnum + 1
90-
with End_of_file -> ())
9186

9287
let lnum t = t.lnum
9388

@@ -182,7 +177,7 @@ let action ~resolve_sourcemap_url ~drop_source_map file line =
182177
module Units : sig
183178
val read : Line_reader.t -> Unit_info.t -> Unit_info.t
184179

185-
val scan_file : string -> Build_info.t option * Unit_info.t list
180+
val scan_file : string -> Build_info.t option * Unit_info.t list * Line_reader.t
186181
end = struct
187182
let rec read ic uinfo =
188183
match Line_reader.peek ic with
@@ -230,8 +225,8 @@ end = struct
230225
in
231226
let build_info = find_build_info ic in
232227
let units = scan_all ic [] in
233-
Line_reader.close ic;
234-
build_info, units
228+
Line_reader.reset ic;
229+
build_info, units, ic
235230
end
236231

237232
let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source_map =
@@ -246,7 +241,7 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
246241
List.fold_right
247242
files
248243
~init:(StringSet.empty, StringSet.empty, StringSet.empty)
249-
~f:(fun (_file, (build_info, units)) acc ->
244+
~f:(fun (_file, (build_info, units, _reader)) acc ->
250245
let cmo_file =
251246
match build_info with
252247
| Some bi -> (
@@ -286,7 +281,7 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
286281
let t = Timer.make () in
287282
let sym = ref Ocaml_compiler.Symtable.GlobalMap.empty in
288283
let sym_js = ref [] in
289-
List.iter files ~f:(fun (_, (_, units)) ->
284+
List.iter files ~f:(fun (_, (_, units, _)) ->
290285
List.iter units ~f:(fun (u : Unit_info.t) ->
291286
StringSet.iter
292287
(fun s ->
@@ -299,7 +294,7 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
299294
u.Unit_info.provides));
300295

301296
let build_info_emitted = ref false in
302-
List.iter files ~f:(fun (file, (build_info_for_file, units)) ->
297+
List.iter files ~f:(fun (file, (build_info_for_file, units, ic)) ->
303298
let is_runtime =
304299
match build_info_for_file with
305300
| Some bi -> (
@@ -309,7 +304,6 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
309304
| None -> None
310305
in
311306
let sm_for_file = ref None in
312-
let ic = Line_reader.open_ file in
313307
let skip ic = Line_reader.drop ic in
314308
let line_offset = Line_writer.lnum oc in
315309
let reloc = ref [] in
@@ -412,7 +406,7 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
412406
read ()
413407
in
414408
read ();
415-
Line_reader.close ic;
409+
Line_reader.reset ic;
416410
(match is_runtime with
417411
| None -> ()
418412
| Some bi ->

0 commit comments

Comments
 (0)