]> git.lizzy.rs Git - rust.git/blob - src/librustc_incremental/persist/save.rs
Rollup merge of #39526 - canndrew:uninhabited-while-let-fix, r=arielb1
[rust.git] / src / librustc_incremental / persist / save.rs
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.
4 //
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.
10
11 use rustc::dep_graph::DepNode;
12 use rustc::hir::def_id::DefId;
13 use rustc::hir::svh::Svh;
14 use rustc::session::Session;
15 use rustc::ty::TyCtxt;
16 use rustc_data_structures::fx::FxHashMap;
17 use rustc_data_structures::graph::{NodeIndex, INCOMING};
18 use rustc_serialize::Encodable as RustcEncodable;
19 use rustc_serialize::opaque::Encoder;
20 use std::hash::Hash;
21 use std::io::{self, Cursor, Write};
22 use std::fs::{self, File};
23 use std::path::PathBuf;
24
25 use IncrementalHashesMap;
26 use ich::Fingerprint;
27 use super::data::*;
28 use super::directory::*;
29 use super::hash::*;
30 use super::preds::*;
31 use super::fs::*;
32 use super::dirty_clean;
33 use super::file_format;
34 use super::work_product;
35 use calculate_svh::IchHasher;
36
37 pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
38                                 incremental_hashes_map: &IncrementalHashesMap,
39                                 svh: Svh) {
40     debug!("save_dep_graph()");
41     let _ignore = tcx.dep_graph.in_ignore();
42     let sess = tcx.sess;
43     if sess.opts.incremental.is_none() {
44         return;
45     }
46
47     let mut builder = DefIdDirectoryBuilder::new(tcx);
48     let query = tcx.dep_graph.query();
49
50     if tcx.sess.opts.debugging_opts.incremental_info {
51         println!("incremental: {} nodes in dep-graph", query.graph.len_nodes());
52         println!("incremental: {} edges in dep-graph", query.graph.len_edges());
53     }
54
55     let mut hcx = HashContext::new(tcx, incremental_hashes_map);
56     let preds = Predecessors::new(&query, &mut hcx);
57     let mut current_metadata_hashes = FxHashMap();
58
59     if sess.opts.debugging_opts.incremental_cc ||
60        sess.opts.debugging_opts.query_dep_graph {
61         // IMPORTANT: We are saving the metadata hashes *before* the dep-graph,
62         //            since metadata-encoding might add new entries to the
63         //            DefIdDirectory (which is saved in the dep-graph file).
64         save_in(sess,
65                 metadata_hash_export_path(sess),
66                 |e| encode_metadata_hashes(tcx,
67                                            svh,
68                                            &preds,
69                                            &mut builder,
70                                            &mut current_metadata_hashes,
71                                            e));
72     }
73
74     save_in(sess,
75             dep_graph_path(sess),
76             |e| encode_dep_graph(&preds, &mut builder, e));
77
78     let prev_metadata_hashes = incremental_hashes_map.prev_metadata_hashes.borrow();
79     dirty_clean::check_dirty_clean_metadata(tcx,
80                                             &*prev_metadata_hashes,
81                                             &current_metadata_hashes);
82 }
83
84 pub fn save_work_products(sess: &Session) {
85     if sess.opts.incremental.is_none() {
86         return;
87     }
88
89     debug!("save_work_products()");
90     let _ignore = sess.dep_graph.in_ignore();
91     let path = work_products_path(sess);
92     save_in(sess, path, |e| encode_work_products(sess, e));
93
94     // We also need to clean out old work-products, as not all of them are
95     // deleted during invalidation. Some object files don't change their
96     // content, they are just not needed anymore.
97     let new_work_products = sess.dep_graph.work_products();
98     let previous_work_products = sess.dep_graph.previous_work_products();
99
100     for (id, wp) in previous_work_products.iter() {
101         if !new_work_products.contains_key(id) {
102             work_product::delete_workproduct_files(sess, wp);
103             debug_assert!(wp.saved_files.iter().all(|&(_, ref file_name)| {
104                 !in_incr_comp_dir_sess(sess, file_name).exists()
105             }));
106         }
107     }
108
109     // Check that we did not delete one of the current work-products:
110     debug_assert!({
111         new_work_products.iter()
112                          .flat_map(|(_, wp)| wp.saved_files
113                                                .iter()
114                                                .map(|&(_, ref name)| name))
115                          .map(|name| in_incr_comp_dir_sess(sess, name))
116                          .all(|path| path.exists())
117     });
118 }
119
120 fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
121     where F: FnOnce(&mut Encoder) -> io::Result<()>
122 {
123     debug!("save: storing data in {}", path_buf.display());
124
125     // delete the old dep-graph, if any
126     // Note: It's important that we actually delete the old file and not just
127     // truncate and overwrite it, since it might be a shared hard-link, the
128     // underlying data of which we don't want to modify
129     if path_buf.exists() {
130         match fs::remove_file(&path_buf) {
131             Ok(()) => {
132                 debug!("save: remove old file");
133             }
134             Err(err) => {
135                 sess.err(&format!("unable to delete old dep-graph at `{}`: {}",
136                                   path_buf.display(),
137                                   err));
138                 return;
139             }
140         }
141     }
142
143     // generate the data in a memory buffer
144     let mut wr = Cursor::new(Vec::new());
145     file_format::write_file_header(&mut wr).unwrap();
146     match encode(&mut Encoder::new(&mut wr)) {
147         Ok(()) => {}
148         Err(err) => {
149             sess.err(&format!("could not encode dep-graph to `{}`: {}",
150                               path_buf.display(),
151                               err));
152             return;
153         }
154     }
155
156     // write the data out
157     let data = wr.into_inner();
158     match File::create(&path_buf).and_then(|mut file| file.write_all(&data)) {
159         Ok(_) => {
160             debug!("save: data written to disk successfully");
161         }
162         Err(err) => {
163             sess.err(&format!("failed to write dep-graph to `{}`: {}",
164                               path_buf.display(),
165                               err));
166             return;
167         }
168     }
169 }
170
171 pub fn encode_dep_graph(preds: &Predecessors,
172                         builder: &mut DefIdDirectoryBuilder,
173                         encoder: &mut Encoder)
174                         -> io::Result<()> {
175     // First encode the commandline arguments hash
176     let tcx = builder.tcx();
177     tcx.sess.opts.dep_tracking_hash().encode(encoder)?;
178
179     // Create a flat list of (Input, WorkProduct) edges for
180     // serialization.
181     let mut edges = FxHashMap();
182     for edge in preds.reduced_graph.all_edges() {
183         let source = *preds.reduced_graph.node_data(edge.source());
184         let target = *preds.reduced_graph.node_data(edge.target());
185         match *target {
186             DepNode::MetaData(ref def_id) => {
187                 // Metadata *targets* are always local metadata nodes. We have
188                 // already handled those in `encode_metadata_hashes`.
189                 assert!(def_id.is_local());
190                 continue;
191             }
192             _ => (),
193         }
194         debug!("serialize edge: {:?} -> {:?}", source, target);
195         let source = builder.map(source);
196         let target = builder.map(target);
197         edges.entry(source).or_insert(vec![]).push(target);
198     }
199
200     if tcx.sess.opts.debugging_opts.incremental_dump_hash {
201         for (dep_node, hash) in &preds.hashes {
202             println!("HIR hash for {:?} is {}", dep_node, hash);
203         }
204     }
205
206     // Create the serialized dep-graph.
207     let edges = edges.into_iter()
208                      .map(|(k, v)| SerializedEdgeSet { source: k, targets: v })
209                      .collect();
210     let graph = SerializedDepGraph {
211         edges: edges,
212         hashes: preds.hashes
213             .iter()
214             .map(|(&dep_node, &hash)| {
215                 SerializedHash {
216                     dep_node: builder.map(dep_node),
217                     hash: hash,
218                 }
219             })
220             .collect(),
221     };
222
223     if tcx.sess.opts.debugging_opts.incremental_info {
224         println!("incremental: {} edges in serialized dep-graph", graph.edges.len());
225         println!("incremental: {} hashes in serialized dep-graph", graph.hashes.len());
226     }
227
228     debug!("graph = {:#?}", graph);
229
230     // Encode the directory and then the graph data.
231     builder.directory().encode(encoder)?;
232     graph.encode(encoder)?;
233
234     Ok(())
235 }
236
237 pub fn encode_metadata_hashes(tcx: TyCtxt,
238                               svh: Svh,
239                               preds: &Predecessors,
240                               builder: &mut DefIdDirectoryBuilder,
241                               current_metadata_hashes: &mut FxHashMap<DefId, Fingerprint>,
242                               encoder: &mut Encoder)
243                               -> io::Result<()> {
244     // For each `MetaData(X)` node where `X` is local, accumulate a
245     // hash.  These are the metadata items we export. Downstream
246     // crates will want to see a hash that tells them whether we might
247     // have changed the metadata for a given item since they last
248     // compiled.
249     //
250     // (I initially wrote this with an iterator, but it seemed harder to read.)
251     let mut serialized_hashes = SerializedMetadataHashes {
252         hashes: vec![],
253         index_map: FxHashMap()
254     };
255
256     let mut def_id_hashes = FxHashMap();
257
258     for (index, target) in preds.reduced_graph.all_nodes().iter().enumerate() {
259         let index = NodeIndex(index);
260         let def_id = match *target.data {
261             DepNode::MetaData(def_id) if def_id.is_local() => def_id,
262             _ => continue,
263         };
264
265         let mut def_id_hash = |def_id: DefId| -> u64 {
266             *def_id_hashes.entry(def_id)
267                 .or_insert_with(|| {
268                     let index = builder.add(def_id);
269                     let path = builder.lookup_def_path(index);
270                     path.deterministic_hash(tcx)
271                 })
272         };
273
274         // To create the hash for each item `X`, we don't hash the raw
275         // bytes of the metadata (though in principle we
276         // could). Instead, we walk the predecessors of `MetaData(X)`
277         // from the dep-graph. This corresponds to all the inputs that
278         // were read to construct the metadata. To create the hash for
279         // the metadata, we hash (the hash of) all of those inputs.
280         debug!("save: computing metadata hash for {:?}", def_id);
281
282         // Create a vector containing a pair of (source-id, hash).
283         // The source-id is stored as a `DepNode<u64>`, where the u64
284         // is the det. hash of the def-path. This is convenient
285         // because we can sort this to get a stable ordering across
286         // compilations, even if the def-ids themselves have changed.
287         let mut hashes: Vec<(DepNode<u64>, Fingerprint)> =
288             preds.reduced_graph
289                  .depth_traverse(index, INCOMING)
290                  .map(|index| preds.reduced_graph.node_data(index))
291                  .filter(|dep_node| HashContext::is_hashable(dep_node))
292                  .map(|dep_node| {
293                      let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id)))
294                                                  .unwrap();
295                      let hash = preds.hashes[dep_node];
296                      (hash_dep_node, hash)
297                  })
298                  .collect();
299
300         hashes.sort();
301         let mut state = IchHasher::new();
302         hashes.hash(&mut state);
303         let hash = state.finish();
304
305         debug!("save: metadata hash for {:?} is {}", def_id, hash);
306
307         if tcx.sess.opts.debugging_opts.incremental_dump_hash {
308             println!("metadata hash for {:?} is {}", def_id, hash);
309             for pred_index in preds.reduced_graph.depth_traverse(index, INCOMING) {
310                 let dep_node = preds.reduced_graph.node_data(pred_index);
311                 if HashContext::is_hashable(&dep_node) {
312                     println!("metadata hash for {:?} depends on {:?} with hash {}",
313                              def_id, dep_node, preds.hashes[dep_node]);
314                 }
315             }
316         }
317
318         serialized_hashes.hashes.push(SerializedMetadataHash {
319             def_index: def_id.index,
320             hash: hash,
321         });
322     }
323
324     if tcx.sess.opts.debugging_opts.query_dep_graph {
325         for serialized_hash in &serialized_hashes.hashes {
326             let def_id = DefId::local(serialized_hash.def_index);
327
328             // Store entry in the index_map
329             let def_path_index = builder.add(def_id);
330             serialized_hashes.index_map.insert(def_id.index, def_path_index);
331
332             // Record hash in current_metadata_hashes
333             current_metadata_hashes.insert(def_id, serialized_hash.hash);
334         }
335
336         debug!("save: stored index_map (len={}) for serialized hashes",
337                serialized_hashes.index_map.len());
338     }
339
340     // Encode everything.
341     svh.encode(encoder)?;
342     serialized_hashes.encode(encoder)?;
343
344     Ok(())
345 }
346
347 pub fn encode_work_products(sess: &Session, encoder: &mut Encoder) -> io::Result<()> {
348     let work_products: Vec<_> = sess.dep_graph
349         .work_products()
350         .iter()
351         .map(|(id, work_product)| {
352             SerializedWorkProduct {
353                 id: id.clone(),
354                 work_product: work_product.clone(),
355             }
356         })
357         .collect();
358
359     work_products.encode(encoder)
360 }