]>
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 | ||
11 | use calculate_svh::SvhCalculate; | |
12 | use rbml::Error; | |
13 | use rbml::opaque::Decoder; | |
14 | use rustc::dep_graph::DepNode; | |
15 | use rustc::hir::def_id::DefId; | |
16 | use rustc::hir::svh::Svh; | |
17 | use rustc::ty::TyCtxt; | |
18 | use rustc_data_structures::fnv::FnvHashMap; | |
19 | use rustc_serialize::Decodable; | |
20 | use std::io::{ErrorKind, Read}; | |
21 | use std::fs::File; | |
22 | use syntax::ast; | |
23 | ||
24 | use super::data::*; | |
25 | use super::util::*; | |
26 | ||
27 | pub struct HashContext<'a, 'tcx: 'a> { | |
28 | pub tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
29 | item_metadata_hashes: FnvHashMap<DefId, u64>, | |
30 | crate_hashes: FnvHashMap<ast::CrateNum, Svh>, | |
31 | } | |
32 | ||
33 | impl<'a, 'tcx> HashContext<'a, 'tcx> { | |
34 | pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { | |
35 | HashContext { | |
36 | tcx: tcx, | |
37 | item_metadata_hashes: FnvHashMap(), | |
38 | crate_hashes: FnvHashMap(), | |
39 | } | |
40 | } | |
41 | ||
5bcae85e SL |
42 | pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool { |
43 | match *dep_node { | |
44 | DepNode::Hir(_) => true, | |
45 | DepNode::MetaData(def_id) => !def_id.is_local(), | |
46 | _ => false, | |
47 | } | |
48 | } | |
49 | ||
50 | pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<(DefId, u64)> { | |
3157f602 | 51 | match *dep_node { |
a7813a04 XL |
52 | // HIR nodes (which always come from our crate) are an input: |
53 | DepNode::Hir(def_id) => { | |
5bcae85e | 54 | Some((def_id, self.hir_hash(def_id))) |
a7813a04 XL |
55 | } |
56 | ||
57 | // MetaData from other crates is an *input* to us. | |
58 | // MetaData nodes from *our* crates are an *output*; we | |
59 | // don't hash them, but we do compute a hash for them and | |
60 | // save it for others to use. | |
61 | DepNode::MetaData(def_id) if !def_id.is_local() => { | |
5bcae85e | 62 | Some((def_id, self.metadata_hash(def_id))) |
a7813a04 XL |
63 | } |
64 | ||
65 | _ => { | |
66 | // Other kinds of nodes represent computed by-products | |
67 | // that we don't hash directly; instead, they should | |
68 | // have some transitive dependency on a Hir or | |
69 | // MetaData node, so we'll just hash that | |
70 | None | |
71 | } | |
72 | } | |
73 | } | |
74 | ||
75 | fn hir_hash(&mut self, def_id: DefId) -> u64 { | |
5bcae85e SL |
76 | assert!(def_id.is_local(), |
77 | "cannot hash HIR for non-local def-id {:?} => {:?}", | |
78 | def_id, | |
79 | self.tcx.item_path_str(def_id)); | |
80 | ||
81 | assert!(!self.tcx.map.is_inlined_def_id(def_id), | |
82 | "cannot hash HIR for inlined def-id {:?} => {:?}", | |
83 | def_id, | |
84 | self.tcx.item_path_str(def_id)); | |
85 | ||
a7813a04 XL |
86 | // FIXME(#32753) -- should we use a distinct hash here |
87 | self.tcx.calculate_item_hash(def_id) | |
88 | } | |
89 | ||
90 | fn metadata_hash(&mut self, def_id: DefId) -> u64 { | |
91 | debug!("metadata_hash(def_id={:?})", def_id); | |
92 | ||
93 | assert!(!def_id.is_local()); | |
94 | loop { | |
95 | // check whether we have a result cached for this def-id | |
96 | if let Some(&hash) = self.item_metadata_hashes.get(&def_id) { | |
97 | debug!("metadata_hash: def_id={:?} hash={:?}", def_id, hash); | |
98 | return hash; | |
99 | } | |
100 | ||
101 | // check whether we did not find detailed metadata for this | |
102 | // krate; in that case, we just use the krate's overall hash | |
103 | if let Some(&hash) = self.crate_hashes.get(&def_id.krate) { | |
104 | debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash); | |
105 | ||
106 | // micro-"optimization": avoid a cache miss if we ask | |
107 | // for metadata from this particular def-id again. | |
108 | self.item_metadata_hashes.insert(def_id, hash.as_u64()); | |
109 | ||
110 | return hash.as_u64(); | |
111 | } | |
112 | ||
113 | // otherwise, load the data and repeat. | |
114 | self.load_data(def_id.krate); | |
115 | assert!(self.crate_hashes.contains_key(&def_id.krate)); | |
116 | } | |
117 | } | |
118 | ||
119 | fn load_data(&mut self, cnum: ast::CrateNum) { | |
120 | debug!("load_data(cnum={})", cnum); | |
121 | ||
122 | let svh = self.tcx.sess.cstore.crate_hash(cnum); | |
123 | let old = self.crate_hashes.insert(cnum, svh); | |
124 | debug!("load_data: svh={}", svh); | |
125 | assert!(old.is_none(), "loaded data for crate {:?} twice", cnum); | |
126 | ||
127 | if let Some(path) = metadata_hash_path(self.tcx, cnum) { | |
128 | debug!("load_data: path={:?}", path); | |
129 | let mut data = vec![]; | |
130 | match | |
131 | File::open(&path) | |
132 | .and_then(|mut file| file.read_to_end(&mut data)) | |
133 | { | |
134 | Ok(_) => { | |
135 | match self.load_from_data(cnum, &data) { | |
136 | Ok(()) => { } | |
137 | Err(err) => { | |
138 | bug!("decoding error in dep-graph from `{}`: {}", | |
139 | path.display(), err); | |
140 | } | |
141 | } | |
142 | } | |
143 | Err(err) => { | |
144 | match err.kind() { | |
145 | ErrorKind::NotFound => { | |
146 | // If the file is not found, that's ok. | |
147 | } | |
148 | _ => { | |
149 | self.tcx.sess.err( | |
150 | &format!("could not load dep information from `{}`: {}", | |
151 | path.display(), err)); | |
152 | return; | |
153 | } | |
154 | } | |
155 | } | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | fn load_from_data(&mut self, cnum: ast::CrateNum, data: &[u8]) -> Result<(), Error> { | |
161 | debug!("load_from_data(cnum={})", cnum); | |
162 | ||
163 | // Load up the hashes for the def-ids from this crate. | |
164 | let mut decoder = Decoder::new(data, 0); | |
165 | let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder)); | |
166 | for serialized_hash in serialized_hashes.hashes { | |
167 | // the hashes are stored with just a def-index, which is | |
168 | // always relative to the old crate; convert that to use | |
169 | // our internal crate number | |
170 | let def_id = DefId { krate: cnum, index: serialized_hash.def_index }; | |
171 | ||
172 | // record the hash for this dep-node | |
173 | let old = self.item_metadata_hashes.insert(def_id, serialized_hash.hash); | |
174 | debug!("load_from_data: def_id={:?} hash={}", def_id, serialized_hash.hash); | |
175 | assert!(old.is_none(), "already have hash for {:?}", def_id); | |
176 | } | |
177 | Ok(()) | |
178 | } | |
179 | } |