]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
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 | ||
abe05a73 | 11 | use errors::DiagnosticBuilder; |
0531ce1d | 12 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
ea8adc8c XL |
13 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
14 | use rustc_data_structures::indexed_vec::{Idx, IndexVec}; | |
0531ce1d | 15 | use rustc_data_structures::sync::Lrc; |
5bcae85e | 16 | use std::cell::{Ref, RefCell}; |
ea8adc8c XL |
17 | use std::env; |
18 | use std::hash::Hash; | |
ea8adc8c | 19 | use ty::TyCtxt; |
3b2f2976 | 20 | use util::common::{ProfileQueriesMsg, profq_msg}; |
54a0048b | 21 | |
0531ce1d | 22 | use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; |
ea8adc8c XL |
23 | |
24 | use super::debug::EdgeFilter; | |
041b39d2 | 25 | use super::dep_node::{DepNode, DepKind, WorkProductId}; |
54a0048b SL |
26 | use super::query::DepGraphQuery; |
27 | use super::raii; | |
8bb4bdeb | 28 | use super::safe::DepGraphSafe; |
ea8adc8c XL |
29 | use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; |
30 | use super::prev::PreviousDepGraph; | |
54a0048b SL |
31 | |
32 | #[derive(Clone)] | |
33 | pub struct DepGraph { | |
0531ce1d | 34 | data: Option<Lrc<DepGraphData>>, |
ea8adc8c | 35 | |
ff7c6d11 XL |
36 | // A vector mapping depnodes from the current graph to their associated |
37 | // result value fingerprints. Do not rely on the length of this vector | |
38 | // being the same as the number of nodes in the graph. The vector can | |
39 | // contain an arbitrary number of zero-entries at the end. | |
0531ce1d | 40 | fingerprints: Lrc<RefCell<IndexVec<DepNodeIndex, Fingerprint>>> |
ea8adc8c XL |
41 | } |
42 | ||
43 | ||
abe05a73 | 44 | newtype_index!(DepNodeIndex); |
ea8adc8c XL |
45 | |
46 | impl DepNodeIndex { | |
abe05a73 | 47 | const INVALID: DepNodeIndex = DepNodeIndex(::std::u32::MAX); |
ea8adc8c XL |
48 | } |
49 | ||
50 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | |
51 | pub enum DepNodeColor { | |
52 | Red, | |
53 | Green(DepNodeIndex) | |
54 | } | |
55 | ||
56 | impl DepNodeColor { | |
57 | pub fn is_green(self) -> bool { | |
58 | match self { | |
59 | DepNodeColor::Red => false, | |
60 | DepNodeColor::Green(_) => true, | |
61 | } | |
62 | } | |
5bcae85e SL |
63 | } |
64 | ||
65 | struct DepGraphData { | |
ea8adc8c XL |
66 | /// The new encoding of the dependency graph, optimized for red/green |
67 | /// tracking. The `current` field is the dependency graph of only the | |
68 | /// current compilation session: We don't merge the previous dep-graph into | |
69 | /// current one anymore. | |
70 | current: RefCell<CurrentDepGraph>, | |
71 | ||
72 | /// The dep-graph from the previous compilation session. It contains all | |
73 | /// nodes and edges as well as all fingerprints of nodes that have them. | |
74 | previous: PreviousDepGraph, | |
75 | ||
0531ce1d | 76 | colors: RefCell<DepNodeColorMap>, |
5bcae85e SL |
77 | |
78 | /// When we load, there may be `.o` files, cached mir, or other such | |
79 | /// things available to us. If we find that they are not dirty, we | |
80 | /// load the path to the file storing those work-products here into | |
81 | /// this map. We can later look for and extract that data. | |
041b39d2 | 82 | previous_work_products: RefCell<FxHashMap<WorkProductId, WorkProduct>>, |
5bcae85e SL |
83 | |
84 | /// Work-products that we generate in this run. | |
041b39d2 XL |
85 | work_products: RefCell<FxHashMap<WorkProductId, WorkProduct>>, |
86 | ||
87 | dep_node_debug: RefCell<FxHashMap<DepNode, String>>, | |
ea8adc8c XL |
88 | |
89 | // Used for testing, only populated when -Zquery-dep-graph is specified. | |
90 | loaded_from_cache: RefCell<FxHashMap<DepNodeIndex, bool>>, | |
54a0048b SL |
91 | } |
92 | ||
93 | impl DepGraph { | |
ea8adc8c XL |
94 | |
95 | pub fn new(prev_graph: PreviousDepGraph) -> DepGraph { | |
ff7c6d11 XL |
96 | // Pre-allocate the fingerprints array. We over-allocate a little so |
97 | // that we hopefully don't have to re-allocate during this compilation | |
98 | // session. | |
0531ce1d XL |
99 | let prev_graph_node_count = prev_graph.node_count(); |
100 | ||
ff7c6d11 | 101 | let fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, |
0531ce1d | 102 | (prev_graph_node_count * 115) / 100); |
54a0048b | 103 | DepGraph { |
0531ce1d | 104 | data: Some(Lrc::new(DepGraphData { |
ea8adc8c XL |
105 | previous_work_products: RefCell::new(FxHashMap()), |
106 | work_products: RefCell::new(FxHashMap()), | |
107 | dep_node_debug: RefCell::new(FxHashMap()), | |
108 | current: RefCell::new(CurrentDepGraph::new()), | |
109 | previous: prev_graph, | |
0531ce1d | 110 | colors: RefCell::new(DepNodeColorMap::new(prev_graph_node_count)), |
ea8adc8c XL |
111 | loaded_from_cache: RefCell::new(FxHashMap()), |
112 | })), | |
0531ce1d | 113 | fingerprints: Lrc::new(RefCell::new(fingerprints)), |
ea8adc8c XL |
114 | } |
115 | } | |
116 | ||
117 | pub fn new_disabled() -> DepGraph { | |
118 | DepGraph { | |
119 | data: None, | |
0531ce1d | 120 | fingerprints: Lrc::new(RefCell::new(IndexVec::new())), |
54a0048b SL |
121 | } |
122 | } | |
123 | ||
32a655c1 SL |
124 | /// True if we are actually building the full dep-graph. |
125 | #[inline] | |
126 | pub fn is_fully_enabled(&self) -> bool { | |
041b39d2 | 127 | self.data.is_some() |
32a655c1 SL |
128 | } |
129 | ||
041b39d2 | 130 | pub fn query(&self) -> DepGraphQuery { |
ea8adc8c XL |
131 | let current_dep_graph = self.data.as_ref().unwrap().current.borrow(); |
132 | let nodes: Vec<_> = current_dep_graph.nodes.iter().cloned().collect(); | |
133 | let mut edges = Vec::new(); | |
134 | for (index, edge_targets) in current_dep_graph.edges.iter_enumerated() { | |
135 | let from = current_dep_graph.nodes[index]; | |
136 | for &edge_target in edge_targets { | |
137 | let to = current_dep_graph.nodes[edge_target]; | |
138 | edges.push((from, to)); | |
139 | } | |
140 | } | |
54a0048b | 141 | |
ea8adc8c | 142 | DepGraphQuery::new(&nodes[..], &edges[..]) |
54a0048b SL |
143 | } |
144 | ||
2c00a5a8 XL |
145 | pub fn assert_ignored(&self) |
146 | { | |
147 | if let Some(ref data) = self.data { | |
148 | match data.current.borrow().task_stack.last() { | |
149 | Some(&OpenTask::Ignore) | None => { | |
150 | // ignored | |
151 | } | |
152 | _ => panic!("expected an ignore context") | |
153 | } | |
154 | } | |
54a0048b SL |
155 | } |
156 | ||
157 | pub fn with_ignore<OP,R>(&self, op: OP) -> R | |
158 | where OP: FnOnce() -> R | |
159 | { | |
2c00a5a8 | 160 | let _task = self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.current)); |
54a0048b SL |
161 | op() |
162 | } | |
163 | ||
8bb4bdeb XL |
164 | /// Starts a new dep-graph task. Dep-graph tasks are specified |
165 | /// using a free function (`task`) and **not** a closure -- this | |
166 | /// is intentional because we want to exercise tight control over | |
167 | /// what state they have access to. In particular, we want to | |
168 | /// prevent implicit 'leaks' of tracked state into the task (which | |
169 | /// could then be read without generating correct edges in the | |
0531ce1d | 170 | /// dep-graph -- see the [rustc guide] for more details on |
ff7c6d11 | 171 | /// the dep-graph). To this end, the task function gets exactly two |
8bb4bdeb XL |
172 | /// pieces of state: the context `cx` and an argument `arg`. Both |
173 | /// of these bits of state must be of some type that implements | |
174 | /// `DepGraphSafe` and hence does not leak. | |
175 | /// | |
176 | /// The choice of two arguments is not fundamental. One argument | |
177 | /// would work just as well, since multiple values can be | |
178 | /// collected using tuples. However, using two arguments works out | |
179 | /// to be quite convenient, since it is common to need a context | |
180 | /// (`cx`) and some argument (e.g., a `DefId` identifying what | |
181 | /// item to process). | |
182 | /// | |
183 | /// For cases where you need some other number of arguments: | |
184 | /// | |
185 | /// - If you only need one argument, just use `()` for the `arg` | |
186 | /// parameter. | |
187 | /// - If you need 3+ arguments, use a tuple for the | |
188 | /// `arg` parameter. | |
189 | /// | |
0531ce1d XL |
190 | /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/incremental-compilation.html |
191 | pub fn with_task<'gcx, C, A, R>(&self, | |
ea8adc8c XL |
192 | key: DepNode, |
193 | cx: C, | |
194 | arg: A, | |
195 | task: fn(C, A) -> R) | |
196 | -> (R, DepNodeIndex) | |
0531ce1d XL |
197 | where C: DepGraphSafe + StableHashingContextProvider<'gcx>, |
198 | R: HashStable<StableHashingContext<'gcx>>, | |
abe05a73 XL |
199 | { |
200 | self.with_task_impl(key, cx, arg, task, | |
201 | |data, key| data.borrow_mut().push_task(key), | |
202 | |data, key| data.borrow_mut().pop_task(key)) | |
203 | } | |
204 | ||
0531ce1d | 205 | fn with_task_impl<'gcx, C, A, R>(&self, |
abe05a73 XL |
206 | key: DepNode, |
207 | cx: C, | |
208 | arg: A, | |
209 | task: fn(C, A) -> R, | |
210 | push: fn(&RefCell<CurrentDepGraph>, DepNode), | |
211 | pop: fn(&RefCell<CurrentDepGraph>, DepNode) -> DepNodeIndex) | |
212 | -> (R, DepNodeIndex) | |
0531ce1d XL |
213 | where C: DepGraphSafe + StableHashingContextProvider<'gcx>, |
214 | R: HashStable<StableHashingContext<'gcx>>, | |
54a0048b | 215 | { |
041b39d2 | 216 | if let Some(ref data) = self.data { |
abe05a73 | 217 | push(&data.current, key); |
ea8adc8c XL |
218 | |
219 | // In incremental mode, hash the result of the task. We don't | |
220 | // do anything with the hash yet, but we are computing it | |
221 | // anyway so that | |
222 | // - we make sure that the infrastructure works and | |
223 | // - we can get an idea of the runtime cost. | |
0531ce1d XL |
224 | let mut hcx = cx.get_stable_hashing_context(); |
225 | ||
226 | if cfg!(debug_assertions) { | |
227 | profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone())) | |
228 | }; | |
ea8adc8c | 229 | |
041b39d2 | 230 | let result = task(cx, arg); |
0531ce1d | 231 | |
3b2f2976 | 232 | if cfg!(debug_assertions) { |
0531ce1d | 233 | profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd) |
3b2f2976 | 234 | }; |
ea8adc8c | 235 | |
abe05a73 | 236 | let dep_node_index = pop(&data.current, key); |
ea8adc8c XL |
237 | |
238 | let mut stable_hasher = StableHasher::new(); | |
239 | result.hash_stable(&mut hcx, &mut stable_hasher); | |
240 | ||
241 | let current_fingerprint = stable_hasher.finish(); | |
242 | ||
243 | // Store the current fingerprint | |
244 | { | |
ff7c6d11 XL |
245 | let mut fingerprints = self.fingerprints.borrow_mut(); |
246 | ||
247 | if dep_node_index.index() >= fingerprints.len() { | |
248 | fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO); | |
249 | } | |
250 | ||
251 | debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO, | |
ea8adc8c XL |
252 | "DepGraph::with_task() - Duplicate fingerprint \ |
253 | insertion for {:?}", key); | |
ff7c6d11 | 254 | fingerprints[dep_node_index] = current_fingerprint; |
ea8adc8c XL |
255 | } |
256 | ||
257 | // Determine the color of the new DepNode. | |
0531ce1d XL |
258 | if let Some(prev_index) = data.previous.node_to_index_opt(&key) { |
259 | let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); | |
ea8adc8c | 260 | |
0531ce1d | 261 | let color = if current_fingerprint == prev_fingerprint { |
ea8adc8c XL |
262 | DepNodeColor::Green(dep_node_index) |
263 | } else { | |
264 | DepNodeColor::Red | |
265 | }; | |
266 | ||
0531ce1d XL |
267 | let mut colors = data.colors.borrow_mut(); |
268 | debug_assert!(colors.get(prev_index).is_none(), | |
ea8adc8c XL |
269 | "DepGraph::with_task() - Duplicate DepNodeColor \ |
270 | insertion for {:?}", key); | |
0531ce1d XL |
271 | |
272 | colors.insert(prev_index, color); | |
ea8adc8c XL |
273 | } |
274 | ||
041b39d2 XL |
275 | (result, dep_node_index) |
276 | } else { | |
ea8adc8c | 277 | if key.kind.fingerprint_needed_for_crate_hash() { |
0531ce1d | 278 | let mut hcx = cx.get_stable_hashing_context(); |
ea8adc8c XL |
279 | let result = task(cx, arg); |
280 | let mut stable_hasher = StableHasher::new(); | |
281 | result.hash_stable(&mut hcx, &mut stable_hasher); | |
ff7c6d11 XL |
282 | let fingerprint = stable_hasher.finish(); |
283 | ||
284 | let mut fingerprints = self.fingerprints.borrow_mut(); | |
285 | let dep_node_index = DepNodeIndex::new(fingerprints.len()); | |
286 | fingerprints.push(fingerprint); | |
0531ce1d | 287 | |
ff7c6d11 XL |
288 | debug_assert!(fingerprints[dep_node_index] == fingerprint, |
289 | "DepGraph::with_task() - Assigned fingerprint to \ | |
290 | unexpected index for {:?}", key); | |
0531ce1d | 291 | |
ff7c6d11 | 292 | (result, dep_node_index) |
ea8adc8c XL |
293 | } else { |
294 | (task(cx, arg), DepNodeIndex::INVALID) | |
295 | } | |
041b39d2 | 296 | } |
54a0048b SL |
297 | } |
298 | ||
041b39d2 XL |
299 | /// Execute something within an "anonymous" task, that is, a task the |
300 | /// DepNode of which is determined by the list of inputs it read from. | |
301 | pub fn with_anon_task<OP,R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex) | |
302 | where OP: FnOnce() -> R | |
303 | { | |
304 | if let Some(ref data) = self.data { | |
ea8adc8c | 305 | data.current.borrow_mut().push_anon_task(); |
041b39d2 | 306 | let result = op(); |
ea8adc8c XL |
307 | let dep_node_index = data.current |
308 | .borrow_mut() | |
309 | .pop_anon_task(dep_kind); | |
310 | (result, dep_node_index) | |
041b39d2 XL |
311 | } else { |
312 | (op(), DepNodeIndex::INVALID) | |
313 | } | |
314 | } | |
315 | ||
abe05a73 XL |
316 | /// Execute something within an "eval-always" task which is a task |
317 | // that runs whenever anything changes. | |
0531ce1d | 318 | pub fn with_eval_always_task<'gcx, C, A, R>(&self, |
abe05a73 XL |
319 | key: DepNode, |
320 | cx: C, | |
321 | arg: A, | |
322 | task: fn(C, A) -> R) | |
323 | -> (R, DepNodeIndex) | |
0531ce1d XL |
324 | where C: DepGraphSafe + StableHashingContextProvider<'gcx>, |
325 | R: HashStable<StableHashingContext<'gcx>>, | |
abe05a73 XL |
326 | { |
327 | self.with_task_impl(key, cx, arg, task, | |
328 | |data, key| data.borrow_mut().push_eval_always_task(key), | |
329 | |data, key| data.borrow_mut().pop_eval_always_task(key)) | |
330 | } | |
331 | ||
041b39d2 XL |
332 | #[inline] |
333 | pub fn read(&self, v: DepNode) { | |
334 | if let Some(ref data) = self.data { | |
ea8adc8c XL |
335 | let mut current = data.current.borrow_mut(); |
336 | if let Some(&dep_node_index) = current.node_to_node_index.get(&v) { | |
337 | current.read_index(dep_node_index); | |
338 | } else { | |
339 | bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind) | |
340 | } | |
041b39d2 XL |
341 | } |
342 | } | |
343 | ||
344 | #[inline] | |
ea8adc8c | 345 | pub fn read_index(&self, dep_node_index: DepNodeIndex) { |
041b39d2 | 346 | if let Some(ref data) = self.data { |
ea8adc8c | 347 | data.current.borrow_mut().read_index(dep_node_index); |
c30ab7b3 | 348 | } |
54a0048b SL |
349 | } |
350 | ||
abe05a73 | 351 | #[inline] |
ff7c6d11 XL |
352 | pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { |
353 | self.data | |
354 | .as_ref() | |
355 | .unwrap() | |
356 | .current | |
357 | .borrow_mut() | |
358 | .node_to_node_index | |
359 | .get(dep_node) | |
360 | .cloned() | |
361 | .unwrap() | |
362 | } | |
363 | ||
0531ce1d XL |
364 | #[inline] |
365 | pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { | |
366 | if let Some(ref data) = self.data { | |
367 | data.current.borrow_mut().node_to_node_index.contains_key(dep_node) | |
368 | } else { | |
369 | false | |
370 | } | |
371 | } | |
372 | ||
ff7c6d11 XL |
373 | #[inline] |
374 | pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { | |
375 | match self.fingerprints.borrow().get(dep_node_index) { | |
abe05a73 XL |
376 | Some(&fingerprint) => fingerprint, |
377 | None => { | |
ff7c6d11 XL |
378 | if let Some(ref data) = self.data { |
379 | let dep_node = data.current.borrow().nodes[dep_node_index]; | |
380 | bug!("Could not find current fingerprint for {:?}", dep_node) | |
381 | } else { | |
382 | bug!("Could not find current fingerprint for {:?}", dep_node_index) | |
383 | } | |
abe05a73 XL |
384 | } |
385 | } | |
041b39d2 XL |
386 | } |
387 | ||
ea8adc8c XL |
388 | pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> { |
389 | self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) | |
3b2f2976 XL |
390 | } |
391 | ||
abe05a73 XL |
392 | #[inline] |
393 | pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { | |
394 | self.data.as_ref().unwrap().previous.node_to_index(dep_node) | |
395 | } | |
396 | ||
5bcae85e SL |
397 | /// Indicates that a previous work product exists for `v`. This is |
398 | /// invoked during initial start-up based on what nodes are clean | |
399 | /// (and what files exist in the incr. directory). | |
041b39d2 | 400 | pub fn insert_previous_work_product(&self, v: &WorkProductId, data: WorkProduct) { |
5bcae85e | 401 | debug!("insert_previous_work_product({:?}, {:?})", v, data); |
041b39d2 XL |
402 | self.data |
403 | .as_ref() | |
404 | .unwrap() | |
405 | .previous_work_products | |
406 | .borrow_mut() | |
407 | .insert(v.clone(), data); | |
5bcae85e SL |
408 | } |
409 | ||
410 | /// Indicates that we created the given work-product in this run | |
411 | /// for `v`. This record will be preserved and loaded in the next | |
412 | /// run. | |
041b39d2 | 413 | pub fn insert_work_product(&self, v: &WorkProductId, data: WorkProduct) { |
5bcae85e | 414 | debug!("insert_work_product({:?}, {:?})", v, data); |
041b39d2 XL |
415 | self.data |
416 | .as_ref() | |
417 | .unwrap() | |
418 | .work_products | |
419 | .borrow_mut() | |
420 | .insert(v.clone(), data); | |
54a0048b | 421 | } |
5bcae85e SL |
422 | |
423 | /// Check whether a previous work product exists for `v` and, if | |
424 | /// so, return the path that leads to it. Used to skip doing work. | |
041b39d2 XL |
425 | pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> { |
426 | self.data | |
427 | .as_ref() | |
428 | .and_then(|data| { | |
429 | data.previous_work_products.borrow().get(v).cloned() | |
430 | }) | |
5bcae85e SL |
431 | } |
432 | ||
433 | /// Access the map of work-products created during this run. Only | |
434 | /// used during saving of the dep-graph. | |
041b39d2 XL |
435 | pub fn work_products(&self) -> Ref<FxHashMap<WorkProductId, WorkProduct>> { |
436 | self.data.as_ref().unwrap().work_products.borrow() | |
5bcae85e | 437 | } |
32a655c1 SL |
438 | |
439 | /// Access the map of work-products created during the cached run. Only | |
440 | /// used during saving of the dep-graph. | |
041b39d2 XL |
441 | pub fn previous_work_products(&self) -> Ref<FxHashMap<WorkProductId, WorkProduct>> { |
442 | self.data.as_ref().unwrap().previous_work_products.borrow() | |
443 | } | |
444 | ||
445 | #[inline(always)] | |
446 | pub fn register_dep_node_debug_str<F>(&self, | |
447 | dep_node: DepNode, | |
448 | debug_str_gen: F) | |
449 | where F: FnOnce() -> String | |
450 | { | |
ea8adc8c | 451 | let dep_node_debug = &self.data.as_ref().unwrap().dep_node_debug; |
041b39d2 | 452 | |
ea8adc8c XL |
453 | if dep_node_debug.borrow().contains_key(&dep_node) { |
454 | return | |
455 | } | |
456 | let debug_str = debug_str_gen(); | |
457 | dep_node_debug.borrow_mut().insert(dep_node, debug_str); | |
041b39d2 XL |
458 | } |
459 | ||
460 | pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option<String> { | |
461 | self.data.as_ref().and_then(|t| t.dep_node_debug.borrow().get(&dep_node).cloned()) | |
32a655c1 | 462 | } |
ea8adc8c | 463 | |
abe05a73 XL |
464 | pub fn edge_deduplication_data(&self) -> (u64, u64) { |
465 | let current_dep_graph = self.data.as_ref().unwrap().current.borrow(); | |
466 | ||
467 | (current_dep_graph.total_read_count, current_dep_graph.total_duplicate_read_count) | |
468 | } | |
469 | ||
ea8adc8c | 470 | pub fn serialize(&self) -> SerializedDepGraph { |
ff7c6d11 | 471 | let mut fingerprints = self.fingerprints.borrow_mut(); |
ea8adc8c XL |
472 | let current_dep_graph = self.data.as_ref().unwrap().current.borrow(); |
473 | ||
ff7c6d11 XL |
474 | // Make sure we don't run out of bounds below. |
475 | if current_dep_graph.nodes.len() > fingerprints.len() { | |
476 | fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::ZERO); | |
477 | } | |
478 | ||
0531ce1d XL |
479 | let fingerprints = fingerprints.clone().convert_index_type(); |
480 | let nodes = current_dep_graph.nodes.clone().convert_index_type(); | |
ea8adc8c XL |
481 | |
482 | let total_edge_count: usize = current_dep_graph.edges.iter() | |
483 | .map(|v| v.len()) | |
484 | .sum(); | |
485 | ||
486 | let mut edge_list_indices = IndexVec::with_capacity(nodes.len()); | |
487 | let mut edge_list_data = Vec::with_capacity(total_edge_count); | |
488 | ||
489 | for (current_dep_node_index, edges) in current_dep_graph.edges.iter_enumerated() { | |
490 | let start = edge_list_data.len() as u32; | |
491 | // This should really just be a memcpy :/ | |
492 | edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index()))); | |
493 | let end = edge_list_data.len() as u32; | |
494 | ||
495 | debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len()); | |
496 | edge_list_indices.push((start, end)); | |
497 | } | |
498 | ||
499 | debug_assert!(edge_list_data.len() <= ::std::u32::MAX as usize); | |
500 | debug_assert_eq!(edge_list_data.len(), total_edge_count); | |
501 | ||
502 | SerializedDepGraph { | |
503 | nodes, | |
0531ce1d | 504 | fingerprints, |
ea8adc8c XL |
505 | edge_list_indices, |
506 | edge_list_data, | |
507 | } | |
508 | } | |
509 | ||
510 | pub fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> { | |
0531ce1d XL |
511 | if let Some(ref data) = self.data { |
512 | if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { | |
513 | return data.colors.borrow().get(prev_index) | |
514 | } else { | |
515 | // This is a node that did not exist in the previous compilation | |
516 | // session, so we consider it to be red. | |
517 | return Some(DepNodeColor::Red) | |
518 | } | |
519 | } | |
520 | ||
521 | None | |
ea8adc8c XL |
522 | } |
523 | ||
ff7c6d11 XL |
524 | pub fn try_mark_green<'tcx>(&self, |
525 | tcx: TyCtxt<'_, 'tcx, 'tcx>, | |
526 | dep_node: &DepNode) | |
527 | -> Option<DepNodeIndex> { | |
ea8adc8c XL |
528 | debug!("try_mark_green({:?}) - BEGIN", dep_node); |
529 | let data = self.data.as_ref().unwrap(); | |
530 | ||
ea8adc8c XL |
531 | debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node)); |
532 | ||
533 | if dep_node.kind.is_input() { | |
534 | // We should only hit try_mark_green() for inputs that do not exist | |
535 | // anymore in the current compilation session. Existing inputs are | |
536 | // eagerly marked as either red/green before any queries are | |
537 | // executed. | |
538 | debug_assert!(dep_node.extract_def_id(tcx).is_none()); | |
539 | debug!("try_mark_green({:?}) - END - DepNode is deleted input", dep_node); | |
540 | return None; | |
541 | } | |
542 | ||
543 | let (prev_deps, prev_dep_node_index) = match data.previous.edges_from(dep_node) { | |
544 | Some(prev) => { | |
545 | // This DepNode and the corresponding query invocation existed | |
546 | // in the previous compilation session too, so we can try to | |
547 | // mark it as green by recursively marking all of its | |
548 | // dependencies green. | |
549 | prev | |
550 | } | |
551 | None => { | |
552 | // This DepNode did not exist in the previous compilation session, | |
553 | // so we cannot mark it as green. | |
554 | debug!("try_mark_green({:?}) - END - DepNode does not exist in \ | |
555 | current compilation session anymore", dep_node); | |
556 | return None | |
557 | } | |
558 | }; | |
559 | ||
0531ce1d XL |
560 | debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none()); |
561 | ||
ea8adc8c XL |
562 | let mut current_deps = Vec::new(); |
563 | ||
564 | for &dep_dep_node_index in prev_deps { | |
0531ce1d | 565 | let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); |
ea8adc8c | 566 | |
ea8adc8c XL |
567 | match dep_dep_node_color { |
568 | Some(DepNodeColor::Green(node_index)) => { | |
569 | // This dependency has been marked as green before, we are | |
570 | // still fine and can continue with checking the other | |
571 | // dependencies. | |
572 | debug!("try_mark_green({:?}) --- found dependency {:?} to \ | |
0531ce1d XL |
573 | be immediately green", |
574 | dep_node, | |
575 | data.previous.index_to_node(dep_dep_node_index)); | |
ea8adc8c XL |
576 | current_deps.push(node_index); |
577 | } | |
578 | Some(DepNodeColor::Red) => { | |
579 | // We found a dependency the value of which has changed | |
580 | // compared to the previous compilation session. We cannot | |
581 | // mark the DepNode as green and also don't need to bother | |
582 | // with checking any of the other dependencies. | |
583 | debug!("try_mark_green({:?}) - END - dependency {:?} was \ | |
0531ce1d XL |
584 | immediately red", |
585 | dep_node, | |
586 | data.previous.index_to_node(dep_dep_node_index)); | |
ea8adc8c XL |
587 | return None |
588 | } | |
589 | None => { | |
0531ce1d XL |
590 | let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); |
591 | ||
abe05a73 XL |
592 | // We don't know the state of this dependency. If it isn't |
593 | // an input node, let's try to mark it green recursively. | |
594 | if !dep_dep_node.kind.is_input() { | |
595 | debug!("try_mark_green({:?}) --- state of dependency {:?} \ | |
596 | is unknown, trying to mark it green", dep_node, | |
597 | dep_dep_node); | |
598 | ||
599 | if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) { | |
600 | debug!("try_mark_green({:?}) --- managed to MARK \ | |
601 | dependency {:?} as green", dep_node, dep_dep_node); | |
602 | current_deps.push(node_index); | |
603 | continue; | |
604 | } | |
ea8adc8c | 605 | } else { |
abe05a73 XL |
606 | match dep_dep_node.kind { |
607 | DepKind::Hir | | |
608 | DepKind::HirBody | | |
609 | DepKind::CrateMetadata => { | |
610 | if dep_node.extract_def_id(tcx).is_none() { | |
611 | // If the node does not exist anymore, we | |
612 | // just fail to mark green. | |
ea8adc8c | 613 | return None |
abe05a73 XL |
614 | } else { |
615 | // If the node does exist, it should have | |
616 | // been pre-allocated. | |
617 | bug!("DepNode {:?} should have been \ | |
618 | pre-allocated but wasn't.", | |
619 | dep_dep_node) | |
ea8adc8c | 620 | } |
ea8adc8c | 621 | } |
abe05a73 XL |
622 | _ => { |
623 | // For other kinds of inputs it's OK to be | |
624 | // forced. | |
625 | } | |
ea8adc8c XL |
626 | } |
627 | } | |
abe05a73 XL |
628 | |
629 | // We failed to mark it green, so we try to force the query. | |
630 | debug!("try_mark_green({:?}) --- trying to force \ | |
631 | dependency {:?}", dep_node, dep_dep_node); | |
632 | if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) { | |
0531ce1d XL |
633 | let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); |
634 | ||
abe05a73 XL |
635 | match dep_dep_node_color { |
636 | Some(DepNodeColor::Green(node_index)) => { | |
637 | debug!("try_mark_green({:?}) --- managed to \ | |
638 | FORCE dependency {:?} to green", | |
639 | dep_node, dep_dep_node); | |
640 | current_deps.push(node_index); | |
641 | } | |
642 | Some(DepNodeColor::Red) => { | |
643 | debug!("try_mark_green({:?}) - END - \ | |
644 | dependency {:?} was red after forcing", | |
645 | dep_node, | |
646 | dep_dep_node); | |
647 | return None | |
648 | } | |
649 | None => { | |
0531ce1d XL |
650 | if !tcx.sess.has_errors() { |
651 | bug!("try_mark_green() - Forcing the DepNode \ | |
652 | should have set its color") | |
653 | } else { | |
654 | // If the query we just forced has resulted | |
655 | // in some kind of compilation error, we | |
656 | // don't expect that the corresponding | |
657 | // dep-node color has been updated. | |
658 | } | |
abe05a73 XL |
659 | } |
660 | } | |
661 | } else { | |
662 | // The DepNode could not be forced. | |
663 | debug!("try_mark_green({:?}) - END - dependency {:?} \ | |
664 | could not be forced", dep_node, dep_dep_node); | |
665 | return None | |
666 | } | |
ea8adc8c XL |
667 | } |
668 | } | |
669 | } | |
670 | ||
671 | ||
672 | // If we got here without hitting a `return` that means that all | |
673 | // dependencies of this DepNode could be marked as green. Therefore we | |
674 | // can also mark this DepNode as green. We do so by... | |
675 | ||
676 | // ... allocating an entry for it in the current dependency graph and | |
677 | // adding all the appropriate edges imported from the previous graph ... | |
678 | let dep_node_index = data.current | |
679 | .borrow_mut() | |
680 | .alloc_node(*dep_node, current_deps); | |
681 | ||
682 | // ... copying the fingerprint from the previous graph too, so we don't | |
683 | // have to recompute it ... | |
ff7c6d11 XL |
684 | { |
685 | let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index); | |
686 | let mut fingerprints = self.fingerprints.borrow_mut(); | |
687 | ||
688 | if dep_node_index.index() >= fingerprints.len() { | |
689 | fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO); | |
690 | } | |
691 | ||
692 | debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO, | |
693 | "DepGraph::try_mark_green() - Duplicate fingerprint \ | |
694 | insertion for {:?}", dep_node); | |
695 | ||
696 | fingerprints[dep_node_index] = fingerprint; | |
697 | } | |
ea8adc8c | 698 | |
abe05a73 XL |
699 | // ... emitting any stored diagnostic ... |
700 | { | |
701 | let diagnostics = tcx.on_disk_query_result_cache | |
ff7c6d11 | 702 | .load_diagnostics(tcx, prev_dep_node_index); |
abe05a73 XL |
703 | |
704 | if diagnostics.len() > 0 { | |
705 | let handle = tcx.sess.diagnostic(); | |
706 | ||
707 | // Promote the previous diagnostics to the current session. | |
708 | tcx.on_disk_query_result_cache | |
709 | .store_diagnostics(dep_node_index, diagnostics.clone()); | |
710 | ||
711 | for diagnostic in diagnostics { | |
712 | DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); | |
713 | } | |
714 | } | |
715 | } | |
716 | ||
ea8adc8c | 717 | // ... and finally storing a "Green" entry in the color map. |
0531ce1d XL |
718 | let mut colors = data.colors.borrow_mut(); |
719 | debug_assert!(colors.get(prev_dep_node_index).is_none(), | |
ea8adc8c XL |
720 | "DepGraph::try_mark_green() - Duplicate DepNodeColor \ |
721 | insertion for {:?}", dep_node); | |
722 | ||
0531ce1d XL |
723 | colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); |
724 | ||
ea8adc8c XL |
725 | debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node); |
726 | Some(dep_node_index) | |
727 | } | |
728 | ||
0531ce1d XL |
729 | // Returns true if the given node has been marked as green during the |
730 | // current compilation session. Used in various assertions | |
731 | pub fn is_green(&self, dep_node: &DepNode) -> bool { | |
732 | self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) | |
ea8adc8c XL |
733 | } |
734 | ||
ff7c6d11 XL |
735 | // This method loads all on-disk cacheable query results into memory, so |
736 | // they can be written out to the new cache file again. Most query results | |
737 | // will already be in memory but in the case where we marked something as | |
738 | // green but then did not need the value, that value will never have been | |
739 | // loaded from disk. | |
740 | // | |
741 | // This method will only load queries that will end up in the disk cache. | |
742 | // Other queries will not be executed. | |
743 | pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { | |
744 | let green_nodes: Vec<DepNode> = { | |
745 | let data = self.data.as_ref().unwrap(); | |
0531ce1d XL |
746 | let colors = data.colors.borrow(); |
747 | colors.values.indices().filter_map(|prev_index| { | |
748 | match colors.get(prev_index) { | |
749 | Some(DepNodeColor::Green(_)) => { | |
750 | let dep_node = data.previous.index_to_node(prev_index); | |
751 | if dep_node.cache_on_disk(tcx) { | |
752 | Some(dep_node) | |
753 | } else { | |
754 | None | |
755 | } | |
756 | } | |
757 | None | | |
758 | Some(DepNodeColor::Red) => { | |
759 | // We can skip red nodes because a node can only be marked | |
760 | // as red if the query result was recomputed and thus is | |
761 | // already in memory. | |
ff7c6d11 XL |
762 | None |
763 | } | |
764 | } | |
ff7c6d11 XL |
765 | }).collect() |
766 | }; | |
767 | ||
768 | for dep_node in green_nodes { | |
769 | dep_node.load_from_on_disk_cache(tcx); | |
770 | } | |
771 | } | |
772 | ||
ea8adc8c XL |
773 | pub fn mark_loaded_from_cache(&self, dep_node_index: DepNodeIndex, state: bool) { |
774 | debug!("mark_loaded_from_cache({:?}, {})", | |
775 | self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index], | |
776 | state); | |
777 | ||
778 | self.data | |
779 | .as_ref() | |
780 | .unwrap() | |
781 | .loaded_from_cache | |
782 | .borrow_mut() | |
783 | .insert(dep_node_index, state); | |
784 | } | |
785 | ||
786 | pub fn was_loaded_from_cache(&self, dep_node: &DepNode) -> Option<bool> { | |
787 | let data = self.data.as_ref().unwrap(); | |
788 | let dep_node_index = data.current.borrow().node_to_node_index[dep_node]; | |
789 | data.loaded_from_cache.borrow().get(&dep_node_index).cloned() | |
790 | } | |
5bcae85e SL |
791 | } |
792 | ||
793 | /// A "work product" is an intermediate result that we save into the | |
794 | /// incremental directory for later re-use. The primary example are | |
795 | /// the object files that we save for each partition at code | |
796 | /// generation time. | |
797 | /// | |
798 | /// Each work product is associated with a dep-node, representing the | |
799 | /// process that produced the work-product. If that dep-node is found | |
800 | /// to be dirty when we load up, then we will delete the work-product | |
801 | /// at load time. If the work-product is found to be clean, then we | |
802 | /// will keep a record in the `previous_work_products` list. | |
803 | /// | |
804 | /// In addition, work products have an associated hash. This hash is | |
805 | /// an extra hash that can be used to decide if the work-product from | |
806 | /// a previous compilation can be re-used (in addition to the dirty | |
807 | /// edges check). | |
808 | /// | |
809 | /// As the primary example, consider the object files we generate for | |
810 | /// each partition. In the first run, we create partitions based on | |
811 | /// the symbols that need to be compiled. For each partition P, we | |
812 | /// hash the symbols in P and create a `WorkProduct` record associated | |
813 | /// with `DepNode::TransPartition(P)`; the hash is the set of symbols | |
814 | /// in P. | |
815 | /// | |
816 | /// The next time we compile, if the `DepNode::TransPartition(P)` is | |
817 | /// judged to be clean (which means none of the things we read to | |
818 | /// generate the partition were found to be dirty), it will be loaded | |
819 | /// into previous work products. We will then regenerate the set of | |
820 | /// symbols in the partition P and hash them (note that new symbols | |
821 | /// may be added -- for example, new monomorphizations -- even if | |
822 | /// nothing in P changed!). We will compare that hash against the | |
823 | /// previous hash. If it matches up, we can reuse the object file. | |
824 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
825 | pub struct WorkProduct { | |
041b39d2 | 826 | pub cgu_name: String, |
5bcae85e | 827 | /// Saved files associated with this CGU |
abe05a73 XL |
828 | pub saved_files: Vec<(WorkProductFileKind, String)>, |
829 | } | |
830 | ||
831 | #[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)] | |
832 | pub enum WorkProductFileKind { | |
833 | Object, | |
834 | Bytecode, | |
835 | BytecodeCompressed, | |
54a0048b | 836 | } |
ea8adc8c XL |
837 | |
838 | pub(super) struct CurrentDepGraph { | |
839 | nodes: IndexVec<DepNodeIndex, DepNode>, | |
840 | edges: IndexVec<DepNodeIndex, Vec<DepNodeIndex>>, | |
841 | node_to_node_index: FxHashMap<DepNode, DepNodeIndex>, | |
842 | task_stack: Vec<OpenTask>, | |
843 | forbidden_edge: Option<EdgeFilter>, | |
844 | ||
845 | // Anonymous DepNodes are nodes the ID of which we compute from the list of | |
846 | // their edges. This has the beneficial side-effect that multiple anonymous | |
847 | // nodes can be coalesced into one without changing the semantics of the | |
848 | // dependency graph. However, the merging of nodes can lead to a subtle | |
849 | // problem during red-green marking: The color of an anonymous node from | |
850 | // the current session might "shadow" the color of the node with the same | |
851 | // ID from the previous session. In order to side-step this problem, we make | |
852 | // sure that anon-node IDs allocated in different sessions don't overlap. | |
853 | // This is implemented by mixing a session-key into the ID fingerprint of | |
854 | // each anon node. The session-key is just a random number generated when | |
855 | // the DepGraph is created. | |
856 | anon_id_seed: Fingerprint, | |
abe05a73 XL |
857 | |
858 | total_read_count: u64, | |
859 | total_duplicate_read_count: u64, | |
ea8adc8c XL |
860 | } |
861 | ||
862 | impl CurrentDepGraph { | |
863 | fn new() -> CurrentDepGraph { | |
864 | use std::time::{SystemTime, UNIX_EPOCH}; | |
865 | ||
866 | let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); | |
867 | let nanos = duration.as_secs() * 1_000_000_000 + | |
868 | duration.subsec_nanos() as u64; | |
869 | let mut stable_hasher = StableHasher::new(); | |
870 | nanos.hash(&mut stable_hasher); | |
871 | ||
872 | let forbidden_edge = if cfg!(debug_assertions) { | |
873 | match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { | |
874 | Ok(s) => { | |
875 | match EdgeFilter::new(&s) { | |
876 | Ok(f) => Some(f), | |
877 | Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), | |
878 | } | |
879 | } | |
880 | Err(_) => None, | |
881 | } | |
882 | } else { | |
883 | None | |
884 | }; | |
885 | ||
886 | CurrentDepGraph { | |
887 | nodes: IndexVec::new(), | |
888 | edges: IndexVec::new(), | |
889 | node_to_node_index: FxHashMap(), | |
890 | anon_id_seed: stable_hasher.finish(), | |
891 | task_stack: Vec::new(), | |
892 | forbidden_edge, | |
abe05a73 XL |
893 | total_read_count: 0, |
894 | total_duplicate_read_count: 0, | |
ea8adc8c XL |
895 | } |
896 | } | |
897 | ||
898 | pub(super) fn push_ignore(&mut self) { | |
899 | self.task_stack.push(OpenTask::Ignore); | |
900 | } | |
901 | ||
902 | pub(super) fn pop_ignore(&mut self) { | |
903 | let popped_node = self.task_stack.pop().unwrap(); | |
904 | debug_assert_eq!(popped_node, OpenTask::Ignore); | |
905 | } | |
906 | ||
907 | pub(super) fn push_task(&mut self, key: DepNode) { | |
908 | self.task_stack.push(OpenTask::Regular { | |
909 | node: key, | |
910 | reads: Vec::new(), | |
911 | read_set: FxHashSet(), | |
912 | }); | |
913 | } | |
914 | ||
915 | pub(super) fn pop_task(&mut self, key: DepNode) -> DepNodeIndex { | |
916 | let popped_node = self.task_stack.pop().unwrap(); | |
917 | ||
918 | if let OpenTask::Regular { | |
919 | node, | |
920 | read_set: _, | |
921 | reads | |
922 | } = popped_node { | |
abe05a73 XL |
923 | assert_eq!(node, key); |
924 | ||
925 | // If this is an input node, we expect that it either has no | |
926 | // dependencies, or that it just depends on DepKind::CrateMetadata | |
927 | // or DepKind::Krate. This happens for some "thin wrapper queries" | |
928 | // like `crate_disambiguator` which sometimes have zero deps (for | |
929 | // when called for LOCAL_CRATE) or they depend on a CrateMetadata | |
930 | // node. | |
931 | if cfg!(debug_assertions) { | |
932 | if node.kind.is_input() && reads.len() > 0 && | |
933 | // FIXME(mw): Special case for DefSpan until Spans are handled | |
934 | // better in general. | |
935 | node.kind != DepKind::DefSpan && | |
936 | reads.iter().any(|&i| { | |
937 | !(self.nodes[i].kind == DepKind::CrateMetadata || | |
938 | self.nodes[i].kind == DepKind::Krate) | |
939 | }) | |
940 | { | |
941 | bug!("Input node {:?} with unexpected reads: {:?}", | |
942 | node, | |
943 | reads.iter().map(|&i| self.nodes[i]).collect::<Vec<_>>()) | |
944 | } | |
945 | } | |
946 | ||
ea8adc8c XL |
947 | self.alloc_node(node, reads) |
948 | } else { | |
949 | bug!("pop_task() - Expected regular task to be popped") | |
950 | } | |
951 | } | |
952 | ||
953 | fn push_anon_task(&mut self) { | |
954 | self.task_stack.push(OpenTask::Anon { | |
955 | reads: Vec::new(), | |
956 | read_set: FxHashSet(), | |
957 | }); | |
958 | } | |
959 | ||
960 | fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndex { | |
961 | let popped_node = self.task_stack.pop().unwrap(); | |
962 | ||
963 | if let OpenTask::Anon { | |
964 | read_set: _, | |
965 | reads | |
966 | } = popped_node { | |
abe05a73 XL |
967 | debug_assert!(!kind.is_input()); |
968 | ||
ea8adc8c XL |
969 | let mut fingerprint = self.anon_id_seed; |
970 | let mut hasher = StableHasher::new(); | |
971 | ||
972 | for &read in reads.iter() { | |
973 | let read_dep_node = self.nodes[read]; | |
974 | ||
975 | ::std::mem::discriminant(&read_dep_node.kind).hash(&mut hasher); | |
976 | ||
977 | // Fingerprint::combine() is faster than sending Fingerprint | |
978 | // through the StableHasher (at least as long as StableHasher | |
979 | // is so slow). | |
980 | fingerprint = fingerprint.combine(read_dep_node.hash); | |
981 | } | |
982 | ||
983 | fingerprint = fingerprint.combine(hasher.finish()); | |
984 | ||
985 | let target_dep_node = DepNode { | |
986 | kind, | |
987 | hash: fingerprint, | |
988 | }; | |
989 | ||
990 | if let Some(&index) = self.node_to_node_index.get(&target_dep_node) { | |
991 | index | |
992 | } else { | |
993 | self.alloc_node(target_dep_node, reads) | |
994 | } | |
995 | } else { | |
996 | bug!("pop_anon_task() - Expected anonymous task to be popped") | |
997 | } | |
998 | } | |
999 | ||
abe05a73 XL |
1000 | fn push_eval_always_task(&mut self, key: DepNode) { |
1001 | self.task_stack.push(OpenTask::EvalAlways { node: key }); | |
1002 | } | |
1003 | ||
1004 | fn pop_eval_always_task(&mut self, key: DepNode) -> DepNodeIndex { | |
1005 | let popped_node = self.task_stack.pop().unwrap(); | |
1006 | ||
1007 | if let OpenTask::EvalAlways { | |
1008 | node, | |
1009 | } = popped_node { | |
1010 | debug_assert_eq!(node, key); | |
1011 | let krate_idx = self.node_to_node_index[&DepNode::new_no_params(DepKind::Krate)]; | |
1012 | self.alloc_node(node, vec![krate_idx]) | |
1013 | } else { | |
1014 | bug!("pop_eval_always_task() - Expected eval always task to be popped"); | |
1015 | } | |
1016 | } | |
1017 | ||
ea8adc8c XL |
1018 | fn read_index(&mut self, source: DepNodeIndex) { |
1019 | match self.task_stack.last_mut() { | |
1020 | Some(&mut OpenTask::Regular { | |
1021 | ref mut reads, | |
1022 | ref mut read_set, | |
1023 | node: ref target, | |
1024 | }) => { | |
abe05a73 | 1025 | self.total_read_count += 1; |
ea8adc8c XL |
1026 | if read_set.insert(source) { |
1027 | reads.push(source); | |
1028 | ||
1029 | if cfg!(debug_assertions) { | |
1030 | if let Some(ref forbidden_edge) = self.forbidden_edge { | |
1031 | let source = self.nodes[source]; | |
1032 | if forbidden_edge.test(&source, &target) { | |
1033 | bug!("forbidden edge {:?} -> {:?} created", | |
1034 | source, | |
1035 | target) | |
1036 | } | |
1037 | } | |
1038 | } | |
abe05a73 XL |
1039 | } else { |
1040 | self.total_duplicate_read_count += 1; | |
ea8adc8c XL |
1041 | } |
1042 | } | |
1043 | Some(&mut OpenTask::Anon { | |
1044 | ref mut reads, | |
1045 | ref mut read_set, | |
1046 | }) => { | |
1047 | if read_set.insert(source) { | |
1048 | reads.push(source); | |
1049 | } | |
1050 | } | |
abe05a73 XL |
1051 | Some(&mut OpenTask::Ignore) | |
1052 | Some(&mut OpenTask::EvalAlways { .. }) | None => { | |
ea8adc8c XL |
1053 | // ignore |
1054 | } | |
1055 | } | |
1056 | } | |
1057 | ||
1058 | fn alloc_node(&mut self, | |
1059 | dep_node: DepNode, | |
1060 | edges: Vec<DepNodeIndex>) | |
1061 | -> DepNodeIndex { | |
1062 | debug_assert_eq!(self.edges.len(), self.nodes.len()); | |
1063 | debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len()); | |
1064 | debug_assert!(!self.node_to_node_index.contains_key(&dep_node)); | |
1065 | let dep_node_index = DepNodeIndex::new(self.nodes.len()); | |
1066 | self.nodes.push(dep_node); | |
1067 | self.node_to_node_index.insert(dep_node, dep_node_index); | |
1068 | self.edges.push(edges); | |
1069 | dep_node_index | |
1070 | } | |
1071 | } | |
1072 | ||
1073 | #[derive(Clone, Debug, PartialEq)] | |
1074 | enum OpenTask { | |
1075 | Regular { | |
1076 | node: DepNode, | |
1077 | reads: Vec<DepNodeIndex>, | |
1078 | read_set: FxHashSet<DepNodeIndex>, | |
1079 | }, | |
1080 | Anon { | |
1081 | reads: Vec<DepNodeIndex>, | |
1082 | read_set: FxHashSet<DepNodeIndex>, | |
1083 | }, | |
1084 | Ignore, | |
abe05a73 XL |
1085 | EvalAlways { |
1086 | node: DepNode, | |
1087 | }, | |
ea8adc8c | 1088 | } |
0531ce1d XL |
1089 | |
1090 | // A data structure that stores Option<DepNodeColor> values as a contiguous | |
1091 | // array, using one u32 per entry. | |
1092 | struct DepNodeColorMap { | |
1093 | values: IndexVec<SerializedDepNodeIndex, u32>, | |
1094 | } | |
1095 | ||
1096 | const COMPRESSED_NONE: u32 = 0; | |
1097 | const COMPRESSED_RED: u32 = 1; | |
1098 | const COMPRESSED_FIRST_GREEN: u32 = 2; | |
1099 | ||
1100 | impl DepNodeColorMap { | |
1101 | fn new(size: usize) -> DepNodeColorMap { | |
1102 | DepNodeColorMap { | |
1103 | values: IndexVec::from_elem_n(COMPRESSED_NONE, size) | |
1104 | } | |
1105 | } | |
1106 | ||
1107 | fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> { | |
1108 | match self.values[index] { | |
1109 | COMPRESSED_NONE => None, | |
1110 | COMPRESSED_RED => Some(DepNodeColor::Red), | |
1111 | value => Some(DepNodeColor::Green(DepNodeIndex(value - COMPRESSED_FIRST_GREEN))) | |
1112 | } | |
1113 | } | |
1114 | ||
1115 | fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) { | |
1116 | self.values[index] = match color { | |
1117 | DepNodeColor::Red => COMPRESSED_RED, | |
1118 | DepNodeColor::Green(index) => index.0 + COMPRESSED_FIRST_GREEN, | |
1119 | } | |
1120 | } | |
1121 | } |