diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 96d6b0f79cf..5fa0cedfe74 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -34,14 +34,11 @@ use super::prev::PreviousDepGraph; pub struct DepGraph { data: Option>, - // At the moment we are using DepNode as key here. In the future it might - // be possible to use an IndexVec here. At the moment there - // are a few problems with that: - // - Some fingerprints are needed even if incr. comp. is disabled -- yet - // we need to have a dep-graph to generate DepNodeIndices. - // - The architecture is still in flux and it's not clear what how to best - // implement things. - fingerprints: Rc>> + // A vector mapping depnodes from the current graph to their associated + // result value fingerprints. Do not rely on the length of this vector + // being the same as the number of nodes in the graph. The vector can + // contain an arbitrary number of zero-entries at the end. + fingerprints: Rc>> } @@ -97,6 +94,11 @@ struct DepGraphData { impl DepGraph { pub fn new(prev_graph: PreviousDepGraph) -> DepGraph { + // Pre-allocate the fingerprints array. We over-allocate a little so + // that we hopefully don't have to re-allocate during this compilation + // session. + let fingerprints = IndexVec::from_elem_n(Fingerprint::zero(), + (prev_graph.node_count() * 115) / 100); DepGraph { data: Some(Rc::new(DepGraphData { previous_work_products: RefCell::new(FxHashMap()), @@ -107,14 +109,14 @@ impl DepGraph { colors: RefCell::new(FxHashMap()), loaded_from_cache: RefCell::new(FxHashMap()), })), - fingerprints: Rc::new(RefCell::new(FxHashMap())), + fingerprints: Rc::new(RefCell::new(fingerprints)), } } pub fn new_disabled() -> DepGraph { DepGraph { data: None, - fingerprints: Rc::new(RefCell::new(FxHashMap())), + fingerprints: Rc::new(RefCell::new(IndexVec::new())), } } @@ -231,12 +233,16 @@ impl DepGraph { // Store the current fingerprint { - let old_value = self.fingerprints - .borrow_mut() - .insert(key, current_fingerprint); - debug_assert!(old_value.is_none(), + let mut fingerprints = self.fingerprints.borrow_mut(); + + if dep_node_index.index() >= fingerprints.len() { + fingerprints.resize(dep_node_index.index() + 1, Fingerprint::zero()); + } + + debug_assert!(fingerprints[dep_node_index] == Fingerprint::zero(), "DepGraph::with_task() - Duplicate fingerprint \ insertion for {:?}", key); + fingerprints[dep_node_index] = current_fingerprint; } // Determine the color of the new DepNode. @@ -262,13 +268,15 @@ impl DepGraph { let result = task(cx, arg); let mut stable_hasher = StableHasher::new(); result.hash_stable(&mut hcx, &mut stable_hasher); - let old_value = self.fingerprints - .borrow_mut() - .insert(key, stable_hasher.finish()); - debug_assert!(old_value.is_none(), - "DepGraph::with_task() - Duplicate fingerprint \ - insertion for {:?}", key); - (result, DepNodeIndex::INVALID) + let fingerprint = stable_hasher.finish(); + + let mut fingerprints = self.fingerprints.borrow_mut(); + let dep_node_index = DepNodeIndex::new(fingerprints.len()); + fingerprints.push(fingerprint); + debug_assert!(fingerprints[dep_node_index] == fingerprint, + "DepGraph::with_task() - Assigned fingerprint to \ + unexpected index for {:?}", key); + (result, dep_node_index) } else { (task(cx, arg), DepNodeIndex::INVALID) } @@ -328,11 +336,29 @@ impl DepGraph { } #[inline] - pub fn fingerprint_of(&self, dep_node: &DepNode) -> Fingerprint { - match self.fingerprints.borrow().get(dep_node) { + pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { + self.data + .as_ref() + .unwrap() + .current + .borrow_mut() + .node_to_node_index + .get(dep_node) + .cloned() + .unwrap() + } + + #[inline] + pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { + match self.fingerprints.borrow().get(dep_node_index) { Some(&fingerprint) => fingerprint, None => { - bug!("Could not find current fingerprint for {:?}", dep_node) + if let Some(ref data) = self.data { + let dep_node = data.current.borrow().nodes[dep_node_index]; + bug!("Could not find current fingerprint for {:?}", dep_node) + } else { + bug!("Could not find current fingerprint for {:?}", dep_node_index) + } } } } @@ -420,14 +446,17 @@ impl DepGraph { } pub fn serialize(&self) -> SerializedDepGraph { - let fingerprints = self.fingerprints.borrow(); + let mut fingerprints = self.fingerprints.borrow_mut(); let current_dep_graph = self.data.as_ref().unwrap().current.borrow(); - let nodes: IndexVec<_, _> = current_dep_graph.nodes.iter().map(|dep_node| { - let fingerprint = fingerprints.get(dep_node) - .cloned() - .unwrap_or(Fingerprint::zero()); - (*dep_node, fingerprint) + // Make sure we don't run out of bounds below. + if current_dep_graph.nodes.len() > fingerprints.len() { + fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::zero()); + } + + let nodes: IndexVec<_, (DepNode, Fingerprint)> = + current_dep_graph.nodes.iter_enumerated().map(|(idx, &dep_node)| { + (dep_node, fingerprints[idx]) }).collect(); let total_edge_count: usize = current_dep_graph.edges.iter() @@ -610,13 +639,20 @@ impl DepGraph { // ... 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); - let old_fingerprint = self.fingerprints - .borrow_mut() - .insert(*dep_node, fingerprint); - debug_assert!(old_fingerprint.is_none(), - "DepGraph::try_mark_green() - Duplicate fingerprint \ - insertion for {:?}", dep_node); + { + let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index); + let mut fingerprints = self.fingerprints.borrow_mut(); + + if dep_node_index.index() >= fingerprints.len() { + fingerprints.resize(dep_node_index.index() + 1, Fingerprint::zero()); + } + + debug_assert!(fingerprints[dep_node_index] == Fingerprint::zero(), + "DepGraph::try_mark_green() - Duplicate fingerprint \ + insertion for {:?}", dep_node); + + fingerprints[dep_node_index] = fingerprint; + } // ... emitting any stored diagnostic ... { diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs index 6c43b5c5ff1..50e1ee88a46 100644 --- a/src/librustc/dep_graph/prev.rs +++ b/src/librustc/dep_graph/prev.rs @@ -62,4 +62,8 @@ impl PreviousDepGraph { -> Fingerprint { self.data.nodes[dep_node_index].1 } + + pub fn node_count(&self) -> usize { + self.index.len() + } } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 02a1e33eeb9..68b103111ca 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -12,6 +12,7 @@ use super::*; use dep_graph::{DepGraph, DepKind, DepNodeIndex}; use hir::intravisit::{Visitor, NestedVisitorMap}; +use hir::svh::Svh; use middle::cstore::CrateStore; use session::CrateDisambiguator; use std::iter::repeat; @@ -44,7 +45,7 @@ pub(super) struct NodeCollector<'a, 'hir> { // We are collecting DepNode::HirBody hashes here so we can compute the // crate hash from then later on. - hir_body_nodes: Vec, + hir_body_nodes: Vec<(DefPathHash, DepNodeIndex)>, } impl<'a, 'hir> NodeCollector<'a, 'hir> { @@ -99,7 +100,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { ); } - let hir_body_nodes = vec![root_mod_def_path_hash]; + let hir_body_nodes = vec![(root_mod_def_path_hash, root_mod_full_dep_index)]; let mut collector = NodeCollector { krate, @@ -123,13 +124,12 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { crate_disambiguator: CrateDisambiguator, cstore: &CrateStore, commandline_args_hash: u64) - -> Vec> { + -> (Vec>, Svh) { let mut node_hashes: Vec<_> = self .hir_body_nodes .iter() - .map(|&def_path_hash| { - let dep_node = def_path_hash.to_dep_node(DepKind::HirBody); - (def_path_hash, self.dep_graph.fingerprint_of(&dep_node)) + .map(|&(def_path_hash, dep_node_index)| { + (def_path_hash, self.dep_graph.fingerprint_of(dep_node_index)) }) .collect(); @@ -147,13 +147,19 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { (name1, dis1).cmp(&(name2, dis2)) }); - self.dep_graph.with_task(DepNode::new_no_params(DepKind::Krate), - &self.hcx, - ((node_hashes, upstream_crates), - (commandline_args_hash, - crate_disambiguator.to_fingerprint())), - identity_fn); - self.map + let (_, crate_dep_node_index) = self + .dep_graph + .with_task(DepNode::new_no_params(DepKind::Krate), + &self.hcx, + ((node_hashes, upstream_crates), + (commandline_args_hash, + crate_disambiguator.to_fingerprint())), + identity_fn); + + let svh = Svh::new(self.dep_graph + .fingerprint_of(crate_dep_node_index) + .to_smaller_hash()); + (self.map, svh) } fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'hir>) { @@ -255,7 +261,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { identity_fn ).1; - self.hir_body_nodes.push(def_path_hash); + self.hir_body_nodes.push((def_path_hash, self.current_full_dep_index)); self.current_dep_node_owner = dep_node_owner; self.currently_in_body = false; diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 014e5771656..33debf6aeb0 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -26,6 +26,7 @@ use syntax_pos::Span; use hir::*; use hir::print::Nested; +use hir::svh::Svh; use util::nodemap::{DefIdMap, FxHashMap}; use arena::TypedArena; @@ -241,6 +242,9 @@ pub struct Map<'hir> { /// deref. This is a gratuitous micro-optimization. pub dep_graph: DepGraph, + /// The SVH of the local crate. + pub crate_hash: Svh, + /// NodeIds are sequential integers from 0, so we can be /// super-compact by storing them in a vector. Not everything with /// a NodeId is in the map, but empirically the occupancy is about @@ -1048,7 +1052,7 @@ pub fn map_crate<'hir>(sess: &::session::Session, forest: &'hir mut Forest, definitions: &'hir Definitions) -> Map<'hir> { - let map = { + let (map, crate_hash) = { let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore); let mut collector = NodeCollector::root(&forest.krate, @@ -1087,6 +1091,7 @@ pub fn map_crate<'hir>(sess: &::session::Session, let map = Map { forest, dep_graph: forest.dep_graph.clone(), + crate_hash, map, hir_to_node_id, definitions, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 8875439be6b..5d7a050267f 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -438,7 +438,7 @@ macro_rules! define_maps { use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use ich::Fingerprint; - assert!(Some(tcx.dep_graph.fingerprint_of(dep_node)) == + assert!(Some(tcx.dep_graph.fingerprint_of(dep_node_index)) == tcx.dep_graph.prev_fingerprint_of(dep_node), "Fingerprint for green query instance not loaded \ from cache: {:?}", dep_node); @@ -452,7 +452,7 @@ macro_rules! define_maps { let new_hash: Fingerprint = hasher.finish(); debug!("END verify_ich({:?})", dep_node); - let old_hash = tcx.dep_graph.fingerprint_of(dep_node); + let old_hash = tcx.dep_graph.fingerprint_of(dep_node_index); assert!(new_hash == old_hash, "Found unstable fingerprints \ for {:?}", dep_node); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 220e1e971ac..815f89a408e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -19,6 +19,7 @@ use hir::{map as hir_map, FreevarMap, TraitMap}; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use hir::map::DefPathData; +use hir::svh::Svh; use ich::StableHashingContext; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; @@ -2659,6 +2660,13 @@ fn original_crate_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.crate_name.clone() } +fn crate_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + crate_num: CrateNum) + -> Svh { + assert_eq!(crate_num, LOCAL_CRATE); + tcx.hir.crate_hash +} + pub fn provide(providers: &mut ty::maps::Providers) { context::provide(providers); erase_regions::provide(providers); @@ -2674,6 +2682,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { trait_of_item, crate_disambiguator, original_crate_name, + crate_hash, trait_impls_of: trait_def::trait_impls_of_provider, ..*providers }; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 7c3f903f228..b17503137f5 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -480,7 +480,8 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { fn assert_dirty(&self, item_span: Span, dep_node: DepNode) { debug!("assert_dirty({:?})", dep_node); - let current_fingerprint = self.tcx.dep_graph.fingerprint_of(&dep_node); + let dep_node_index = self.tcx.dep_graph.dep_node_index_of(&dep_node); + let current_fingerprint = self.tcx.dep_graph.fingerprint_of(dep_node_index); let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node); if Some(current_fingerprint) == prev_fingerprint { @@ -494,7 +495,8 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { fn assert_clean(&self, item_span: Span, dep_node: DepNode) { debug!("assert_clean({:?})", dep_node); - let current_fingerprint = self.tcx.dep_graph.fingerprint_of(&dep_node); + let dep_node_index = self.tcx.dep_graph.dep_node_index_of(&dep_node); + let current_fingerprint = self.tcx.dep_graph.fingerprint_of(dep_node_index); let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node); if Some(current_fingerprint) != prev_fingerprint { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 79b3d314e12..5b2ca29ac40 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -43,7 +43,7 @@ use rustc::middle::cstore::{EncodedMetadata}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; use rustc::ty::maps::Providers; -use rustc::dep_graph::{DepNode, DepKind, DepConstructor}; +use rustc::dep_graph::{DepNode, DepConstructor}; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; use rustc::util::common::{time, print_time_passes_entry}; use rustc::session::config::{self, NoDebugInfo}; @@ -709,8 +709,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let crate_hash = tcx.dep_graph - .fingerprint_of(&DepNode::new_no_params(DepKind::Krate)); + let crate_hash = tcx.crate_hash(LOCAL_CRATE); let link_meta = link::build_link_meta(crate_hash); let exported_symbol_node_ids = find_exported_symbols(tcx); diff --git a/src/librustc_trans_utils/link.rs b/src/librustc_trans_utils/link.rs index c1e670cc7ca..643494e411d 100644 --- a/src/librustc_trans_utils/link.rs +++ b/src/librustc_trans_utils/link.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::ich::Fingerprint; use rustc::session::config::{self, OutputFilenames, Input, OutputType}; use rustc::session::Session; use rustc::middle::cstore::{self, LinkMeta}; @@ -50,9 +49,9 @@ fn is_writeable(p: &Path) -> bool { } } -pub fn build_link_meta(crate_hash: Fingerprint) -> LinkMeta { +pub fn build_link_meta(crate_hash: Svh) -> LinkMeta { let r = LinkMeta { - crate_hash: Svh::new(crate_hash.to_smaller_hash()), + crate_hash, }; info!("{:?}", r); return r; diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index 800c3063c02..122914fa40b 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -41,7 +41,7 @@ use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; use rustc::middle::cstore::EncodedMetadata; use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait; -use rustc::dep_graph::{DepGraph, DepNode, DepKind}; +use rustc::dep_graph::DepGraph; use rustc_back::target::Target; use link::{build_link_meta, out_filename}; @@ -197,9 +197,7 @@ impl TransCrate for MetadataOnlyTransCrate { let _ = tcx.native_libraries(LOCAL_CRATE); tcx.sess.abort_if_errors(); - let crate_hash = tcx.dep_graph - .fingerprint_of(&DepNode::new_no_params(DepKind::Krate)); - let link_meta = build_link_meta(crate_hash); + let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE)); let exported_symbols = ::find_exported_symbols(tcx); let metadata = tcx.encode_metadata(&link_meta, &exported_symbols);