]> git.lizzy.rs Git - rust.git/blob - src/librustc_incremental/calculate_svh/mod.rs
Use 128 instead of 64 bits for DefPath hashes
[rust.git] / src / librustc_incremental / calculate_svh / mod.rs
1 // Copyright 2012-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 //! Calculation of the (misnamed) "strict version hash" for crates and
12 //! items. This hash is used to tell when the HIR changed in such a
13 //! way that results from previous compilations may no longer be
14 //! applicable and hence must be recomputed. It should probably be
15 //! renamed to the ICH (incremental compilation hash).
16 //!
17 //! The hashes for all items are computed once at the beginning of
18 //! compilation and stored into a map. In addition, a hash is computed
19 //! of the **entire crate**.
20 //!
21 //! Storing the hashes in a map avoids the need to compute them twice
22 //! (once when loading prior incremental results and once when
23 //! saving), but it is also important for correctness: at least as of
24 //! the time of this writing, the typeck passes rewrites entries in
25 //! the dep-map in-place to accommodate UFCS resolutions. Since name
26 //! resolution is part of the hash, the result is that hashes computed
27 //! at the end of compilation would be different from those computed
28 //! at the beginning.
29
30 use std::cell::RefCell;
31 use std::hash::Hash;
32 use std::sync::Arc;
33 use rustc::dep_graph::DepNode;
34 use rustc::hir;
35 use rustc::hir::def_id::{LOCAL_CRATE, CRATE_DEF_INDEX, DefId};
36 use rustc::hir::itemlikevisit::ItemLikeVisitor;
37 use rustc::ich::{Fingerprint, StableHashingContext};
38 use rustc::ty::TyCtxt;
39 use rustc::util::common::record_time;
40 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
41 use rustc_data_structures::fx::FxHashMap;
42 use rustc_data_structures::accumulate_vec::AccumulateVec;
43
44 pub type IchHasher = StableHasher<Fingerprint>;
45
46 pub struct IncrementalHashesMap {
47     hashes: FxHashMap<DepNode<DefId>, Fingerprint>,
48
49     // These are the metadata hashes for the current crate as they were stored
50     // during the last compilation session. They are only loaded if
51     // -Z query-dep-graph was specified and are needed for auto-tests using
52     // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
53     // check whether some metadata hash has changed in between two revisions.
54     pub prev_metadata_hashes: RefCell<FxHashMap<DefId, Fingerprint>>,
55 }
56
57 impl IncrementalHashesMap {
58     pub fn new() -> IncrementalHashesMap {
59         IncrementalHashesMap {
60             hashes: FxHashMap(),
61             prev_metadata_hashes: RefCell::new(FxHashMap()),
62         }
63     }
64
65     pub fn get(&self, k: &DepNode<DefId>) -> Option<&Fingerprint> {
66         self.hashes.get(k)
67     }
68
69     pub fn insert(&mut self, k: DepNode<DefId>, v: Fingerprint) -> Option<Fingerprint> {
70         self.hashes.insert(k, v)
71     }
72
73     pub fn iter<'a>(&'a self)
74                     -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, Fingerprint> {
75         self.hashes.iter()
76     }
77
78     pub fn len(&self) -> usize {
79         self.hashes.len()
80     }
81 }
82
83 impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
84     type Output = Fingerprint;
85
86     fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
87         match self.hashes.get(index) {
88             Some(fingerprint) => fingerprint,
89             None => {
90                 bug!("Could not find ICH for {:?}", index);
91             }
92         }
93     }
94 }
95
96 struct ComputeItemHashesVisitor<'a, 'tcx: 'a> {
97     hcx: StableHashingContext<'a, 'tcx>,
98     hashes: IncrementalHashesMap,
99 }
100
101 impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
102     fn compute_and_store_ich_for_item_like<T>(&mut self,
103                                               dep_node: DepNode<DefId>,
104                                               hash_bodies: bool,
105                                               item_like: T)
106         where T: HashStable<StableHashingContext<'a, 'tcx>>
107     {
108         if !hash_bodies && !self.hcx.tcx().sess.opts.build_dep_graph() {
109             // If we just need the hashes in order to compute the SVH, we don't
110             // need have two hashes per item. Just the one containing also the
111             // item's body is sufficient.
112             return
113         }
114
115         let mut hasher = IchHasher::new();
116         self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| {
117             item_like.hash_stable(hcx, &mut hasher);
118         });
119
120         let bytes_hashed = hasher.bytes_hashed();
121         let item_hash = hasher.finish();
122         debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
123         self.hashes.insert(dep_node, item_hash);
124
125         let tcx = self.hcx.tcx();
126         let bytes_hashed =
127             tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
128             bytes_hashed;
129         tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
130     }
131
132     fn compute_crate_hash(&mut self) {
133         let tcx = self.hcx.tcx();
134         let krate = tcx.hir.krate();
135
136         let mut crate_state = IchHasher::new();
137
138         let crate_disambiguator = tcx.sess.local_crate_disambiguator();
139         "crate_disambiguator".hash(&mut crate_state);
140         crate_disambiguator.as_str().len().hash(&mut crate_state);
141         crate_disambiguator.as_str().hash(&mut crate_state);
142
143         // add each item (in some deterministic order) to the overall
144         // crate hash.
145         {
146             let hcx = &mut self.hcx;
147             let mut item_hashes: Vec<_> =
148                 self.hashes.iter()
149                            .filter_map(|(item_dep_node, &item_hash)| {
150                                 // This `match` determines what kinds of nodes
151                                 // go into the SVH:
152                                 match *item_dep_node {
153                                     DepNode::Hir(_) |
154                                     DepNode::HirBody(_) => {
155                                         // We want to incoporate these into the
156                                         // SVH.
157                                     }
158                                     DepNode::FileMap(..) => {
159                                         // These don't make a semantic
160                                         // difference, filter them out.
161                                         return None
162                                     }
163                                     DepNode::AllLocalTraitImpls => {
164                                         // These are already covered by hashing
165                                         // the HIR.
166                                         return None
167                                     }
168                                     ref other => {
169                                         bug!("Found unexpected DepNode during \
170                                               SVH computation: {:?}",
171                                              other)
172                                     }
173                                 }
174
175                                 // Convert from a DepNode<DefId> to a
176                                 // DepNode<u64> where the u64 is the hash of
177                                 // the def-id's def-path:
178                                 let item_dep_node =
179                                     item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did)))
180                                                  .unwrap();
181                                 Some((item_dep_node, item_hash))
182                            })
183                            .collect();
184             item_hashes.sort_unstable(); // avoid artificial dependencies on item ordering
185             item_hashes.hash(&mut crate_state);
186         }
187
188         krate.attrs.hash_stable(&mut self.hcx, &mut crate_state);
189
190         let crate_hash = crate_state.finish();
191         self.hashes.insert(DepNode::Krate, crate_hash);
192         debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
193     }
194
195     fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) {
196         let hir::Crate {
197             ref module,
198             // Crate attributes are not copied over to the root `Mod`, so hash
199             // them explicitly here.
200             ref attrs,
201             span,
202
203             // These fields are handled separately:
204             exported_macros: _,
205             items: _,
206             trait_items: _,
207             impl_items: _,
208             bodies: _,
209             trait_impls: _,
210             trait_default_impl: _,
211             body_ids: _,
212         } = *krate;
213
214         let def_id = DefId::local(CRATE_DEF_INDEX);
215         self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id),
216                                                  false,
217                                                  (module, (span, attrs)));
218         self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id),
219                                                  true,
220                                                  (module, (span, attrs)));
221     }
222
223     fn compute_and_store_ich_for_trait_impls(&mut self, krate: &'tcx hir::Crate)
224     {
225         let tcx = self.hcx.tcx();
226
227         let mut impls: Vec<(Fingerprint, Fingerprint)> = krate
228             .trait_impls
229             .iter()
230             .map(|(&trait_id, impls)| {
231                 let trait_id = tcx.def_path_hash(trait_id);
232                 let mut impls: AccumulateVec<[_; 32]> = impls
233                     .iter()
234                     .map(|&node_id| {
235                         let def_id = tcx.hir.local_def_id(node_id);
236                         tcx.def_path_hash(def_id)
237                     })
238                     .collect();
239
240                 impls.sort_unstable();
241                 let mut hasher = StableHasher::new();
242                 impls.hash_stable(&mut self.hcx, &mut hasher);
243                 (trait_id, hasher.finish())
244             })
245             .collect();
246
247         impls.sort_unstable();
248
249         let mut default_impls: AccumulateVec<[_; 32]> = krate
250             .trait_default_impl
251             .iter()
252             .map(|(&trait_def_id, &impl_node_id)| {
253                 let impl_def_id = tcx.hir.local_def_id(impl_node_id);
254                 (tcx.def_path_hash(trait_def_id), tcx.def_path_hash(impl_def_id))
255             })
256             .collect();
257
258         default_impls.sort_unstable();
259
260         let mut hasher = StableHasher::new();
261         impls.hash_stable(&mut self.hcx, &mut hasher);
262
263         self.hashes.insert(DepNode::AllLocalTraitImpls, hasher.finish());
264     }
265 }
266
267 impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
268     fn visit_item(&mut self, item: &'tcx hir::Item) {
269         let def_id = self.hcx.tcx().hir.local_def_id(item.id);
270         self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
271         self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
272     }
273
274     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
275         let def_id = self.hcx.tcx().hir.local_def_id(item.id);
276         self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
277         self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
278     }
279
280     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
281         let def_id = self.hcx.tcx().hir.local_def_id(item.id);
282         self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
283         self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
284     }
285 }
286
287
288
289 pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
290                                                     -> IncrementalHashesMap {
291     let _ignore = tcx.dep_graph.in_ignore();
292     let krate = tcx.hir.krate();
293
294     let mut visitor = ComputeItemHashesVisitor {
295         hcx: StableHashingContext::new(tcx),
296         hashes: IncrementalHashesMap::new(),
297     };
298
299     record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
300         visitor.hash_crate_root_module(krate);
301         krate.visit_all_item_likes(&mut visitor);
302
303         for macro_def in krate.exported_macros.iter() {
304             let def_id = tcx.hir.local_def_id(macro_def.id);
305             visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def);
306             visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def);
307         }
308
309         for filemap in tcx.sess
310                           .codemap()
311                           .files_untracked()
312                           .iter()
313                           .filter(|fm| !fm.is_imported()) {
314             assert_eq!(LOCAL_CRATE.as_u32(), filemap.crate_of_origin);
315             let def_id = DefId {
316                 krate: LOCAL_CRATE,
317                 index: CRATE_DEF_INDEX,
318             };
319             let name = Arc::new(filemap.name.clone());
320             let dep_node = DepNode::FileMap(def_id, name);
321             let mut hasher = IchHasher::new();
322             filemap.hash_stable(&mut visitor.hcx, &mut hasher);
323             let fingerprint = hasher.finish();
324             visitor.hashes.insert(dep_node, fingerprint);
325         }
326
327         visitor.compute_and_store_ich_for_trait_impls(krate);
328     });
329
330     tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
331
332     record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
333     visitor.hashes
334 }