]> git.lizzy.rs Git - rust.git/commitdiff
incr.comp.: Introduce the concept of anonymous DepNodes.
authorMichael Woerister <michaelwoerister@posteo.net>
Fri, 23 Jun 2017 14:37:12 +0000 (16:37 +0200)
committerMichael Woerister <michaelwoerister@posteo.net>
Mon, 10 Jul 2017 10:21:39 +0000 (12:21 +0200)
src/librustc/dep_graph/dep_node.rs
src/librustc/dep_graph/edges.rs
src/librustc/dep_graph/graph.rs

index bb5244ad3f4557cf6d1790d171993b41d92915e3..c6275e84645843296d34ac08bb6781de4c4b9a82 100644 (file)
@@ -79,9 +79,14 @@ macro_rules! erase {
     ($x:tt) => ({})
 }
 
     ($x:tt) => ({})
 }
 
+macro_rules! anon_attr_to_bool {
+    (anon) => (true)
+}
+
 macro_rules! define_dep_nodes {
     (<$tcx:tt>
     $(
 macro_rules! define_dep_nodes {
     (<$tcx:tt>
     $(
+        [$($anon:ident)*]
         $variant:ident $(( $($tuple_arg:tt),* ))*
                        $({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
       ,)*
         $variant:ident $(( $($tuple_arg:tt),* ))*
                        $({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
       ,)*
@@ -117,6 +122,19 @@ pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
                 }
             }
 
                 }
             }
 
+            #[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 {
             #[allow(unreachable_code)]
             #[inline]
             pub fn has_params(&self) -> bool {
@@ -356,100 +374,101 @@ pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode {
     // 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.
     // 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
 
     // 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.
 
     // 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.
 
     // 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.
 
     // 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.
 
     // 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.
 
     // 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> },
-
-    BorrowCheckKrate,
-    BorrowCheck(DefId),
-    RvalueCheck(DefId),
-    Reachability,
-    MirKeys,
-    TransWriteMetadata,
-    CrateVariances,
+    [] MirConstQualif(DefId),
+    [] MirConst(DefId),
+    [] MirValidated(DefId),
+    [] MirOptimized(DefId),
+    [] MirShim { instance_def: InstanceDef<'tcx> },
+
+    [] 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.
 
     // 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),
-
-    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),
+    [] 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),
+
+    [anon] IsCopy(DefId),
+    [anon] IsSized(DefId),
+    [anon] IsFreeze(DefId),
+    [anon] NeedsDrop(DefId),
+    [anon] Layout(DefId),
 
     // The set of impls for a given trait.
 
     // 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.
 
     // 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<Bar>`, there could be
 
     // Trait selection cache is a little funny. Given a trait
     // reference like `Foo: SomeTrait<Bar>`, there could be
@@ -476,35 +495,45 @@ pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode {
     // 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.
     // 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.
 
     // For proj. cache, we just keep a list of all def-ids, since it is
     // not a hotspot.
-    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),
+    [] 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),
 );
 
 );
 
-trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> {
+trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
     const CAN_RECONSTRUCT_QUERY_KEY: bool;
     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
 }
 
 impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T
index 389e7f08dfd2957198de18339d0fb0435cd9916d..e67d65841d5923dab9560f03bd113354e59b7688 100644 (file)
@@ -8,9 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 // 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::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::StableHasher;
 use std::env;
 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 {
 use super::debug::EdgeFilter;
 
 pub struct DepGraphEdges {
@@ -44,6 +48,10 @@ enum OpenTask {
         reads: Vec<DepNode>,
         read_set: FxHashSet<DepNode>,
     },
         reads: Vec<DepNode>,
         read_set: FxHashSet<DepNode>,
     },
+    Anon {
+        reads: Vec<DepNode>,
+        read_set: FxHashSet<DepNode>,
+    },
     Ignore,
 }
 
     Ignore,
 }
 
@@ -114,6 +122,56 @@ pub fn pop_task(&mut self, key: DepNode) {
         }
     }
 
         }
     }
 
+    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
     /// 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 @@ pub fn read(&mut self, source: DepNode) {
                     }
                 }
             }
                     }
                 }
             }
+            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
             }
             Some(&mut OpenTask::Ignore) | None => {
                 // ignore
             }
index b657102df39f49c2e47723d25a9ad59ad7468109..295b402c533eecfe30f430be663de8601c60cb17 100644 (file)
@@ -13,7 +13,7 @@
 use std::cell::{Ref, RefCell};
 use std::rc::Rc;
 
 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;
 use super::query::DepGraphQuery;
 use super::raii;
 use super::safe::DepGraphSafe;
@@ -115,6 +115,21 @@ pub fn with_task<C, A, R>(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) ->
         task(cx, arg)
     }
 
         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<OP,R>(&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 {
     #[inline]
     pub fn read(&self, v: DepNode) {
         if let Some(ref data) = self.data {