]> git.lizzy.rs Git - rust.git/blob - src/librustc_incremental/calculate_svh/mod.rs
ICH: Don't store hashes for individual foreign items.
[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 syntax::ast;
31 use std::cell::RefCell;
32 use std::hash::Hash;
33 use rustc::dep_graph::DepNode;
34 use rustc::hir;
35 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
36 use rustc::hir::intravisit as visit;
37 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
38 use rustc::ty::TyCtxt;
39 use rustc_data_structures::stable_hasher::StableHasher;
40 use ich::Fingerprint;
41 use rustc_data_structures::fx::FxHashMap;
42 use rustc::util::common::record_time;
43 use rustc::session::config::DebugInfoLevel::NoDebugInfo;
44
45 use self::def_path_hash::DefPathHashes;
46 use self::svh_visitor::StrictVersionHashVisitor;
47 use self::caching_codemap_view::CachingCodemapView;
48
49 mod def_path_hash;
50 mod svh_visitor;
51 mod caching_codemap_view;
52
53 pub type IchHasher = StableHasher<Fingerprint>;
54
55 pub struct IncrementalHashesMap {
56     hashes: FxHashMap<DepNode<DefId>, Fingerprint>,
57
58     // These are the metadata hashes for the current crate as they were stored
59     // during the last compilation session. They are only loaded if
60     // -Z query-dep-graph was specified and are needed for auto-tests using
61     // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
62     // check whether some metadata hash has changed in between two revisions.
63     pub prev_metadata_hashes: RefCell<FxHashMap<DefId, Fingerprint>>,
64 }
65
66 impl IncrementalHashesMap {
67     pub fn new() -> IncrementalHashesMap {
68         IncrementalHashesMap {
69             hashes: FxHashMap(),
70             prev_metadata_hashes: RefCell::new(FxHashMap()),
71         }
72     }
73
74     pub fn insert(&mut self, k: DepNode<DefId>, v: Fingerprint) -> Option<Fingerprint> {
75         self.hashes.insert(k, v)
76     }
77
78     pub fn iter<'a>(&'a self)
79                     -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, Fingerprint> {
80         self.hashes.iter()
81     }
82
83     pub fn len(&self) -> usize {
84         self.hashes.len()
85     }
86 }
87
88 impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
89     type Output = Fingerprint;
90
91     fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
92         match self.hashes.get(index) {
93             Some(fingerprint) => fingerprint,
94             None => {
95                 bug!("Could not find ICH for {:?}", index);
96             }
97         }
98     }
99 }
100
101
102 pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
103                                                     -> IncrementalHashesMap {
104     let _ignore = tcx.dep_graph.in_ignore();
105     let krate = tcx.map.krate();
106     let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo;
107     let mut visitor = HashItemsVisitor {
108         tcx: tcx,
109         hashes: IncrementalHashesMap::new(),
110         def_path_hashes: DefPathHashes::new(tcx),
111         codemap: CachingCodemapView::new(tcx),
112         hash_spans: hash_spans,
113     };
114     record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
115         visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| {
116             v.hash_crate_root_module(krate);
117         });
118         krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
119
120         for macro_def in krate.exported_macros.iter() {
121             visitor.calculate_node_id(macro_def.id,
122                                       |v| v.visit_macro_def(macro_def));
123         }
124     });
125
126     tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
127
128     record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
129     visitor.hashes
130 }
131
132 struct HashItemsVisitor<'a, 'tcx: 'a> {
133     tcx: TyCtxt<'a, 'tcx, 'tcx>,
134     def_path_hashes: DefPathHashes<'a, 'tcx>,
135     codemap: CachingCodemapView<'tcx>,
136     hashes: IncrementalHashesMap,
137     hash_spans: bool,
138 }
139
140 impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
141     fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W)
142         where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
143     {
144         let def_id = self.tcx.map.local_def_id(id);
145         self.calculate_def_id(def_id, walk_op)
146     }
147
148     fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
149         where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
150     {
151         assert!(def_id.is_local());
152         debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
153         self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op);
154         self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op);
155     }
156
157     fn calculate_def_hash<W>(&mut self,
158                              dep_node: DepNode<DefId>,
159                              hash_bodies: bool,
160                              walk_op: &mut W)
161         where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
162     {
163         let mut state = IchHasher::new();
164         walk_op(&mut StrictVersionHashVisitor::new(&mut state,
165                                                    self.tcx,
166                                                    &mut self.def_path_hashes,
167                                                    &mut self.codemap,
168                                                    self.hash_spans,
169                                                    hash_bodies));
170         let bytes_hashed = state.bytes_hashed();
171         let item_hash = state.finish();
172         debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
173         self.hashes.insert(dep_node, item_hash);
174
175         let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
176             bytes_hashed;
177         self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
178     }
179
180     fn compute_crate_hash(&mut self) {
181         let krate = self.tcx.map.krate();
182
183         let mut crate_state = IchHasher::new();
184
185         let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
186         "crate_disambiguator".hash(&mut crate_state);
187         crate_disambiguator.as_str().len().hash(&mut crate_state);
188         crate_disambiguator.as_str().hash(&mut crate_state);
189
190         // add each item (in some deterministic order) to the overall
191         // crate hash.
192         {
193             let def_path_hashes = &mut self.def_path_hashes;
194             let mut item_hashes: Vec<_> =
195                 self.hashes.iter()
196                            .map(|(item_dep_node, &item_hash)| {
197                                // convert from a DepNode<DefId> tp a
198                                // DepNode<u64> where the u64 is the
199                                // hash of the def-id's def-path:
200                                let item_dep_node =
201                                    item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did)))
202                                                 .unwrap();
203                                (item_dep_node, item_hash)
204                            })
205                            .collect();
206             item_hashes.sort(); // avoid artificial dependencies on item ordering
207             item_hashes.hash(&mut crate_state);
208         }
209
210         {
211             let mut visitor = StrictVersionHashVisitor::new(&mut crate_state,
212                                                             self.tcx,
213                                                             &mut self.def_path_hashes,
214                                                             &mut self.codemap,
215                                                             self.hash_spans,
216                                                             false);
217             visitor.hash_attributes(&krate.attrs);
218         }
219
220         let crate_hash = crate_state.finish();
221         self.hashes.insert(DepNode::Krate, crate_hash);
222         debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
223     }
224 }
225
226
227 impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
228     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
229         NestedVisitorMap::None
230     }
231
232     fn visit_item(&mut self, item: &'tcx hir::Item) {
233         self.calculate_node_id(item.id, |v| v.visit_item(item));
234         visit::walk_item(self, item);
235     }
236
237     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
238         self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
239         visit::walk_impl_item(self, impl_item);
240     }
241 }