File: import_approx.ml

package info (click to toggle)
ocaml 5.3.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 43,124 kB
  • sloc: ml: 355,439; ansic: 51,636; sh: 25,098; asm: 5,413; makefile: 3,673; python: 919; javascript: 273; awk: 253; perl: 59; fortran: 21; cs: 9
file content (221 lines) | stat: -rw-r--r-- 8,853 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
(**************************************************************************)
(*                                                                        *)
(*                                 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 A = Simple_value_approx

let import_set_of_closures =
  let import_function_declarations (clos : A.function_declarations)
        : A.function_declarations =
    (* CR-soon mshinwell for pchambart: Do we still need to do this
       rewriting?  I'm wondering if maybe we don't have to any more. *)
    let sym_to_fun_var_map (clos : A.function_declarations) =
      Variable.Map.fold (fun fun_var _ acc ->
           let closure_id = Closure_id.wrap fun_var in
           let sym = Compilenv.closure_symbol closure_id in
           Symbol.Map.add sym fun_var acc)
        clos.funs Symbol.Map.empty
    in
    let sym_map = sym_to_fun_var_map clos in
    let f_named (named : Flambda.named) =
      match named with
      | Symbol sym ->
        begin try Flambda.Expr (Var (Symbol.Map.find sym sym_map)) with
        | Not_found -> named
        end
      | named -> named
    in
    let funs =
      Variable.Map.map (fun (function_decl : A.function_declaration) ->
        A.update_function_declaration_body function_decl
          (Flambda_iterators.map_toplevel_named f_named))
        clos.funs
    in
    A.update_function_declarations clos ~funs
  in
  let aux set_of_closures_id =
    match
      Compilenv.approx_for_global
        (Set_of_closures_id.get_compilation_unit set_of_closures_id)
    with
    | None -> None
    | Some ex_info ->
      try
        let function_declarations =
          Set_of_closures_id.Map.find set_of_closures_id
            ex_info.sets_of_closures
        in
        Some (import_function_declarations function_declarations)
      with Not_found ->
        Misc.fatal_error "Cannot find set of closures"
  in
  Set_of_closures_id.Tbl.memoize Compilenv.imported_sets_of_closures_table aux

let rec import_ex ex =
  let import_value_set_of_closures ~set_of_closures_id ~bound_vars ~free_vars
        ~(ex_info : Export_info.t) ~what : A.value_set_of_closures option =
    let bound_vars = Var_within_closure.Map.map import_approx bound_vars in
    match import_set_of_closures set_of_closures_id with
    | None -> None
    | Some function_decls ->
      (* CR-someday xclerc: add a test to the test suite to ensure that
         classic mode behaves as expected. *)
      let is_classic_mode = function_decls.is_classic_mode in
      let invariant_params =
        match
          Set_of_closures_id.Map.find set_of_closures_id
            ex_info.invariant_params
        with
        | exception Not_found ->
          if is_classic_mode then
            Variable.Map.empty
          else
            Misc.fatal_errorf "Set of closures ID %a not found in \
                               invariant_params (when importing [%a: %s])"
              Set_of_closures_id.print set_of_closures_id
              Export_id.print ex
              what
        | found -> found
      in
      let recursive =
        match
          Set_of_closures_id.Map.find set_of_closures_id ex_info.recursive
        with
        | exception Not_found ->
          if is_classic_mode then
            Variable.Set.empty
          else
            Misc.fatal_errorf "Set of closures ID %a not found in \
                               recursive (when importing [%a: %s])"
              Set_of_closures_id.print set_of_closures_id
              Export_id.print ex
              what
        | found -> found
      in
      Some (A.create_value_set_of_closures
        ~function_decls
        ~bound_vars
        ~free_vars
        ~invariant_params:(lazy invariant_params)
        ~recursive:(lazy recursive)
        ~specialised_args:Variable.Map.empty
        ~freshening:Freshening.Project_var.empty
        ~direct_call_surrogates:Closure_id.Map.empty)
  in
  let compilation_unit = Export_id.get_compilation_unit ex in
  match Compilenv.approx_for_global compilation_unit with
  | None -> A.value_unknown Other
  | Some ex_info ->
    match Export_info.find_description ex_info ex with
    | exception Not_found ->
      Misc.fatal_errorf "Cannot find export id %a" Export_id.print ex
    | Value_unknown_descr -> A.value_unknown Other
    | Value_int i -> A.value_int i
    | Value_char c -> A.value_char c
    | Value_float f -> A.value_float f
    | Value_float_array float_array ->
      begin match float_array.contents with
      | Unknown_or_mutable ->
        A.value_mutable_float_array ~size:float_array.size
      | Contents contents ->
        A.value_immutable_float_array
          (Array.map (function
             | None -> A.value_any_float
             | Some f -> A.value_float f)
             contents)
      end
    | Export_info.Value_boxed_int (t, i) -> A.value_boxed_int t i
    | Value_string { size; contents } ->
      let contents =
        match contents with
        | Unknown_or_mutable -> None
        | Contents contents -> Some contents
      in
      A.value_string size contents
    | Value_mutable_block _ -> A.value_unknown Other
    | Value_block (tag, fields) ->
      A.value_block tag (Array.map import_approx fields)
    | Value_closure { closure_id;
          set_of_closures =
            { set_of_closures_id; bound_vars; free_vars; aliased_symbol } } ->
      let value_set_of_closures =
        import_value_set_of_closures
          ~set_of_closures_id ~bound_vars ~free_vars ~ex_info
          ~what:(Format.asprintf "Value_closure %a" Closure_id.print closure_id)
      in
      begin match value_set_of_closures with
      | None -> A.value_unresolved (Set_of_closures_id set_of_closures_id)
      | Some value_set_of_closures ->
        A.value_closure ?set_of_closures_symbol:aliased_symbol
          value_set_of_closures closure_id
      end
    | Value_set_of_closures
        { set_of_closures_id; bound_vars; free_vars; aliased_symbol } ->
      let value_set_of_closures =
        import_value_set_of_closures ~set_of_closures_id
          ~bound_vars ~free_vars ~ex_info ~what:"Value_set_of_closures"
      in
      match value_set_of_closures with
      | None ->
        A.value_unresolved (Set_of_closures_id set_of_closures_id)
      | Some value_set_of_closures ->
        let approx = A.value_set_of_closures value_set_of_closures in
        match aliased_symbol with
        | None -> approx
        | Some symbol -> A.augment_with_symbol approx symbol

and import_approx (ap : Export_info.approx) =
  match ap with
  | Value_unknown -> A.value_unknown Other
  | Value_id ex -> A.value_extern ex
  | Value_symbol sym -> A.value_symbol sym

let import_symbol sym =
  if Compilenv.is_predefined_exception sym then
    A.value_unknown Other
  else begin
    let compilation_unit = Symbol.compilation_unit sym in
    match Compilenv.approx_for_global compilation_unit with
    | None -> A.value_unresolved (Symbol sym)
    | Some export_info ->
      match Symbol.Map.find sym export_info.symbol_id with
      | approx -> A.augment_with_symbol (import_ex approx) sym
      | exception Not_found ->
        Misc.fatal_errorf
          "Compilation unit = %a Cannot find symbol %a"
          Compilation_unit.print compilation_unit
          Symbol.print sym
  end

(* Note for code reviewers: Observe that [really_import] iterates until
   the approximation description is fully resolved (or a necessary .cmx
   file is missing). *)

let rec really_import (approx : A.descr) =
  match approx with
  | Value_extern ex -> really_import_ex ex
  | Value_symbol sym -> really_import_symbol sym
  | r -> r

and really_import_ex ex =
  really_import (import_ex ex).descr

and really_import_symbol sym =
  really_import (import_symbol sym).descr

let really_import_approx (approx : Simple_value_approx.t) =
  A.replace_description approx (really_import approx.descr)