Skip to content

Commit 4f030d0

Browse files
committed
integrate anon dep nodes into trait selection
1 parent 8ac29bd commit 4f030d0

File tree

6 files changed

+83
-120
lines changed

6 files changed

+83
-120
lines changed

src/librustc/dep_graph/dep_node.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ define_dep_nodes!( <'tcx>
495495
// imprecision in our dep-graph tracking. The important thing is
496496
// that for any given trait-ref, we always map to the **same**
497497
// trait-select node.
498-
[] TraitSelect { trait_def_id: DefId, input_def_id: DefId },
498+
[anon] TraitSelect,
499499

500500
// For proj. cache, we just keep a list of all def-ids, since it is
501501
// not a hotspot.

src/librustc/dep_graph/dep_tracking_map.rs

+9-31
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,23 @@ use rustc_data_structures::fx::FxHashMap;
1212
use std::cell::RefCell;
1313
use std::hash::Hash;
1414
use std::marker::PhantomData;
15-
use ty::TyCtxt;
1615
use util::common::MemoizationMap;
1716

18-
use super::{DepNode, DepGraph};
17+
use super::{DepKind, DepNodeIndex, DepGraph};
1918

2019
/// A DepTrackingMap offers a subset of the `Map` API and ensures that
2120
/// we make calls to `read` and `write` as appropriate. We key the
2221
/// maps with a unique type for brevity.
2322
pub struct DepTrackingMap<M: DepTrackingMapConfig> {
2423
phantom: PhantomData<M>,
2524
graph: DepGraph,
26-
map: FxHashMap<M::Key, M::Value>,
25+
map: FxHashMap<M::Key, (M::Value, DepNodeIndex)>,
2726
}
2827

2928
pub trait DepTrackingMapConfig {
3029
type Key: Eq + Hash + Clone;
3130
type Value: Clone;
32-
fn to_dep_node(tcx: TyCtxt, key: &Self::Key) -> DepNode;
31+
fn to_dep_kind() -> DepKind;
3332
}
3433

3534
impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
@@ -40,27 +39,6 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
4039
map: FxHashMap(),
4140
}
4241
}
43-
44-
/// Registers a (synthetic) read from the key `k`. Usually this
45-
/// is invoked automatically by `get`.
46-
fn read(&self, tcx: TyCtxt, k: &M::Key) {
47-
let dep_node = M::to_dep_node(tcx, k);
48-
self.graph.read(dep_node);
49-
}
50-
51-
pub fn get(&self, tcx: TyCtxt, k: &M::Key) -> Option<&M::Value> {
52-
self.read(tcx, k);
53-
self.map.get(k)
54-
}
55-
56-
pub fn contains_key(&self, tcx: TyCtxt, k: &M::Key) -> bool {
57-
self.read(tcx, k);
58-
self.map.contains_key(k)
59-
}
60-
61-
pub fn keys(&self) -> Vec<M::Key> {
62-
self.map.keys().cloned().collect()
63-
}
6442
}
6543

6644
impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
@@ -98,22 +76,22 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
9876
/// The key is the line marked `(*)`: the closure implicitly
9977
/// accesses the body of the item `item`, so we register a read
10078
/// from `Hir(item_def_id)`.
101-
fn memoize<OP>(&self, tcx: TyCtxt, key: M::Key, op: OP) -> M::Value
79+
fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
10280
where OP: FnOnce() -> M::Value
10381
{
10482
let graph;
10583
{
10684
let this = self.borrow();
107-
if let Some(result) = this.map.get(&key) {
108-
this.read(tcx, &key);
85+
if let Some(&(ref result, dep_node)) = this.map.get(&key) {
86+
this.graph.read_index(dep_node);
10987
return result.clone();
11088
}
11189
graph = this.graph.clone();
11290
}
11391

114-
let _task = graph.in_task(M::to_dep_node(tcx, &key));
115-
let result = op();
116-
self.borrow_mut().map.insert(key, result.clone());
92+
let (result, dep_node) = graph.with_anon_task(M::to_dep_kind(), op);
93+
self.borrow_mut().map.insert(key, (result.clone(), dep_node));
94+
graph.read_index(dep_node);
11795
result
11896
}
11997
}

src/librustc/traits/select.rs

+64-24
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use super::{VtableImplData, VtableObjectData, VtableBuiltinData,
3030
VtableClosureData, VtableDefaultImplData, VtableFnPointerData};
3131
use super::util;
3232

33+
use dep_graph::{DepNodeIndex, DepKind};
3334
use hir::def_id::DefId;
3435
use infer;
3536
use infer::{InferCtxt, InferOk, TypeFreshener};
@@ -105,7 +106,7 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
105106
#[derive(Clone)]
106107
pub struct SelectionCache<'tcx> {
107108
hashmap: RefCell<FxHashMap<ty::TraitRef<'tcx>,
108-
SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
109+
WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>>,
109110
}
110111

111112
/// The selection process begins by considering all impls, where
@@ -369,7 +370,7 @@ impl EvaluationResult {
369370

370371
#[derive(Clone)]
371372
pub struct EvaluationCache<'tcx> {
372-
hashmap: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, EvaluationResult>>
373+
hashmap: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>>
373374
}
374375

375376
impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
@@ -466,8 +467,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
466467
assert!(!obligation.predicate.has_escaping_regions());
467468

468469
let tcx = self.tcx();
469-
let dep_node = obligation.predicate.dep_node(tcx);
470-
let _task = tcx.dep_graph.in_task(dep_node);
471470

472471
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
473472
let ret = match self.candidate_from_obligation(&stack)? {
@@ -710,12 +709,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
710709
return result;
711710
}
712711

713-
let result = self.evaluate_stack(&stack);
712+
let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
714713

715714
debug!("CACHE MISS: EVAL({:?})={:?}",
716715
fresh_trait_ref,
717716
result);
718-
self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, result);
717+
self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
719718

720719
result
721720
}
@@ -870,22 +869,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
870869
trait_ref: ty::PolyTraitRef<'tcx>)
871870
-> Option<EvaluationResult>
872871
{
872+
let tcx = self.tcx();
873873
if self.can_use_global_caches(param_env) {
874-
let cache = self.tcx().evaluation_cache.hashmap.borrow();
874+
let cache = tcx.evaluation_cache.hashmap.borrow();
875875
if let Some(cached) = cache.get(&trait_ref) {
876-
let dep_node = trait_ref
877-
.to_poly_trait_predicate()
878-
.dep_node(self.tcx());
879-
self.tcx().hir.dep_graph.read(dep_node);
880-
return Some(cached.clone());
876+
return Some(cached.get(tcx));
881877
}
882878
}
883-
self.infcx.evaluation_cache.hashmap.borrow().get(&trait_ref).cloned()
879+
self.infcx.evaluation_cache.hashmap
880+
.borrow()
881+
.get(&trait_ref)
882+
.map(|v| v.get(tcx))
884883
}
885884

886885
fn insert_evaluation_cache(&mut self,
887886
param_env: ty::ParamEnv<'tcx>,
888887
trait_ref: ty::PolyTraitRef<'tcx>,
888+
dep_node: DepNodeIndex,
889889
result: EvaluationResult)
890890
{
891891
// Avoid caching results that depend on more than just the trait-ref:
@@ -902,12 +902,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
902902
if self.can_use_global_caches(param_env) {
903903
let mut cache = self.tcx().evaluation_cache.hashmap.borrow_mut();
904904
if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) {
905-
cache.insert(trait_ref, result);
905+
cache.insert(trait_ref, WithDepNode::new(dep_node, result));
906906
return;
907907
}
908908
}
909909

910-
self.infcx.evaluation_cache.hashmap.borrow_mut().insert(trait_ref, result);
910+
self.infcx.evaluation_cache.hashmap
911+
.borrow_mut()
912+
.insert(trait_ref, WithDepNode::new(dep_node, result));
911913
}
912914

913915
///////////////////////////////////////////////////////////////////////////
@@ -949,19 +951,32 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
949951
}
950952

951953
// If no match, compute result and insert into cache.
952-
let candidate = self.candidate_from_obligation_no_cache(stack);
954+
let (candidate, dep_node) = self.in_task(|this| {
955+
this.candidate_from_obligation_no_cache(stack)
956+
});
953957

954958
if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) {
955959
debug!("CACHE MISS: SELECT({:?})={:?}",
956960
cache_fresh_trait_pred, candidate);
957961
self.insert_candidate_cache(stack.obligation.param_env,
958962
cache_fresh_trait_pred,
963+
dep_node,
959964
candidate.clone());
960965
}
961966

962967
candidate
963968
}
964969

970+
fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
971+
where OP: FnOnce(&mut Self) -> R
972+
{
973+
let (result, dep_node) = self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || {
974+
op(self)
975+
});
976+
self.tcx().dep_graph.read_index(dep_node);
977+
(result, dep_node)
978+
}
979+
965980
// Treat negative impls as unimplemented
966981
fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
967982
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
@@ -1151,33 +1166,41 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
11511166
cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>)
11521167
-> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>>
11531168
{
1169+
let tcx = self.tcx();
11541170
let trait_ref = &cache_fresh_trait_pred.0.trait_ref;
11551171
if self.can_use_global_caches(param_env) {
1156-
let cache = self.tcx().selection_cache.hashmap.borrow();
1172+
let cache = tcx.selection_cache.hashmap.borrow();
11571173
if let Some(cached) = cache.get(&trait_ref) {
1158-
return Some(cached.clone());
1174+
return Some(cached.get(tcx));
11591175
}
11601176
}
1161-
self.infcx.selection_cache.hashmap.borrow().get(trait_ref).cloned()
1177+
self.infcx.selection_cache.hashmap
1178+
.borrow()
1179+
.get(trait_ref)
1180+
.map(|v| v.get(tcx))
11621181
}
11631182

11641183
fn insert_candidate_cache(&mut self,
11651184
param_env: ty::ParamEnv<'tcx>,
11661185
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
1186+
dep_node: DepNodeIndex,
11671187
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>)
11681188
{
1189+
let tcx = self.tcx();
11691190
let trait_ref = cache_fresh_trait_pred.0.trait_ref;
11701191
if self.can_use_global_caches(param_env) {
1171-
let mut cache = self.tcx().selection_cache.hashmap.borrow_mut();
1172-
if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) {
1173-
if let Some(candidate) = self.tcx().lift_to_global(&candidate) {
1174-
cache.insert(trait_ref, candidate);
1192+
let mut cache = tcx.selection_cache.hashmap.borrow_mut();
1193+
if let Some(trait_ref) = tcx.lift_to_global(&trait_ref) {
1194+
if let Some(candidate) = tcx.lift_to_global(&candidate) {
1195+
cache.insert(trait_ref, WithDepNode::new(dep_node, candidate));
11751196
return;
11761197
}
11771198
}
11781199
}
11791200

1180-
self.infcx.selection_cache.hashmap.borrow_mut().insert(trait_ref, candidate);
1201+
self.infcx.selection_cache.hashmap
1202+
.borrow_mut()
1203+
.insert(trait_ref, WithDepNode::new(dep_node, candidate));
11811204
}
11821205

11831206
fn should_update_candidate_cache(&mut self,
@@ -3138,3 +3161,20 @@ impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> {
31383161
write!(f, "TraitObligationStack({:?})", self.obligation)
31393162
}
31403163
}
3164+
3165+
#[derive(Clone)]
3166+
pub struct WithDepNode<T> {
3167+
dep_node: DepNodeIndex,
3168+
cached_value: T
3169+
}
3170+
3171+
impl<T: Clone> WithDepNode<T> {
3172+
pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
3173+
WithDepNode { dep_node, cached_value }
3174+
}
3175+
3176+
pub fn get(&self, tcx: TyCtxt) -> T {
3177+
tcx.dep_graph.read_index(self.dep_node);
3178+
self.cached_value.clone()
3179+
}
3180+
}

src/librustc/traits/trans/mod.rs

+7-32
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313
// seems likely that they should eventually be merged into more
1414
// general routines.
1515

16-
use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig,
17-
DepConstructor};
18-
use hir::def_id::DefId;
16+
use dep_graph::{DepGraph, DepKind, DepTrackingMap, DepTrackingMapConfig};
1917
use infer::TransNormalize;
2018
use std::cell::RefCell;
2119
use std::marker::PhantomData;
@@ -41,7 +39,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
4139
// Remove any references to regions; this helps improve caching.
4240
let trait_ref = self.erase_regions(&trait_ref);
4341

44-
self.trans_trait_caches.trait_cache.memoize(self, trait_ref, || {
42+
self.trans_trait_caches.trait_cache.memoize(trait_ref, || {
4543
debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
4644
trait_ref, trait_ref.def_id());
4745

@@ -139,7 +137,7 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
139137
if !ty.has_projection_types() {
140138
ty
141139
} else {
142-
self.tcx.trans_trait_caches.project_cache.memoize(self.tcx, ty, || {
140+
self.tcx.trans_trait_caches.project_cache.memoize(ty, || {
143141
debug!("AssociatedTypeNormalizer: ty={:?}", ty);
144142
self.tcx.normalize_associated_type(&ty)
145143
})
@@ -171,8 +169,8 @@ pub struct TraitSelectionCache<'tcx> {
171169
impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
172170
type Key = ty::PolyTraitRef<'tcx>;
173171
type Value = Vtable<'tcx, ()>;
174-
fn to_dep_node(tcx: TyCtxt, key: &ty::PolyTraitRef<'tcx>) -> DepNode {
175-
key.to_poly_trait_predicate().dep_node(tcx)
172+
fn to_dep_kind() -> DepKind {
173+
DepKind::TraitSelect
176174
}
177175
}
178176

@@ -185,31 +183,8 @@ pub struct ProjectionCache<'gcx> {
185183
impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
186184
type Key = Ty<'gcx>;
187185
type Value = Ty<'gcx>;
188-
fn to_dep_node(tcx: TyCtxt, key: &Self::Key) -> DepNode {
189-
// Ideally, we'd just put `key` into the dep-node, but we
190-
// can't put full types in there. So just collect up all the
191-
// def-ids of structs/enums as well as any traits that we
192-
// project out of. It doesn't matter so much what we do here,
193-
// except that if we are too coarse, we'll create overly
194-
// coarse edges between impls and the trans. For example, if
195-
// we just used the def-id of things we are projecting out of,
196-
// then the key for `<Foo as SomeTrait>::T` and `<Bar as
197-
// SomeTrait>::T` would both share a dep-node
198-
// (`TraitSelect(SomeTrait)`), and hence the impls for both
199-
// `Foo` and `Bar` would be considered inputs. So a change to
200-
// `Bar` would affect things that just normalized `Foo`.
201-
// Anyway, this heuristic is not ideal, but better than
202-
// nothing.
203-
let def_ids: Vec<DefId> =
204-
key.walk()
205-
.filter_map(|t| match t.sty {
206-
ty::TyAdt(adt_def, _) => Some(adt_def.did),
207-
ty::TyProjection(ref proj) => Some(proj.item_def_id),
208-
_ => None,
209-
})
210-
.collect();
211-
212-
DepNode::new(tcx, DepConstructor::ProjectionCache { def_ids: def_ids })
186+
fn to_dep_kind() -> DepKind {
187+
DepKind::TraitSelect
213188
}
214189
}
215190

0 commit comments

Comments
 (0)