diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index bb5244ad3f45..c6275e846458 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -79,9 +79,14 @@ macro_rules! erase { ($x:tt) => ({}) } +macro_rules! anon_attr_to_bool { + (anon) => (true) +} + macro_rules! define_dep_nodes { (<$tcx:tt> $( + [$($anon:ident)*] $variant:ident $(( $($tuple_arg:tt),* ))* $({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })* ,)* @@ -117,6 +122,19 @@ macro_rules! define_dep_nodes { } } + #[allow(unreachable_code)] + #[inline] + pub fn is_anon<$tcx>(&self) -> bool { + match *self { + $( + DepKind :: $variant => { + $(return anon_attr_to_bool!($anon);)* + false + } + )* + } + } + #[allow(unreachable_code)] #[inline] pub fn has_params(&self) -> bool { @@ -356,100 +374,101 @@ define_dep_nodes!( <'tcx> // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain // access to the krate, but you must remember to add suitable // edges yourself for the individual items that you read. - Krate, + [] Krate, // Represents the HIR node with the given node-id - Hir(DefId), + [] Hir(DefId), // Represents the body of a function or method. The def-id is that of the // function/method. - HirBody(DefId), + [] HirBody(DefId), // Represents the metadata for a given HIR node, typically found // in an extern crate. - MetaData(DefId), + [] MetaData(DefId), // Represents some artifact that we save to disk. Note that these // do not have a def-id as part of their identifier. - WorkProduct(WorkProductId), + [] WorkProduct(WorkProductId), // Represents different phases in the compiler. - RegionMaps(DefId), - Coherence, - Resolve, - CoherenceCheckTrait(DefId), - PrivacyAccessLevels(CrateNum), + [] RegionMaps(DefId), + [] Coherence, + [] Resolve, + [] CoherenceCheckTrait(DefId), + [] PrivacyAccessLevels(CrateNum), // Represents the MIR for a fn; also used as the task node for // things read/modify that MIR. - MirConstQualif(DefId), - MirConst(DefId), - MirValidated(DefId), - MirOptimized(DefId), - MirShim { instance_def: InstanceDef<'tcx> }, + [] MirConstQualif(DefId), + [] MirConst(DefId), + [] MirValidated(DefId), + [] MirOptimized(DefId), + [] MirShim { instance_def: InstanceDef<'tcx> }, - BorrowCheckKrate, - BorrowCheck(DefId), - RvalueCheck(DefId), - Reachability, - MirKeys, - TransWriteMetadata, - CrateVariances, + [] BorrowCheckKrate, + [] BorrowCheck(DefId), + [] RvalueCheck(DefId), + [] Reachability, + [] MirKeys, + [] TransWriteMetadata, + [] CrateVariances, // Nodes representing bits of computed IR in the tcx. Each shared // table in the tcx (or elsewhere) maps to one of these // nodes. - AssociatedItems(DefId), - TypeOfItem(DefId), - GenericsOfItem(DefId), - PredicatesOfItem(DefId), - SuperPredicatesOfItem(DefId), - TraitDefOfItem(DefId), - AdtDefOfItem(DefId), - IsDefaultImpl(DefId), - ImplTraitRef(DefId), - ImplPolarity(DefId), - ClosureKind(DefId), - FnSignature(DefId), - CoerceUnsizedInfo(DefId), + [] AssociatedItems(DefId), + [] TypeOfItem(DefId), + [] GenericsOfItem(DefId), + [] PredicatesOfItem(DefId), + [] SuperPredicatesOfItem(DefId), + [] TraitDefOfItem(DefId), + [] AdtDefOfItem(DefId), + [] IsDefaultImpl(DefId), + [] ImplTraitRef(DefId), + [] ImplPolarity(DefId), + [] ClosureKind(DefId), + [] FnSignature(DefId), + [] CoerceUnsizedInfo(DefId), - ItemVarianceConstraints(DefId), - ItemVariances(DefId), - IsConstFn(DefId), - IsForeignItem(DefId), - TypeParamPredicates { item_id: DefId, param_id: DefId }, - SizedConstraint(DefId), - DtorckConstraint(DefId), - AdtDestructor(DefId), - AssociatedItemDefIds(DefId), - InherentImpls(DefId), - TypeckBodiesKrate, - TypeckTables(DefId), - HasTypeckTables(DefId), - ConstEval { def_id: DefId, substs: &'tcx Substs<'tcx> }, - SymbolName(DefId), - InstanceSymbolName { instance: Instance<'tcx> }, - SpecializationGraph(DefId), - ObjectSafety(DefId), - IsCopy(DefId), - IsSized(DefId), - IsFreeze(DefId), - NeedsDrop(DefId), - Layout(DefId), + [] ItemVarianceConstraints(DefId), + [] ItemVariances(DefId), + [] IsConstFn(DefId), + [] IsForeignItem(DefId), + [] TypeParamPredicates { item_id: DefId, param_id: DefId }, + [] SizedConstraint(DefId), + [] DtorckConstraint(DefId), + [] AdtDestructor(DefId), + [] AssociatedItemDefIds(DefId), + [] InherentImpls(DefId), + [] TypeckBodiesKrate, + [] TypeckTables(DefId), + [] HasTypeckTables(DefId), + [] ConstEval { def_id: DefId, substs: &'tcx Substs<'tcx> }, + [] SymbolName(DefId), + [] InstanceSymbolName { instance: Instance<'tcx> }, + [] SpecializationGraph(DefId), + [] ObjectSafety(DefId), + + [anon] IsCopy(DefId), + [anon] IsSized(DefId), + [anon] IsFreeze(DefId), + [anon] NeedsDrop(DefId), + [anon] Layout(DefId), // The set of impls for a given trait. - TraitImpls(DefId), - RelevantTraitImpls(DefId, SimplifiedType), + [] TraitImpls(DefId), + [] RelevantTraitImpls(DefId, SimplifiedType), - AllLocalTraitImpls, + [] AllLocalTraitImpls, // Nodes representing caches. To properly handle a true cache, we // don't use a DepTrackingMap, but rather we push a task node. // Otherwise the write into the map would be incorrectly // attributed to the first task that happened to fill the cache, // which would yield an overly conservative dep-graph. - TraitItems(DefId), - ReprHints(DefId), + [] TraitItems(DefId), + [] ReprHints(DefId), // Trait selection cache is a little funny. Given a trait // reference like `Foo: SomeTrait`, there could be @@ -476,35 +495,45 @@ define_dep_nodes!( <'tcx> // imprecision in our dep-graph tracking. The important thing is // that for any given trait-ref, we always map to the **same** // trait-select node. - TraitSelect { trait_def_id: DefId, input_def_id: DefId }, + [] TraitSelect { trait_def_id: DefId, input_def_id: DefId }, // For proj. cache, we just keep a list of all def-ids, since it is // not a hotspot. - ProjectionCache { def_ids: DefIdList }, + [] ProjectionCache { def_ids: DefIdList }, - ParamEnv(DefId), - DescribeDef(DefId), - DefSpan(DefId), - Stability(DefId), - Deprecation(DefId), - ItemBodyNestedBodies(DefId), - ConstIsRvaluePromotableToStatic(DefId), - ImplParent(DefId), - TraitOfItem(DefId), - IsExportedSymbol(DefId), - IsMirAvailable(DefId), - ItemAttrs(DefId), - FnArgNames(DefId), - DylibDepFormats(DefId), - IsAllocator(DefId), - IsPanicRuntime(DefId), - ExternCrate(DefId), + [] ParamEnv(DefId), + [] DescribeDef(DefId), + [] DefSpan(DefId), + [] Stability(DefId), + [] Deprecation(DefId), + [] ItemBodyNestedBodies(DefId), + [] ConstIsRvaluePromotableToStatic(DefId), + [] ImplParent(DefId), + [] TraitOfItem(DefId), + [] IsExportedSymbol(DefId), + [] IsMirAvailable(DefId), + [] ItemAttrs(DefId), + [] FnArgNames(DefId), + [] DylibDepFormats(DefId), + [] IsAllocator(DefId), + [] IsPanicRuntime(DefId), + [] ExternCrate(DefId), ); -trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> { +trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { const CAN_RECONSTRUCT_QUERY_KEY: bool; - fn to_fingerprint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint; - fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String; + + /// This method turns the parameters of a DepNodeConstructor into an opaque + /// Fingerprint to be used in DepNode. + /// Not all DepNodeParams support being turned into a Fingerprint (they + /// don't need to if the corresponding DepNode is anonymous). + fn to_fingerprint(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint { + panic!("Not implemented. Accidentally called on anonymous node?") + } + + fn to_debug_str(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> String { + format!("{:?}", self) + } } impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs index 389e7f08dfd2..e67d65841d59 100644 --- a/src/librustc/dep_graph/edges.rs +++ b/src/librustc/dep_graph/edges.rs @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use ich::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stable_hasher::StableHasher; use std::env; -use super::{DepGraphQuery, DepNode}; +use std::hash::Hash; +use std::mem; +use super::{DepGraphQuery, DepKind, DepNode}; use super::debug::EdgeFilter; pub struct DepGraphEdges { @@ -44,6 +48,10 @@ enum OpenTask { reads: Vec, read_set: FxHashSet, }, + Anon { + reads: Vec, + read_set: FxHashSet, + }, Ignore, } @@ -114,6 +122,56 @@ impl DepGraphEdges { } } + pub fn push_anon_task(&mut self) { + self.task_stack.push(OpenTask::Anon { + reads: Vec::new(), + read_set: FxHashSet(), + }); + } + + pub fn pop_anon_task(&mut self, kind: DepKind) -> DepNode { + let popped_node = self.task_stack.pop().unwrap(); + + if let OpenTask::Anon { + read_set: _, + reads + } = popped_node { + let mut fingerprint = Fingerprint::zero(); + let mut hasher = StableHasher::new(); + + for read in reads.iter() { + mem::discriminant(&read.kind).hash(&mut hasher); + + // Fingerprint::combine() is faster than sending Fingerprint + // through the StableHasher (at least as long as StableHasher + // is so slow). + fingerprint = fingerprint.combine(read.hash); + } + + fingerprint = fingerprint.combine(hasher.finish()); + + let target_dep_node = DepNode { + kind, + hash: fingerprint, + }; + + if self.indices.contains_key(&target_dep_node) { + return target_dep_node; + } + + let target_id = self.get_or_create_node(target_dep_node); + + for read in reads.into_iter() { + let source_id = self.get_or_create_node(read); + self.edges.insert((source_id, target_id)); + } + + target_dep_node + } else { + bug!("pop_anon_task() - Expected anonymous task to be popped") + } + } + /// Indicates that the current task `C` reads `v` by adding an /// edge from `v` to `C`. If there is no current task, has no /// effect. Note that *reading* from tracked state is harmless if @@ -138,6 +196,14 @@ impl DepGraphEdges { } } } + Some(&mut OpenTask::Anon { + ref mut reads, + ref mut read_set, + }) => { + if read_set.insert(source) { + reads.push(source); + } + } Some(&mut OpenTask::Ignore) | None => { // ignore } diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index b657102df39f..295b402c533e 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -13,7 +13,7 @@ use session::config::OutputType; use std::cell::{Ref, RefCell}; use std::rc::Rc; -use super::dep_node::{DepNode, WorkProductId}; +use super::dep_node::{DepNode, DepKind, WorkProductId}; use super::query::DepGraphQuery; use super::raii; use super::safe::DepGraphSafe; @@ -115,6 +115,21 @@ impl DepGraph { task(cx, arg) } + /// Execute something within an "anonymous" task, that is, a task the + /// DepNode of which is determined by the list of inputs it read from. + pub fn with_anon_task(&self, dep_kind: DepKind, op: OP) -> (R, DepNode) + where OP: FnOnce() -> R + { + if let Some(ref data) = self.data { + data.edges.borrow_mut().push_anon_task(); + let result = op(); + let dep_node = data.edges.borrow_mut().pop_anon_task(dep_kind); + (result, dep_node) + } else { + (op(), DepNode::new_no_params(DepKind::Krate)) + } + } + #[inline] pub fn read(&self, v: DepNode) { if let Some(ref data) = self.data {