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