[proc-cfg][3/5] stop caching whole-file cfgs in exe_env

Summary:
Load proc descs from the "procedures" sqlite table instead of from
file-wide cfgs stored in the "source_files" table. This removes the need
for a cache of these file-wide CFGs, which was needed because loading
them is expensive and potentially needed in case we need to load the
proc descs of several procedures in the same file. Now we can just load
the proc descs one by one and not worry about caching.

Reviewed By: jberdine

Differential Revision: D10173355

fbshipit-source-id: 665636121
master
Jules Villard 6 years ago committed by Facebook Github Bot
parent 7615963bf4
commit 31e01a9aa0

@ -61,7 +61,7 @@ FROM (
FROM procedures
WHERE proc_name = :pname )
WHERE attr_kind < :akind
OR (attr_kind = :akind AND source_file < :sfile) )|}
OR (attr_kind = :akind AND source_file <= :sfile) )|}
let replace pname pname_blob akind loc_file attr_blob proc_desc =

@ -63,6 +63,9 @@ type t =
; proc_name: Typ.Procname.t (** name of the procedure *)
; ret_type: Typ.t (** return type *)
; has_added_return_param: bool (** whether or not a return param was added *) }
[@@deriving compare]
let equal = [%compare.equal: t]
let default translation_unit proc_name =
{ access= PredSymb.Default
@ -165,7 +168,7 @@ let pp f
F.fprintf f "; clang_method_kind= %a@,"
(Pp.to_string ~f:ClangMethodKind.to_string)
clang_method_kind ;
if not (Location.equal default.loc loc) then F.fprintf f "; loc= %a@," Location.pp loc ;
if not (Location.equal default.loc loc) then F.fprintf f "; loc= %a@," Location.pp_file_pos loc ;
if not ([%compare.equal: var_data list] default.locals locals) then
F.fprintf f "; locals= [@[%a@]]@,"
(Pp.semicolon_seq ~print_env:Pp.text_break pp_var_data)

@ -47,6 +47,9 @@ type t =
; ret_type: Typ.t (** return type *)
; has_added_return_param: bool (** whether or not a return param was added *) }
val equal : t -> t -> bool [@@warning "-32"]
(** can be useful for debugging *)
val default : SourceFile.t -> Typ.Procname.t -> t
(** Create a proc_attributes with default values. *)

@ -755,3 +755,15 @@ let is_connected proc_desc =
module SQLite = SqliteUtils.MarshalledNullableData (struct
type nonrec t = t
end)
let load_statement =
ResultsDatabase.register_statement "SELECT cfg FROM procedures WHERE proc_name = :k"
let load pname =
ResultsDatabase.with_registered_statement load_statement ~f:(fun db stmt ->
Typ.Procname.SQLite.serialize pname
|> Sqlite3.bind stmt 1
|> SqliteUtils.check_result_code db ~log:"load bind proc name" ;
SqliteUtils.result_single_column_option ~finalize:false ~log:"Procdesc.load" db stmt
|> Option.bind ~f:SQLite.deserialize )

@ -291,3 +291,5 @@ val is_connected : t -> (unit, [`Join | `Other]) Result.t
(** per-procedure CFGs are stored in the SQLite "procedures" table as NULL if the procedure has no
CFG *)
module SQLite : SqliteUtils.Data with type t = t option
val load : Typ.Procname.t -> t option

@ -44,11 +44,10 @@ let register_cluster_callback ~name language (callback : cluster_callback_t) =
(** Collect what we need to know about a procedure for the analysis. *)
let get_procedure_definition exe_env proc_name =
Option.map
~f:(fun proc_desc ->
let tenv = Exe_env.get_tenv exe_env proc_name in
(tenv, proc_desc) )
(Exe_env.get_proc_desc exe_env proc_name)
Procdesc.load proc_name
|> Option.map ~f:(fun proc_desc ->
let tenv = Exe_env.get_tenv exe_env proc_name in
(tenv, proc_desc) )
(** Invoke all registered procedure callbacks on the given procedure. *)
@ -57,11 +56,14 @@ let iterate_procedure_callbacks exe_env summary proc_desc =
let procedure_language = Typ.Procname.get_language proc_name in
Language.curr_language := procedure_language ;
let get_procs_in_file proc_name =
match Exe_env.get_cfg exe_env proc_name with
| Some cfg ->
Cfg.get_all_defined_proc_names cfg
| None ->
[]
let source_file =
match Attributes.load proc_name with
| Some {ProcAttributes.translation_unit} ->
Some translation_unit
| None ->
None
in
Option.value_map source_file ~default:[] ~f:SourceFiles.proc_names_of_source
in
let tenv = Exe_env.get_tenv exe_env proc_name in
let is_specialized = Procdesc.is_specialized proc_desc in

@ -14,15 +14,13 @@ open! IStd
module L = Logging
(** per-file data: type environment and cfg *)
type file_data = {source: SourceFile.t; mutable tenv: Tenv.t option; mutable cfg: Cfg.t option}
type file_data = {source: SourceFile.t; mutable tenv: Tenv.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 *)
; cfg= None (* Cfg.load_cfg_from_file cfg_file *) }
{source; tenv= None (* Sil.load_tenv_from_file tenv_file *)}
let create_file_data table source =
@ -65,11 +63,6 @@ let file_data_to_tenv file_data =
file_data.tenv
let file_data_to_cfg file_data =
if is_none file_data.cfg then file_data.cfg <- Cfg.load file_data.source ;
file_data.cfg
let java_global_tenv =
lazy
( match Tenv.load_global () with
@ -102,22 +95,4 @@ let get_tenv exe_env proc_name =
SourceFile.pp loc.Location.file Location.pp loc )
(** return the cfg associated to the procedure *)
let get_cfg exe_env pname =
match get_file_data exe_env pname with
| None ->
None
| Some file_data ->
file_data_to_cfg file_data
(** return the proc desc associated to the procedure *)
let get_proc_desc exe_env pname =
match get_cfg exe_env pname with
| Some cfg ->
Typ.Procname.Hash.find_opt cfg pname
| None ->
None
let mk () = {proc_map= Typ.Procname.Hash.create 17; file_map= SourceFile.Hash.create 1}

@ -8,7 +8,7 @@
open! IStd
(** Execution environments: basically a cache of where procedures are and what is their CFG and type
(** Execution environments: basically a cache of where procedures are and what is their type
environment *)
type file_data
@ -22,9 +22,3 @@ val mk : unit -> t
val get_tenv : t -> Typ.Procname.t -> Tenv.t
(** return the type environment associated with the procedure *)
val get_cfg : t -> Typ.Procname.t -> Cfg.t option
(** return the cfg associated with the procedure *)
val get_proc_desc : t -> Typ.Procname.t -> Procdesc.t option
(** return the proc desc associated with the procedure *)

@ -236,8 +236,7 @@ let analyze_proc_desc ~caller_pdesc callee_pdesc =
(** Find a proc desc for the procedure, perhaps loading it from disk. *)
let get_proc_desc callee_pname =
let callbacks = Option.value_exn !callbacks_ref in
match Exe_env.get_proc_desc callbacks.exe_env callee_pname with
match Procdesc.load callee_pname with
| Some _ as pdesc_opt ->
pdesc_opt
| None ->

@ -61,7 +61,7 @@ let do_source_file (translation_unit_context : CFrontend_config.translation_unit
Config.debug_mode || Config.testing_mode || Config.frontend_tests
|| Option.is_some Config.icfg_dotty_outfile
then Dotty.print_icfg_dotty source_file cfg ;
L.(debug Capture Verbose) "%a" Cfg.pp_proc_signatures cfg ;
L.(debug Capture Verbose) "Stored on disk:@[<v>%a@]@." Cfg.pp_proc_signatures cfg ;
let procedures_translated_summary =
EventLogger.ProceduresTranslatedSummary
{ procedures_translated_total= !CFrontend_config.procedures_attempted

Loading…
Cancel
Save