Skip to content

Commit

Permalink
Cleanup function summary caches (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
hermanventer authored Dec 6, 2024
1 parent fc3dd65 commit 53e47c1
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 25 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified binaries/summary_store.tar
Binary file not shown.
10 changes: 5 additions & 5 deletions checker/src/call_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,18 +340,18 @@ impl<'call, 'block, 'analysis, 'compilation, 'tcx>
if let Some(func_ref) = &self.callee_func_ref.clone() {
// If the actual arguments include any function constants, collect them together
// and pass them to get_summary_for_function_constant so that their signatures
// can be included in the type specific key that is used to look up non generic
// can be included in the type specific key that is used to look up non-generic
// predefined summaries.

let func_args = self.get_function_constant_signature(self.function_constant_args);
let tcx = self.block_visitor.bv.tcx;
let callee_defid = func_ref.def_id.unwrap_or(self.callee_def_id);
let callee_def_id = func_ref.def_id.unwrap_or(self.callee_def_id);
self.block_visitor.bv.cv.call_graph.add_call_site(
self.block_visitor.bv.current_span,
self.block_visitor.bv.def_id,
callee_defid,
!tcx.is_mir_available(callee_defid)
|| (!callee_defid.is_local()
callee_def_id,
!tcx.is_mir_available(callee_def_id)
|| (!callee_def_id.is_local()
&& (self.callee_generic_arguments.is_none()
|| self
.callee_generic_arguments
Expand Down
35 changes: 22 additions & 13 deletions checker/src/summaries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,20 +352,26 @@ fn extract_reachable_heap_allocations(
}
}

/// If a call site provides type arguments to a generic function, or if some of the arguments
/// are constant functions, the function summary used at the call site needs to be specialized
/// with respect to these arguments and when we store summaries in a cache we need the cache
/// key to be based on these arguments.
#[derive(PartialEq, Eq)]
pub struct CallSiteKey<'tcx> {
/// If this is None, type_args must not be None.
func_args: Option<Rc<Vec<Rc<FunctionReference>>>>,
type_cache: Option<Rc<HashMap<Rc<Path>, Ty<'tcx>>>>,
/// If this is None, func_args must not be None.
type_args: Option<Rc<HashMap<Rc<Path>, Ty<'tcx>>>>,
}

impl<'tcx> CallSiteKey<'tcx> {
pub fn new(
func_args: Option<Rc<Vec<Rc<FunctionReference>>>>,
type_cache: Option<Rc<HashMap<Rc<Path>, Ty<'tcx>>>>,
type_args: Option<Rc<HashMap<Rc<Path>, Ty<'tcx>>>>,
) -> CallSiteKey<'tcx> {
CallSiteKey {
func_args,
type_cache,
type_args,
}
}
}
Expand All @@ -375,7 +381,7 @@ impl Hash for CallSiteKey<'_> {
if let Some(func_args) = &self.func_args {
func_args.hash(state);
}
if let Some(cache) = &self.type_cache {
if let Some(cache) = &self.type_args {
for (path, ty) in cache.iter() {
path.hash(state);
ty.kind().hash(state);
Expand All @@ -396,9 +402,14 @@ pub struct PersistentSummaryCache<'tcx> {
/// Functions that are generic instances are identified by their function_id and their summaries
/// are cached here.
typed_cache: HashMap<usize, Summary>,
/// Maps call sites to specialized summary of the referenced function.
/// Call site specialization involves using the actual generic arguments supplied by the call
/// site, along with the values of any constant functions that are supplied as actual arguments.
typed_cache_table: HashMap<CallSiteKey<'tcx>, HashMap<usize, Summary>>,
/// Functions that have no def_id (and hence no function_id) and no type signature are
/// cached here. Such functions are either entry points or dummy functions that provide
/// summaries for functions that have no MIR and are shadowed by definitions in a contracts crate.
reference_cache: HashMap<Rc<FunctionReference>, Summary>,
typed_reference_cache: HashMap<Rc<FunctionReference>, Summary>,
key_cache: HashMap<DefId, Rc<str>>,
type_context: TyCtxt<'tcx>,
}
Expand Down Expand Up @@ -445,7 +456,6 @@ impl<'tcx> PersistentSummaryCache<'tcx> {
typed_cache: HashMap::new(),
typed_cache_table: HashMap::new(),
reference_cache: HashMap::new(),
typed_reference_cache: HashMap::new(),
key_cache: HashMap::new(),
type_context,
}
Expand Down Expand Up @@ -505,14 +515,13 @@ impl<'tcx> PersistentSummaryCache<'tcx> {
&mut self,
func_ref: &Rc<FunctionReference>,
func_args: &Option<Rc<Vec<Rc<FunctionReference>>>>,
initial_type_cache: &Option<Rc<HashMap<Rc<Path>, Ty<'tcx>>>>,
type_args: &Option<Rc<HashMap<Rc<Path>, Ty<'tcx>>>>,
) -> &Summary {
match (func_ref.def_id, func_ref.function_id) {
// Use the ids as keys if they are available, since they make much better keys.
(Some(def_id), Some(function_id)) => {
if func_args.is_some() || initial_type_cache.is_some() {
let typed_cache_key =
CallSiteKey::new(func_args.clone(), initial_type_cache.clone());
if func_args.is_some() || type_args.is_some() {
let typed_cache_key = CallSiteKey::new(func_args.clone(), type_args.clone());
// Need the double lookup in order to allow the recursive call to get_summary_for_function_constant.
let summary_is_cached =
if let Some(type_table) = self.typed_cache_table.get(&typed_cache_key) {
Expand Down Expand Up @@ -566,16 +575,16 @@ impl<'tcx> PersistentSummaryCache<'tcx> {
// was created. We look them up in the database. If they are not found there, we use
// a default summary. Either way, we cache the summary in the appropriate reference cache.
_ => {
if self.typed_reference_cache.contains_key(func_ref) {
let result = self.typed_reference_cache.get(func_ref);
if self.reference_cache.contains_key(func_ref) {
let result = self.reference_cache.get(func_ref);
result.expect("value disappeared from typed_reference_cache")
} else {
if let Some(summary) = self.get_persistent_summary_using_arg_types_if_possible(
&func_ref.summary_cache_key,
&func_ref.argument_type_key,
) {
return self
.typed_reference_cache
.reference_cache
.entry(func_ref.clone())
.or_insert(summary);
}
Expand Down
2 changes: 1 addition & 1 deletion validate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ cargo update
# Run format checks
cargo fmt --all
# Run lint checks
#cargo audit
cargo audit
cargo clippy --no-default-features --all-targets -- -D warnings
# Build mirai (in debug mode) so that we can build the standard contracts
cargo build --no-default-features
Expand Down

0 comments on commit 53e47c1

Please sign in to comment.