source/interprocedural/fixpointState.ml (125 lines of code) (raw):
(*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open Core
module SharedMemory = Memory
module Epoch = struct
type t = int [@@deriving show]
let predefined = 0
let initial = 1
end
type step = {
epoch: Epoch.t;
iteration: int;
}
[@@deriving show]
type t = {
is_partial: bool;
(* Whether to reanalyze this and its callers. *)
model: AnalysisResult.model_t;
(* Model to use at call sites. *)
result: AnalysisResult.result_t; (* The result of the analysis. *)
}
module SharedModels =
SharedMemory.WithCache.Make
(Target.Key)
(struct
type t = AnalysisResult.model_t
let prefix = Prefix.make ()
let description = "InterproceduralFixpointModel"
let unmarshall value = Marshal.from_string value 0
end)
module SharedResults =
SharedMemory.WithCache.Make
(Target.Key)
(struct
type t = AnalysisResult.result_t
let prefix = Prefix.make ()
let description = "InterproceduralFixpointResults"
let unmarshall value = Marshal.from_string value 0
end)
type meta_data = {
is_partial: bool;
step: step;
}
(* Caches the fixpoint state (is_partial) of a call model. *)
module SharedFixpoint =
SharedMemory.WithCache.Make
(Target.Key)
(struct
type t = meta_data
let prefix = Prefix.make ()
let description = "InterproceduralFixpointMetadata"
let unmarshall value = Marshal.from_string value 0
end)
module KeySet = SharedModels.KeySet
module KeyMap = SharedModels.KeyMap
let get_new_model callable =
let callable = (callable :> Target.t) in
SharedModels.get callable
let get_old_model callable =
let callable = (callable :> Target.t) in
SharedModels.get_old callable
let get_model callable =
let callable = (callable :> Target.t) in
match get_new_model callable with
| Some _ as model -> model
| None -> get_old_model callable
let get_result callable =
let callable = (callable :> Target.t) in
SharedResults.get callable |> Option.value ~default:AnalysisResult.empty_result
let get_is_partial callable =
let callable = (callable :> Target.t) in
match SharedFixpoint.get callable with
| Some { is_partial; _ } -> is_partial
| None -> (
match SharedFixpoint.get_old callable with
| None -> true
| Some { is_partial; _ } -> is_partial)
let get_meta_data callable =
let callable = (callable :> Target.t) in
match SharedFixpoint.get callable with
| Some _ as meta_data -> meta_data
| None -> SharedFixpoint.get_old callable
let has_model callable =
let key = (callable :> Target.t) in
SharedModels.mem key
let meta_data_to_string { is_partial; step = { epoch; iteration } } =
Format.sprintf "{ partial: %b; epoch: %d; iteration: %d }" is_partial epoch iteration
let add step callable state =
let callable = (callable :> Target.t) in
(* Separate diagnostics from state to speed up lookups, and cache fixpoint state separately. *)
let () = SharedModels.add callable state.model in
(* Skip result writing unless necessary (e.g. overrides don't have results) *)
let () =
match callable with
| #Target.t_with_result -> SharedResults.add callable state.result
| _ -> ()
in
SharedFixpoint.add callable { is_partial = state.is_partial; step }
let add_predefined epoch callable model =
let callable = (callable :> Target.t) in
let () = SharedModels.add callable model in
let step = { epoch; iteration = 0 } in
SharedFixpoint.add callable { is_partial = false; step }
let get_new_models = SharedModels.get_batch
let get_new_results = SharedResults.get_batch
let oldify callable_set =
SharedModels.oldify_batch callable_set;
SharedFixpoint.oldify_batch callable_set;
(* Old results are never looked up, so remove them. *)
SharedResults.remove_batch callable_set
let remove_new callable_set =
SharedModels.remove_batch callable_set;
SharedFixpoint.remove_batch callable_set;
SharedResults.remove_batch callable_set
let remove_old callable_set =
SharedModels.remove_old_batch callable_set;
SharedFixpoint.remove_old_batch callable_set
(* No old results. *)
let is_initial_iteration { epoch = _; iteration } = iteration = 0
let invalidate_model_cache = SharedModels.invalidate_cache
let invalidate_result_cache = SharedResults.invalidate_cache