diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs index 29c0ba66f3f..b12db11cb6a 100644 --- a/src/librustc/dep_graph/edges.rs +++ b/src/librustc/dep_graph/edges.rs @@ -17,7 +17,7 @@ use std::mem; use super::{DepGraphQuery, DepKind, DepNode}; use super::debug::EdgeFilter; -pub struct DepGraphEdges { +pub(super) struct DepGraphEdges { nodes: Vec, indices: FxHashMap, edges: FxHashSet<(DepNodeIndex, DepNodeIndex)>, @@ -31,8 +31,8 @@ pub struct DepGraphEdges { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct DepNodeIndex { - index: u32 +pub(super) struct DepNodeIndex { + index: u32, } impl DepNodeIndex { diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 90a29b63482..b823ea71d14 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHashingContextProvider}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use session::config::OutputType; use std::cell::{Ref, RefCell}; +use std::hash::Hash; use std::rc::Rc; use util::common::{ProfileQueriesMsg, profq_msg}; @@ -22,7 +24,7 @@ use super::dep_node::{DepNode, DepKind, WorkProductId}; use super::query::DepGraphQuery; use super::raii; use super::safe::DepGraphSafe; -use super::edges::{DepGraphEdges, DepNodeIndex}; +use super::edges::{self, DepGraphEdges}; #[derive(Clone)] pub struct DepGraph { @@ -38,10 +40,34 @@ pub struct DepGraph { fingerprints: Rc>> } +/// As a temporary measure, while transitioning to the new DepGraph +/// implementation, we maintain the old and the new dep-graph encoding in +/// parallel, so a DepNodeIndex actually contains two indices, one for each +/// version. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct DepNodeIndex { + legacy: edges::DepNodeIndex, + new: DepNodeIndexNew, +} + +impl DepNodeIndex { + pub const INVALID: DepNodeIndex = DepNodeIndex { + legacy: edges::DepNodeIndex::INVALID, + new: DepNodeIndexNew::INVALID, + }; +} + struct DepGraphData { - /// The actual graph data. + /// The old, initial encoding of the dependency graph. This will soon go + /// away. edges: RefCell, + /// The new encoding of the dependency graph, optimized for red/green + /// tracking. The `current` field is the dependency graph of only the + /// current compilation session: We don't merge the previous dep-graph into + /// current one anymore. + current: RefCell, + /// When we load, there may be `.o` files, cached mir, or other such /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into @@ -63,6 +89,7 @@ impl DepGraph { work_products: RefCell::new(FxHashMap()), edges: RefCell::new(DepGraphEdges::new()), dep_node_debug: RefCell::new(FxHashMap()), + current: RefCell::new(CurrentDepGraph::new()), })) } else { None @@ -82,7 +109,8 @@ impl DepGraph { } pub fn in_ignore<'graph>(&'graph self) -> Option> { - self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.edges)) + self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.edges, + &data.current)) } pub fn with_ignore(&self, op: OP) -> R @@ -130,6 +158,7 @@ impl DepGraph { { if let Some(ref data) = self.data { data.edges.borrow_mut().push_task(key); + data.current.borrow_mut().push_task(key); if cfg!(debug_assertions) { profq_msg(ProfileQueriesMsg::TaskBegin(key.clone())) }; @@ -145,7 +174,9 @@ impl DepGraph { if cfg!(debug_assertions) { profq_msg(ProfileQueriesMsg::TaskEnd) }; - let dep_node_index = data.edges.borrow_mut().pop_task(key); + + let dep_node_index_legacy = data.edges.borrow_mut().pop_task(key); + let dep_node_index_new = data.current.borrow_mut().pop_task(key); let mut stable_hasher = StableHasher::new(); result.hash_stable(&mut hcx, &mut stable_hasher); @@ -155,7 +186,10 @@ impl DepGraph { .insert(key, stable_hasher.finish()) .is_none()); - (result, dep_node_index) + (result, DepNodeIndex { + legacy: dep_node_index_legacy, + new: dep_node_index_new, + }) } else { if key.kind.fingerprint_needed_for_crate_hash() { let mut hcx = cx.create_stable_hashing_context(); @@ -180,9 +214,14 @@ impl DepGraph { { if let Some(ref data) = self.data { data.edges.borrow_mut().push_anon_task(); + data.current.borrow_mut().push_anon_task(); let result = op(); - let dep_node = data.edges.borrow_mut().pop_anon_task(dep_kind); - (result, dep_node) + let dep_node_index_legacy = data.edges.borrow_mut().pop_anon_task(dep_kind); + let dep_node_index_new = data.current.borrow_mut().pop_anon_task(dep_kind); + (result, DepNodeIndex { + legacy: dep_node_index_legacy, + new: dep_node_index_new, + }) } else { (op(), DepNodeIndex::INVALID) } @@ -192,13 +231,15 @@ impl DepGraph { pub fn read(&self, v: DepNode) { if let Some(ref data) = self.data { data.edges.borrow_mut().read(v); + data.current.borrow_mut().read(v); } } #[inline] pub fn read_index(&self, v: DepNodeIndex) { if let Some(ref data) = self.data { - data.edges.borrow_mut().read_index(v); + data.edges.borrow_mut().read_index(v.legacy); + data.current.borrow_mut().read_index(v.new); } } @@ -215,7 +256,13 @@ impl DepGraph { pub fn alloc_input_node(&self, node: DepNode) -> DepNodeIndex { if let Some(ref data) = self.data { - data.edges.borrow_mut().add_node(node) + let dep_node_index_legacy = data.edges.borrow_mut().add_node(node); + let dep_node_index_new = data.current.borrow_mut() + .alloc_node(node, Vec::new()); + DepNodeIndex { + legacy: dep_node_index_legacy, + new: dep_node_index_new, + } } else { DepNodeIndex::INVALID } @@ -335,3 +382,208 @@ pub struct WorkProduct { /// Saved files associated with this CGU pub saved_files: Vec<(OutputType, String)>, } + +pub(super) struct CurrentDepGraph { + nodes: IndexVec, + edges: IndexVec>, + node_to_node_index: FxHashMap, + + task_stack: Vec, +} + +impl CurrentDepGraph { + fn new() -> CurrentDepGraph { + CurrentDepGraph { + nodes: IndexVec::new(), + edges: IndexVec::new(), + node_to_node_index: FxHashMap(), + task_stack: Vec::new(), + } + } + + pub(super) fn push_ignore(&mut self) { + self.task_stack.push(OpenTask::Ignore); + } + + pub(super) fn pop_ignore(&mut self) { + let popped_node = self.task_stack.pop().unwrap(); + debug_assert_eq!(popped_node, OpenTask::Ignore); + } + + pub(super) fn push_task(&mut self, key: DepNode) { + self.task_stack.push(OpenTask::Regular { + node: key, + reads: Vec::new(), + read_set: FxHashSet(), + }); + } + + pub(super) fn pop_task(&mut self, key: DepNode) -> DepNodeIndexNew { + let popped_node = self.task_stack.pop().unwrap(); + + if let OpenTask::Regular { + node, + read_set: _, + reads + } = popped_node { + debug_assert_eq!(node, key); + self.alloc_node(node, reads) + } else { + bug!("pop_task() - Expected regular task to be popped") + } + } + + fn push_anon_task(&mut self) { + self.task_stack.push(OpenTask::Anon { + reads: Vec::new(), + read_set: FxHashSet(), + }); + } + + fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndexNew { + 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() { + let read_dep_node = self.nodes[read]; + + ::std::mem::discriminant(&read_dep_node.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_dep_node.hash); + } + + fingerprint = fingerprint.combine(hasher.finish()); + + let target_dep_node = DepNode { + kind, + hash: fingerprint, + }; + + if let Some(&index) = self.node_to_node_index.get(&target_dep_node) { + return index; + } + + self.alloc_node(target_dep_node, reads) + } else { + bug!("pop_anon_task() - Expected anonymous task to be popped") + } + } + + fn read(&mut self, source: DepNode) { + let dep_node_index = self.maybe_alloc_node(source); + self.read_index(dep_node_index); + } + + fn read_index(&mut self, source: DepNodeIndexNew) { + match self.task_stack.last_mut() { + Some(&mut OpenTask::Regular { + ref mut reads, + ref mut read_set, + node: _, + }) => { + if read_set.insert(source) { + reads.push(source); + } + } + 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 + } + } + } + + fn alloc_node(&mut self, + dep_node: DepNode, + edges: Vec) + -> DepNodeIndexNew { + debug_assert_eq!(self.edges.len(), self.nodes.len()); + debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len()); + debug_assert!(!self.node_to_node_index.contains_key(&dep_node)); + let dep_node_index = DepNodeIndexNew::new(self.nodes.len()); + self.nodes.push(dep_node); + self.node_to_node_index.insert(dep_node, dep_node_index); + self.edges.push(edges); + dep_node_index + } + + fn maybe_alloc_node(&mut self, + dep_node: DepNode) + -> DepNodeIndexNew { + debug_assert_eq!(self.edges.len(), self.nodes.len()); + debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len()); + + let CurrentDepGraph { + ref mut node_to_node_index, + ref mut nodes, + ref mut edges, + .. + } = *self; + + *node_to_node_index.entry(dep_node).or_insert_with(|| { + let next_id = nodes.len(); + nodes.push(dep_node); + edges.push(Vec::new()); + DepNodeIndexNew::new(next_id) + }) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub(super) struct DepNodeIndexNew { + index: u32, +} + +impl Idx for DepNodeIndexNew { + fn new(idx: usize) -> Self { + DepNodeIndexNew::new(idx) + } + fn index(self) -> usize { + self.index() + } +} + +impl DepNodeIndexNew { + + const INVALID: DepNodeIndexNew = DepNodeIndexNew { + index: ::std::u32::MAX, + }; + + fn new(v: usize) -> DepNodeIndexNew { + assert!((v & 0xFFFF_FFFF) == v); + DepNodeIndexNew { index: v as u32 } + } + + fn index(self) -> usize { + self.index as usize + } +} + +#[derive(Clone, Debug, PartialEq)] +enum OpenTask { + Regular { + node: DepNode, + reads: Vec, + read_set: FxHashSet, + }, + Anon { + reads: Vec, + read_set: FxHashSet, + }, + Ignore, +} diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index ac0c88ced93..1a4c5381abf 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -22,10 +22,9 @@ pub use self::dep_node::DepNode; pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; -pub use self::edges::DepNodeIndex; +pub use self::graph::DepNodeIndex; pub use self::query::DepGraphQuery; pub use self::safe::AssertDepGraphSafe; pub use self::safe::DepGraphSafe; -pub use self::raii::DepTask; pub use self::dep_node::{DepKind, DepConstructor}; diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index ce261ca68e8..6e9e4f4a18b 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -8,50 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::DepNode; use super::edges::DepGraphEdges; +use super::graph::CurrentDepGraph; use std::cell::RefCell; -pub struct DepTask<'graph> { - graph: &'graph RefCell, - key: DepNode, -} - -impl<'graph> DepTask<'graph> { - pub fn new(graph: &'graph RefCell, - key: DepNode) - -> DepTask<'graph> { - graph.borrow_mut().push_task(key); - DepTask { - graph, - key, - } - } -} - -impl<'graph> Drop for DepTask<'graph> { - fn drop(&mut self) { - self.graph.borrow_mut().pop_task(self.key); - } -} - pub struct IgnoreTask<'graph> { - graph: &'graph RefCell, + legacy_graph: &'graph RefCell, + new_graph: &'graph RefCell, } impl<'graph> IgnoreTask<'graph> { - pub fn new(graph: &'graph RefCell) -> IgnoreTask<'graph> { - graph.borrow_mut().push_ignore(); + pub(super) fn new(legacy_graph: &'graph RefCell, + new_graph: &'graph RefCell) + -> IgnoreTask<'graph> { + legacy_graph.borrow_mut().push_ignore(); + new_graph.borrow_mut().push_ignore(); IgnoreTask { - graph + legacy_graph, + new_graph, } } } impl<'graph> Drop for IgnoreTask<'graph> { fn drop(&mut self) { - self.graph.borrow_mut().pop_ignore(); + self.legacy_graph.borrow_mut().pop_ignore(); + self.new_graph.borrow_mut().pop_ignore(); } } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 51433238f2c..80fadcda277 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -88,6 +88,15 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { ).1; } + { + dep_graph.with_task( + DepNode::new_no_params(DepKind::AllLocalTraitImpls), + &hcx, + &krate.trait_impls, + identity_fn + ); + } + let hir_body_nodes = vec![root_mod_def_path_hash]; let mut collector = NodeCollector {