]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
1 | // Copyright 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 | ||
a7813a04 | 11 | use rustc::dep_graph::DepNode; |
7cac9316 | 12 | use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; |
a7813a04 | 13 | use rustc::hir::svh::Svh; |
cc61c64b | 14 | use rustc::ich::Fingerprint; |
a7813a04 | 15 | use rustc::ty::TyCtxt; |
476ff2be | 16 | use rustc_data_structures::fx::FxHashMap; |
9e0c209e | 17 | use rustc_data_structures::flock; |
a7813a04 | 18 | use rustc_serialize::Decodable; |
9e0c209e | 19 | use rustc_serialize::opaque::Decoder; |
a7813a04 | 20 | |
9e0c209e | 21 | use IncrementalHashesMap; |
a7813a04 | 22 | use super::data::*; |
9e0c209e SL |
23 | use super::fs::*; |
24 | use super::file_format; | |
a7813a04 | 25 | |
7cac9316 XL |
26 | use std::hash::Hash; |
27 | use std::fmt::Debug; | |
28 | ||
a7813a04 XL |
29 | pub struct HashContext<'a, 'tcx: 'a> { |
30 | pub tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
9e0c209e | 31 | incremental_hashes_map: &'a IncrementalHashesMap, |
476ff2be SL |
32 | item_metadata_hashes: FxHashMap<DefId, Fingerprint>, |
33 | crate_hashes: FxHashMap<CrateNum, Svh>, | |
7cac9316 | 34 | global_metadata_hashes: FxHashMap<DepNode<DefId>, Fingerprint>, |
a7813a04 XL |
35 | } |
36 | ||
37 | impl<'a, 'tcx> HashContext<'a, 'tcx> { | |
9e0c209e SL |
38 | pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
39 | incremental_hashes_map: &'a IncrementalHashesMap) | |
40 | -> Self { | |
a7813a04 XL |
41 | HashContext { |
42 | tcx: tcx, | |
9e0c209e | 43 | incremental_hashes_map: incremental_hashes_map, |
476ff2be SL |
44 | item_metadata_hashes: FxHashMap(), |
45 | crate_hashes: FxHashMap(), | |
7cac9316 | 46 | global_metadata_hashes: FxHashMap(), |
a7813a04 XL |
47 | } |
48 | } | |
49 | ||
5bcae85e SL |
50 | pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool { |
51 | match *dep_node { | |
9e0c209e | 52 | DepNode::Krate | |
476ff2be SL |
53 | DepNode::Hir(_) | |
54 | DepNode::HirBody(_) => | |
55 | true, | |
7cac9316 XL |
56 | DepNode::MetaData(def_id) | |
57 | DepNode::GlobalMetaData(def_id, _) => !def_id.is_local(), | |
5bcae85e SL |
58 | _ => false, |
59 | } | |
60 | } | |
61 | ||
c30ab7b3 | 62 | pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<Fingerprint> { |
3157f602 | 63 | match *dep_node { |
9e0c209e SL |
64 | DepNode::Krate => { |
65 | Some(self.incremental_hashes_map[dep_node]) | |
66 | } | |
67 | ||
a7813a04 | 68 | // HIR nodes (which always come from our crate) are an input: |
7cac9316 XL |
69 | DepNode::Hir(def_id) | |
70 | DepNode::HirBody(def_id) => { | |
9e0c209e SL |
71 | assert!(def_id.is_local(), |
72 | "cannot hash HIR for non-local def-id {:?} => {:?}", | |
73 | def_id, | |
74 | self.tcx.item_path_str(def_id)); | |
75 | ||
9e0c209e | 76 | Some(self.incremental_hashes_map[dep_node]) |
a7813a04 XL |
77 | } |
78 | ||
79 | // MetaData from other crates is an *input* to us. | |
80 | // MetaData nodes from *our* crates are an *output*; we | |
81 | // don't hash them, but we do compute a hash for them and | |
82 | // save it for others to use. | |
83 | DepNode::MetaData(def_id) if !def_id.is_local() => { | |
7cac9316 XL |
84 | Some(self.metadata_hash(def_id, |
85 | def_id.krate, | |
86 | |this| &mut this.item_metadata_hashes)) | |
87 | } | |
88 | ||
89 | DepNode::GlobalMetaData(def_id, kind) => { | |
90 | Some(self.metadata_hash(DepNode::GlobalMetaData(def_id, kind), | |
91 | def_id.krate, | |
92 | |this| &mut this.global_metadata_hashes)) | |
a7813a04 XL |
93 | } |
94 | ||
95 | _ => { | |
96 | // Other kinds of nodes represent computed by-products | |
97 | // that we don't hash directly; instead, they should | |
98 | // have some transitive dependency on a Hir or | |
99 | // MetaData node, so we'll just hash that | |
100 | None | |
101 | } | |
102 | } | |
103 | } | |
104 | ||
7cac9316 XL |
105 | fn metadata_hash<K, C>(&mut self, |
106 | key: K, | |
107 | cnum: CrateNum, | |
108 | cache: C) | |
109 | -> Fingerprint | |
110 | where K: Hash + Eq + Debug, | |
111 | C: Fn(&mut Self) -> &mut FxHashMap<K, Fingerprint>, | |
112 | { | |
113 | debug!("metadata_hash(key={:?})", key); | |
114 | ||
115 | debug_assert!(cnum != LOCAL_CRATE); | |
a7813a04 XL |
116 | loop { |
117 | // check whether we have a result cached for this def-id | |
7cac9316 | 118 | if let Some(&hash) = cache(self).get(&key) { |
a7813a04 XL |
119 | return hash; |
120 | } | |
121 | ||
122 | // check whether we did not find detailed metadata for this | |
123 | // krate; in that case, we just use the krate's overall hash | |
7cac9316 | 124 | if let Some(&svh) = self.crate_hashes.get(&cnum) { |
a7813a04 XL |
125 | // micro-"optimization": avoid a cache miss if we ask |
126 | // for metadata from this particular def-id again. | |
c30ab7b3 | 127 | let fingerprint = svh_to_fingerprint(svh); |
7cac9316 | 128 | cache(self).insert(key, fingerprint); |
a7813a04 | 129 | |
c30ab7b3 | 130 | return fingerprint; |
a7813a04 XL |
131 | } |
132 | ||
133 | // otherwise, load the data and repeat. | |
7cac9316 XL |
134 | self.load_data(cnum); |
135 | assert!(self.crate_hashes.contains_key(&cnum)); | |
a7813a04 XL |
136 | } |
137 | } | |
138 | ||
9e0c209e | 139 | fn load_data(&mut self, cnum: CrateNum) { |
a7813a04 XL |
140 | debug!("load_data(cnum={})", cnum); |
141 | ||
142 | let svh = self.tcx.sess.cstore.crate_hash(cnum); | |
143 | let old = self.crate_hashes.insert(cnum, svh); | |
144 | debug!("load_data: svh={}", svh); | |
145 | assert!(old.is_none(), "loaded data for crate {:?} twice", cnum); | |
146 | ||
9e0c209e SL |
147 | if let Some(session_dir) = find_metadata_hashes_for(self.tcx, cnum) { |
148 | debug!("load_data: session_dir={:?}", session_dir); | |
149 | ||
150 | // Lock the directory we'll be reading the hashes from. | |
151 | let lock_file_path = lock_file_path(&session_dir); | |
152 | let _lock = match flock::Lock::new(&lock_file_path, | |
153 | false, // don't wait | |
154 | false, // don't create the lock-file | |
155 | false) { // shared lock | |
156 | Ok(lock) => lock, | |
157 | Err(err) => { | |
158 | debug!("Could not acquire lock on `{}` while trying to \ | |
159 | load metadata hashes: {}", | |
160 | lock_file_path.display(), | |
161 | err); | |
162 | ||
163 | // Could not acquire the lock. The directory is probably in | |
164 | // in the process of being deleted. It's OK to just exit | |
165 | // here. It's the same scenario as if the file had not | |
166 | // existed in the first place. | |
167 | return | |
168 | } | |
169 | }; | |
170 | ||
171 | let hashes_file_path = metadata_hash_import_path(&session_dir); | |
172 | ||
476ff2be | 173 | match file_format::read_file(self.tcx.sess, &hashes_file_path) |
a7813a04 | 174 | { |
9e0c209e SL |
175 | Ok(Some(data)) => { |
176 | match self.load_from_data(cnum, &data, svh) { | |
a7813a04 XL |
177 | Ok(()) => { } |
178 | Err(err) => { | |
179 | bug!("decoding error in dep-graph from `{}`: {}", | |
9e0c209e | 180 | &hashes_file_path.display(), err); |
a7813a04 XL |
181 | } |
182 | } | |
183 | } | |
9e0c209e SL |
184 | Ok(None) => { |
185 | // If the file is not found, that's ok. | |
186 | } | |
a7813a04 | 187 | Err(err) => { |
9e0c209e SL |
188 | self.tcx.sess.err( |
189 | &format!("could not load dep information from `{}`: {}", | |
190 | hashes_file_path.display(), err)); | |
a7813a04 XL |
191 | } |
192 | } | |
193 | } | |
194 | } | |
195 | ||
9e0c209e SL |
196 | fn load_from_data(&mut self, |
197 | cnum: CrateNum, | |
198 | data: &[u8], | |
199 | expected_svh: Svh) -> Result<(), String> { | |
a7813a04 XL |
200 | debug!("load_from_data(cnum={})", cnum); |
201 | ||
202 | // Load up the hashes for the def-ids from this crate. | |
203 | let mut decoder = Decoder::new(data, 0); | |
9e0c209e SL |
204 | let svh_in_hashes_file = Svh::decode(&mut decoder)?; |
205 | ||
206 | if svh_in_hashes_file != expected_svh { | |
207 | // We should not be able to get here. If we do, then | |
208 | // `fs::find_metadata_hashes_for()` has messed up. | |
209 | bug!("mismatch between SVH in crate and SVH in incr. comp. hashes") | |
210 | } | |
211 | ||
212 | let serialized_hashes = SerializedMetadataHashes::decode(&mut decoder)?; | |
7cac9316 | 213 | for serialized_hash in serialized_hashes.entry_hashes { |
a7813a04 XL |
214 | // the hashes are stored with just a def-index, which is |
215 | // always relative to the old crate; convert that to use | |
216 | // our internal crate number | |
217 | let def_id = DefId { krate: cnum, index: serialized_hash.def_index }; | |
218 | ||
219 | // record the hash for this dep-node | |
220 | let old = self.item_metadata_hashes.insert(def_id, serialized_hash.hash); | |
221 | debug!("load_from_data: def_id={:?} hash={}", def_id, serialized_hash.hash); | |
222 | assert!(old.is_none(), "already have hash for {:?}", def_id); | |
223 | } | |
7cac9316 XL |
224 | |
225 | for (dep_node, fingerprint) in serialized_hashes.global_hashes { | |
226 | // Here we need to remap the CrateNum in the DepNode. | |
227 | let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; | |
228 | let dep_node = match dep_node { | |
229 | DepNode::GlobalMetaData(_, kind) => DepNode::GlobalMetaData(def_id, kind), | |
230 | other => { | |
231 | bug!("unexpected DepNode variant: {:?}", other) | |
232 | } | |
233 | }; | |
234 | ||
235 | // record the hash for this dep-node | |
236 | debug!("load_from_data: def_node={:?} hash={}", dep_node, fingerprint); | |
237 | let old = self.global_metadata_hashes.insert(dep_node.clone(), fingerprint); | |
238 | assert!(old.is_none(), "already have hash for {:?}", dep_node); | |
239 | } | |
240 | ||
a7813a04 XL |
241 | Ok(()) |
242 | } | |
243 | } | |
c30ab7b3 SL |
244 | |
245 | fn svh_to_fingerprint(svh: Svh) -> Fingerprint { | |
246 | Fingerprint::from_smaller_hash(svh.as_u64()) | |
247 | } |