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