1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use rbml::opaque::Encoder;
12 use rustc::dep_graph::DepNode;
13 use rustc::middle::cstore::LOCAL_CRATE;
14 use rustc::session::Session;
15 use rustc::ty::TyCtxt;
16 use rustc_serialize::{Encodable as RustcEncodable};
17 use std::hash::{Hasher, SipHasher};
18 use std::io::{self, Cursor, Write};
19 use std::fs::{self, File};
20 use std::path::PathBuf;
23 use super::directory::*;
27 pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
28 debug!("save_dep_graph()");
29 let _ignore = tcx.dep_graph.in_ignore();
31 let mut hcx = HashContext::new(tcx);
32 save_in(sess, dep_graph_path(tcx), |e| encode_dep_graph(&mut hcx, e));
33 save_in(sess, metadata_hash_path(tcx, LOCAL_CRATE), |e| encode_metadata_hashes(&mut hcx, e));
36 pub fn save_work_products(sess: &Session, local_crate_name: &str) {
37 debug!("save_work_products()");
38 let _ignore = sess.dep_graph.in_ignore();
39 let path = sess_work_products_path(sess, local_crate_name);
40 save_in(sess, path, |e| encode_work_products(sess, e));
43 fn save_in<F>(sess: &Session,
44 opt_path_buf: Option<PathBuf>,
46 where F: FnOnce(&mut Encoder) -> io::Result<()>
48 let path_buf = match opt_path_buf {
53 // FIXME(#32754) lock file?
55 // delete the old dep-graph, if any
56 if path_buf.exists() {
57 match fs::remove_file(&path_buf) {
61 &format!("unable to delete old dep-graph at `{}`: {}",
62 path_buf.display(), err));
68 // generate the data in a memory buffer
69 let mut wr = Cursor::new(Vec::new());
70 match encode(&mut Encoder::new(&mut wr)) {
74 &format!("could not encode dep-graph to `{}`: {}",
75 path_buf.display(), err));
81 let data = wr.into_inner();
83 File::create(&path_buf)
84 .and_then(|mut file| file.write_all(&data))
89 &format!("failed to write dep-graph to `{}`: {}",
90 path_buf.display(), err));
96 pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
97 encoder: &mut Encoder)
101 let query = tcx.dep_graph.query();
103 let mut builder = DefIdDirectoryBuilder::new(tcx);
105 // Create hashes for inputs.
109 .filter_map(|dep_node| {
112 let node = builder.map(dep_node);
113 SerializedHash { node: node, hash: hash }
118 // Create the serialized dep-graph.
119 let graph = SerializedDepGraph {
120 nodes: query.nodes().into_iter()
121 .map(|node| builder.map(node))
123 edges: query.edges().into_iter()
124 .map(|(source_node, target_node)| {
125 let source = builder.map(source_node);
126 let target = builder.map(target_node);
133 debug!("graph = {:#?}", graph);
135 // Encode the directory and then the graph data.
136 let directory = builder.into_directory();
137 try!(directory.encode(encoder));
138 try!(graph.encode(encoder));
143 pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
144 encoder: &mut Encoder)
148 let query = tcx.dep_graph.query();
150 let serialized_hashes = {
151 // Identify the `MetaData(X)` nodes where `X` is local. These are
152 // the metadata items we export. Downstream crates will want to
153 // see a hash that tells them whether we might have changed the
154 // metadata for a given item since they last compiled.
155 let meta_data_def_ids =
158 .filter_map(|dep_node| match *dep_node {
159 DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id),
163 // To create the hash for each item `X`, we don't hash the raw
164 // bytes of the metadata (though in principle we
165 // could). Instead, we walk the predecessors of `MetaData(X)`
166 // from the dep-graph. This corresponds to all the inputs that
167 // were read to construct the metadata. To create the hash for
168 // the metadata, we hash (the hash of) all of those inputs.
172 assert!(def_id.is_local());
173 let dep_node = DepNode::MetaData(def_id);
174 let mut state = SipHasher::new();
175 debug!("save: computing metadata hash for {:?}", dep_node);
176 for node in query.transitive_predecessors(&dep_node) {
177 if let Some(hash) = hcx.hash(&node) {
178 debug!("save: predecessor {:?} has hash {}", node, hash);
179 state.write_u64(hash.to_le());
181 debug!("save: predecessor {:?} cannot be hashed", node);
184 let hash = state.finish();
185 debug!("save: metadata hash for {:?} is {}", dep_node, hash);
186 SerializedMetadataHash {
187 def_index: def_id.index,
192 // Collect these up into a vector.
193 SerializedMetadataHashes {
194 hashes: hashes.collect()
198 // Encode everything.
199 try!(serialized_hashes.encode(encoder));
204 pub fn encode_work_products(sess: &Session,
205 encoder: &mut Encoder)
208 let work_products: Vec<_> =
209 sess.dep_graph.work_products()
211 .map(|(id, work_product)| {
212 SerializedWorkProduct {
214 work_product: work_product.clone(),
219 work_products.encode(encoder)