about summary refs log tree commit diff
path: root/src/librustc/dep_graph
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo>2017-09-25 13:51:49 +0200
committerMichael Woerister <michaelwoerister@posteo>2017-10-02 15:36:47 +0200
commit6db27d9f90223693e84d230e5654d4c1a5afe700 (patch)
tree8c531466374214251f179d026e8de608fdc2bf3a /src/librustc/dep_graph
parenta948be81cda8ed8145f4e1d7cf6b0a59efb8e240 (diff)
downloadrust-6db27d9f90223693e84d230e5654d4c1a5afe700.tar.gz
rust-6db27d9f90223693e84d230e5654d4c1a5afe700.zip
incr.comp.: Add minimal version of try_mark_green procedure.
Diffstat (limited to 'src/librustc/dep_graph')
-rw-r--r--src/librustc/dep_graph/graph.rs146
-rw-r--r--src/librustc/dep_graph/mod.rs2
-rw-r--r--src/librustc/dep_graph/prev.rs31
3 files changed, 154 insertions, 25 deletions
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index f76f9279e5b..071f233b188 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -16,6 +16,7 @@ use session::config::OutputType;
 use std::cell::{Ref, RefCell};
 use std::hash::Hash;
 use std::rc::Rc;
+use ty::TyCtxt;
 use util::common::{ProfileQueriesMsg, profq_msg};
 
 use ich::Fingerprint;
@@ -28,6 +29,7 @@ use super::edges::{self, DepGraphEdges};
 use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 use super::prev::PreviousDepGraph;
 
+
 #[derive(Clone)]
 pub struct DepGraph {
     data: Option<Rc<DepGraphData>>,
@@ -62,8 +64,7 @@ impl DepNodeIndex {
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum DepNodeColor {
     Red,
-    Green,
-    Gray
+    Green(DepNodeIndex)
 }
 
 struct DepGraphData {
@@ -178,6 +179,8 @@ impl DepGraph {
               R: HashStable<HCX>,
     {
         if let Some(ref data) = self.data {
+            debug_assert!(!data.colors.borrow().contains_key(&key));
+
             data.edges.borrow_mut().push_task(key);
             data.current.borrow_mut().push_task(key);
             if cfg!(debug_assertions) {
@@ -212,7 +215,10 @@ impl DepGraph {
             let prev_fingerprint = data.previous.fingerprint_of(&key);
 
             let color = if Some(current_fingerprint) == prev_fingerprint {
-                DepNodeColor::Green
+                DepNodeColor::Green(DepNodeIndex {
+                    legacy: dep_node_index_legacy,
+                    new: dep_node_index_new,
+                })
             } else {
                 DepNodeColor::Red
             };
@@ -310,18 +316,6 @@ impl DepGraph {
         self.data.as_ref().unwrap().previous.fingerprint_of(dep_node)
     }
 
-    pub fn node_color(&self, dep_node: &DepNode) -> DepNodeColor {
-        match self.data.as_ref().unwrap().colors.borrow().get(dep_node) {
-            Some(&color) => {
-                debug_assert!(color != DepNodeColor::Gray);
-                color
-            }
-            None => {
-                DepNodeColor::Gray
-            }
-        }
-    }
-
     /// Indicates that a previous work product exists for `v`. This is
     /// invoked during initial start-up based on what nodes are clean
     /// (and what files exist in the incr. directory).
@@ -426,6 +420,128 @@ impl DepGraph {
             edge_list_data,
         }
     }
+
+    pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
+        self.data.as_ref().and_then(|data| data.colors.borrow().get(dep_node).cloned())
+    }
+
+    pub fn try_mark_green(&self,
+                          tcx: TyCtxt,
+                          dep_node: &DepNode)
+                          -> Option<DepNodeIndex> {
+        let data = self.data.as_ref().unwrap();
+
+        debug_assert!(!data.colors.borrow().contains_key(dep_node));
+        debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node));
+
+        if dep_node.kind.is_input() {
+            // We should only hit try_mark_green() for inputs that do not exist
+            // anymore in the current compilation session. Existing inputs are
+            // eagerly marked as either red/green before any queries are
+            // executed.
+            debug_assert!(dep_node.extract_def_id(tcx).is_none());
+            return None;
+        }
+
+        let (prev_deps, prev_dep_node_index) = match data.previous.edges_from(dep_node) {
+            Some(prev) => {
+                // This DepNode and the corresponding query invocation existed
+                // in the previous compilation session too, so we can try to
+                // mark it as green by recursively marking all of its
+                // dependencies green.
+                prev
+            }
+            None => {
+                // This DepNode did not exist in the previous compilation session,
+                // so we cannot mark it as green.
+                return None
+            }
+        };
+
+        let mut current_deps = Vec::new();
+
+        for &dep_dep_node in prev_deps {
+            let dep_dep_node = &data.previous.index_to_node(dep_dep_node);
+            let dep_dep_node_color = data.colors.borrow().get(dep_dep_node).cloned();
+            match dep_dep_node_color {
+                Some(DepNodeColor::Green(node_index)) => {
+                    // This dependency has been marked as green before, we are
+                    // still fine and can continue with checking the other
+                    // dependencies.
+                    current_deps.push(node_index);
+                }
+                Some(DepNodeColor::Red) => {
+                    // We found a dependency the value of which has changed
+                    // compared to the previous compilation session. We cannot
+                    // mark the DepNode as green and also don't need to bother
+                    // with checking any of the other dependencies.
+                    return None
+                }
+                None => {
+                    // We don't know the state of this dependency. Let's try to
+                    // mark it green.
+                    if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) {
+                        current_deps.push(node_index);
+                    } else {
+                        // We failed to mark it green. This can have various
+                        // reasons.
+                        return None
+                    }
+                }
+            }
+        }
+
+        // If we got here without hitting a `return` that means that all
+        // dependencies of this DepNode could be marked as green. Therefore we
+        // can also mark this DepNode as green. We do so by...
+
+        // ... allocating an entry for it in the current dependency graph and
+        // adding all the appropriate edges imported from the previous graph ...
+        let node_index_new = data.current
+                                 .borrow_mut()
+                                 .alloc_node(*dep_node,
+                                             current_deps.iter().map(|n| n.new).collect());
+        let dep_node_index_legacy = {
+            let mut legacy_graph = data.edges.borrow_mut();
+            legacy_graph.push_task(*dep_node);
+            for node_index in current_deps.into_iter().map(|n| n.legacy) {
+                legacy_graph.read_index(node_index);
+            }
+            legacy_graph.pop_task(*dep_node)
+        };
+
+        // ... copying the fingerprint from the previous graph too, so we don't
+        // have to recompute it ...
+        let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index);
+        assert!(self.fingerprints
+                    .borrow_mut()
+                    .insert(*dep_node, fingerprint)
+                    .is_none());
+
+        let node_index = DepNodeIndex {
+            legacy: dep_node_index_legacy,
+            new: node_index_new,
+        };
+
+        // ... and finally storing a "Green" entry in the color map.
+        assert!(data.colors
+                    .borrow_mut()
+                    .insert(*dep_node, DepNodeColor::Green(node_index))
+                    .is_none());
+
+        Some(node_index)
+    }
+
+    // Used in various assertions
+    pub fn is_green(&self, dep_node_index: DepNodeIndex) -> bool {
+        let dep_node = self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index.new];
+        self.data.as_ref().unwrap().colors.borrow().get(&dep_node).map(|&color| {
+            match color {
+                DepNodeColor::Red => false,
+                DepNodeColor::Green(_) => true,
+            }
+        }).unwrap_or(false)
+    }
 }
 
 /// A "work product" is an intermediate result that we save into the
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index cd77e06bdd6..a8f78336b37 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -21,7 +21,7 @@ mod serialized;
 
 pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
 pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId};
-pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex};
+pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor};
 pub use self::prev::PreviousDepGraph;
 pub use self::query::DepGraphQuery;
 pub use self::safe::AssertDepGraphSafe;
diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs
index 0236f9c2292..17001bbb0c3 100644
--- a/src/librustc/dep_graph/prev.rs
+++ b/src/librustc/dep_graph/prev.rs
@@ -28,20 +28,33 @@ impl PreviousDepGraph {
         PreviousDepGraph { data, index }
     }
 
-    pub fn with_edges_from<F>(&self, dep_node: &DepNode, mut f: F)
-    where
-        F: FnMut(&(DepNode, Fingerprint)),
-    {
-        let node_index = self.index[dep_node];
-        self.data
-            .edge_targets_from(node_index)
-            .into_iter()
-            .for_each(|&index| f(&self.data.nodes[index]));
+    #[inline]
+    pub fn edges_from(&self,
+                      dep_node: &DepNode)
+                      -> Option<(&[SerializedDepNodeIndex], SerializedDepNodeIndex)> {
+        self.index
+            .get(dep_node)
+            .map(|&node_index| {
+                (self.data.edge_targets_from(node_index), node_index)
+            })
+    }
+
+    #[inline]
+    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode {
+        self.data.nodes[dep_node_index].0
     }
 
+    #[inline]
     pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
         self.index
             .get(dep_node)
             .map(|&node_index| self.data.nodes[node_index].1)
     }
+
+    #[inline]
+    pub fn fingerprint_by_index(&self,
+                                dep_node_index: SerializedDepNodeIndex)
+                                -> Fingerprint {
+        self.data.nodes[dep_node_index].1
+    }
 }