Introduce an abstraction for EvaluationCache and SelectionCache.
This commit is contained in:
parent
2c28244cf0
commit
e288d05012
4 changed files with 81 additions and 87 deletions
|
@ -6,29 +6,18 @@ use self::EvaluationResult::*;
|
||||||
|
|
||||||
use super::{SelectionError, SelectionResult};
|
use super::{SelectionError, SelectionResult};
|
||||||
|
|
||||||
use crate::dep_graph::DepNodeIndex;
|
use crate::ty;
|
||||||
use crate::ty::{self, TyCtxt};
|
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
|
||||||
use rustc_data_structures::sync::Lock;
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_query_system::cache::Cache;
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
pub type SelectionCache<'tcx> = Cache<
|
||||||
pub struct SelectionCache<'tcx> {
|
ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
|
||||||
pub hashmap: Lock<
|
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
|
||||||
FxHashMap<
|
>;
|
||||||
ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
|
|
||||||
WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> SelectionCache<'tcx> {
|
pub type EvaluationCache<'tcx> =
|
||||||
/// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
|
Cache<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, EvaluationResult>;
|
||||||
pub fn clear(&self) {
|
|
||||||
*self.hashmap.borrow_mut() = Default::default();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The selection process begins by considering all impls, where
|
/// The selection process begins by considering all impls, where
|
||||||
/// clauses, and so forth that might resolve an obligation. Sometimes
|
/// clauses, and so forth that might resolve an obligation. Sometimes
|
||||||
|
@ -265,37 +254,6 @@ impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
|
||||||
pub struct EvaluationCache<'tcx> {
|
|
||||||
pub hashmap: Lock<
|
|
||||||
FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
|
|
||||||
>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> EvaluationCache<'tcx> {
|
|
||||||
/// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
|
|
||||||
pub fn clear(&self) {
|
|
||||||
*self.hashmap.borrow_mut() = Default::default();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
|
||||||
pub struct WithDepNode<T> {
|
|
||||||
dep_node: DepNodeIndex,
|
|
||||||
cached_value: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> WithDepNode<T> {
|
|
||||||
pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
|
|
||||||
WithDepNode { dep_node, cached_value }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, tcx: TyCtxt<'_>) -> T {
|
|
||||||
tcx.dep_graph.read_index(self.dep_node);
|
|
||||||
self.cached_value.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum IntercrateAmbiguityCause {
|
pub enum IntercrateAmbiguityCause {
|
||||||
DownstreamCrate { trait_desc: String, self_desc: Option<String> },
|
DownstreamCrate { trait_desc: String, self_desc: Option<String> },
|
||||||
|
|
62
src/librustc_query_system/cache.rs
Normal file
62
src/librustc_query_system/cache.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
//! Cache for candidate selection.
|
||||||
|
|
||||||
|
use crate::dep_graph::DepNodeIndex;
|
||||||
|
use crate::query::QueryContext;
|
||||||
|
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_data_structures::sync::HashMapExt;
|
||||||
|
use rustc_data_structures::sync::Lock;
|
||||||
|
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Cache<Key, Value> {
|
||||||
|
hashmap: Lock<FxHashMap<Key, WithDepNode<Value>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Key, Value> Default for Cache<Key, Value> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { hashmap: Default::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Key, Value> Cache<Key, Value> {
|
||||||
|
/// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
|
||||||
|
pub fn clear(&self) {
|
||||||
|
*self.hashmap.borrow_mut() = Default::default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Key: Eq + Hash, Value: Clone> Cache<Key, Value> {
|
||||||
|
pub fn get<CTX: QueryContext>(&self, key: &Key, tcx: CTX) -> Option<Value> {
|
||||||
|
Some(self.hashmap.borrow().get(key)?.get(tcx))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&self, key: Key, dep_node: DepNodeIndex, value: Value) {
|
||||||
|
self.hashmap.borrow_mut().insert(key, WithDepNode::new(dep_node, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_same(&self, key: Key, dep_node: DepNodeIndex, value: Value)
|
||||||
|
where
|
||||||
|
Value: Eq,
|
||||||
|
{
|
||||||
|
self.hashmap.borrow_mut().insert_same(key, WithDepNode::new(dep_node, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
|
pub struct WithDepNode<T> {
|
||||||
|
dep_node: DepNodeIndex,
|
||||||
|
cached_value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> WithDepNode<T> {
|
||||||
|
pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
|
||||||
|
WithDepNode { dep_node, cached_value }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<CTX: QueryContext>(&self, tcx: CTX) -> T {
|
||||||
|
tcx.dep_graph().read_index(self.dep_node);
|
||||||
|
self.cached_value.clone()
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,5 +11,6 @@ extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc_data_structures;
|
extern crate rustc_data_structures;
|
||||||
|
|
||||||
|
pub mod cache;
|
||||||
pub mod dep_graph;
|
pub mod dep_graph;
|
||||||
pub mod query;
|
pub mod query;
|
||||||
|
|
|
@ -833,17 +833,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
) -> Option<EvaluationResult> {
|
) -> Option<EvaluationResult> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
let cache = tcx.evaluation_cache.hashmap.borrow();
|
if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) {
|
||||||
if let Some(cached) = cache.get(¶m_env.and(trait_ref)) {
|
return Some(res);
|
||||||
return Some(cached.get(tcx));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx
|
self.infcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx)
|
||||||
.evaluation_cache
|
|
||||||
.hashmap
|
|
||||||
.borrow()
|
|
||||||
.get(¶m_env.and(trait_ref))
|
|
||||||
.map(|v| v.get(tcx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_evaluation_cache(
|
fn insert_evaluation_cache(
|
||||||
|
@ -869,21 +863,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// FIXME: Due to #50507 this overwrites the different values
|
// FIXME: Due to #50507 this overwrites the different values
|
||||||
// This should be changed to use HashMapExt::insert_same
|
// This should be changed to use HashMapExt::insert_same
|
||||||
// when that is fixed
|
// when that is fixed
|
||||||
self.tcx()
|
self.tcx().evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
|
||||||
.evaluation_cache
|
|
||||||
.hashmap
|
|
||||||
.borrow_mut()
|
|
||||||
.insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,);
|
debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,);
|
||||||
self.infcx
|
self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
|
||||||
.evaluation_cache
|
|
||||||
.hashmap
|
|
||||||
.borrow_mut()
|
|
||||||
.insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For various reasons, it's possible for a subobligation
|
/// For various reasons, it's possible for a subobligation
|
||||||
|
@ -1180,17 +1166,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
|
let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
|
||||||
if self.can_use_global_caches(param_env) {
|
if self.can_use_global_caches(param_env) {
|
||||||
let cache = tcx.selection_cache.hashmap.borrow();
|
if let Some(res) = tcx.selection_cache.get(¶m_env.and(*trait_ref), tcx) {
|
||||||
if let Some(cached) = cache.get(¶m_env.and(*trait_ref)) {
|
return Some(res);
|
||||||
return Some(cached.get(tcx));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.infcx
|
self.infcx.selection_cache.get(¶m_env.and(*trait_ref), tcx)
|
||||||
.selection_cache
|
|
||||||
.hashmap
|
|
||||||
.borrow()
|
|
||||||
.get(¶m_env.and(*trait_ref))
|
|
||||||
.map(|v| v.get(tcx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether can we safely cache the result
|
/// Determines whether can we safely cache the result
|
||||||
|
@ -1248,10 +1228,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
trait_ref, candidate,
|
trait_ref, candidate,
|
||||||
);
|
);
|
||||||
// This may overwrite the cache with the same value.
|
// This may overwrite the cache with the same value.
|
||||||
tcx.selection_cache
|
tcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
|
||||||
.hashmap
|
|
||||||
.borrow_mut()
|
|
||||||
.insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1261,11 +1238,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
"insert_candidate_cache(trait_ref={:?}, candidate={:?}) local",
|
"insert_candidate_cache(trait_ref={:?}, candidate={:?}) local",
|
||||||
trait_ref, candidate,
|
trait_ref, candidate,
|
||||||
);
|
);
|
||||||
self.infcx
|
self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
|
||||||
.selection_cache
|
|
||||||
.hashmap
|
|
||||||
.borrow_mut()
|
|
||||||
.insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_projection_obligation_against_definition_bounds(
|
fn match_projection_obligation_against_definition_bounds(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue