]> git.lizzy.rs Git - rust.git/blob - src/librustc_incremental/calculate_svh/mod.rs
Rollup merge of #41135 - japaric:unstable-docs, r=steveklabnik
[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 rustc::dep_graph::DepNode;
33 use rustc::hir;
34 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
35 use rustc::hir::itemlikevisit::ItemLikeVisitor;
36 use rustc::ich::{Fingerprint, StableHashingContext};
37 use rustc::ty::TyCtxt;
38 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
39 use rustc_data_structures::fx::FxHashMap;
40 use rustc::util::common::record_time;
41
42 pub type IchHasher = StableHasher<Fingerprint>;
43
44 pub struct IncrementalHashesMap {
45     hashes: FxHashMap<DepNode<DefId>, Fingerprint>,
46
47     // These are the metadata hashes for the current crate as they were stored
48     // during the last compilation session. They are only loaded if
49     // -Z query-dep-graph was specified and are needed for auto-tests using
50     // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
51     // check whether some metadata hash has changed in between two revisions.
52     pub prev_metadata_hashes: RefCell<FxHashMap<DefId, Fingerprint>>,
53 }
54
55 impl IncrementalHashesMap {
56     pub fn new() -> IncrementalHashesMap {
57         IncrementalHashesMap {
58             hashes: FxHashMap(),
59             prev_metadata_hashes: RefCell::new(FxHashMap()),
60         }
61     }
62
63     pub fn insert(&mut self, k: DepNode<DefId>, v: Fingerprint) -> Option<Fingerprint> {
64         self.hashes.insert(k, v)
65     }
66
67     pub fn iter<'a>(&'a self)
68                     -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, Fingerprint> {
69         self.hashes.iter()
70     }
71
72     pub fn len(&self) -> usize {
73         self.hashes.len()
74     }
75 }
76
77 impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
78     type Output = Fingerprint;
79
80     fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
81         match self.hashes.get(index) {
82             Some(fingerprint) => fingerprint,
83             None => {
84                 bug!("Could not find ICH for {:?}", index);
85             }
86         }
87     }
88 }
89
90 struct ComputeItemHashesVisitor<'a, 'tcx: 'a> {
91     hcx: StableHashingContext<'a, 'tcx>,
92     hashes: IncrementalHashesMap,
93 }
94
95 impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
96     fn compute_and_store_ich_for_item_like<T>(&mut self,
97                                               dep_node: DepNode<DefId>,
98                                               hash_bodies: bool,
99                                               item_like: T)
100         where T: HashStable<StableHashingContext<'a, 'tcx>>
101     {
102         if !hash_bodies && !self.hcx.tcx().sess.opts.build_dep_graph() {
103             // If we just need the hashes in order to compute the SVH, we don't
104             // need have two hashes per item. Just the one containing also the
105             // item's body is sufficient.
106             return
107         }
108
109         let mut hasher = IchHasher::new();
110         self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| {
111             item_like.hash_stable(hcx, &mut hasher);
112         });
113
114         let bytes_hashed = hasher.bytes_hashed();
115         let item_hash = hasher.finish();
116         debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
117         self.hashes.insert(dep_node, item_hash);
118
119         let tcx = self.hcx.tcx();
120         let bytes_hashed =
121             tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
122             bytes_hashed;
123         tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
124     }
125
126     fn compute_crate_hash(&mut self) {
127         let tcx = self.hcx.tcx();
128         let krate = tcx.hir.krate();
129
130         let mut crate_state = IchHasher::new();
131
132         let crate_disambiguator = tcx.sess.local_crate_disambiguator();
133         "crate_disambiguator".hash(&mut crate_state);
134         crate_disambiguator.as_str().len().hash(&mut crate_state);
135         crate_disambiguator.as_str().hash(&mut crate_state);
136
137         // add each item (in some deterministic order) to the overall
138         // crate hash.
139         {
140             let hcx = &mut self.hcx;
141             let mut item_hashes: Vec<_> =
142                 self.hashes.iter()
143                            .map(|(item_dep_node, &item_hash)| {
144                                // convert from a DepNode<DefId> tp a
145                                // DepNode<u64> where the u64 is the
146                                // hash of the def-id's def-path:
147                                let item_dep_node =
148                                    item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did)))
149                                                 .unwrap();
150                                (item_dep_node, item_hash)
151                            })
152                            .collect();
153             item_hashes.sort_unstable(); // avoid artificial dependencies on item ordering
154             item_hashes.hash(&mut crate_state);
155         }
156
157         krate.attrs.hash_stable(&mut self.hcx, &mut crate_state);
158
159         let crate_hash = crate_state.finish();
160         self.hashes.insert(DepNode::Krate, crate_hash);
161         debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
162     }
163
164     fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) {
165         let hir::Crate {
166             ref module,
167             // Crate attributes are not copied over to the root `Mod`, so hash
168             // them explicitly here.
169             ref attrs,
170             span,
171
172             // These fields are handled separately:
173             exported_macros: _,
174             items: _,
175             trait_items: _,
176             impl_items: _,
177             bodies: _,
178             trait_impls: _,
179             trait_default_impl: _,
180             body_ids: _,
181         } = *krate;
182
183         let def_id = DefId::local(CRATE_DEF_INDEX);
184         self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id),
185                                                  false,
186                                                  (module, (span, attrs)));
187         self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id),
188                                                  true,
189                                                  (module, (span, attrs)));
190     }
191 }
192
193 impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
194     fn visit_item(&mut self, item: &'tcx hir::Item) {
195         let def_id = self.hcx.tcx().hir.local_def_id(item.id);
196         self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
197         self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
198     }
199
200     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
201         let def_id = self.hcx.tcx().hir.local_def_id(item.id);
202         self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
203         self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
204     }
205
206     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
207         let def_id = self.hcx.tcx().hir.local_def_id(item.id);
208         self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
209         self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
210     }
211 }
212
213 pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
214                                                     -> IncrementalHashesMap {
215     let _ignore = tcx.dep_graph.in_ignore();
216     let krate = tcx.hir.krate();
217
218     let mut visitor = ComputeItemHashesVisitor {
219         hcx: StableHashingContext::new(tcx),
220         hashes: IncrementalHashesMap::new(),
221     };
222
223     record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
224         visitor.hash_crate_root_module(krate);
225         krate.visit_all_item_likes(&mut visitor);
226
227         for macro_def in krate.exported_macros.iter() {
228             let def_id = tcx.hir.local_def_id(macro_def.id);
229             visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def);
230             visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def);
231         }
232     });
233
234     tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
235
236     record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
237     visitor.hashes
238 }