Skip to content

Commit 48cf239

Browse files
committed
Optimize sourcemap processing
1 parent bfbeb69 commit 48cf239

File tree

14 files changed

+978
-382
lines changed

14 files changed

+978
-382
lines changed

compiler/bin-js_of_ocaml/cmd_arg.ml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,11 @@ let options =
318318
; file
319319
; sourceroot = sourcemap_root
320320
; sources = []
321-
; sources_content = (if sourcemap_don't_inline_content then None else Some [])
321+
; sources_contents =
322+
(if sourcemap_don't_inline_content then None
323+
else Some (Source_map.Sources_contents.encode []))
322324
; names = []
323-
; mappings = []
325+
; mappings = Source_map.Mappings.empty
324326
} )
325327
else None
326328
in
@@ -557,9 +559,11 @@ let options_runtime_only =
557559
; file
558560
; sourceroot = sourcemap_root
559561
; sources = []
560-
; sources_content = (if sourcemap_don't_inline_content then None else Some [])
562+
; sources_contents =
563+
(if sourcemap_don't_inline_content then None
564+
else Some (Source_map.Sources_contents.encode []))
561565
; names = []
562-
; mappings = []
566+
; mappings = Source_map.Mappings.empty
563567
} )
564568
else None
565569
in

compiler/bin-js_of_ocaml/link.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ let options =
106106
; file
107107
; sourceroot = sourcemap_root
108108
; sources = []
109-
; sources_content = Some []
109+
; sources_contents = Some (Source_map.Sources_contents.encode [])
110110
; names = []
111-
; mappings = []
111+
; mappings = Source_map.Mappings.empty
112112
} )
113113
else None
114114
in

compiler/lib/js_output.ml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,8 +1905,8 @@ let program ?(accept_unnamed_var = false) f ?source_map p =
19051905
let names = Hashtbl.create 17 in
19061906
let contents : string option list ref option =
19071907
match source_map with
1908-
| None | Some { Source_map.sources_content = None; _ } -> None
1909-
| Some { Source_map.sources_content = Some _; _ } -> Some (ref [])
1908+
| None | Some { Source_map.sources_contents = None; _ } -> None
1909+
| Some { Source_map.sources_contents = Some _; _ } -> Some (ref [])
19101910
in
19111911
let push_mapping, get_file_index, get_name_index, source_map_enabled =
19121912
let source_map_enabled =
@@ -1925,7 +1925,10 @@ let program ?(accept_unnamed_var = false) f ?source_map p =
19251925
Option.iter contents ~f:(fun r -> r := y :: !r);
19261926
loop xs ys
19271927
in
1928-
loop sm.sources (Option.value ~default:[] sm.sources_content);
1928+
let sources_contents =
1929+
Option.map ~f:Source_map.Sources_contents.decode sm.sources_contents
1930+
in
1931+
loop sm.sources (Option.value ~default:[] sources_contents);
19291932
List.iter sm.Source_map.names ~f:(fun f ->
19301933
Hashtbl.add names f (Hashtbl.length names));
19311934
true
@@ -1979,19 +1982,20 @@ let program ?(accept_unnamed_var = false) f ?source_map p =
19791982
| Some sm ->
19801983
let sources = hashtbl_to_list files in
19811984
let names = hashtbl_to_list names in
1982-
let sources_content =
1983-
match contents with
1984-
| None -> None
1985-
| Some r -> Some (List.rev !r)
1985+
let sources_contents =
1986+
let open Option.Syntax in
1987+
let* r = contents in
1988+
Option.return (Source_map.Sources_contents.encode (List.rev !r))
19861989
in
19871990
let sources =
19881991
List.map sources ~f:(fun filename ->
19891992
match Builtins.find filename with
19901993
| None -> filename
19911994
| Some _ -> Filename.concat "/builtin" filename)
19921995
in
1996+
let sm_mappings = Source_map.Mappings.decode sm.mappings in
19931997
let mappings =
1994-
List.rev_append_map !temp_mappings sm.mappings ~f:(fun (pos, m) ->
1998+
List.rev_append_map !temp_mappings sm_mappings ~f:(fun (pos, m) ->
19951999
let gen_line = pos.PP.p_line + 1 in
19962000
let gen_col = pos.PP.p_col in
19972001
match m with
@@ -2006,7 +2010,8 @@ let program ?(accept_unnamed_var = false) f ?source_map p =
20062010
Source_map.Gen_Ori_Name
20072011
{ gen_line; gen_col; ori_source; ori_line; ori_col; ori_name })
20082012
in
2009-
Some { sm with Source_map.sources; names; sources_content; mappings }
2013+
let mappings = Source_map.Mappings.encode mappings in
2014+
Some { sm with Source_map.sources; names; sources_contents; mappings }
20102015
in
20112016
PP.check f;
20122017
(if stats ()

compiler/lib/link_js.ml

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ module Line_writer : sig
9999

100100
val of_channel : out_channel -> t
101101

102-
val write : ?source:Line_reader.t -> t -> string -> unit
102+
val write : ?source:Line_reader.t -> t -> string -> int
103103

104-
val write_lines : ?source:Line_reader.t -> t -> string -> unit
104+
val write_lines : ?source:Line_reader.t -> t -> string -> int
105105

106106
val lnum : t -> int
107107
end = struct
@@ -134,17 +134,20 @@ end = struct
134134
output_string t.oc "\n";
135135
let lnum_off = lnum_off + 1 in
136136
t.source <- source;
137-
t.lnum <- t.lnum + lnum_off
137+
t.lnum <- t.lnum + lnum_off;
138+
lnum_off
138139

139140
let write_lines ?source t lines =
141+
let lnum = t.lnum in
140142
let l = String.split_on_char ~sep:'\n' lines in
141143
let rec w = function
142144
| [ "" ] | [] -> ()
143145
| s :: xs ->
144-
write ?source t s;
146+
let _ = write ?source t s in
145147
w xs
146148
in
147-
w l
149+
w l;
150+
t.lnum - lnum
148151

149152
let lnum t = t.lnum
150153
end
@@ -318,12 +321,26 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
318321
in
319322
let sm_for_file = ref None in
320323
let ic = Line_reader.open_ file in
321-
let skip ic = Line_reader.drop ic in
322-
let reloc = ref [] in
324+
let old_line_count = Line_writer.lnum oc in
325+
let edits = ref [] in
326+
let skip ic =
327+
edits := Source_map.Line_edits.Drop :: !edits;
328+
Line_reader.drop ic
329+
in
323330
let copy ic oc =
324331
let line = Line_reader.next ic in
325-
Line_writer.write ~source:ic oc line;
326-
reloc := (Line_reader.lnum ic, Line_writer.lnum oc) :: !reloc
332+
let count = Line_writer.write ~source:ic oc line in
333+
if count > 1
334+
then edits := Source_map.Line_edits.Add { count = count - 1 } :: !edits;
335+
edits := Source_map.Line_edits.Keep :: !edits
336+
in
337+
let write_line oc str =
338+
let count = Line_writer.write oc str in
339+
edits := Source_map.Line_edits.(Add { count }) :: !edits
340+
in
341+
let write_lines oc str =
342+
let count = Line_writer.write_lines oc str in
343+
edits := Source_map.Line_edits.(Add { count }) :: !edits
327344
in
328345
let rec read () =
329346
match Line_reader.peek ic with
@@ -342,7 +359,7 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
342359
if not !build_info_emitted
343360
then (
344361
let bi = Build_info.with_kind bi (if mklib then `Cma else `Unknown) in
345-
Line_writer.write_lines oc (Build_info.to_string bi);
362+
write_lines oc (Build_info.to_string bi);
346363
build_info_emitted := true)
347364
| Drop -> skip ic
348365
| Unit ->
@@ -358,7 +375,7 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
358375
(if mklib
359376
then
360377
let u = if linkall then { u with force_link = true } else u in
361-
Line_writer.write_lines oc (Unit_info.to_string u));
378+
write_lines oc (Unit_info.to_string u));
362379
let size = ref 0 in
363380
while
364381
match Line_reader.peek ic with
@@ -402,7 +419,7 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
402419
read ()
403420
in
404421
read ();
405-
Line_writer.write oc "";
422+
write_line oc "";
406423
Line_reader.close ic;
407424
(match is_runtime with
408425
| None -> ()
@@ -424,10 +441,10 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
424441
(Parse_bytecode.Debug.create ~include_cmis:false false)
425442
code;
426443
let content = Buffer.contents b in
427-
Line_writer.write_lines oc content);
444+
write_lines oc content);
428445
(match !sm_for_file with
429446
| None -> ()
430-
| Some x -> sm := (x, !reloc) :: !sm);
447+
| Some x -> sm := (x, List.rev !edits, Line_writer.lnum oc - old_line_count) :: !sm);
431448
match !build_info, build_info_for_file with
432449
| None, None -> ()
433450
| Some _, None -> ()
@@ -440,32 +457,55 @@ let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source
440457
match source_map with
441458
| None -> ()
442459
| Some (file, init_sm) ->
443-
let sm =
444-
List.rev_map !sm ~f:(fun (sm, reloc) ->
445-
let tbl = Hashtbl.create 17 in
446-
List.iter reloc ~f:(fun (a, b) -> Hashtbl.add tbl a b);
447-
Source_map.filter_map sm ~f:(Hashtbl.find_opt tbl))
460+
let sourcemaps_and_line_counts =
461+
List.rev_map !sm ~f:(fun (sm, edits, lcount) ->
462+
(*
463+
(match file with
464+
| Some f -> Format.eprintf "file = %s@," f
465+
| None -> ());
466+
Format.eprintf "@[<v 2>edits =@ %a@,@]" Source_map.Line_edits.pp edits;
467+
*)
468+
let mappings = sm.Source_map.mappings in
469+
(*
470+
Format.eprintf "mappings = %s@," sm.Source_map.mappings;
471+
*)
472+
let mappings = Source_map.Mappings.edit ~strict:false mappings edits in
473+
{ sm with mappings }, lcount)
448474
in
449-
(match Source_map.merge (init_sm :: sm) with
450-
| None -> ()
451-
| Some sm -> (
452-
(* preserve some info from [init_sm] *)
453-
let sm =
454-
{ sm with
455-
version = init_sm.version
456-
; file = init_sm.file
457-
; sourceroot = init_sm.sourceroot
458-
}
459-
in
460-
match file with
461-
| None ->
462-
let data = Source_map_io.to_string sm in
463-
let s = sourceMappingURL_base64 ^ Base64.encode_exn data in
464-
Line_writer.write oc s
465-
| Some file ->
466-
Source_map_io.to_file sm file;
467-
let s = sourceMappingURL ^ Filename.basename file in
468-
Line_writer.write oc s));
475+
let merged_sourcemap =
476+
let open Source_map in
477+
assert (match init_sm.mappings with Uninterpreted "" -> true | _ -> false);
478+
{ version = init_sm.version
479+
; file = init_sm.file
480+
; Composite.sections =
481+
(let _, sections =
482+
List.fold_right
483+
sourcemaps_and_line_counts
484+
~f:(fun (sm, generated_line_count) (cur_ofs, sections) ->
485+
let offset = Composite.{ gen_line = cur_ofs; gen_column = 0 } in
486+
cur_ofs + generated_line_count, (offset, `Map sm) :: sections)
487+
~init:(0, [])
488+
in
489+
List.rev sections)
490+
}
491+
in
492+
(* preserve some info from [init_sm] *)
493+
let merged_sourcemap =
494+
{ merged_sourcemap with
495+
sections =
496+
List.map merged_sourcemap.sections ~f:(fun (ofs, `Map sm) ->
497+
ofs, `Map { sm with sourceroot = init_sm.sourceroot })
498+
}
499+
in
500+
(match file with
501+
| None ->
502+
let data = Source_map_io.Composite.to_string merged_sourcemap in
503+
let s = sourceMappingURL_base64 ^ Base64.encode_exn data in
504+
Line_writer.write oc s |> ignore
505+
| Some file ->
506+
Source_map_io.Composite.to_file merged_sourcemap file;
507+
let s = sourceMappingURL ^ Filename.basename file in
508+
Line_writer.write oc s |> ignore);
469509
if times () then Format.eprintf " sourcemap: %a@." Timer.print t
470510

471511
let link ~output ~linkall ~mklib ~toplevel ~files ~resolve_sourcemap_url ~source_map =

0 commit comments

Comments
 (0)