1use std::assert_matches::assert_matches;
2use std::fmt::Debug;
3use std::hash::Hash;
4use std::marker::PhantomData;
5use std::sync::Arc;
6use std::sync::atomic::{AtomicU32, Ordering};
7
8use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
9use rustc_data_structures::fx::{FxHashMap, FxHashSet};
10use rustc_data_structures::profiling::{QueryInvocationId, SelfProfilerRef};
11use rustc_data_structures::sharded::{self, ShardedHashMap};
12use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
13use rustc_data_structures::sync::{AtomicU64, Lock};
14use rustc_data_structures::unord::UnordMap;
15use rustc_errors::DiagInner;
16use rustc_index::IndexVec;
17use rustc_macros::{Decodable, Encodable};
18use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
19use tracing::{debug, instrument};
20#[cfg(debug_assertions)]
21use {super::debug::EdgeFilter, std::env};
22
23use super::query::DepGraphQuery;
24use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
25use super::{DepContext, DepKind, DepNode, Deps, HasDepContext, WorkProductId};
26use crate::dep_graph::edges::EdgesVec;
27use crate::ich::StableHashingContext;
28use crate::query::{QueryContext, QuerySideEffect};
29
30#[derive(Clone)]
31pub struct DepGraph<D: Deps> {
32 data: Option<Arc<DepGraphData<D>>>,
33
34 virtual_dep_node_index: Arc<AtomicU32>,
39}
40
41rustc_index::newtype_index! {
42 pub struct DepNodeIndex {}
43}
44
45rustc_data_structures::static_assert_size!(Option<DepNodeIndex>, 4);
49
50impl DepNodeIndex {
51 const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::ZERO;
52 pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
53}
54
55impl From<DepNodeIndex> for QueryInvocationId {
56 #[inline(always)]
57 fn from(dep_node_index: DepNodeIndex) -> Self {
58 QueryInvocationId(dep_node_index.as_u32())
59 }
60}
61
62pub struct MarkFrame<'a> {
63 index: SerializedDepNodeIndex,
64 parent: Option<&'a MarkFrame<'a>>,
65}
66
67enum DepNodeColor {
68 Red,
69 Green(DepNodeIndex),
70}
71
72impl DepNodeColor {
73 #[inline]
74 fn is_green(self) -> bool {
75 match self {
76 DepNodeColor::Red => false,
77 DepNodeColor::Green(_) => true,
78 }
79 }
80}
81
82pub(crate) struct DepGraphData<D: Deps> {
83 current: CurrentDepGraph<D>,
88
89 previous: Arc<SerializedDepGraph>,
92
93 colors: DepNodeColorMap,
94
95 previous_work_products: WorkProductMap,
100
101 dep_node_debug: Lock<FxHashMap<DepNode, String>>,
102
103 debug_loaded_from_disk: Lock<FxHashSet<DepNode>>,
107}
108
109pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint
110where
111 R: for<'a> HashStable<StableHashingContext<'a>>,
112{
113 let mut stable_hasher = StableHasher::new();
114 result.hash_stable(hcx, &mut stable_hasher);
115 stable_hasher.finish()
116}
117
118impl<D: Deps> DepGraph<D> {
119 pub fn new(
120 profiler: &SelfProfilerRef,
121 prev_graph: Arc<SerializedDepGraph>,
122 prev_work_products: WorkProductMap,
123 encoder: FileEncoder,
124 record_graph: bool,
125 record_stats: bool,
126 ) -> DepGraph<D> {
127 let prev_graph_node_count = prev_graph.node_count();
128
129 let current = CurrentDepGraph::new(
130 profiler,
131 prev_graph_node_count,
132 encoder,
133 record_graph,
134 record_stats,
135 Arc::clone(&prev_graph),
136 );
137
138 let colors = DepNodeColorMap::new(prev_graph_node_count);
139
140 let _green_node_index = current.intern_new_node(
142 DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() },
143 EdgesVec::new(),
144 Fingerprint::ZERO,
145 );
146 assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
147
148 let (red_node_index, red_node_prev_index_and_color) = current.intern_node(
150 &prev_graph,
151 DepNode { kind: D::DEP_KIND_RED, hash: Fingerprint::ZERO.into() },
152 EdgesVec::new(),
153 None,
154 );
155 assert_eq!(red_node_index, DepNodeIndex::FOREVER_RED_NODE);
156 match red_node_prev_index_and_color {
157 None => {
158 assert!(prev_graph_node_count == 0);
160 }
161 Some((prev_red_node_index, DepNodeColor::Red)) => {
162 assert_eq!(prev_red_node_index.as_usize(), red_node_index.as_usize());
163 colors.insert(prev_red_node_index, DepNodeColor::Red);
164 }
165 Some((_, DepNodeColor::Green(_))) => {
166 panic!("DepNodeIndex::FOREVER_RED_NODE evaluated to DepNodeColor::Green")
168 }
169 }
170
171 DepGraph {
172 data: Some(Arc::new(DepGraphData {
173 previous_work_products: prev_work_products,
174 dep_node_debug: Default::default(),
175 current,
176 previous: prev_graph,
177 colors,
178 debug_loaded_from_disk: Default::default(),
179 })),
180 virtual_dep_node_index: Arc::new(AtomicU32::new(0)),
181 }
182 }
183
184 pub fn new_disabled() -> DepGraph<D> {
185 DepGraph { data: None, virtual_dep_node_index: Arc::new(AtomicU32::new(0)) }
186 }
187
188 #[inline]
189 pub(crate) fn data(&self) -> Option<&DepGraphData<D>> {
190 self.data.as_deref()
191 }
192
193 #[inline]
195 pub fn is_fully_enabled(&self) -> bool {
196 self.data.is_some()
197 }
198
199 pub fn with_query(&self, f: impl Fn(&DepGraphQuery)) {
200 if let Some(data) = &self.data {
201 data.current.encoder.with_query(f)
202 }
203 }
204
205 pub fn assert_ignored(&self) {
206 if let Some(..) = self.data {
207 D::read_deps(|task_deps| {
208 assert_matches!(
209 task_deps,
210 TaskDepsRef::Ignore,
211 "expected no task dependency tracking"
212 );
213 })
214 }
215 }
216
217 pub fn with_ignore<OP, R>(&self, op: OP) -> R
218 where
219 OP: FnOnce() -> R,
220 {
221 D::with_deps(TaskDepsRef::Ignore, op)
222 }
223
224 pub fn with_query_deserialization<OP, R>(&self, op: OP) -> R
271 where
272 OP: FnOnce() -> R,
273 {
274 D::with_deps(TaskDepsRef::Forbid, op)
275 }
276
277 #[inline(always)]
278 pub fn with_task<Ctxt: HasDepContext<Deps = D>, A: Debug, R>(
279 &self,
280 key: DepNode,
281 cx: Ctxt,
282 arg: A,
283 task: fn(Ctxt, A) -> R,
284 hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
285 ) -> (R, DepNodeIndex) {
286 match self.data() {
287 Some(data) => data.with_task(key, cx, arg, task, hash_result),
288 None => (task(cx, arg), self.next_virtual_depnode_index()),
289 }
290 }
291
292 pub fn with_anon_task<Tcx: DepContext<Deps = D>, OP, R>(
293 &self,
294 cx: Tcx,
295 dep_kind: DepKind,
296 op: OP,
297 ) -> (R, DepNodeIndex)
298 where
299 OP: FnOnce() -> R,
300 {
301 match self.data() {
302 Some(data) => {
303 let (result, index) = data.with_anon_task_inner(cx, dep_kind, op);
304 self.read_index(index);
305 (result, index)
306 }
307 None => (op(), self.next_virtual_depnode_index()),
308 }
309 }
310}
311
312impl<D: Deps> DepGraphData<D> {
313 #[inline(always)]
341 pub(crate) fn with_task<Ctxt: HasDepContext<Deps = D>, A: Debug, R>(
342 &self,
343 key: DepNode,
344 cx: Ctxt,
345 arg: A,
346 task: fn(Ctxt, A) -> R,
347 hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
348 ) -> (R, DepNodeIndex) {
349 assert!(
355 !self.dep_node_exists(&key),
356 "forcing query with already existing `DepNode`\n\
357 - query-key: {arg:?}\n\
358 - dep-node: {key:?}"
359 );
360
361 let with_deps = |task_deps| D::with_deps(task_deps, || task(cx, arg));
362 let (result, edges) = if cx.dep_context().is_eval_always(key.kind) {
363 (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new())
364 } else {
365 let task_deps = Lock::new(TaskDeps {
366 #[cfg(debug_assertions)]
367 node: Some(key),
368 reads: EdgesVec::new(),
369 read_set: Default::default(),
370 phantom_data: PhantomData,
371 });
372 (with_deps(TaskDepsRef::Allow(&task_deps)), task_deps.into_inner().reads)
373 };
374
375 let dcx = cx.dep_context();
376 let dep_node_index =
377 self.hash_result_and_intern_node(dcx, key, edges, &result, hash_result);
378
379 (result, dep_node_index)
380 }
381
382 pub(crate) fn with_anon_task_inner<Tcx: DepContext<Deps = D>, OP, R>(
394 &self,
395 cx: Tcx,
396 dep_kind: DepKind,
397 op: OP,
398 ) -> (R, DepNodeIndex)
399 where
400 OP: FnOnce() -> R,
401 {
402 debug_assert!(!cx.is_eval_always(dep_kind));
403
404 let task_deps = Lock::new(TaskDeps::default());
405 let result = D::with_deps(TaskDepsRef::Allow(&task_deps), op);
406 let task_deps = task_deps.into_inner();
407 let task_deps = task_deps.reads;
408
409 let dep_node_index = match task_deps.len() {
410 0 => {
411 DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE
417 }
418 1 => {
419 task_deps[0]
421 }
422 _ => {
423 let mut hasher = StableHasher::new();
429 task_deps.hash(&mut hasher);
430
431 let target_dep_node = DepNode {
432 kind: dep_kind,
433 hash: self.current.anon_id_seed.combine(hasher.finish()).into(),
437 };
438
439 self.current.intern_new_node(target_dep_node, task_deps, Fingerprint::ZERO)
440 }
441 };
442
443 (result, dep_node_index)
444 }
445
446 fn hash_result_and_intern_node<Ctxt: DepContext<Deps = D>, R>(
448 &self,
449 cx: &Ctxt,
450 node: DepNode,
451 edges: EdgesVec,
452 result: &R,
453 hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
454 ) -> DepNodeIndex {
455 let hashing_timer = cx.profiler().incr_result_hashing();
456 let current_fingerprint = hash_result.map(|hash_result| {
457 cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result))
458 });
459
460 let (dep_node_index, prev_and_color) =
462 self.current.intern_node(&self.previous, node, edges, current_fingerprint);
463
464 hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
465
466 if let Some((prev_index, color)) = prev_and_color {
467 debug_assert!(
468 self.colors.get(prev_index).is_none(),
469 "DepGraph::with_task() - Duplicate DepNodeColor insertion for {node:?}",
470 );
471
472 self.colors.insert(prev_index, color);
473 }
474
475 dep_node_index
476 }
477}
478
479impl<D: Deps> DepGraph<D> {
480 #[inline]
481 pub fn read_index(&self, dep_node_index: DepNodeIndex) {
482 if let Some(ref data) = self.data {
483 D::read_deps(|task_deps| {
484 let mut task_deps = match task_deps {
485 TaskDepsRef::Allow(deps) => deps.lock(),
486 TaskDepsRef::EvalAlways => {
487 return;
490 }
491 TaskDepsRef::Ignore => return,
492 TaskDepsRef::Forbid => {
493 panic_on_forbidden_read(data, dep_node_index)
495 }
496 };
497 let task_deps = &mut *task_deps;
498
499 if cfg!(debug_assertions) {
500 data.current.total_read_count.fetch_add(1, Ordering::Relaxed);
501 }
502
503 let new_read = if task_deps.reads.len() < EdgesVec::INLINE_CAPACITY {
506 task_deps.reads.iter().all(|other| *other != dep_node_index)
507 } else {
508 task_deps.read_set.insert(dep_node_index)
509 };
510 if new_read {
511 task_deps.reads.push(dep_node_index);
512 if task_deps.reads.len() == EdgesVec::INLINE_CAPACITY {
513 task_deps.read_set.extend(task_deps.reads.iter().copied());
516 }
517
518 #[cfg(debug_assertions)]
519 {
520 if let Some(target) = task_deps.node {
521 if let Some(ref forbidden_edge) = data.current.forbidden_edge {
522 let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
523 if forbidden_edge.test(&src, &target) {
524 panic!("forbidden edge {:?} -> {:?} created", src, target)
525 }
526 }
527 }
528 }
529 } else if cfg!(debug_assertions) {
530 data.current.total_duplicate_read_count.fetch_add(1, Ordering::Relaxed);
531 }
532 })
533 }
534 }
535
536 #[inline]
539 pub fn record_diagnostic<Qcx: QueryContext>(&self, qcx: Qcx, diagnostic: &DiagInner) {
540 if let Some(ref data) = self.data {
541 D::read_deps(|task_deps| match task_deps {
542 TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return,
543 TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => {
544 self.read_index(data.encode_diagnostic(qcx, diagnostic));
545 }
546 })
547 }
548 }
549 #[inline]
552 pub fn force_diagnostic_node<Qcx: QueryContext>(
553 &self,
554 qcx: Qcx,
555 prev_index: SerializedDepNodeIndex,
556 ) {
557 if let Some(ref data) = self.data {
558 data.force_diagnostic_node(qcx, prev_index);
559 }
560 }
561
562 pub fn with_feed_task<Ctxt: DepContext<Deps = D>, R: Debug>(
578 &self,
579 node: DepNode,
580 cx: Ctxt,
581 result: &R,
582 hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
583 ) -> DepNodeIndex {
584 if let Some(data) = self.data.as_ref() {
585 if let Some(prev_index) = data.previous.node_to_index_opt(&node) {
592 let dep_node_index = data.current.prev_index_to_index.lock()[prev_index];
593 if let Some(dep_node_index) = dep_node_index {
594 crate::query::incremental_verify_ich(
595 cx,
596 data,
597 result,
598 prev_index,
599 hash_result,
600 |value| format!("{value:?}"),
601 );
602
603 #[cfg(debug_assertions)]
604 if hash_result.is_some() {
605 data.current.record_edge(
606 dep_node_index,
607 node,
608 data.prev_fingerprint_of(prev_index),
609 );
610 }
611
612 return dep_node_index;
613 }
614 }
615
616 let mut edges = EdgesVec::new();
617 D::read_deps(|task_deps| match task_deps {
618 TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()),
619 TaskDepsRef::EvalAlways => {
620 edges.push(DepNodeIndex::FOREVER_RED_NODE);
621 }
622 TaskDepsRef::Ignore => {}
623 TaskDepsRef::Forbid => {
624 panic!("Cannot summarize when dependencies are not recorded.")
625 }
626 });
627
628 data.hash_result_and_intern_node(&cx, node, edges, result, hash_result)
629 } else {
630 self.next_virtual_depnode_index()
635 }
636 }
637}
638
639impl<D: Deps> DepGraphData<D> {
640 #[inline]
641 fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option<DepNodeIndex> {
642 if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
643 self.current.prev_index_to_index.lock()[prev_index]
644 } else {
645 self.current.new_node_to_index.get(dep_node)
646 }
647 }
648
649 #[inline]
650 fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
651 self.dep_node_index_of_opt(dep_node).is_some()
652 }
653
654 fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
655 if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
656 self.colors.get(prev_index)
657 } else {
658 None
660 }
661 }
662
663 #[inline]
666 pub(crate) fn is_index_green(&self, prev_index: SerializedDepNodeIndex) -> bool {
667 self.colors.get(prev_index).is_some_and(|c| c.is_green())
668 }
669
670 #[inline]
671 pub(crate) fn prev_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
672 self.previous.fingerprint_by_index(prev_index)
673 }
674
675 #[inline]
676 pub(crate) fn prev_node_of(&self, prev_index: SerializedDepNodeIndex) -> DepNode {
677 self.previous.index_to_node(prev_index)
678 }
679
680 pub(crate) fn mark_debug_loaded_from_disk(&self, dep_node: DepNode) {
681 self.debug_loaded_from_disk.lock().insert(dep_node);
682 }
683
684 #[inline]
687 fn encode_diagnostic<Qcx: QueryContext>(
688 &self,
689 qcx: Qcx,
690 diagnostic: &DiagInner,
691 ) -> DepNodeIndex {
692 let dep_node_index = self.current.encoder.send(
694 DepNode {
695 kind: D::DEP_KIND_SIDE_EFFECT,
696 hash: PackedFingerprint::from(Fingerprint::ZERO),
697 },
698 Fingerprint::ZERO,
699 std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
702 );
703 let side_effect = QuerySideEffect::Diagnostic(diagnostic.clone());
704 qcx.store_side_effect(dep_node_index, side_effect);
705 dep_node_index
706 }
707
708 #[inline]
711 fn force_diagnostic_node<Qcx: QueryContext>(
712 &self,
713 qcx: Qcx,
714 prev_index: SerializedDepNodeIndex,
715 ) {
716 D::with_deps(TaskDepsRef::Ignore, || {
717 let side_effect = qcx.load_side_effect(prev_index).unwrap();
718
719 match &side_effect {
720 QuerySideEffect::Diagnostic(diagnostic) => {
721 qcx.dep_context().sess().dcx().emit_diagnostic(diagnostic.clone());
722 }
723 }
724
725 let index = self.current.promote_node_and_deps_to_current(&self.previous, prev_index);
727 qcx.store_side_effect(index, side_effect);
729
730 self.colors.insert(prev_index, DepNodeColor::Green(index));
732 })
733 }
734}
735
736impl<D: Deps> DepGraph<D> {
737 #[inline]
738 pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
739 self.data.as_ref().is_some_and(|data| data.dep_node_exists(dep_node))
740 }
741
742 pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
745 self.data.as_ref().and_then(|data| data.previous_work_products.get(v).cloned())
746 }
747
748 pub fn previous_work_products(&self) -> &WorkProductMap {
751 &self.data.as_ref().unwrap().previous_work_products
752 }
753
754 pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode) -> bool {
755 self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node)
756 }
757
758 #[cfg(debug_assertions)]
759 #[inline(always)]
760 pub(crate) fn register_dep_node_debug_str<F>(&self, dep_node: DepNode, debug_str_gen: F)
761 where
762 F: FnOnce() -> String,
763 {
764 let dep_node_debug = &self.data.as_ref().unwrap().dep_node_debug;
765
766 if dep_node_debug.borrow().contains_key(&dep_node) {
767 return;
768 }
769 let debug_str = self.with_ignore(debug_str_gen);
770 dep_node_debug.borrow_mut().insert(dep_node, debug_str);
771 }
772
773 pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option<String> {
774 self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned()
775 }
776
777 fn node_color(&self, dep_node: &DepNode) -> Option<DepNodeColor> {
778 if let Some(ref data) = self.data {
779 return data.node_color(dep_node);
780 }
781
782 None
783 }
784
785 pub fn try_mark_green<Qcx: QueryContext<Deps = D>>(
786 &self,
787 qcx: Qcx,
788 dep_node: &DepNode,
789 ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
790 self.data().and_then(|data| data.try_mark_green(qcx, dep_node))
791 }
792}
793
794impl<D: Deps> DepGraphData<D> {
795 pub(crate) fn try_mark_green<Qcx: QueryContext<Deps = D>>(
801 &self,
802 qcx: Qcx,
803 dep_node: &DepNode,
804 ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
805 debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
806
807 let prev_index = self.previous.node_to_index_opt(dep_node)?;
809
810 match self.colors.get(prev_index) {
811 Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)),
812 Some(DepNodeColor::Red) => None,
813 None => {
814 self.try_mark_previous_green(qcx, prev_index, dep_node, None)
819 .map(|dep_node_index| (prev_index, dep_node_index))
820 }
821 }
822 }
823
824 #[instrument(skip(self, qcx, parent_dep_node_index, frame), level = "debug")]
825 fn try_mark_parent_green<Qcx: QueryContext<Deps = D>>(
826 &self,
827 qcx: Qcx,
828 parent_dep_node_index: SerializedDepNodeIndex,
829 frame: Option<&MarkFrame<'_>>,
830 ) -> Option<()> {
831 let dep_dep_node_color = self.colors.get(parent_dep_node_index);
832 let dep_dep_node = &self.previous.index_to_node(parent_dep_node_index);
833
834 match dep_dep_node_color {
835 Some(DepNodeColor::Green(_)) => {
836 debug!("dependency {dep_dep_node:?} was immediately green");
840 return Some(());
841 }
842 Some(DepNodeColor::Red) => {
843 debug!("dependency {dep_dep_node:?} was immediately red");
848 return None;
849 }
850 None => {}
851 }
852
853 if !qcx.dep_context().is_eval_always(dep_dep_node.kind) {
856 debug!(
857 "state of dependency {:?} ({}) is unknown, trying to mark it green",
858 dep_dep_node, dep_dep_node.hash,
859 );
860
861 let node_index =
862 self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node, frame);
863
864 if node_index.is_some() {
865 debug!("managed to MARK dependency {dep_dep_node:?} as green",);
866 return Some(());
867 }
868 }
869
870 debug!("trying to force dependency {dep_dep_node:?}");
872 if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node, parent_dep_node_index, frame) {
873 debug!("dependency {dep_dep_node:?} could not be forced");
875 return None;
876 }
877
878 let dep_dep_node_color = self.colors.get(parent_dep_node_index);
879
880 match dep_dep_node_color {
881 Some(DepNodeColor::Green(_)) => {
882 debug!("managed to FORCE dependency {dep_dep_node:?} to green");
883 return Some(());
884 }
885 Some(DepNodeColor::Red) => {
886 debug!("dependency {dep_dep_node:?} was red after forcing",);
887 return None;
888 }
889 None => {}
890 }
891
892 if let None = qcx.dep_context().sess().dcx().has_errors_or_delayed_bugs() {
893 panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
894 }
895
896 debug!("dependency {dep_dep_node:?} resulted in compilation error",);
907 return None;
908 }
909
910 #[instrument(skip(self, qcx, prev_dep_node_index, frame), level = "debug")]
912 fn try_mark_previous_green<Qcx: QueryContext<Deps = D>>(
913 &self,
914 qcx: Qcx,
915 prev_dep_node_index: SerializedDepNodeIndex,
916 dep_node: &DepNode,
917 frame: Option<&MarkFrame<'_>>,
918 ) -> Option<DepNodeIndex> {
919 let frame = MarkFrame { index: prev_dep_node_index, parent: frame };
920
921 debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
923
924 debug_assert_eq!(self.previous.index_to_node(prev_dep_node_index), *dep_node);
925
926 let prev_deps = self.previous.edge_targets_from(prev_dep_node_index);
927
928 for dep_dep_node_index in prev_deps {
929 self.try_mark_parent_green(qcx, dep_dep_node_index, Some(&frame))?;
930 }
931
932 let dep_node_index =
941 self.current.promote_node_and_deps_to_current(&self.previous, prev_dep_node_index);
942
943 self.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
948
949 debug!("successfully marked {dep_node:?} as green");
950 Some(dep_node_index)
951 }
952}
953
954impl<D: Deps> DepGraph<D> {
955 pub fn is_red(&self, dep_node: &DepNode) -> bool {
958 matches!(self.node_color(dep_node), Some(DepNodeColor::Red))
959 }
960
961 pub fn is_green(&self, dep_node: &DepNode) -> bool {
964 self.node_color(dep_node).is_some_and(|c| c.is_green())
965 }
966
967 pub fn exec_cache_promotions<Tcx: DepContext>(&self, tcx: Tcx) {
976 let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
977
978 let data = self.data.as_ref().unwrap();
979 for prev_index in data.colors.values.indices() {
980 match data.colors.get(prev_index) {
981 Some(DepNodeColor::Green(_)) => {
982 let dep_node = data.previous.index_to_node(prev_index);
983 tcx.try_load_from_on_disk_cache(dep_node);
984 }
985 None | Some(DepNodeColor::Red) => {
986 }
990 }
991 }
992 }
993
994 pub fn print_incremental_info(&self) {
995 if let Some(data) = &self.data {
996 data.current.encoder.print_incremental_info(
997 data.current.total_read_count.load(Ordering::Relaxed),
998 data.current.total_duplicate_read_count.load(Ordering::Relaxed),
999 )
1000 }
1001 }
1002
1003 pub fn finish_encoding(&self) -> FileEncodeResult {
1004 if let Some(data) = &self.data { data.current.encoder.finish() } else { Ok(0) }
1005 }
1006
1007 pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex {
1008 debug_assert!(self.data.is_none());
1009 let index = self.virtual_dep_node_index.fetch_add(1, Ordering::Relaxed);
1010 DepNodeIndex::from_u32(index)
1011 }
1012}
1013
1014#[derive(Clone, Debug, Encodable, Decodable)]
1046pub struct WorkProduct {
1047 pub cgu_name: String,
1048 pub saved_files: UnordMap<String, String>,
1054}
1055
1056pub type WorkProductMap = UnordMap<WorkProductId, WorkProduct>;
1057
1058rustc_index::newtype_index! {
1060 struct EdgeIndex {}
1061}
1062
1063pub(super) struct CurrentDepGraph<D: Deps> {
1087 encoder: GraphEncoder<D>,
1088 new_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
1089 prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>,
1090
1091 #[cfg(debug_assertions)]
1094 fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>,
1095
1096 #[cfg(debug_assertions)]
1099 forbidden_edge: Option<EdgeFilter>,
1100
1101 anon_id_seed: Fingerprint,
1113
1114 total_read_count: AtomicU64,
1117 total_duplicate_read_count: AtomicU64,
1118}
1119
1120impl<D: Deps> CurrentDepGraph<D> {
1121 fn new(
1122 profiler: &SelfProfilerRef,
1123 prev_graph_node_count: usize,
1124 encoder: FileEncoder,
1125 record_graph: bool,
1126 record_stats: bool,
1127 previous: Arc<SerializedDepGraph>,
1128 ) -> Self {
1129 use std::time::{SystemTime, UNIX_EPOCH};
1130
1131 let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
1132 let nanos = duration.as_nanos();
1133 let mut stable_hasher = StableHasher::new();
1134 nanos.hash(&mut stable_hasher);
1135 let anon_id_seed = stable_hasher.finish();
1136
1137 #[cfg(debug_assertions)]
1138 let forbidden_edge = match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
1139 Ok(s) => match EdgeFilter::new(&s) {
1140 Ok(f) => Some(f),
1141 Err(err) => panic!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
1142 },
1143 Err(_) => None,
1144 };
1145
1146 let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200;
1147
1148 CurrentDepGraph {
1149 encoder: GraphEncoder::new(
1150 encoder,
1151 prev_graph_node_count,
1152 record_graph,
1153 record_stats,
1154 profiler,
1155 previous,
1156 ),
1157 new_node_to_index: ShardedHashMap::with_capacity(
1158 new_node_count_estimate / sharded::shards(),
1159 ),
1160 prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)),
1161 anon_id_seed,
1162 #[cfg(debug_assertions)]
1163 forbidden_edge,
1164 #[cfg(debug_assertions)]
1165 fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
1166 total_read_count: AtomicU64::new(0),
1167 total_duplicate_read_count: AtomicU64::new(0),
1168 }
1169 }
1170
1171 #[cfg(debug_assertions)]
1172 fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) {
1173 if let Some(forbidden_edge) = &self.forbidden_edge {
1174 forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
1175 }
1176 let previous = *self.fingerprints.lock().get_or_insert_with(dep_node_index, || fingerprint);
1177 assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key);
1178 }
1179
1180 #[inline(always)]
1183 fn intern_new_node(
1184 &self,
1185 key: DepNode,
1186 edges: EdgesVec,
1187 current_fingerprint: Fingerprint,
1188 ) -> DepNodeIndex {
1189 let dep_node_index = self
1190 .new_node_to_index
1191 .get_or_insert_with(key, || self.encoder.send(key, current_fingerprint, edges));
1192
1193 #[cfg(debug_assertions)]
1194 self.record_edge(dep_node_index, key, current_fingerprint);
1195
1196 dep_node_index
1197 }
1198
1199 fn intern_node(
1200 &self,
1201 prev_graph: &SerializedDepGraph,
1202 key: DepNode,
1203 edges: EdgesVec,
1204 fingerprint: Option<Fingerprint>,
1205 ) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) {
1206 if let Some(prev_index) = prev_graph.node_to_index_opt(&key) {
1207 let get_dep_node_index = |fingerprint| {
1208 let mut prev_index_to_index = self.prev_index_to_index.lock();
1209
1210 let dep_node_index = match prev_index_to_index[prev_index] {
1211 Some(dep_node_index) => dep_node_index,
1212 None => {
1213 let dep_node_index = self.encoder.send(key, fingerprint, edges);
1214 prev_index_to_index[prev_index] = Some(dep_node_index);
1215 dep_node_index
1216 }
1217 };
1218
1219 #[cfg(debug_assertions)]
1220 self.record_edge(dep_node_index, key, fingerprint);
1221
1222 dep_node_index
1223 };
1224
1225 if let Some(fingerprint) = fingerprint {
1227 if fingerprint == prev_graph.fingerprint_by_index(prev_index) {
1228 let dep_node_index = get_dep_node_index(fingerprint);
1231 (dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index))))
1232 } else {
1233 let dep_node_index = get_dep_node_index(fingerprint);
1236 (dep_node_index, Some((prev_index, DepNodeColor::Red)))
1237 }
1238 } else {
1239 let dep_node_index = get_dep_node_index(Fingerprint::ZERO);
1244 (dep_node_index, Some((prev_index, DepNodeColor::Red)))
1245 }
1246 } else {
1247 let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
1248
1249 let dep_node_index = self.intern_new_node(key, edges, fingerprint);
1251
1252 (dep_node_index, None)
1253 }
1254 }
1255
1256 fn promote_node_and_deps_to_current(
1257 &self,
1258 prev_graph: &SerializedDepGraph,
1259 prev_index: SerializedDepNodeIndex,
1260 ) -> DepNodeIndex {
1261 self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
1262
1263 let mut prev_index_to_index = self.prev_index_to_index.lock();
1264
1265 match prev_index_to_index[prev_index] {
1266 Some(dep_node_index) => dep_node_index,
1267 None => {
1268 let dep_node_index = self.encoder.send_promoted(prev_index, &*prev_index_to_index);
1269 prev_index_to_index[prev_index] = Some(dep_node_index);
1270 #[cfg(debug_assertions)]
1271 self.record_edge(
1272 dep_node_index,
1273 prev_graph.index_to_node(prev_index),
1274 prev_graph.fingerprint_by_index(prev_index),
1275 );
1276 dep_node_index
1277 }
1278 }
1279 }
1280
1281 #[inline]
1282 fn debug_assert_not_in_new_nodes(
1283 &self,
1284 prev_graph: &SerializedDepGraph,
1285 prev_index: SerializedDepNodeIndex,
1286 ) {
1287 let node = &prev_graph.index_to_node(prev_index);
1288 debug_assert!(
1289 !self.new_node_to_index.get(node).is_some(),
1290 "node from previous graph present in new node collection"
1291 );
1292 }
1293}
1294
1295#[derive(Debug, Clone, Copy)]
1296pub enum TaskDepsRef<'a> {
1297 Allow(&'a Lock<TaskDeps>),
1301 EvalAlways,
1307 Ignore,
1309 Forbid,
1314}
1315
1316#[derive(Debug)]
1317pub struct TaskDeps {
1318 #[cfg(debug_assertions)]
1319 node: Option<DepNode>,
1320 reads: EdgesVec,
1321 read_set: FxHashSet<DepNodeIndex>,
1322 phantom_data: PhantomData<DepNode>,
1323}
1324
1325impl Default for TaskDeps {
1326 fn default() -> Self {
1327 Self {
1328 #[cfg(debug_assertions)]
1329 node: None,
1330 reads: EdgesVec::new(),
1331 read_set: FxHashSet::with_capacity_and_hasher(128, Default::default()),
1332 phantom_data: PhantomData,
1333 }
1334 }
1335}
1336struct DepNodeColorMap {
1339 values: IndexVec<SerializedDepNodeIndex, AtomicU32>,
1340}
1341
1342const COMPRESSED_NONE: u32 = 0;
1343const COMPRESSED_RED: u32 = 1;
1344const COMPRESSED_FIRST_GREEN: u32 = 2;
1345
1346impl DepNodeColorMap {
1347 fn new(size: usize) -> DepNodeColorMap {
1348 DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() }
1349 }
1350
1351 #[inline]
1352 fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> {
1353 match self.values[index].load(Ordering::Acquire) {
1354 COMPRESSED_NONE => None,
1355 COMPRESSED_RED => Some(DepNodeColor::Red),
1356 value => {
1357 Some(DepNodeColor::Green(DepNodeIndex::from_u32(value - COMPRESSED_FIRST_GREEN)))
1358 }
1359 }
1360 }
1361
1362 #[inline]
1363 fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) {
1364 self.values[index].store(
1365 match color {
1366 DepNodeColor::Red => COMPRESSED_RED,
1367 DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN,
1368 },
1369 Ordering::Release,
1370 )
1371 }
1372}
1373
1374#[inline(never)]
1375#[cold]
1376pub(crate) fn print_markframe_trace<D: Deps>(graph: &DepGraph<D>, frame: Option<&MarkFrame<'_>>) {
1377 let data = graph.data.as_ref().unwrap();
1378
1379 eprintln!("there was a panic while trying to force a dep node");
1380 eprintln!("try_mark_green dep node stack:");
1381
1382 let mut i = 0;
1383 let mut current = frame;
1384 while let Some(frame) = current {
1385 let node = data.previous.index_to_node(frame.index);
1386 eprintln!("#{i} {node:?}");
1387 current = frame.parent;
1388 i += 1;
1389 }
1390
1391 eprintln!("end of try_mark_green dep node stack");
1392}
1393
1394#[cold]
1395#[inline(never)]
1396fn panic_on_forbidden_read<D: Deps>(data: &DepGraphData<D>, dep_node_index: DepNodeIndex) -> ! {
1397 let mut dep_node = None;
1401
1402 for (prev_index, index) in data.current.prev_index_to_index.lock().iter_enumerated() {
1405 if index == &Some(dep_node_index) {
1406 dep_node = Some(data.previous.index_to_node(prev_index));
1407 break;
1408 }
1409 }
1410
1411 if dep_node.is_none() {
1412 for shard in data.current.new_node_to_index.lock_shards() {
1414 if let Some((node, _)) = shard.iter().find(|(_, index)| *index == dep_node_index) {
1415 dep_node = Some(*node);
1416 break;
1417 }
1418 }
1419 }
1420
1421 let dep_node = dep_node.map_or_else(
1422 || format!("with index {:?}", dep_node_index),
1423 |dep_node| format!("`{:?}`", dep_node),
1424 );
1425
1426 panic!(
1427 "Error: trying to record dependency on DepNode {dep_node} in a \
1428 context that does not allow it (e.g. during query deserialization). \
1429 The most common case of recording a dependency on a DepNode `foo` is \
1430 when the corresponding query `foo` is invoked. Invoking queries is not \
1431 allowed as part of loading something from the incremental on-disk cache. \
1432 See <https://github.com/rust-lang/rust/pull/91919>."
1433 )
1434}