1 // Copyright 2012-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.
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.
11 //! Calculation of the (misnamed) "strict version hash" for crates and
12 //! items. This hash is used to tell when the HIR changed in such a
13 //! way that results from previous compilations may no longer be
14 //! applicable and hence must be recomputed. It should probably be
15 //! renamed to the ICH (incremental compilation hash).
17 //! The hashes for all items are computed once at the beginning of
18 //! compilation and stored into a map. In addition, a hash is computed
19 //! of the **entire crate**.
21 //! Storing the hashes in a map avoids the need to compute them twice
22 //! (once when loading prior incremental results and once when
23 //! saving), but it is also important for correctness: at least as of
24 //! the time of this writing, the typeck passes rewrites entries in
25 //! the dep-map in-place to accommodate UFCS resolutions. Since name
26 //! resolution is part of the hash, the result is that hashes computed
27 //! at the end of compilation would be different from those computed
31 use std
::cell
::RefCell
;
33 use rustc
::dep_graph
::DepNode
;
35 use rustc
::hir
::def_id
::{CRATE_DEF_INDEX, DefId}
;
36 use rustc
::hir
::intravisit
as visit
;
37 use rustc
::ty
::TyCtxt
;
38 use rustc_data_structures
::fnv
::FnvHashMap
;
39 use rustc
::util
::common
::record_time
;
40 use rustc
::session
::config
::DebugInfoLevel
::NoDebugInfo
;
42 use self::def_path_hash
::DefPathHashes
;
43 use self::svh_visitor
::StrictVersionHashVisitor
;
44 use self::caching_codemap_view
::CachingCodemapView
;
45 use self::hasher
::IchHasher
;
50 mod caching_codemap_view
;
53 pub struct IncrementalHashesMap
{
54 hashes
: FnvHashMap
<DepNode
<DefId
>, Fingerprint
>,
56 // These are the metadata hashes for the current crate as they were stored
57 // during the last compilation session. They are only loaded if
58 // -Z query-dep-graph was specified and are needed for auto-tests using
59 // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
60 // check whether some metadata hash has changed in between two revisions.
61 pub prev_metadata_hashes
: RefCell
<FnvHashMap
<DefId
, Fingerprint
>>,
64 impl IncrementalHashesMap
{
65 pub fn new() -> IncrementalHashesMap
{
66 IncrementalHashesMap
{
68 prev_metadata_hashes
: RefCell
::new(FnvHashMap()),
72 pub fn insert(&mut self, k
: DepNode
<DefId
>, v
: Fingerprint
) -> Option
<Fingerprint
> {
73 self.hashes
.insert(k
, v
)
76 pub fn iter
<'a
>(&'a
self)
77 -> ::std
::collections
::hash_map
::Iter
<'a
, DepNode
<DefId
>, Fingerprint
> {
81 pub fn len(&self) -> usize {
86 impl<'a
> ::std
::ops
::Index
<&'a DepNode
<DefId
>> for IncrementalHashesMap
{
87 type Output
= Fingerprint
;
89 fn index(&self, index
: &'a DepNode
<DefId
>) -> &Fingerprint
{
95 pub fn compute_incremental_hashes_map
<'a
, 'tcx
: 'a
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>)
96 -> IncrementalHashesMap
{
97 let _ignore
= tcx
.dep_graph
.in_ignore();
98 let krate
= tcx
.map
.krate();
99 let hash_spans
= tcx
.sess
.opts
.debuginfo
!= NoDebugInfo
;
100 let mut visitor
= HashItemsVisitor
{
102 hashes
: IncrementalHashesMap
::new(),
103 def_path_hashes
: DefPathHashes
::new(tcx
),
104 codemap
: CachingCodemapView
::new(tcx
),
105 hash_spans
: hash_spans
,
107 record_time(&tcx
.sess
.perf_stats
.incr_comp_hashes_time
, || {
108 visitor
.calculate_def_id(DefId
::local(CRATE_DEF_INDEX
),
109 |v
| visit
::walk_crate(v
, krate
));
110 krate
.visit_all_items(&mut visitor
);
113 tcx
.sess
.perf_stats
.incr_comp_hashes_count
.set(visitor
.hashes
.len() as u64);
115 record_time(&tcx
.sess
.perf_stats
.svh_time
, || visitor
.compute_crate_hash());
119 struct HashItemsVisitor
<'a
, 'tcx
: 'a
> {
120 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
121 def_path_hashes
: DefPathHashes
<'a
, 'tcx
>,
122 codemap
: CachingCodemapView
<'tcx
>,
123 hashes
: IncrementalHashesMap
,
127 impl<'a
, 'tcx
> HashItemsVisitor
<'a
, 'tcx
> {
128 fn calculate_node_id
<W
>(&mut self, id
: ast
::NodeId
, walk_op
: W
)
129 where W
: for<'v
> FnMut(&mut StrictVersionHashVisitor
<'v
, 'a
, 'tcx
>)
131 let def_id
= self.tcx
.map
.local_def_id(id
);
132 self.calculate_def_id(def_id
, walk_op
)
135 fn calculate_def_id
<W
>(&mut self, def_id
: DefId
, mut walk_op
: W
)
136 where W
: for<'v
> FnMut(&mut StrictVersionHashVisitor
<'v
, 'a
, 'tcx
>)
138 assert
!(def_id
.is_local());
139 debug
!("HashItemsVisitor::calculate(def_id={:?})", def_id
);
140 let mut state
= IchHasher
::new();
141 walk_op(&mut StrictVersionHashVisitor
::new(&mut state
,
143 &mut self.def_path_hashes
,
146 let bytes_hashed
= state
.bytes_hashed();
147 let item_hash
= state
.finish();
148 self.hashes
.insert(DepNode
::Hir(def_id
), item_hash
);
149 debug
!("calculate_item_hash: def_id={:?} hash={:?}", def_id
, item_hash
);
151 let bytes_hashed
= self.tcx
.sess
.perf_stats
.incr_comp_bytes_hashed
.get() +
153 self.tcx
.sess
.perf_stats
.incr_comp_bytes_hashed
.set(bytes_hashed
);
156 fn compute_crate_hash(&mut self) {
157 let krate
= self.tcx
.map
.krate();
159 let mut crate_state
= IchHasher
::new();
161 let crate_disambiguator
= self.tcx
.sess
.local_crate_disambiguator();
162 "crate_disambiguator".hash(&mut crate_state
);
163 crate_disambiguator
.len().hash(&mut crate_state
);
164 crate_disambiguator
.hash(&mut crate_state
);
166 // add each item (in some deterministic order) to the overall
169 let def_path_hashes
= &mut self.def_path_hashes
;
170 let mut item_hashes
: Vec
<_
> =
172 .map(|(item_dep_node
, &item_hash
)| {
173 // convert from a DepNode<DefId> tp a
174 // DepNode<u64> where the u64 is the
175 // hash of the def-id's def-path:
177 item_dep_node
.map_def(|&did
| Some(def_path_hashes
.hash(did
)))
179 (item_dep_node
, item_hash
)
182 item_hashes
.sort(); // avoid artificial dependencies on item ordering
183 item_hashes
.hash(&mut crate_state
);
187 let mut visitor
= StrictVersionHashVisitor
::new(&mut crate_state
,
189 &mut self.def_path_hashes
,
192 visitor
.hash_attributes(&krate
.attrs
);
195 let crate_hash
= crate_state
.finish();
196 self.hashes
.insert(DepNode
::Krate
, crate_hash
);
197 debug
!("calculate_crate_hash: crate_hash={:?}", crate_hash
);
202 impl<'a
, 'tcx
> visit
::Visitor
<'tcx
> for HashItemsVisitor
<'a
, 'tcx
> {
203 fn visit_item(&mut self, item
: &'tcx hir
::Item
) {
204 self.calculate_node_id(item
.id
, |v
| v
.visit_item(item
));
205 visit
::walk_item(self, item
);
208 fn visit_foreign_item(&mut self, item
: &'tcx hir
::ForeignItem
) {
209 self.calculate_node_id(item
.id
, |v
| v
.visit_foreign_item(item
));
210 visit
::walk_foreign_item(self, item
);