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