Skip to content

Commit d48f48f

Browse files
committed
Refactor compiler to make use of dep-tracking-maps. Also, in cases where
we were using interior mutability (RefCells, TyIvar), add some reads/writes.
1 parent 5d9dd7c commit d48f48f

File tree

10 files changed

+511
-316
lines changed

10 files changed

+511
-316
lines changed

src/librustc/dep_graph/dep_tracking_map.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::cell::RefCell;
1313
use std::ops::Index;
1414
use std::hash::Hash;
1515
use std::marker::PhantomData;
16+
use util::common::MemoizationMap;
1617

1718
use super::{DepNode, DepGraph};
1819

@@ -70,6 +71,61 @@ impl<M: DepTrackingMapId> DepTrackingMap<M> {
7071
}
7172
}
7273

74+
impl<M: DepTrackingMapId> MemoizationMap for RefCell<DepTrackingMap<M>> {
75+
type Key = M::Key;
76+
type Value = M::Value;
77+
78+
/// Memoizes an entry in the dep-tracking-map. If the entry is not
79+
/// already present, then `op` will be executed to compute its value.
80+
/// The resulting dependency graph looks like this:
81+
///
82+
/// [op] -> Map(key) -> CurrentTask
83+
///
84+
/// Here, `[op]` represents whatever nodes `op` reads in the
85+
/// course of execution; `Map(key)` represents the node for this
86+
/// map; and `CurrentTask` represents the current task when
87+
/// `memoize` is invoked.
88+
///
89+
/// **Important:* when `op` is invoked, the current task will be
90+
/// switched to `Map(key)`. Therefore, if `op` makes use of any
91+
/// HIR nodes or shared state accessed through its closure
92+
/// environment, it must explicitly read that state. As an
93+
/// example, see `type_scheme_of_item` in `collect`, which looks
94+
/// something like this:
95+
///
96+
/// ```
97+
/// fn type_scheme_of_item(..., item: &hir::Item) -> ty::TypeScheme<'tcx> {
98+
/// let item_def_id = ccx.tcx.map.local_def_id(it.id);
99+
/// ccx.tcx.tcache.memoized(item_def_id, || {
100+
/// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
101+
/// compute_type_scheme_of_item(ccx, item)
102+
/// });
103+
/// }
104+
/// ```
105+
///
106+
/// The key is the line marked `(*)`: the closure implicitly
107+
/// accesses the body of the item `item`, so we register a read
108+
/// from `Hir(item_def_id)`.
109+
fn memoize<OP>(&self, key: M::Key, op: OP) -> M::Value
110+
where OP: FnOnce() -> M::Value
111+
{
112+
let graph;
113+
{
114+
let this = self.borrow();
115+
if let Some(result) = this.map.get(&key) {
116+
this.read(&key);
117+
return result.clone();
118+
}
119+
graph = this.graph.clone();
120+
}
121+
122+
let _task = graph.in_task(M::to_dep_node(&key));
123+
let result = op();
124+
self.borrow_mut().map.insert(key, result.clone());
125+
result
126+
}
127+
}
128+
73129
impl<'k, M: DepTrackingMapId> Index<&'k M::Key> for DepTrackingMap<M> {
74130
type Output = M::Value;
75131

src/librustc/middle/ty/contents.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use middle::def_id::{DefId};
1212
use middle::ty::{self, Ty};
13-
use util::common::{memoized};
13+
use util::common::MemoizationMap;
1414
use util::nodemap::FnvHashMap;
1515

1616
use std::fmt;
@@ -141,9 +141,7 @@ impl fmt::Debug for TypeContents {
141141

142142
impl<'tcx> ty::TyS<'tcx> {
143143
pub fn type_contents(&'tcx self, cx: &ty::ctxt<'tcx>) -> TypeContents {
144-
return memoized(&cx.tc_cache, self, |ty| {
145-
tc_ty(cx, ty, &mut FnvHashMap())
146-
});
144+
return cx.tc_cache.memoize(self, || tc_ty(cx, self, &mut FnvHashMap()));
147145

148146
fn tc_ty<'tcx>(cx: &ty::ctxt<'tcx>,
149147
ty: Ty<'tcx>,

src/librustc/middle/ty/context.rs

Lines changed: 86 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ use middle::traits;
3030
use middle::ty::{self, TraitRef, Ty, TypeAndMut};
3131
use middle::ty::{TyS, TypeVariants};
3232
use middle::ty::{AdtDef, ClosureSubsts, ExistentialBounds, Region};
33-
use middle::ty::{FreevarMap, GenericPredicates};
33+
use middle::ty::{FreevarMap};
3434
use middle::ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitTy};
3535
use middle::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
3636
use middle::ty::TypeVariants::*;
37+
use middle::ty::maps;
38+
use util::common::MemoizationMap;
3739
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
3840
use util::nodemap::FnvHashMap;
3941

@@ -248,57 +250,78 @@ pub struct ctxt<'tcx> {
248250
pub tables: RefCell<Tables<'tcx>>,
249251

250252
/// Maps from a trait item to the trait item "descriptor"
251-
pub impl_or_trait_items: RefCell<DefIdMap<ty::ImplOrTraitItem<'tcx>>>,
253+
pub impl_or_trait_items: RefCell<DepTrackingMap<maps::ImplOrTraitItems<'tcx>>>,
252254

253255
/// Maps from a trait def-id to a list of the def-ids of its trait items
254-
pub trait_item_def_ids: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItemId>>>>,
256+
pub trait_item_def_ids: RefCell<DepTrackingMap<maps::TraitItemDefIds<'tcx>>>,
255257

256-
/// A cache for the trait_items() routine
257-
pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItem<'tcx>>>>>,
258+
/// A cache for the trait_items() routine; note that the routine
259+
/// itself pushes the `TraitItems` dependency node. This cache is
260+
/// "encapsulated" and thus does not need to be itself tracked.
261+
trait_items_cache: RefCell<DefIdMap<Rc<Vec<ty::ImplOrTraitItem<'tcx>>>>>,
258262

259-
pub impl_trait_refs: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
260-
pub trait_defs: RefCell<DefIdMap<&'tcx ty::TraitDef<'tcx>>>,
261-
pub adt_defs: RefCell<DefIdMap<ty::AdtDefMaster<'tcx>>>,
263+
pub impl_trait_refs: RefCell<DepTrackingMap<maps::ImplTraitRefs<'tcx>>>,
264+
pub trait_defs: RefCell<DepTrackingMap<maps::TraitDefs<'tcx>>>,
265+
pub adt_defs: RefCell<DepTrackingMap<maps::AdtDefs<'tcx>>>,
262266

263267
/// Maps from the def-id of an item (trait/struct/enum/fn) to its
264268
/// associated predicates.
265-
pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
269+
pub predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
266270

267271
/// Maps from the def-id of a trait to the list of
268272
/// super-predicates. This is a subset of the full list of
269273
/// predicates. We store these in a separate map because we must
270274
/// evaluate them even during type conversion, often before the
271275
/// full predicates are available (note that supertraits have
272276
/// additional acyclicity requirements).
273-
pub super_predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
277+
pub super_predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
274278

275279
pub map: ast_map::Map<'tcx>,
280+
281+
// Records the free variables refrenced by every closure
282+
// expression. Do not track deps for this, just recompute it from
283+
// scratch every time.
276284
pub freevars: RefCell<FreevarMap>,
277-
pub tcache: RefCell<DefIdMap<ty::TypeScheme<'tcx>>>,
285+
286+
// Records the type of every item.
287+
pub tcache: RefCell<DepTrackingMap<maps::Tcache<'tcx>>>,
288+
289+
// Internal cache for metadata decoding. No need to track deps on this.
278290
pub rcache: RefCell<FnvHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
291+
292+
// Cache for the type-contents routine. FIXME -- track deps?
279293
pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
294+
295+
// Cache for various types within a method body and so forth.
296+
//
297+
// FIXME this should be made local to typeck, but it is currently used by one lint
280298
pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
299+
300+
// FIXME no dep tracking, but we should be able to remove this
281301
pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
302+
303+
// FIXME dep tracking -- should be harmless enough
282304
pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
305+
283306
pub lang_items: middle::lang_items::LanguageItems,
284307

285308
/// Maps from def-id of a type or region parameter to its
286309
/// (inferred) variance.
287-
pub item_variance_map: RefCell<DefIdMap<Rc<ty::ItemVariances>>>,
310+
pub item_variance_map: RefCell<DepTrackingMap<maps::ItemVariances<'tcx>>>,
288311

289312
/// True if the variance has been computed yet; false otherwise.
290313
pub variance_computed: Cell<bool>,
291314

292315
/// Maps a DefId of a type to a list of its inherent impls.
293316
/// Contains implementations of methods that are inherent to a type.
294317
/// Methods in these implementations don't need to be exported.
295-
pub inherent_impls: RefCell<DefIdMap<Rc<Vec<DefId>>>>,
318+
pub inherent_impls: RefCell<DepTrackingMap<maps::InherentImpls<'tcx>>>,
296319

297320
/// Maps a DefId of an impl to a list of its items.
298321
/// Note that this contains all of the impls that we know about,
299322
/// including ones in other crates. It's not clear that this is the best
300323
/// way to do it.
301-
pub impl_items: RefCell<DefIdMap<Vec<ty::ImplOrTraitItemId>>>,
324+
pub impl_items: RefCell<DepTrackingMap<maps::ImplItems<'tcx>>>,
302325

303326
/// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
304327
/// present in this set can be warned about.
@@ -312,6 +335,7 @@ pub struct ctxt<'tcx> {
312335
/// The set of external nominal types whose implementations have been read.
313336
/// This is used for lazy resolution of methods.
314337
pub populated_external_types: RefCell<DefIdSet>,
338+
315339
/// The set of external primitive types whose implementations have been read.
316340
/// FIXME(arielb1): why is this separate from populated_external_types?
317341
pub populated_external_primitive_impls: RefCell<DefIdSet>,
@@ -347,7 +371,9 @@ pub struct ctxt<'tcx> {
347371
pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
348372

349373
/// Caches the representation hints for struct definitions.
350-
pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
374+
///
375+
/// This is encapsulated by the `ReprHints` task and hence is not tracked.
376+
repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
351377

352378
/// Maps Expr NodeId's to their constant qualification.
353379
pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
@@ -499,31 +525,31 @@ impl<'tcx> ctxt<'tcx> {
499525
named_region_map: named_region_map,
500526
region_maps: region_maps,
501527
free_region_maps: RefCell::new(FnvHashMap()),
502-
item_variance_map: RefCell::new(DefIdMap()),
528+
item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
503529
variance_computed: Cell::new(false),
504530
sess: s,
505531
def_map: def_map,
506532
tables: RefCell::new(Tables::empty()),
507-
impl_trait_refs: RefCell::new(DefIdMap()),
508-
trait_defs: RefCell::new(DefIdMap()),
509-
adt_defs: RefCell::new(DefIdMap()),
510-
predicates: RefCell::new(DefIdMap()),
511-
super_predicates: RefCell::new(DefIdMap()),
533+
impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
534+
trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
535+
adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
536+
predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
537+
super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
512538
fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
513539
map: map,
514540
freevars: RefCell::new(freevars),
515-
tcache: RefCell::new(DefIdMap()),
541+
tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
516542
rcache: RefCell::new(FnvHashMap()),
517543
tc_cache: RefCell::new(FnvHashMap()),
518544
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
519-
impl_or_trait_items: RefCell::new(DefIdMap()),
520-
trait_item_def_ids: RefCell::new(DefIdMap()),
545+
impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
546+
trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
521547
trait_items_cache: RefCell::new(DefIdMap()),
522548
ty_param_defs: RefCell::new(NodeMap()),
523549
normalized_cache: RefCell::new(FnvHashMap()),
524550
lang_items: lang_items,
525-
inherent_impls: RefCell::new(DefIdMap()),
526-
impl_items: RefCell::new(DefIdMap()),
551+
inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
552+
impl_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
527553
used_unsafe: RefCell::new(NodeSet()),
528554
used_mut_nodes: RefCell::new(NodeSet()),
529555
populated_external_types: RefCell::new(DefIdSet()),
@@ -1004,4 +1030,38 @@ impl<'tcx> ctxt<'tcx> {
10041030
pub fn mk_param_from_def(&self, def: &ty::TypeParameterDef) -> Ty<'tcx> {
10051031
self.mk_param(def.space, def.index, def.name)
10061032
}
1033+
1034+
pub fn trait_items(&self, trait_did: DefId) -> Rc<Vec<ty::ImplOrTraitItem<'tcx>>> {
1035+
// since this is cached, pushing a dep-node for the
1036+
// computation yields the correct dependencies.
1037+
let _task = self.dep_graph.in_task(DepNode::TraitItems(trait_did));
1038+
1039+
let mut trait_items = self.trait_items_cache.borrow_mut();
1040+
match trait_items.get(&trait_did).cloned() {
1041+
Some(trait_items) => trait_items,
1042+
None => {
1043+
let def_ids = self.trait_item_def_ids(trait_did);
1044+
let items: Rc<Vec<_>> =
1045+
Rc::new(def_ids.iter()
1046+
.map(|d| self.impl_or_trait_item(d.def_id()))
1047+
.collect());
1048+
trait_items.insert(trait_did, items.clone());
1049+
items
1050+
}
1051+
}
1052+
}
1053+
1054+
/// Obtain the representation annotation for a struct definition.
1055+
pub fn lookup_repr_hints(&self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
1056+
let _task = self.dep_graph.in_task(DepNode::ReprHints(did));
1057+
self.repr_hint_cache.memoize(did, || {
1058+
Rc::new(if did.is_local() {
1059+
self.get_attrs(did).iter().flat_map(|meta| {
1060+
attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
1061+
}).collect()
1062+
} else {
1063+
self.sess.cstore.repr_attrs(did)
1064+
})
1065+
})
1066+
}
10071067
}

src/librustc/middle/ty/ivar.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use dep_graph::DepNode;
1112
use middle::ty::{Ty, TyS};
13+
use middle::ty::tls;
1214

1315
use rustc_data_structures::ivar;
1416

@@ -27,6 +29,10 @@ use core::nonzero::NonZero;
2729
/// (B) no aliases to this value with a 'tcx longer than this
2830
/// value's 'lt exist
2931
///
32+
/// Dependency tracking: each ivar does not know what node in the
33+
/// dependency graph it is associated with, so when you get/fulfill
34+
/// you must supply a `DepNode` id. This should always be the same id!
35+
///
3036
/// NonZero is used rather than Unique because Unique isn't Copy.
3137
pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar<NonZero<*const TyS<'static>>>,
3238
PhantomData<fn(TyS<'lt>)->TyS<'tcx>>);
@@ -40,19 +46,28 @@ impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
4046
}
4147

4248
#[inline]
43-
pub fn get(&self) -> Option<Ty<'tcx>> {
49+
pub fn get(&self, dep_node: DepNode) -> Option<Ty<'tcx>> {
50+
tls::with(|tcx| tcx.dep_graph.read(dep_node));
51+
self.untracked_get()
52+
}
53+
54+
#[inline]
55+
fn untracked_get(&self) -> Option<Ty<'tcx>> {
4456
match self.0.get() {
4557
None => None,
4658
// valid because of invariant (A)
4759
Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) })
4860
}
4961
}
62+
5063
#[inline]
51-
pub fn unwrap(&self) -> Ty<'tcx> {
52-
self.get().unwrap()
64+
pub fn unwrap(&self, dep_node: DepNode) -> Ty<'tcx> {
65+
self.get(dep_node).unwrap()
5366
}
5467

55-
pub fn fulfill(&self, value: Ty<'lt>) {
68+
pub fn fulfill(&self, dep_node: DepNode, value: Ty<'lt>) {
69+
tls::with(|tcx| tcx.dep_graph.write(dep_node));
70+
5671
// Invariant (A) is fulfilled, because by (B), every alias
5772
// of this has a 'tcx longer than 'lt.
5873
let value: *const TyS<'lt> = value;
@@ -64,7 +79,7 @@ impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
6479

6580
impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> {
6681
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67-
match self.get() {
82+
match self.untracked_get() {
6883
Some(val) => write!(f, "TyIVar({:?})", val),
6984
None => f.write_str("TyIVar(<unfulfilled>)")
7085
}

0 commit comments

Comments
 (0)