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.
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 //! 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).
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**.
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
30 use std::cell::RefCell;
32 use rustc::dep_graph::DepNode;
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::util::common::record_time;
39 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
40 use rustc_data_structures::fx::FxHashMap;
41 use rustc_data_structures::accumulate_vec::AccumulateVec;
43 pub type IchHasher = StableHasher<Fingerprint>;
45 pub struct IncrementalHashesMap {
46 hashes: FxHashMap<DepNode<DefId>, Fingerprint>,
48 // These are the metadata hashes for the current crate as they were stored
49 // during the last compilation session. They are only loaded if
50 // -Z query-dep-graph was specified and are needed for auto-tests using
51 // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
52 // check whether some metadata hash has changed in between two revisions.
53 pub prev_metadata_hashes: RefCell<FxHashMap<DefId, Fingerprint>>,
56 impl IncrementalHashesMap {
57 pub fn new() -> IncrementalHashesMap {
58 IncrementalHashesMap {
60 prev_metadata_hashes: RefCell::new(FxHashMap()),
64 pub fn get(&self, k: &DepNode<DefId>) -> Option<&Fingerprint> {
68 pub fn insert(&mut self, k: DepNode<DefId>, v: Fingerprint) -> Option<Fingerprint> {
69 self.hashes.insert(k, v)
72 pub fn iter<'a>(&'a self)
73 -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, Fingerprint> {
77 pub fn len(&self) -> usize {
82 impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
83 type Output = Fingerprint;
85 fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
86 match self.hashes.get(index) {
87 Some(fingerprint) => fingerprint,
89 bug!("Could not find ICH for {:?}", index);
95 struct ComputeItemHashesVisitor<'a, 'tcx: 'a> {
96 hcx: StableHashingContext<'a, 'tcx>,
97 hashes: IncrementalHashesMap,
100 impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
101 fn compute_and_store_ich_for_item_like<T>(&mut self,
102 dep_node: DepNode<DefId>,
105 where T: HashStable<StableHashingContext<'a, 'tcx>>
107 if !hash_bodies && !self.hcx.tcx().sess.opts.build_dep_graph() {
108 // If we just need the hashes in order to compute the SVH, we don't
109 // need have two hashes per item. Just the one containing also the
110 // item's body is sufficient.
114 let mut hasher = IchHasher::new();
115 self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| {
116 item_like.hash_stable(hcx, &mut hasher);
119 let bytes_hashed = hasher.bytes_hashed();
120 let item_hash = hasher.finish();
121 debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
122 self.hashes.insert(dep_node, item_hash);
124 let tcx = self.hcx.tcx();
126 tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
128 tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
131 fn compute_crate_hash(&mut self) {
132 let tcx = self.hcx.tcx();
133 let krate = tcx.hir.krate();
135 let mut crate_state = IchHasher::new();
137 let crate_disambiguator = tcx.sess.local_crate_disambiguator();
138 "crate_disambiguator".hash(&mut crate_state);
139 crate_disambiguator.as_str().len().hash(&mut crate_state);
140 crate_disambiguator.as_str().hash(&mut crate_state);
142 // add each item (in some deterministic order) to the overall
145 let hcx = &mut self.hcx;
146 let mut item_hashes: Vec<_> =
148 .filter_map(|(item_dep_node, &item_hash)| {
149 // This `match` determines what kinds of nodes
151 match *item_dep_node {
153 DepNode::HirBody(_) => {
154 // We want to incoporate these into the
157 DepNode::AllLocalTraitImpls => {
158 // These are already covered by hashing
163 bug!("Found unexpected DepNode during \
164 SVH computation: {:?}",
169 // Convert from a DepNode<DefId> to a
170 // DepNode<u64> where the u64 is the hash of
171 // the def-id's def-path:
173 item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did)))
175 Some((item_dep_node, item_hash))
178 item_hashes.sort_unstable(); // avoid artificial dependencies on item ordering
179 item_hashes.hash(&mut crate_state);
182 krate.attrs.hash_stable(&mut self.hcx, &mut crate_state);
184 let crate_hash = crate_state.finish();
185 self.hashes.insert(DepNode::Krate, crate_hash);
186 debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
189 fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) {
192 // Crate attributes are not copied over to the root `Mod`, so hash
193 // them explicitly here.
197 // These fields are handled separately:
204 trait_default_impl: _,
208 let def_id = DefId::local(CRATE_DEF_INDEX);
209 self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id),
211 (module, (span, attrs)));
212 self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id),
214 (module, (span, attrs)));
217 fn compute_and_store_ich_for_trait_impls(&mut self, krate: &'tcx hir::Crate)
219 let tcx = self.hcx.tcx();
221 let mut impls: Vec<(Fingerprint, Fingerprint)> = krate
224 .map(|(&trait_id, impls)| {
225 let trait_id = tcx.def_path_hash(trait_id);
226 let mut impls: AccumulateVec<[_; 32]> = impls
229 let def_id = tcx.hir.local_def_id(node_id);
230 tcx.def_path_hash(def_id)
234 impls.sort_unstable();
235 let mut hasher = StableHasher::new();
236 impls.hash_stable(&mut self.hcx, &mut hasher);
237 (trait_id, hasher.finish())
241 impls.sort_unstable();
243 let mut default_impls: AccumulateVec<[_; 32]> = krate
246 .map(|(&trait_def_id, &impl_node_id)| {
247 let impl_def_id = tcx.hir.local_def_id(impl_node_id);
248 (tcx.def_path_hash(trait_def_id), tcx.def_path_hash(impl_def_id))
252 default_impls.sort_unstable();
254 let mut hasher = StableHasher::new();
255 impls.hash_stable(&mut self.hcx, &mut hasher);
257 self.hashes.insert(DepNode::AllLocalTraitImpls, hasher.finish());
261 impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
262 fn visit_item(&mut self, item: &'tcx hir::Item) {
263 let def_id = self.hcx.tcx().hir.local_def_id(item.id);
264 self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
265 self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
268 fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
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);
274 fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
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);
283 pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
284 -> IncrementalHashesMap {
285 let _ignore = tcx.dep_graph.in_ignore();
286 let krate = tcx.hir.krate();
288 let mut visitor = ComputeItemHashesVisitor {
289 hcx: StableHashingContext::new(tcx),
290 hashes: IncrementalHashesMap::new(),
293 record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
294 visitor.hash_crate_root_module(krate);
295 krate.visit_all_item_likes(&mut visitor);
297 for macro_def in krate.exported_macros.iter() {
298 let def_id = tcx.hir.local_def_id(macro_def.id);
299 visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def);
300 visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def);
303 visitor.compute_and_store_ich_for_trait_impls(krate);
306 tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
308 record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());