Skip to content

Commit 2f5e987

Browse files
committed
Compiler: refactor sourcemap generation, use Index sourcemap
1 parent 4cd7df4 commit 2f5e987

File tree

22 files changed

+574
-368
lines changed

22 files changed

+574
-368
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
that follows the semantic of the backend (js or wasm)
1919
* Compiler: warn on joo_global_object
2020
* Compiler: revisit static env handling (#1708)
21-
* Compiler: Emit index map when linking multiple js files together (#1714)
21+
* Compiler: Emit index source_map to avoid changing mappings (#1714, #1715)
2222
* Runtime: change Sys.os_type on windows (Cygwin -> Win32)
2323
* Runtime: backtraces are really expensive, they need to be be explicitly
2424
requested at compile time (--enable with-js-error) or at startup (OCAMLRUNPARAM=b=1)

compiler/bin-js_of_ocaml/build_fs.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,13 @@ function jsoo_create_file_extern(name,content){
7474
let code = Code.prepend Code.empty instr in
7575
Filename.gen_file output_file (fun chan ->
7676
let pfs_fmt = Pretty_print.to_out_channel chan in
77-
let (_ : Source_map.Standard.t option) =
77+
let (_ : Source_map.info) =
7878
Driver.f
7979
~standalone:true
8080
~wrap_with_fun:`Iife
8181
~link:`Needed
8282
~formatter:pfs_fmt
83+
~source_map:false
8384
(Parse_bytecode.Debug.create ~include_cmis:false false)
8485
code
8586
in

compiler/bin-js_of_ocaml/cmd_arg.ml

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ let options =
280280
input_file
281281
js_files
282282
keep_unit_names =
283+
let inline_source_content = not sourcemap_don't_inline_content in
283284
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
284285
let runtime_files = js_files in
285286
let fs_external = fs_external || (toplevel && no_cmis) in
@@ -308,13 +309,9 @@ let options =
308309
in
309310
Some
310311
( sm_output_file
311-
, { Source_map.Standard.version = 3
312-
; file
312+
, { (Source_map.Standard.empty ~inline_source_content) with
313+
file
313314
; sourceroot = sourcemap_root
314-
; sources = []
315-
; sources_content = (if sourcemap_don't_inline_content then None else Some [])
316-
; names = []
317-
; mappings = Source_map.Mappings.empty
318315
} )
319316
else None
320317
in
@@ -519,6 +516,7 @@ let options_runtime_only =
519516
target_env
520517
output_file
521518
js_files =
519+
let inline_source_content = not sourcemap_don't_inline_content in
522520
let chop_extension s = try Filename.chop_extension s with Invalid_argument _ -> s in
523521
let runtime_files = js_files in
524522
let output_file =
@@ -537,13 +535,9 @@ let options_runtime_only =
537535
in
538536
Some
539537
( sm_output_file
540-
, { Source_map.Standard.version = 3
541-
; file
538+
, { (Source_map.Standard.empty ~inline_source_content) with
539+
file
542540
; sourceroot = sourcemap_root
543-
; sources = []
544-
; sources_content = (if sourcemap_don't_inline_content then None else Some [])
545-
; names = []
546-
; mappings = Source_map.Mappings.empty
547541
} )
548542
else None
549543
in

compiler/bin-js_of_ocaml/compile.ml

Lines changed: 127 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,36 @@ let header formatter ~custom_header =
3434
| Some c -> Pretty_print.string formatter (c ^ "\n")
3535

3636
let jsoo_header formatter build_info =
37-
Pretty_print.string formatter "// Generated by js_of_ocaml\n";
37+
Pretty_print.string formatter (Printf.sprintf "%s\n" Global_constant.header);
3838
Pretty_print.string formatter (Build_info.to_string build_info)
3939

40+
type source_map_output =
41+
| No_sourcemap
42+
| Inline
43+
| File of string
44+
45+
let source_map_enabled = function
46+
| No_sourcemap -> false
47+
| Inline | File _ -> true
48+
4049
let output_gen ~standalone ~custom_header ~build_info ~source_map output_file f =
4150
let f chan k =
4251
let fmt = Pretty_print.to_out_channel chan in
4352
Driver.configure fmt;
4453
if standalone then header ~custom_header fmt;
4554
if Config.Flag.header () then jsoo_header fmt build_info;
46-
let sm = f ~standalone ~source_map:(Option.map ~f:snd source_map) (k, fmt) in
55+
let sm = f ~standalone ~source_map (k, fmt) in
4756
match source_map, sm with
48-
| None, _ | _, None -> ()
49-
| Some (output_file, _), Some sm ->
50-
let sm = `Standard sm in
57+
| No_sourcemap, _ | _, None -> ()
58+
| ((Inline | File _) as output), Some sm ->
59+
if Debug.find "invariant" () then Source_map.invariant sm;
5160
let urlData =
52-
match output_file with
53-
| None ->
61+
match output with
62+
| No_sourcemap -> assert false
63+
| Inline ->
5464
let data = Source_map.to_string sm in
5565
"data:application/json;base64," ^ Base64.encode_exn data
56-
| Some output_file ->
66+
| File output_file ->
5767
Source_map.to_file sm output_file;
5868
Filename.basename output_file
5969
in
@@ -65,6 +75,50 @@ let output_gen ~standalone ~custom_header ~build_info ~source_map output_file f
6575
| `Stdout -> f stdout `Stdout
6676
| `Name name -> Filename.gen_file name (fun chan -> f chan `File)
6777

78+
let find_source file =
79+
match Builtins.find file with
80+
| Some f -> Some (Source_map.Source_content.create (Builtins.File.content f))
81+
| None ->
82+
if Sys.file_exists file && not (Sys.is_directory file)
83+
then
84+
let content = Fs.read_file file in
85+
Some (Source_map.Source_content.create content)
86+
else None
87+
88+
let sourcemap_section_of_info
89+
~(base : Source_map.Standard.t)
90+
{ Source_map.sources; names; mappings } =
91+
let sources_content =
92+
match base.sources_content with
93+
| None -> None
94+
| Some _ -> Some (List.map ~f:find_source sources)
95+
in
96+
let sources =
97+
List.map sources ~f:(fun filename ->
98+
match Builtins.find filename with
99+
| None -> filename
100+
| Some _ -> Filename.concat "/builtin" filename)
101+
in
102+
let offset, mappings = Source_map.Mappings.encode_with_offset mappings in
103+
let map =
104+
{ (base : Source_map.Standard.t) with sources; sources_content; names; mappings }
105+
in
106+
{ Source_map.Index.offset; map }
107+
108+
let sourcemap_of_infos ~base l =
109+
match base with
110+
| None -> None
111+
| Some (base : Source_map.Standard.t) ->
112+
let sections = List.map l ~f:(sourcemap_section_of_info ~base) in
113+
Some
114+
(Source_map.Index
115+
{ Source_map.Index.version = base.Source_map.Standard.version
116+
; file = base.file
117+
; sections
118+
})
119+
120+
let sourcemap_of_info ~base info = sourcemap_of_infos ~base [ info ]
121+
68122
let run
69123
{ Cmd_arg.common
70124
; profile
@@ -89,6 +143,13 @@ let run
89143
; keep_unit_names
90144
; include_runtime
91145
} =
146+
let source_map_base = Option.map ~f:snd source_map in
147+
let source_map =
148+
match source_map with
149+
| None -> No_sourcemap
150+
| Some (None, _) -> Inline
151+
| Some (Some file, _) -> File file
152+
in
92153
let include_cmis = toplevel && not no_cmis in
93154
let custom_header = common.Jsoo_cmdline.Arg.custom_header in
94155
Config.set_target `JavaScript;
@@ -148,9 +209,9 @@ let run
148209
Linker.check_deps ();
149210
if times () then Format.eprintf " parsing js: %a@." Timer.print t1;
150211
if times () then Format.eprintf "Start parsing...@.";
151-
let need_debug = Option.is_some source_map || Config.Flag.debuginfo () in
212+
let need_debug = source_map_enabled source_map || Config.Flag.debuginfo () in
152213
let check_debug (one : Parse_bytecode.one) =
153-
if Option.is_some source_map && Parse_bytecode.Debug.is_empty one.debug
214+
if source_map_enabled source_map && Parse_bytecode.Debug.is_empty one.debug
154215
then
155216
warn
156217
"Warning: '--source-map' is enabled but the bytecode program was compiled with \
@@ -202,7 +263,7 @@ let run
202263
?profile
203264
~link
204265
~wrap_with_fun
205-
?source_map
266+
~source_map:(source_map_enabled source_map)
206267
~formatter
207268
one.debug
208269
code
@@ -226,7 +287,7 @@ let run
226287
?profile
227288
~link
228289
~wrap_with_fun
229-
?source_map
290+
~source_map:(source_map_enabled source_map)
230291
~formatter
231292
one.debug
232293
code
@@ -310,7 +371,8 @@ let run
310371
~source_map
311372
~standalone
312373
~link:`All
313-
output_file)
374+
output_file
375+
|> sourcemap_of_info ~base:source_map_base)
314376
| (`Stdin | `File _) as bytecode ->
315377
let kind, ic, close_ic, include_dirs =
316378
match bytecode with
@@ -348,7 +410,15 @@ let run
348410
~build_info:(Build_info.create `Exe)
349411
~source_map
350412
(fst output_file)
351-
(output code ~check_sourcemap:true ~link:(if linkall then `All else `Needed))
413+
(fun ~standalone ~source_map output_file ->
414+
output
415+
code
416+
~check_sourcemap:true
417+
~standalone
418+
~source_map
419+
~link:(if linkall then `All else `Needed)
420+
output_file
421+
|> sourcemap_of_info ~base:source_map_base)
352422
| `Cmo cmo ->
353423
let output_file =
354424
match output_file, keep_unit_names with
@@ -379,12 +449,14 @@ let run
379449
~source_map
380450
output_file
381451
(fun ~standalone ~source_map output ->
382-
let source_map =
383-
if not include_runtime
384-
then source_map
385-
else output_partial_runtime ~standalone ~source_map output
386-
in
387-
output_partial cmo code ~standalone ~source_map output)
452+
match include_runtime with
453+
| true ->
454+
let sm1 = output_partial_runtime ~standalone ~source_map output in
455+
let sm2 = output_partial cmo code ~standalone ~source_map output in
456+
sourcemap_of_infos ~base:source_map_base [ sm1; sm2 ]
457+
| false ->
458+
output_partial cmo code ~standalone ~source_map output
459+
|> sourcemap_of_info ~base:source_map_base)
388460
| `Cma cma when keep_unit_names ->
389461
(if include_runtime
390462
then
@@ -406,7 +478,8 @@ let run
406478
~source_map
407479
(`Name output_file)
408480
(fun ~standalone ~source_map output ->
409-
output_partial_runtime ~standalone ~source_map output));
481+
output_partial_runtime ~standalone ~source_map output
482+
|> sourcemap_of_info ~base:source_map_base));
410483
List.iter cma.lib_units ~f:(fun cmo ->
411484
let output_file =
412485
match output_file with
@@ -440,32 +513,43 @@ let run
440513
~build_info:(Build_info.create `Cma)
441514
~source_map
442515
(`Name output_file)
443-
(output_partial cmo code))
516+
(fun ~standalone ~source_map output ->
517+
output_partial ~standalone ~source_map cmo code output
518+
|> sourcemap_of_info ~base:source_map_base))
444519
| `Cma cma ->
445520
let f ~standalone ~source_map output =
446-
let source_map =
521+
let source_map_runtime =
447522
if not include_runtime
448-
then source_map
449-
else output_partial_runtime ~standalone ~source_map output
523+
then None
524+
else Some (output_partial_runtime ~standalone ~source_map output)
525+
in
526+
527+
let source_map_units =
528+
List.map cma.lib_units ~f:(fun cmo ->
529+
let t1 = Timer.make () in
530+
let code =
531+
Parse_bytecode.from_cmo
532+
~includes:include_dirs
533+
~include_cmis
534+
~debug:need_debug
535+
cmo
536+
ic
537+
in
538+
if times ()
539+
then
540+
Format.eprintf
541+
" parsing: %a (%s)@."
542+
Timer.print
543+
t1
544+
(Ocaml_compiler.Cmo_format.name cmo);
545+
output_partial ~standalone ~source_map cmo code output)
546+
in
547+
let sm =
548+
match source_map_runtime with
549+
| None -> source_map_units
550+
| Some x -> x :: source_map_units
450551
in
451-
List.fold_left cma.lib_units ~init:source_map ~f:(fun source_map cmo ->
452-
let t1 = Timer.make () in
453-
let code =
454-
Parse_bytecode.from_cmo
455-
~includes:include_dirs
456-
~include_cmis
457-
~debug:need_debug
458-
cmo
459-
ic
460-
in
461-
if times ()
462-
then
463-
Format.eprintf
464-
" parsing: %a (%s)@."
465-
Timer.print
466-
t1
467-
(Ocaml_compiler.Cmo_format.name cmo);
468-
output_partial cmo ~standalone ~source_map code output)
552+
sourcemap_of_infos ~base:source_map_base sm
469553
in
470554
output_gen
471555
~standalone:false

compiler/bin-js_of_ocaml/link.ml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,9 @@ let options =
102102
in
103103
Some
104104
( sm_output_file
105-
, { Source_map.Standard.version = 3
106-
; file
105+
, { (Source_map.Standard.empty ~inline_source_content:true) with
106+
file
107107
; sourceroot = sourcemap_root
108-
; sources = []
109-
; sources_content = Some []
110-
; names = []
111-
; mappings = Source_map.Mappings.empty
112108
} )
113109
else None
114110
in

compiler/bin-jsoo_minify/jsoo_minify.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ let f { Cmd_arg.common; output_file; use_stdin; files } =
9292
if t () then (m ())#program p else p)
9393
in
9494
let p = Js_assign.program p in
95-
let (_ : Source_map.Standard.t option) = Js_output.program pp p in
95+
let (_ : Source_map.info) = Js_output.program pp p in
9696
()
9797
in
9898
with_output (fun out_channel ->

compiler/lib/driver.ml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ let coloring js =
496496
let output formatter ~source_map () js =
497497
let t = Timer.make () in
498498
if times () then Format.eprintf "Start Writing file...@.";
499-
let sm = Js_output.program formatter ?source_map js in
499+
let sm = Js_output.program formatter ~source_map js in
500500
if times () then Format.eprintf " write: %a@." Timer.print t;
501501
sm
502502

@@ -713,8 +713,8 @@ let full ~standalone ~wrap_with_fun ~profile ~link ~source_map ~formatter d p =
713713
emit formatter optimized_code
714714

715715
let full_no_source_map ~formatter ~standalone ~wrap_with_fun ~profile ~link d p =
716-
let (_ : Source_map.Standard.t option) =
717-
full ~standalone ~wrap_with_fun ~profile ~link ~source_map:None ~formatter d p
716+
let (_ : Source_map.info) =
717+
full ~standalone ~wrap_with_fun ~profile ~link ~source_map:false ~formatter d p
718718
in
719719
()
720720

@@ -723,7 +723,7 @@ let f
723723
?(wrap_with_fun = `Iife)
724724
?(profile = O1)
725725
~link
726-
?source_map
726+
~source_map
727727
~formatter
728728
d
729729
p =

0 commit comments

Comments
 (0)