diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 336197d7d6d7d..682a7051a1e95 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -17,11 +17,20 @@ use rustc::ich::Fingerprint; use rustc::middle::cstore::EncodedMetadataHash; use std::sync::Arc; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; /// Data for use when recompiling the **current crate**. #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedDepGraph { - pub edges: Vec, + /// The set of all DepNodes in the graph + pub nodes: IndexVec>, + /// For each DepNode, stores the list of edges originating from that + /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, + /// which holds the actual DepNodeIndices of the target nodes. + pub edge_list_indices: Vec<(u32, u32)>, + /// A flattened list of all edge targets in the graph. Edge sources are + /// implicit in edge_list_indices. + pub edge_list_data: Vec, /// These are output nodes that have no incoming edges. We track /// these separately so that when we reload all edges, we don't @@ -50,12 +59,30 @@ pub struct SerializedDepGraph { pub hashes: Vec, } -/// Represents a set of "reduced" dependency edge. We group the -/// outgoing edges from a single source together. -#[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct SerializedEdgeSet { - pub source: DepNode, - pub targets: Vec> +/// The index of a DepNode in the SerializedDepGraph::nodes array. +#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, + RustcEncodable, RustcDecodable)] +pub struct DepNodeIndex(pub u32); + +impl DepNodeIndex { + #[inline] + pub fn new(idx: usize) -> DepNodeIndex { + assert!(idx <= ::std::u32::MAX as usize); + DepNodeIndex(idx as u32) + } +} + +impl Idx for DepNodeIndex { + #[inline] + fn new(idx: usize) -> Self { + assert!(idx <= ::std::u32::MAX as usize); + DepNodeIndex(idx as u32) + } + + #[inline] + fn index(self) -> usize { + self.0 as usize + } } #[derive(Debug, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index d383f80d5c2da..b30a1f4d3254f 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -20,6 +20,7 @@ use rustc::ty::TyCtxt; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_serialize::Decodable as RustcDecodable; use rustc_serialize::opaque::Decoder; +use std::default::Default; use std::path::{Path}; use std::sync::Arc; @@ -161,10 +162,23 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let serialized_dep_graph = SerializedDepGraph::decode(&mut dep_graph_decoder)?; - let edge_map: FxHashMap<_, _> = serialized_dep_graph.edges - .into_iter() - .map(|s| (s.source, s.targets)) - .collect(); + let edge_map: FxHashMap, Vec>> = { + let capacity = serialized_dep_graph.edge_list_data.len(); + let mut edge_map = FxHashMap::with_capacity_and_hasher(capacity, Default::default()); + + for (node_index, source) in serialized_dep_graph.nodes.iter().enumerate() { + let (start, end) = serialized_dep_graph.edge_list_indices[node_index]; + let targets = + (&serialized_dep_graph.edge_list_data[start as usize .. end as usize]) + .into_iter() + .map(|&node_index| serialized_dep_graph.nodes[node_index].clone()) + .collect(); + + edge_map.insert(source.clone(), targets); + } + + edge_map + }; // Compute the set of nodes from the old graph where some input // has changed or been removed. These are "raw" source nodes, diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 28ac5a0fdf562..6d717d6f409d5 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -11,11 +11,14 @@ use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; +use rustc::hir::map::DefPathHash; use rustc::ich::Fingerprint; use rustc::middle::cstore::EncodedMetadataHashes; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::graph; +use rustc_data_structures::indexed_vec::IndexVec; use rustc_serialize::Encodable as RustcEncodable; use rustc_serialize::opaque::Encoder; use std::io::{self, Cursor, Write}; @@ -175,65 +178,73 @@ pub fn encode_dep_graph(tcx: TyCtxt, dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))).unwrap() }; - // Create a flat list of (Input, WorkProduct) edges for - // serialization. - let mut edges = FxHashMap(); - for edge in preds.reduced_graph.all_edges() { - let source = *preds.reduced_graph.node_data(edge.source()); - let target = *preds.reduced_graph.node_data(edge.target()); - match *target { - DepNode::MetaData(ref def_id) => { - // Metadata *targets* are always local metadata nodes. We have - // already handled those in `encode_metadata_hashes`. - assert!(def_id.is_local()); - continue; - } - _ => (), - } - debug!("serialize edge: {:?} -> {:?}", source, target); - let source = to_hash_based_node(source); - let target = to_hash_based_node(target); - edges.entry(source).or_insert(vec![]).push(target); - } + // NB: We rely on this Vec being indexable by reduced_graph's NodeIndex. + let nodes: IndexVec> = preds + .reduced_graph + .all_nodes() + .iter() + .map(|node| to_hash_based_node(node.data)) + .collect(); - if tcx.sess.opts.debugging_opts.incremental_dump_hash { - for (dep_node, hash) in &preds.hashes { - println!("HIR hash for {:?} is {}", dep_node, hash); + let mut edge_list_indices = Vec::with_capacity(nodes.len()); + let mut edge_list_data = Vec::with_capacity(preds.reduced_graph.len_edges()); + + for node_index in 0 .. nodes.len() { + let start = edge_list_data.len() as u32; + + for target in preds.reduced_graph.successor_nodes(graph::NodeIndex(node_index)) { + edge_list_data.push(DepNodeIndex::new(target.node_id())); } + + let end = edge_list_data.len() as u32; + debug_assert_eq!(node_index, edge_list_indices.len()); + edge_list_indices.push((start, end)); } - // Create the serialized dep-graph. - let bootstrap_outputs = preds.bootstrap_outputs - .iter() - .map(|n| to_hash_based_node(n)) - .collect(); - let edges = edges.into_iter() - .map(|(k, v)| SerializedEdgeSet { source: k, targets: v }) - .collect(); + // Let's make we had no overflow there. + assert!(edge_list_data.len() <= ::std::u32::MAX as usize); + // Check that we have a consistent number of edges. + assert_eq!(edge_list_data.len(), preds.reduced_graph.len_edges()); + + let bootstrap_outputs = preds + .bootstrap_outputs + .iter() + .map(|n| to_hash_based_node(n)) + .collect(); + + let hashes = preds + .hashes + .iter() + .map(|(&dep_node, &hash)| { + SerializedHash { + dep_node: to_hash_based_node(dep_node), + hash: hash, + } + }) + .collect(); + let graph = SerializedDepGraph { + nodes, + edge_list_indices, + edge_list_data, bootstrap_outputs, - edges, - hashes: preds.hashes - .iter() - .map(|(&dep_node, &hash)| { - SerializedHash { - dep_node: to_hash_based_node(dep_node), - hash: hash, - } - }) - .collect(), + hashes, }; + // Encode the graph data. + graph.encode(encoder)?; + if tcx.sess.opts.debugging_opts.incremental_info { - println!("incremental: {} nodes in reduced dep-graph", preds.reduced_graph.len_nodes()); - println!("incremental: {} edges in serialized dep-graph", graph.edges.len()); + println!("incremental: {} nodes in reduced dep-graph", graph.nodes.len()); + println!("incremental: {} edges in serialized dep-graph", graph.edge_list_data.len()); println!("incremental: {} hashes in serialized dep-graph", graph.hashes.len()); } - debug!("graph = {:#?}", graph); - - // Encode the graph data. - graph.encode(encoder)?; + if tcx.sess.opts.debugging_opts.incremental_dump_hash { + for (dep_node, hash) in &preds.hashes { + println!("ICH for {:?} is {}", dep_node, hash); + } + } Ok(()) }