]> git.proxmox.com Git - rustc.git/blame - src/librustc_incremental/persist/hash.rs
New upstream version 1.19.0+dfsg1
[rustc.git] / src / librustc_incremental / persist / hash.rs
CommitLineData
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 11use rustc::dep_graph::DepNode;
7cac9316 12use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
a7813a04 13use rustc::hir::svh::Svh;
cc61c64b 14use rustc::ich::Fingerprint;
a7813a04 15use rustc::ty::TyCtxt;
476ff2be 16use rustc_data_structures::fx::FxHashMap;
9e0c209e 17use rustc_data_structures::flock;
a7813a04 18use rustc_serialize::Decodable;
9e0c209e 19use rustc_serialize::opaque::Decoder;
a7813a04 20
9e0c209e 21use IncrementalHashesMap;
a7813a04 22use super::data::*;
9e0c209e
SL
23use super::fs::*;
24use super::file_format;
a7813a04 25
7cac9316
XL
26use std::hash::Hash;
27use std::fmt::Debug;
28
a7813a04
XL
29pub 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
37impl<'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
245fn svh_to_fingerprint(svh: Svh) -> Fingerprint {
246 Fingerprint::from_smaller_hash(svh.as_u64())
247}