]> git.proxmox.com Git - rustc.git/blame - src/librustc_incremental/persist/hash.rs
New upstream version 1.12.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
11use calculate_svh::SvhCalculate;
12use rbml::Error;
13use rbml::opaque::Decoder;
14use rustc::dep_graph::DepNode;
15use rustc::hir::def_id::DefId;
16use rustc::hir::svh::Svh;
17use rustc::ty::TyCtxt;
18use rustc_data_structures::fnv::FnvHashMap;
19use rustc_serialize::Decodable;
20use std::io::{ErrorKind, Read};
21use std::fs::File;
22use syntax::ast;
23
24use super::data::*;
25use super::util::*;
26
27pub 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
33impl<'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}