summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes6
-rw-r--r--bytecomp/bytepackager.ml270
-rw-r--r--bytecomp/bytepackager.mli1
-rw-r--r--bytecomp/emitcode.ml7
-rw-r--r--bytecomp/emitcode.mli9
5 files changed, 162 insertions, 131 deletions
diff --git a/Changes b/Changes
index 8039cd5dc9..be2158111c 100644
--- a/Changes
+++ b/Changes
@@ -209,8 +209,10 @@ Working version
- #11446: document switch compilation (lambda/switch.ml)
(Gabriel Scherer, review by Luc Maranget and Vincent Laviron)
-- #11601, #11612: Clean up some global state handling in emitcode, spill.
- (Hugo Heuzard, Stefan Muenzel review by Vincent Laviron and Gabriel Scherer)
+- #11601, #11612, #11628: Clean up some global state handling
+ in emitcode, bytepackager, spill.
+ (Hugo Heuzard, Stefan Muenzel, review by Vincent Laviron, Gabriel Scherer
+ and Nathanaëlle Courant)
- #11627: use return values instead of globals for linear scan intervals
(Stefan Muenzel, review by Nicolás Ojeda Bär)
diff --git a/bytecomp/bytepackager.ml b/bytecomp/bytepackager.ml
index 2458030bd1..449d423252 100644
--- a/bytecomp/bytepackager.ml
+++ b/bytecomp/bytepackager.ml
@@ -21,6 +21,11 @@ open Instruct
open Cmo_format
module String = Misc.Stdlib.String
+let rec rev_append_map f l rest =
+ match l with
+ | [] -> rest
+ | x :: xs -> rev_append_map f xs (f x :: rest)
+
type error =
Forward_reference of string * Ident.t
| Multiple_definition of string * Ident.t
@@ -30,25 +35,39 @@ type error =
exception Error of error
-(* References accumulating information on the .cmo files *)
+type state = {
+ relocs : (reloc_info * int) list; (** accumulated reloc info *)
+ events : debug_event list; (** accumulated debug events *)
+ debug_dirs : String.Set.t; (** accumulated debug_dirs *)
+ primitives : string list; (** accumulated primitives *)
+ offset : int; (** offset of the current unit *)
+ subst : Subst.t; (** Substitution for debug event *)
+ mapping : (Ident.t * bool) Ident.Map.t;
+ (** Mapping from module to packed-module idents.
+ The boolean tells whether we've processed the compilation unit already. *)
+}
-let relocs = ref ([] : (reloc_info * int) list)
-let events = ref ([] : debug_event list)
-let debug_dirs = ref String.Set.empty
-let primitives = ref ([] : string list)
-let force_link = ref false
+let empty_state = {
+ relocs = [];
+ events = [];
+ debug_dirs = String.Set.empty;
+ primitives = [];
+ offset = 0;
+ mapping = Ident.Map.empty;
+ subst = Subst.identity;
+}
-(* Record a relocation. Update its offset, and rename GETGLOBAL and
+(* Update a relocation. adjust its offset, and rename GETGLOBAL and
SETGLOBAL relocations that correspond to one of the units being
consolidated. *)
-let rename_relocation packagename objfile mapping defined base (rel, ofs) =
+let rename_relocation packagename objfile mapping base (rel, ofs) =
let rel' =
match rel with
Reloc_getglobal id ->
begin try
- let id' = List.assoc id mapping in
- if List.mem id defined
+ let id', defined = Ident.Map.find id mapping in
+ if defined
then Reloc_getglobal id'
else raise(Error(Forward_reference(objfile, id)))
with Not_found ->
@@ -63,8 +82,8 @@ let rename_relocation packagename objfile mapping defined base (rel, ofs) =
end
| Reloc_setglobal id ->
begin try
- let id' = List.assoc id mapping in
- if List.mem id defined
+ let id', defined = Ident.Map.find id mapping in
+ if defined
then raise(Error(Multiple_definition(objfile, id)))
else Reloc_setglobal id'
with Not_found ->
@@ -77,15 +96,14 @@ let rename_relocation packagename objfile mapping defined base (rel, ofs) =
end
| _ ->
rel in
- relocs := (rel', base + ofs) :: !relocs
+ (rel', base + ofs)
-(* Record and relocate a debugging event *)
+(* relocate a debugging event *)
let relocate_debug base prefix subst ev =
- let ev' = { ev with ev_pos = base + ev.ev_pos;
- ev_module = prefix ^ "." ^ ev.ev_module;
- ev_typsubst = Subst.compose ev.ev_typsubst subst } in
- events := ev' :: !events
+ { ev with ev_pos = base + ev.ev_pos;
+ ev_module = prefix ^ "." ^ ev.ev_module;
+ ev_typsubst = Subst.compose ev.ev_typsubst subst }
(* Read the unit information from a .cmo file. *)
@@ -94,18 +112,19 @@ type pack_member_kind = PM_intf | PM_impl of compilation_unit
type pack_member =
{ pm_file: string;
pm_name: string;
+ pm_ident: Ident.t;
+ pm_packed_ident: Ident.t;
pm_kind: pack_member_kind }
-let read_member_info file = (
- let name =
- String.capitalize_ascii(Filename.basename(chop_extensions file)) in
+let read_member_info targetname file =
+ let name = String.capitalize_ascii(Filename.basename(chop_extensions file)) in
let kind =
(* PR#7479: make sure it is either a .cmi or a .cmo *)
if Filename.check_suffix file ".cmi" then
PM_intf
else begin
let ic = open_in_bin file in
- try
+ Fun.protect ~finally:(fun () -> close_in ic) (fun () ->
let buffer =
really_input_string ic (String.length Config.cmo_magic_number)
in
@@ -116,82 +135,77 @@ let read_member_info file = (
let compunit = (input_value ic : compilation_unit) in
if compunit.cu_name <> name
then raise(Error(Illegal_renaming(name, file, compunit.cu_name)));
- close_in ic;
- PM_impl compunit
- with x ->
- close_in ic;
- raise x
+ PM_impl compunit)
end in
- { pm_file = file; pm_name = name; pm_kind = kind }
-)
+ let pm_ident = Ident.create_persistent name in
+ let pm_packed_ident = Ident.create_persistent(targetname ^ "." ^ name) in
+ { pm_file = file; pm_name = name; pm_kind = kind; pm_ident; pm_packed_ident }
(* Read the bytecode from a .cmo file.
Write bytecode to channel [oc].
Rename globals as indicated by [mapping] in reloc info.
Accumulate relocs, debug info, etc.
- Return size of bytecode. *)
+ Return the accumulated state. *)
-let rename_append_bytecode packagename oc mapping defined ofs prefix subst
- objfile compunit =
+let rename_append_bytecode packagename oc state objfile compunit =
let ic = open_in_bin objfile in
try
Bytelink.check_consistency objfile compunit;
- List.iter
- (rename_relocation packagename objfile mapping defined ofs)
- compunit.cu_reloc;
- primitives := compunit.cu_primitives @ !primitives;
- if compunit.cu_force_link then force_link := true;
+ let relocs =
+ rev_append_map
+ (rename_relocation packagename objfile state.mapping state.offset)
+ compunit.cu_reloc
+ state.relocs in
+ let primitives = List.rev_append compunit.cu_primitives state.primitives in
seek_in ic compunit.cu_pos;
Misc.copy_file_chunk ic oc compunit.cu_codesize;
- if !Clflags.debug && compunit.cu_debug > 0 then begin
- seek_in ic compunit.cu_debug;
- List.iter (relocate_debug ofs prefix subst) (input_value ic);
- debug_dirs := List.fold_left
- (fun s e -> String.Set.add e s)
- !debug_dirs
- (input_value ic);
- end;
+ let events, debug_dirs =
+ if !Clflags.debug && compunit.cu_debug > 0 then begin
+ seek_in ic compunit.cu_debug;
+ let unit_events = (input_value ic : debug_event list) in
+ let events =
+ rev_append_map
+ (relocate_debug state.offset packagename state.subst)
+ unit_events
+ state.events in
+ let unit_debug_dirs = (input_value ic : string list) in
+ let debug_dirs =
+ String.Set.union
+ state.debug_dirs
+ (String.Set.of_list unit_debug_dirs) in
+ events, debug_dirs
+ end
+ else state.events, state.debug_dirs
+ in
close_in ic;
- compunit.cu_codesize
+ { state with
+ relocs; primitives; events; debug_dirs;
+ offset = state.offset + compunit.cu_codesize;
+ }
with x ->
close_in ic;
raise x
(* Same, for a list of .cmo and .cmi files.
- Return total size of bytecode. *)
-
-let rec rename_append_bytecode_list packagename oc mapping defined ofs
- prefix subst =
- function
- [] ->
- ofs
- | m :: rem ->
- match m.pm_kind with
- | PM_intf ->
- rename_append_bytecode_list packagename oc mapping defined ofs
- prefix subst rem
- | PM_impl compunit ->
- let size =
- rename_append_bytecode packagename oc mapping defined ofs
- prefix subst m.pm_file compunit in
- let id = Ident.create_persistent m.pm_name in
- let root = Path.Pident (Ident.create_persistent prefix) in
- rename_append_bytecode_list packagename oc mapping (id :: defined)
- (ofs + size) prefix
- (Subst.add_module id (Path.Pdot (root, Ident.name id))
- subst)
- rem
+ Return the accumulated state. *)
+let rename_append_pack_member packagename oc state m =
+ match m.pm_kind with
+ | PM_intf -> state
+ | PM_impl compunit ->
+ let state =
+ rename_append_bytecode packagename oc state m.pm_file compunit in
+ let id = m.pm_ident in
+ let root = Path.Pident (Ident.create_persistent packagename) in
+ let mapping = Ident.Map.update id (function
+ | Some (p,false) -> Some (p,true)
+ | Some (_, true) | None -> assert false) state.mapping in
+ let subst =
+ Subst.add_module id (Path.Pdot (root, Ident.name id)) state.subst in
+ { state with subst; mapping }
(* Generate the code that builds the tuple representing the package module *)
-let build_global_target ~ppf_dump oc target_name members mapping pos coercion =
- let components =
- List.map2
- (fun m (_id1, id2) ->
- match m.pm_kind with
- | PM_intf -> None
- | PM_impl _ -> Some id2)
- members mapping in
+let build_global_target ~ppf_dump oc target_name state components coercion =
let lam =
Translmod.transl_package
components (Ident.create_persistent target_name) coercion in
@@ -200,15 +214,20 @@ let build_global_target ~ppf_dump oc target_name members mapping pos coercion =
Format.fprintf ppf_dump "%a@." Printlambda.lambda lam;
let instrs =
Bytegen.compile_implementation target_name lam in
- let rel =
+ let size, pack_relocs, pack_events, pack_debug_dirs =
Emitcode.to_packed_file oc instrs in
- relocs := List.map (fun (r, ofs) -> (r, pos + ofs)) rel @ !relocs
+ let events = List.rev_append pack_events state.events in
+ let debug_dirs = String.Set.union pack_debug_dirs state.debug_dirs in
+ let relocs =
+ rev_append_map
+ (fun (r, ofs) -> (r, state.offset + ofs))
+ pack_relocs state.relocs in
+ { state with events; debug_dirs; relocs; offset = state.offset + size}
(* Build the .cmo file obtained by packaging the given .cmo files. *)
let package_object_files ~ppf_dump files targetfile targetname coercion =
- let members =
- map_left_right read_member_info files in
+ let members = map_left_right (read_member_info targetname) files in
let required_globals =
List.fold_right (fun compunit required_globals -> match compunit with
| { pm_kind = PM_intf } ->
@@ -227,30 +246,43 @@ let package_object_files ~ppf_dump files targetfile targetname coercion =
List.fold_right Ident.Set.add cu_required_globals required_globals)
members Ident.Set.empty
in
- let unit_names =
- List.map (fun m -> m.pm_name) members in
- let mapping =
- List.map
- (fun name ->
- (Ident.create_persistent name,
- Ident.create_persistent(targetname ^ "." ^ name)))
- unit_names in
let oc = open_out_bin targetfile in
- try
+ Fun.protect ~finally:(fun () -> close_out oc) (fun () ->
output_string oc Config.cmo_magic_number;
let pos_depl = pos_out oc in
output_binary_int oc 0;
let pos_code = pos_out oc in
- let ofs = rename_append_bytecode_list targetname oc mapping [] 0
- targetname Subst.identity members in
- build_global_target ~ppf_dump oc targetname members mapping ofs coercion;
+ let state =
+ let mapping =
+ List.map
+ (fun m -> m.pm_ident, (m.pm_packed_ident, false))
+ members
+ |> Ident.Map.of_list in
+ { empty_state with mapping } in
+ let state =
+ List.fold_left (rename_append_pack_member targetname oc) state members in
+ let components =
+ List.map
+ (fun m ->
+ match m.pm_kind with
+ | PM_intf -> None
+ | PM_impl _ -> Some m.pm_packed_ident)
+ members in
+ let state =
+ build_global_target ~ppf_dump oc targetname state components coercion in
let pos_debug = pos_out oc in
- if !Clflags.debug && !events <> [] then begin
- output_value oc (List.rev !events);
- output_value oc (String.Set.elements !debug_dirs);
+ if !Clflags.debug && state.events <> [] then begin
+ output_value oc (List.rev state.events);
+ output_value oc (String.Set.elements state.debug_dirs);
end;
+ let force_link =
+ List.exists (function
+ | {pm_kind = PM_impl {cu_force_link}} -> cu_force_link
+ | _ -> false) members in
let pos_final = pos_out oc in
let imports =
+ let unit_names =
+ List.map (fun m -> m.pm_name) members in
List.filter
(fun (name, _crc) -> not (List.mem name unit_names))
(Bytelink.extract_crc_interfaces()) in
@@ -258,42 +290,38 @@ let package_object_files ~ppf_dump files targetfile targetname coercion =
{ cu_name = targetname;
cu_pos = pos_code;
cu_codesize = pos_debug - pos_code;
- cu_reloc = List.rev !relocs;
+ cu_reloc = List.rev state.relocs;
cu_imports =
(targetname, Some (Env.crc_of_unit targetname)) :: imports;
- cu_primitives = !primitives;
+ cu_primitives = List.rev state.primitives;
cu_required_globals = Ident.Set.elements required_globals;
- cu_force_link = !force_link;
+ cu_force_link = force_link;
cu_debug = if pos_final > pos_debug then pos_debug else 0;
cu_debugsize = pos_final - pos_debug } in
Emitcode.marshal_to_channel_with_possibly_32bit_compat
~filename:targetfile ~kind:"bytecode unit"
oc compunit;
seek_out oc pos_depl;
- output_binary_int oc pos_final;
- close_out oc
- with x ->
- close_out oc;
- raise x
+ output_binary_int oc pos_final)
(* The entry point *)
let package_files ~ppf_dump initial_env files targetfile =
- let files =
+ let files =
List.map
- (fun f ->
- try Load_path.find f
- with Not_found -> raise(Error(File_not_found f)))
- files in
- let prefix = chop_extensions targetfile in
- let targetcmi = prefix ^ ".cmi" in
- let targetname = String.capitalize_ascii(Filename.basename prefix) in
- Misc.try_finally (fun () ->
- let coercion =
- Typemod.package_units initial_env files targetcmi targetname in
- package_object_files ~ppf_dump files targetfile targetname coercion
- )
- ~exceptionally:(fun () -> remove_file targetfile)
+ (fun f ->
+ try Load_path.find f
+ with Not_found -> raise(Error(File_not_found f)))
+ files in
+ let prefix = chop_extensions targetfile in
+ let targetcmi = prefix ^ ".cmi" in
+ let targetname = String.capitalize_ascii(Filename.basename prefix) in
+ Misc.try_finally (fun () ->
+ let coercion =
+ Typemod.package_units initial_env files targetcmi targetname in
+ package_object_files ~ppf_dump files targetfile targetname coercion
+ )
+ ~exceptionally:(fun () -> remove_file targetfile)
(* Error report *)
@@ -323,9 +351,3 @@ let () =
| Error err -> Some (Location.error_of_printer_file report_error err)
| _ -> None
)
-
-let reset () =
- relocs := [];
- events := [];
- primitives := [];
- force_link := false
diff --git a/bytecomp/bytepackager.mli b/bytecomp/bytepackager.mli
index 95177716b3..dbd9d0f46b 100644
--- a/bytecomp/bytepackager.mli
+++ b/bytecomp/bytepackager.mli
@@ -29,4 +29,3 @@ type error =
exception Error of error
val report_error: Format.formatter -> error -> unit
-val reset: unit -> unit
diff --git a/bytecomp/emitcode.ml b/bytecomp/emitcode.ml
index 0bb661f74b..8e600d7fa0 100644
--- a/bytecomp/emitcode.ml
+++ b/bytecomp/emitcode.ml
@@ -465,5 +465,8 @@ let to_packed_file outchan code =
Fun.protect ~finally:clear (fun () ->
emit code;
LongString.output outchan !out_buffer 0 !out_position;
- let reloc = !reloc_info in
- reloc)
+ let reloc = List.rev !reloc_info in
+ let events = !events in
+ let debug_dirs = !debug_dirs in
+ let size = !out_position in
+ (size, reloc, events, debug_dirs))
diff --git a/bytecomp/emitcode.mli b/bytecomp/emitcode.mli
index 40917e7a10..e82633d5cc 100644
--- a/bytecomp/emitcode.mli
+++ b/bytecomp/emitcode.mli
@@ -38,12 +38,17 @@ val to_memory:
relocation information
debug events *)
val to_packed_file:
- out_channel -> instruction list -> (reloc_info * int) list
+ out_channel -> instruction list ->
+ int * (reloc_info * int) list * debug_event list * Misc.Stdlib.String.Set.t
(* Arguments:
channel on output file
list of instructions to emit
Result:
- relocation information (reversed) *)
+ size of the emitted code
+ relocation information
+ debug events
+ debug directory
+ *)
val marshal_to_channel_with_possibly_32bit_compat :
filename:string -> kind:string -> out_channel -> 'a -> unit