ocaml/middle_end/share_constants.ml

130 lines
4.9 KiB
OCaml

(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Pierre Chambart, OCamlPro *)
(* Mark Shinwell and Leo White, Jane Street Europe *)
(* *)
(* Copyright 2013--2016 OCamlPro SAS *)
(* Copyright 2014--2016 Jane Street Group LLC *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
[@@@ocaml.warning "+a-4-9-30-40-41-42"]
module Constant_defining_value = Flambda.Constant_defining_value
let update_constant_for_sharing sharing_symbol_tbl const
: Flambda.constant_defining_value =
let substitute_symbol sym =
match Symbol.Tbl.find sharing_symbol_tbl sym with
| exception Not_found -> sym
| symbol -> symbol
in
match (const:Flambda.constant_defining_value) with
| Allocated_const _ -> const
| Block (tag, fields) ->
let subst_field (field:Flambda.constant_defining_value_block_field) :
Flambda.constant_defining_value_block_field =
match field with
| Const _ -> field
| Symbol sym ->
Symbol (substitute_symbol sym)
in
let fields = List.map subst_field fields in
Block (tag, fields)
| Set_of_closures set_of_closures ->
Set_of_closures (
Flambda_iterators.map_symbols_on_set_of_closures
~f:substitute_symbol set_of_closures
)
| Project_closure (sym, closure_id) ->
Project_closure (substitute_symbol sym, closure_id)
let cannot_share (const : Flambda.constant_defining_value) =
match const with
(* Strings and float arrays are mutable; we never share them. *)
| Allocated_const ((String _) | (Float_array _)) -> true
| Allocated_const _ | Set_of_closures _ | Project_closure _ | Block _ ->
false
let share_definition constant_to_symbol_tbl sharing_symbol_tbl
symbol def end_symbol =
let def = update_constant_for_sharing sharing_symbol_tbl def in
if cannot_share def || Symbol.equal symbol end_symbol then
(* The symbol exported by the unit (end_symbol), cannot be removed
from the module. We prevent it from being shared to avoid that. *)
Some def
else
begin match Constant_defining_value.Tbl.find constant_to_symbol_tbl def with
| exception Not_found ->
Constant_defining_value.Tbl.add constant_to_symbol_tbl def symbol;
Some def
| equal_symbol ->
Symbol.Tbl.add sharing_symbol_tbl symbol equal_symbol;
None
end
let rec end_symbol (program : Flambda.program_body) =
match program with
| End symbol -> symbol
| Let_symbol (_, _, program)
| Let_rec_symbol (_, program)
| Initialize_symbol (_, _, _, program)
| Effect (_, program) ->
end_symbol program
let share_constants (program : Flambda.program) =
let end_symbol = end_symbol program.program_body in
let sharing_symbol_tbl = Symbol.Tbl.create 42 in
let constant_to_symbol_tbl = Constant_defining_value.Tbl.create 42 in
let rec loop (program : Flambda.program_body) : Flambda.program_body =
match program with
| Let_symbol (symbol,def,program) ->
begin match
share_definition constant_to_symbol_tbl sharing_symbol_tbl symbol
def end_symbol
with
| None ->
loop program
| Some def' ->
Let_symbol (symbol,def',loop program)
end
| Let_rec_symbol (defs,program) ->
let defs =
List.map (fun (symbol, def) ->
let def = update_constant_for_sharing sharing_symbol_tbl def in
symbol, def)
defs
in
Let_rec_symbol (defs, loop program)
| Initialize_symbol (symbol,tag,fields,program) ->
let fields =
List.map (fun field ->
Flambda_iterators.map_symbols
~f:(fun symbol ->
try Symbol.Tbl.find sharing_symbol_tbl symbol with
| Not_found -> symbol)
field)
fields
in
Initialize_symbol (symbol,tag,fields,loop program)
| Effect (expr,program) ->
let expr =
Flambda_iterators.map_symbols
~f:(fun symbol ->
try Symbol.Tbl.find sharing_symbol_tbl symbol with
| Not_found -> symbol)
expr
in
Effect (expr, loop program)
| End root -> End root
in
{ program with
program_body = loop program.program_body;
}