]>
Commit | Line | Data |
---|---|---|
7cac9316 XL |
1 | // Copyright 2017 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 encoder::EncodeContext; | |
12 | use schema::{Lazy, LazySeq}; | |
13 | ||
14 | use rustc::ich::{StableHashingContext, Fingerprint}; | |
15 | use rustc::ty::TyCtxt; | |
16 | ||
17 | use rustc_data_structures::accumulate_vec::AccumulateVec; | |
18 | use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; | |
19 | use rustc_serialize::Encodable; | |
20 | ||
21 | /// The IsolatedEncoder provides facilities to write to crate metadata while | |
22 | /// making sure that anything going through it is also feed into an ICH hasher. | |
23 | pub struct IsolatedEncoder<'a, 'b: 'a, 'tcx: 'b> { | |
24 | pub tcx: TyCtxt<'b, 'tcx, 'tcx>, | |
25 | ecx: &'a mut EncodeContext<'b, 'tcx>, | |
ea8adc8c | 26 | hcx: Option<(StableHashingContext<'tcx>, StableHasher<Fingerprint>)>, |
7cac9316 XL |
27 | } |
28 | ||
29 | impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { | |
30 | ||
31 | pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self { | |
32 | let tcx = ecx.tcx; | |
33 | let compute_ich = ecx.compute_ich; | |
34 | IsolatedEncoder { | |
3b2f2976 XL |
35 | tcx, |
36 | ecx, | |
7cac9316 XL |
37 | hcx: if compute_ich { |
38 | // We are always hashing spans for things in metadata because | |
39 | // don't know if a downstream crate will use them or not. | |
40 | // Except when -Zquery-dep-graph is specified because we don't | |
41 | // want to mess up our tests. | |
42 | let hcx = if tcx.sess.opts.debugging_opts.query_dep_graph { | |
ea8adc8c | 43 | tcx.create_stable_hashing_context() |
7cac9316 | 44 | } else { |
ea8adc8c | 45 | tcx.create_stable_hashing_context().force_span_hashing() |
7cac9316 XL |
46 | }; |
47 | ||
48 | Some((hcx, StableHasher::new())) | |
49 | } else { | |
50 | None | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
55 | pub fn finish(self) -> (Option<Fingerprint>, &'a mut EncodeContext<'b, 'tcx>) { | |
56 | if let Some((_, hasher)) = self.hcx { | |
57 | (Some(hasher.finish()), self.ecx) | |
58 | } else { | |
59 | (None, self.ecx) | |
60 | } | |
61 | } | |
62 | ||
63 | pub fn lazy<T>(&mut self, value: &T) -> Lazy<T> | |
ea8adc8c | 64 | where T: Encodable + HashStable<StableHashingContext<'tcx>> |
7cac9316 XL |
65 | { |
66 | if let Some((ref mut hcx, ref mut hasher)) = self.hcx { | |
67 | value.hash_stable(hcx, hasher); | |
68 | debug!("metadata-hash: {:?}", hasher); | |
69 | } | |
70 | self.ecx.lazy(value) | |
71 | } | |
72 | ||
73 | pub fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T> | |
74 | where I: IntoIterator<Item = T>, | |
ea8adc8c | 75 | T: Encodable + HashStable<StableHashingContext<'tcx>> |
7cac9316 XL |
76 | { |
77 | if let Some((ref mut hcx, ref mut hasher)) = self.hcx { | |
78 | let iter = iter.into_iter(); | |
79 | let (lower_bound, upper_bound) = iter.size_hint(); | |
80 | ||
81 | if upper_bound == Some(lower_bound) { | |
82 | lower_bound.hash_stable(hcx, hasher); | |
83 | let mut num_items_hashed = 0; | |
84 | let ret = self.ecx.lazy_seq(iter.inspect(|item| { | |
85 | item.hash_stable(hcx, hasher); | |
86 | num_items_hashed += 1; | |
87 | })); | |
88 | ||
89 | // Sometimes items in a sequence are filtered out without being | |
90 | // hashed (e.g. for &[ast::Attribute]) and this code path cannot | |
91 | // handle that correctly, so we want to make sure we didn't hit | |
92 | // it by accident. | |
93 | if lower_bound != num_items_hashed { | |
94 | bug!("Hashed a different number of items ({}) than expected ({})", | |
95 | num_items_hashed, | |
96 | lower_bound); | |
97 | } | |
98 | debug!("metadata-hash: {:?}", hasher); | |
99 | ret | |
100 | } else { | |
101 | // Collect into a vec so we know the length of the sequence | |
102 | let items: AccumulateVec<[T; 32]> = iter.collect(); | |
103 | items.hash_stable(hcx, hasher); | |
104 | debug!("metadata-hash: {:?}", hasher); | |
105 | self.ecx.lazy_seq(items) | |
106 | } | |
107 | } else { | |
108 | self.ecx.lazy_seq(iter) | |
109 | } | |
110 | } | |
111 | ||
112 | pub fn lazy_seq_ref<'x, I, T>(&mut self, iter: I) -> LazySeq<T> | |
113 | where I: IntoIterator<Item = &'x T>, | |
ea8adc8c | 114 | T: 'x + Encodable + HashStable<StableHashingContext<'tcx>> |
7cac9316 XL |
115 | { |
116 | if let Some((ref mut hcx, ref mut hasher)) = self.hcx { | |
117 | let iter = iter.into_iter(); | |
118 | let (lower_bound, upper_bound) = iter.size_hint(); | |
119 | ||
120 | if upper_bound == Some(lower_bound) { | |
121 | lower_bound.hash_stable(hcx, hasher); | |
122 | let mut num_items_hashed = 0; | |
123 | let ret = self.ecx.lazy_seq_ref(iter.inspect(|item| { | |
124 | item.hash_stable(hcx, hasher); | |
125 | num_items_hashed += 1; | |
126 | })); | |
127 | ||
128 | // Sometimes items in a sequence are filtered out without being | |
129 | // hashed (e.g. for &[ast::Attribute]) and this code path cannot | |
130 | // handle that correctly, so we want to make sure we didn't hit | |
131 | // it by accident. | |
132 | if lower_bound != num_items_hashed { | |
133 | bug!("Hashed a different number of items ({}) than expected ({})", | |
134 | num_items_hashed, | |
135 | lower_bound); | |
136 | } | |
137 | debug!("metadata-hash: {:?}", hasher); | |
138 | ret | |
139 | } else { | |
140 | // Collect into a vec so we know the length of the sequence | |
141 | let items: AccumulateVec<[&'x T; 32]> = iter.collect(); | |
142 | items.hash_stable(hcx, hasher); | |
143 | debug!("metadata-hash: {:?}", hasher); | |
144 | self.ecx.lazy_seq_ref(items.iter().map(|x| *x)) | |
145 | } | |
146 | } else { | |
147 | self.ecx.lazy_seq_ref(iter) | |
148 | } | |
149 | } | |
150 | ||
151 | pub fn lazy_seq_from_slice<T>(&mut self, slice: &[T]) -> LazySeq<T> | |
ea8adc8c | 152 | where T: Encodable + HashStable<StableHashingContext<'tcx>> |
7cac9316 XL |
153 | { |
154 | if let Some((ref mut hcx, ref mut hasher)) = self.hcx { | |
155 | slice.hash_stable(hcx, hasher); | |
156 | debug!("metadata-hash: {:?}", hasher); | |
157 | } | |
158 | self.ecx.lazy_seq_ref(slice.iter()) | |
159 | } | |
160 | ||
161 | pub fn lazy_seq_ref_from_slice<T>(&mut self, slice: &[&T]) -> LazySeq<T> | |
ea8adc8c | 162 | where T: Encodable + HashStable<StableHashingContext<'tcx>> |
7cac9316 XL |
163 | { |
164 | if let Some((ref mut hcx, ref mut hasher)) = self.hcx { | |
165 | slice.hash_stable(hcx, hasher); | |
166 | debug!("metadata-hash: {:?}", hasher); | |
167 | } | |
168 | self.ecx.lazy_seq_ref(slice.iter().map(|x| *x)) | |
169 | } | |
170 | } |