(* * Copyright (c) 2009-2013, Monoidics ltd. * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. *) open! IStd (** Execution environments: basically a cache of where procedures are and what is their CFG and type environment *) module L = Logging (** per-file data: type environment and cfg *) type file_data = { source: SourceFile.t ; mutable tenv: Tenv.t option ; mutable integer_type_widths: Typ.IntegerWidths.t option } (** create a new file_data *) let new_file_data source = (* Do not fill in tenv and cfg as they can be quite large. This makes calls to fork() cheaper until we start filling out these fields. *) {source; tenv= None (* Sil.load_tenv_from_file tenv_file *); integer_type_widths= None} let create_file_data table source = match SourceFile.Hash.find table source with | file_data -> file_data | exception Caml.Not_found -> let file_data = new_file_data source in SourceFile.Hash.add table source file_data ; file_data type t = { proc_map: file_data Typ.Procname.Hash.t (** map from procedure name to file data *) ; file_map: file_data SourceFile.Hash.t (** map from source files to file data *) } let get_file_data exe_env pname = try Some (Typ.Procname.Hash.find exe_env.proc_map pname) with Caml.Not_found -> let source_file_opt = match Attributes.load pname with | None -> L.(debug Analysis Medium) "can't find tenv_cfg_object for %a@." Typ.Procname.pp pname ; None | Some proc_attributes when Config.reactive_capture -> let get_captured_file {ProcAttributes.translation_unit} = translation_unit in OndemandCapture.try_capture proc_attributes |> Option.map ~f:get_captured_file | Some proc_attributes -> Some proc_attributes.ProcAttributes.translation_unit in let get_file_data_for_source source_file = let file_data = create_file_data exe_env.file_map source_file in Typ.Procname.Hash.replace exe_env.proc_map pname file_data ; file_data in Option.map ~f:get_file_data_for_source source_file_opt let file_data_to_tenv file_data = if is_none file_data.tenv then file_data.tenv <- Tenv.load file_data.source ; file_data.tenv let file_data_to_integer_type_widths file_data = if is_none file_data.integer_type_widths then file_data.integer_type_widths <- Option.first_some (Typ.IntegerWidths.load file_data.source) (Some Typ.IntegerWidths.java) ; file_data.integer_type_widths let java_global_tenv = lazy ( match Tenv.load_global () with | None -> L.(die InternalError) "Could not load the global tenv" | Some tenv -> tenv ) let get_column_value ~value_on_java ~file_data_to_value ~column_name exe_env proc_name = match proc_name with | Typ.Procname.Java _ -> Lazy.force value_on_java | _ -> ( match get_file_data exe_env proc_name with | Some file_data -> ( match file_data_to_value file_data with | Some v -> v | None -> let loc = State.get_loc_exn () in L.(die InternalError) "get_column_value: %s not found for %a in file '%a' at %a" column_name Typ.Procname.pp proc_name SourceFile.pp loc.Location.file Location.pp loc ) | None -> let loc = State.get_loc_exn () in L.(die InternalError) "get_column_value: file_data not found for %a in file '%a' at %a" Typ.Procname.pp proc_name SourceFile.pp loc.Location.file Location.pp loc ) (** return the type environment associated to the procedure *) let get_tenv = get_column_value ~value_on_java:java_global_tenv ~file_data_to_value:file_data_to_tenv ~column_name:"tenv" (** return the integer type widths associated to the procedure *) let get_integer_type_widths = get_column_value ~value_on_java:(lazy Typ.IntegerWidths.java) ~file_data_to_value:file_data_to_integer_type_widths ~column_name:"integer type widths" let mk () = {proc_map= Typ.Procname.Hash.create 17; file_map= SourceFile.Hash.create 1}