graph.rs 56.9 KB
Newer Older
1
use parking_lot::Mutex;
2
use rustc_data_structures::fingerprint::Fingerprint;
3
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
R
Ryan Levick 已提交
4
use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef};
M
Mark Rousskov 已提交
5 6
use rustc_data_structures::sharded::{self, Sharded};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
C
Camille GILLOT 已提交
7 8
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
C
Camille GILLOT 已提交
9
use rustc_data_structures::OnDrop;
C
Camille GILLOT 已提交
10 11
use rustc_index::vec::IndexVec;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
12
use smallvec::{smallvec, SmallVec};
13
use std::assert_matches::assert_matches;
M
Mark Rousskov 已提交
14
use std::collections::hash_map::Entry;
C
Camille GILLOT 已提交
15
use std::fmt::Debug;
16
use std::hash::Hash;
C
Camille GILLOT 已提交
17
use std::marker::PhantomData;
M
Michael Woerister 已提交
18
use std::sync::atomic::Ordering::Relaxed;
19 20

use super::query::DepGraphQuery;
C
Camille GILLOT 已提交
21
use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
22
use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
23
use crate::ich::StableHashingContext;
24
use crate::query::{QueryContext, QuerySideEffects};
25

C
Camille GILLOT 已提交
26 27 28
#[cfg(debug_assertions)]
use {super::debug::EdgeFilter, std::env};

29
#[derive(Clone)]
30 31
pub struct DepGraph<K: DepKind> {
    data: Option<Lrc<DepGraphData<K>>>,
32 33 34

    /// This field is used for assigning DepNodeIndices when running in
    /// non-incremental mode. Even in non-incremental mode we make sure that
35
    /// each task has a `DepNodeIndex` that uniquely identifies it. This unique
36 37
    /// ID is used for self-profiling.
    virtual_dep_node_index: Lrc<AtomicU32>,
38 39
}

40
rustc_index::newtype_index! {
41
    pub struct DepNodeIndex {}
42
}
43 44

impl DepNodeIndex {
45
    pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
46
    pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
47
    pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
48 49
}

50
impl From<DepNodeIndex> for QueryInvocationId {
51
    #[inline(always)]
52
    fn from(dep_node_index: DepNodeIndex) -> Self {
M
Michael Woerister 已提交
53
        QueryInvocationId(dep_node_index.as_u32())
54 55 56
    }
}

57
#[derive(PartialEq)]
58 59
pub enum DepNodeColor {
    Red,
M
Mark Rousskov 已提交
60
    Green(DepNodeIndex),
61 62
}

63
impl DepNodeColor {
64
    #[inline]
65 66 67 68 69 70 71 72
    pub fn is_green(self) -> bool {
        match self {
            DepNodeColor::Red => false,
            DepNodeColor::Green(_) => true,
        }
    }
}

73
pub struct DepGraphData<K: DepKind> {
74 75 76
    /// The new encoding of the dependency graph, optimized for red/green
    /// tracking. The `current` field is the dependency graph of only the
    /// current compilation session: We don't merge the previous dep-graph into
77
    /// current one anymore, but we do reference shared data to save space.
78
    current: CurrentDepGraph<K>,
79

80 81
    /// The dep-graph from the previous compilation session. It contains all
    /// nodes and edges as well as all fingerprints of nodes that have them.
C
Camille GILLOT 已提交
82
    previous: SerializedDepGraph<K>,
83

84
    colors: DepNodeColorMap,
85

86
    processed_side_effects: Mutex<FxHashSet<DepNodeIndex>>,
87

A
Alexander Regueiro 已提交
88
    /// When we load, there may be `.o` files, cached MIR, or other such
89 90 91
    /// things available to us. If we find that they are not dirty, we
    /// load the path to the file storing those work-products here into
    /// this map. We can later look for and extract that data.
92
    previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
93

94
    dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
95 96 97 98 99

    /// Used by incremental compilation tests to assert that
    /// a particular query result was decoded from disk
    /// (not just marked green)
    debug_loaded_from_disk: Lock<FxHashSet<DepNode<K>>>,
100 101
}

C
Camille GILLOT 已提交
102
pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint
103
where
104
    R: for<'a> HashStable<StableHashingContext<'a>>,
105 106 107
{
    let mut stable_hasher = StableHasher::new();
    result.hash_stable(hcx, &mut stable_hasher);
C
Camille GILLOT 已提交
108
    stable_hasher.finish()
109 110
}

111
impl<K: DepKind> DepGraph<K> {
M
Mark Rousskov 已提交
112
    pub fn new(
113
        profiler: &SelfProfilerRef,
C
Camille GILLOT 已提交
114
        prev_graph: SerializedDepGraph<K>,
M
Mark Rousskov 已提交
115
        prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
C
Camille GILLOT 已提交
116 117 118
        encoder: FileEncoder,
        record_graph: bool,
        record_stats: bool,
119
    ) -> DepGraph<K> {
120 121
        let prev_graph_node_count = prev_graph.node_count();

122 123 124 125 126 127 128
        let current = CurrentDepGraph::new(
            profiler,
            prev_graph_node_count,
            encoder,
            record_graph,
            record_stats,
        );
129

130 131
        let colors = DepNodeColorMap::new(prev_graph_node_count);

132
        // Instantiate a dependy-less node only once for anonymous queries.
133 134 135 136 137 138
        let _green_node_index = current.intern_new_node(
            profiler,
            DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() },
            smallvec![],
            Fingerprint::ZERO,
        );
139
        assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
140

141 142 143 144
        // Instantiate a dependy-less red node only once for anonymous queries.
        let (_red_node_index, _prev_and_index) = current.intern_node(
            profiler,
            &prev_graph,
145
            DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() },
146 147 148 149
            smallvec![],
            None,
            false,
        );
150 151
        assert_eq!(_red_node_index, DepNodeIndex::FOREVER_RED_NODE);
        assert!(matches!(_prev_and_index, None | Some((_, DepNodeColor::Red))));
152

153
        DepGraph {
154
            data: Some(Lrc::new(DepGraphData {
155
                previous_work_products: prev_work_products,
156
                dep_node_debug: Default::default(),
157
                current,
158
                processed_side_effects: Default::default(),
159
                previous: prev_graph,
160
                colors,
161
                debug_loaded_from_disk: Default::default(),
162
            })),
163
            virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
164 165 166
        }
    }

167
    pub fn new_disabled() -> DepGraph<K> {
168
        DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
169 170
    }

171 172 173 174 175
    #[inline]
    pub fn data(&self) -> Option<&DepGraphData<K>> {
        self.data.as_deref()
    }

A
Alexander Regueiro 已提交
176
    /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise.
177 178
    #[inline]
    pub fn is_fully_enabled(&self) -> bool {
179
        self.data.is_some()
180 181
    }

C
Camille GILLOT 已提交
182 183 184
    pub fn with_query(&self, f: impl Fn(&DepGraphQuery<K>)) {
        if let Some(data) = &self.data {
            data.current.encoder.borrow().with_query(f)
185
        }
186 187
    }

M
Mark Rousskov 已提交
188
    pub fn assert_ignored(&self) {
J
John Kåre Alsaker 已提交
189
        if let Some(..) = self.data {
190
            K::read_deps(|task_deps| {
191 192 193 194 195
                assert_matches!(
                    task_deps,
                    TaskDepsRef::Ignore,
                    "expected no task dependency tracking"
                );
196
            })
197
        }
198 199
    }

M
Mark Rousskov 已提交
200 201 202
    pub fn with_ignore<OP, R>(&self, op: OP) -> R
    where
        OP: FnOnce() -> R,
203
    {
204
        K::with_deps(TaskDepsRef::Ignore, op)
205 206
    }

A
Aaron Hill 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220
    /// Used to wrap the deserialization of a query result from disk,
    /// This method enforces that no new `DepNodes` are created during
    /// query result deserialization.
    ///
    /// Enforcing this makes the query dep graph simpler - all nodes
    /// must be created during the query execution, and should be
    /// created from inside the 'body' of a query (the implementation
    /// provided by a particular compiler crate).
    ///
    /// Consider the case of three queries `A`, `B`, and `C`, where
    /// `A` invokes `B` and `B` invokes `C`:
    ///
    /// `A -> B -> C`
    ///
A
Aaron Hill 已提交
221 222 223
    /// Suppose that decoding the result of query `B` required re-computing
    /// the query `C`. If we did not create a fresh `TaskDeps` when
    /// decoding `B`, we would still be using the `TaskDeps` for query `A`
A
Aaron Hill 已提交
224
    /// (if we needed to re-execute `A`). This would cause us to create
A
Aaron Hill 已提交
225
    /// a new edge `A -> C`. If this edge did not previously
A
Aaron Hill 已提交
226 227 228 229
    /// exist in the `DepGraph`, then we could end up with a different
    /// `DepGraph` at the end of compilation, even if there were no
    /// meaningful changes to the overall program (e.g. a newline was added).
    /// In addition, this edge might cause a subsequent compilation run
A
Aaron Hill 已提交
230 231
    /// to try to force `C` before marking other necessary nodes green. If
    /// `C` did not exist in the new compilation session, then we could
A
Aaron Hill 已提交
232 233
    /// get an ICE. Normally, we would have tried (and failed) to mark
    /// some other query green (e.g. `item_children`) which was used
A
Aaron Hill 已提交
234
    /// to obtain `C`, which would prevent us from ever trying to force
A
Aaron Hill 已提交
235 236 237 238 239 240 241 242 243
    /// a non-existent `D`.
    ///
    /// It might be possible to enforce that all `DepNode`s read during
    /// deserialization already exist in the previous `DepGraph`. In
    /// the above example, we would invoke `D` during the deserialization
    /// of `B`. Since we correctly create a new `TaskDeps` from the decoding
    /// of `B`, this would result in an edge `B -> D`. If that edge already
    /// existed (with the same `DepPathHash`es), then it should be correct
    /// to allow the invocation of the query to proceed during deserialization
A
Aaron Hill 已提交
244 245 246 247 248 249
    /// of a query result. We would merely assert that the dep-graph fragment
    /// that would have been added by invoking `C` while decoding `B`
    /// is equivalent to the dep-graph fragment that we already instantiated for B
    /// (at the point where we successfully marked B as green).
    ///
    /// However, this would require additional complexity
A
Aaron Hill 已提交
250 251 252
    /// in the query infrastructure, and is not currently needed by the
    /// decoding of any query results. Should the need arise in the future,
    /// we should consider extending the query system with this functionality.
J
John Kåre Alsaker 已提交
253
    pub fn with_query_deserialization<OP, R>(&self, op: OP) -> R
A
Aaron Hill 已提交
254 255 256
    where
        OP: FnOnce() -> R,
    {
257
        K::with_deps(TaskDepsRef::Forbid, op)
A
Aaron Hill 已提交
258 259
    }

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    #[inline(always)]
    pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
        &self,
        key: DepNode<K>,
        cx: Ctxt,
        arg: A,
        task: fn(Ctxt, A) -> R,
        hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
    ) -> (R, DepNodeIndex) {
        match self.data() {
            Some(data) => data.with_task(key, cx, arg, task, hash_result),
            None => (task(cx, arg), self.next_virtual_depnode_index()),
        }
    }

    pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>(
        &self,
        cx: Tcx,
        dep_kind: K,
        op: OP,
    ) -> (R, DepNodeIndex)
    where
        OP: FnOnce() -> R,
    {
        match self.data() {
            Some(data) => data.with_anon_task(cx, dep_kind, op),
            None => (op(), self.next_virtual_depnode_index()),
        }
    }
}

impl<K: DepKind> DepGraphData<K> {
292 293 294 295 296 297
    /// Starts a new dep-graph task. Dep-graph tasks are specified
    /// using a free function (`task`) and **not** a closure -- this
    /// is intentional because we want to exercise tight control over
    /// what state they have access to. In particular, we want to
    /// prevent implicit 'leaks' of tracked state into the task (which
    /// could then be read without generating correct edges in the
298
    /// dep-graph -- see the [rustc dev guide] for more details on
M
Malo Jaffré 已提交
299
    /// the dep-graph). To this end, the task function gets exactly two
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
    /// pieces of state: the context `cx` and an argument `arg`. Both
    /// of these bits of state must be of some type that implements
    /// `DepGraphSafe` and hence does not leak.
    ///
    /// The choice of two arguments is not fundamental. One argument
    /// would work just as well, since multiple values can be
    /// collected using tuples. However, using two arguments works out
    /// to be quite convenient, since it is common to need a context
    /// (`cx`) and some argument (e.g., a `DefId` identifying what
    /// item to process).
    ///
    /// For cases where you need some other number of arguments:
    ///
    /// - If you only need one argument, just use `()` for the `arg`
    ///   parameter.
    /// - If you need 3+ arguments, use a tuple for the
    ///   `arg` parameter.
    ///
318
    /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html
319
    #[inline(always)]
C
Camille GILLOT 已提交
320
    pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
321
        &self,
322
        key: DepNode<K>,
323
        cx: Ctxt,
324
        arg: A,
325
        task: fn(Ctxt, A) -> R,
C
Camille GILLOT 已提交
326
        hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
327
    ) -> (R, DepNodeIndex) {
C
Camille GILLOT 已提交
328 329 330 331 332 333 334 335
        // If the following assertion triggers, it can have two reasons:
        // 1. Something is wrong with DepNode creation, either here or
        //    in `DepGraph::try_mark_green()`.
        // 2. Two distinct query keys get mapped to the same `DepNode`
        //    (see for example #48923).
        assert!(
            !self.dep_node_exists(&key),
            "forcing query with already existing `DepNode`\n\
336 337
                 - query-key: {arg:?}\n\
                 - dep-node: {key:?}"
C
Camille GILLOT 已提交
338
        );
C
Camille GILLOT 已提交
339

C
Camille GILLOT 已提交
340
        let task_deps = if cx.dep_context().is_eval_always(key.kind) {
C
Camille GILLOT 已提交
341 342 343 344 345 346 347 348 349 350
            None
        } else {
            Some(Lock::new(TaskDeps {
                #[cfg(debug_assertions)]
                node: Some(key),
                reads: SmallVec::new(),
                read_set: Default::default(),
                phantom_data: PhantomData,
            }))
        };
351 352 353 354 355 356 357

        let task_deps_ref = match &task_deps {
            Some(deps) => TaskDepsRef::Allow(deps),
            None => TaskDepsRef::Ignore,
        };

        let result = K::with_deps(task_deps_ref, || task(cx, arg));
C
Camille GILLOT 已提交
358 359 360 361
        let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);

        let dcx = cx.dep_context();
        let hashing_timer = dcx.profiler().incr_result_hashing();
362 363
        let current_fingerprint =
            hash_result.map(|f| dcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, &result)));
C
Camille GILLOT 已提交
364

365
        let print_status = cfg!(debug_assertions) && dcx.sess().opts.unstable_opts.dep_tasks;
C
Camille GILLOT 已提交
366 367

        // Intern the new `DepNode`.
368
        let (dep_node_index, prev_and_color) = self.current.intern_node(
C
Camille GILLOT 已提交
369
            dcx.profiler(),
370
            &self.previous,
C
Camille GILLOT 已提交
371 372 373 374 375
            key,
            edges,
            current_fingerprint,
            print_status,
        );
R
Ryan Levick 已提交
376

C
Camille GILLOT 已提交
377
        hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
378

C
Camille GILLOT 已提交
379 380
        if let Some((prev_index, color)) = prev_and_color {
            debug_assert!(
381
                self.colors.get(prev_index).is_none(),
C
Camille GILLOT 已提交
382
                "DepGraph::with_task() - Duplicate DepNodeColor \
383
                            insertion for {key:?}"
C
Camille GILLOT 已提交
384
            );
385

386
            self.colors.insert(prev_index, color);
387
        }
C
Camille GILLOT 已提交
388 389

        (result, dep_node_index)
390 391
    }

A
Alexander Regueiro 已提交
392 393
    /// Executes something within an "anonymous" task, that is, a task the
    /// `DepNode` of which is determined by the list of inputs it read from.
394
    pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>(
C
Camille GILLOT 已提交
395
        &self,
396
        cx: Tcx,
C
Camille GILLOT 已提交
397 398 399
        dep_kind: K,
        op: OP,
    ) -> (R, DepNodeIndex)
M
Mark Rousskov 已提交
400 401
    where
        OP: FnOnce() -> R,
402
    {
C
Camille GILLOT 已提交
403
        debug_assert!(!cx.is_eval_always(dep_kind));
404

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
        let task_deps = Lock::new(TaskDeps::default());
        let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op);
        let task_deps = task_deps.into_inner();
        let task_deps = task_deps.reads;

        let dep_node_index = match task_deps.len() {
            0 => {
                // Because the dep-node id of anon nodes is computed from the sets of its
                // dependencies we already know what the ID of this dependency-less node is
                // going to be (i.e. equal to the precomputed
                // `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating
                // a `StableHasher` and sending the node through interning.
                DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE
            }
            1 => {
                // When there is only one dependency, don't bother creating a node.
                task_deps[0]
            }
            _ => {
                // The dep node indices are hashed here instead of hashing the dep nodes of the
                // dependencies. These indices may refer to different nodes per session, but this isn't
                // a problem here because we that ensure the final dep node hash is per session only by
                // combining it with the per session random number `anon_id_seed`. This hash only need
                // to map the dependencies to a single value on a per session basis.
                let mut hasher = StableHasher::new();
                task_deps.hash(&mut hasher);

                let target_dep_node = DepNode {
                    kind: dep_kind,
                    // Fingerprint::combine() is faster than sending Fingerprint
                    // through the StableHasher (at least as long as StableHasher
                    // is so slow).
                    hash: self.current.anon_id_seed.combine(hasher.finish()).into(),
                };
439

440 441 442 443 444 445 446 447 448 449
                self.current.intern_new_node(
                    cx.profiler(),
                    target_dep_node,
                    task_deps,
                    Fingerprint::ZERO,
                )
            }
        };

        (result, dep_node_index)
450
    }
451
}
452

453
impl<K: DepKind> DepGraph<K> {
454
    #[inline]
455
    pub fn read_index(&self, dep_node_index: DepNodeIndex) {
456
        if let Some(ref data) = self.data {
457
            K::read_deps(|task_deps| {
458 459 460 461
                let mut task_deps = match task_deps {
                    TaskDepsRef::Allow(deps) => deps.lock(),
                    TaskDepsRef::Ignore => return,
                    TaskDepsRef::Forbid => {
462
                        panic!("Illegal read of: {dep_node_index:?}")
463
                    }
464 465
                };
                let task_deps = &mut *task_deps;
466

467 468 469
                if cfg!(debug_assertions) {
                    data.current.total_read_count.fetch_add(1, Relaxed);
                }
470

471 472 473 474 475 476 477 478 479 480 481 482 483 484
                // As long as we only have a low number of reads we can avoid doing a hash
                // insert and potentially allocating/reallocating the hashmap
                let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
                    task_deps.reads.iter().all(|other| *other != dep_node_index)
                } else {
                    task_deps.read_set.insert(dep_node_index)
                };
                if new_read {
                    task_deps.reads.push(dep_node_index);
                    if task_deps.reads.len() == TASK_DEPS_READS_CAP {
                        // Fill `read_set` with what we have so far so we can use the hashset
                        // next time
                        task_deps.read_set.extend(task_deps.reads.iter().copied());
                    }
485

486 487 488 489 490 491 492
                    #[cfg(debug_assertions)]
                    {
                        if let Some(target) = task_deps.node {
                            if let Some(ref forbidden_edge) = data.current.forbidden_edge {
                                let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
                                if forbidden_edge.test(&src, &target) {
                                    panic!("forbidden edge {:?} -> {:?} created", src, target)
493 494 495 496
                                }
                            }
                        }
                    }
497 498
                } else if cfg!(debug_assertions) {
                    data.current.total_duplicate_read_count.fetch_add(1, Relaxed);
499 500
                }
            })
501
        }
502 503
    }

504 505 506 507
    /// Create a node when we force-feed a value into the query cache.
    /// This is used to remove cycles during type-checking const generic parameters.
    ///
    /// As usual in the query system, we consider the current state of the calling query
508 509
    /// only depends on the list of dependencies up to now. As a consequence, the value
    /// that this query gives us can only depend on those dependencies too. Therefore,
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
    /// it is sound to use the current dependency set for the created node.
    ///
    /// During replay, the order of the nodes is relevant in the dependency graph.
    /// So the unchanged replay will mark the caller query before trying to mark this one.
    /// If there is a change to report, the caller query will be re-executed before this one.
    ///
    /// FIXME: If the code is changed enough for this node to be marked before requiring the
    /// caller's node, we suppose that those changes will be enough to mark this node red and
    /// force a recomputation using the "normal" way.
    pub fn with_feed_task<Ctxt: DepContext<DepKind = K>, A: Debug, R: Debug>(
        &self,
        node: DepNode<K>,
        cx: Ctxt,
        key: A,
        result: &R,
525
        hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
526 527
    ) -> DepNodeIndex {
        if let Some(data) = self.data.as_ref() {
528
            // The caller query has more dependencies than the node we are creating. We may
C
Camille GILLOT 已提交
529
            // encounter a case where this created node is marked as green, but the caller query is
530
            // subsequently marked as red or recomputed. In this case, we will end up feeding a
C
Camille GILLOT 已提交
531 532 533
            // value to an existing node.
            //
            // For sanity, we still check that the loaded stable hash and the new one match.
534
            if let Some(dep_node_index) = data.dep_node_index_of_opt(&node) {
C
Camille GILLOT 已提交
535
                let _current_fingerprint =
536
                    crate::query::incremental_verify_ich(cx, data, result, &node, hash_result);
C
Camille GILLOT 已提交
537

538
                #[cfg(debug_assertions)]
539 540 541
                if hash_result.is_some() {
                    data.current.record_edge(dep_node_index, node, _current_fingerprint);
                }
542 543 544 545 546 547 548

                return dep_node_index;
            }

            let mut edges = SmallVec::new();
            K::read_deps(|task_deps| match task_deps {
                TaskDepsRef::Allow(deps) => edges.extend(deps.lock().reads.iter().copied()),
549 550
                TaskDepsRef::Ignore => {} // During HIR lowering, we have no dependencies.
                TaskDepsRef::Forbid => {
551 552 553 554 555
                    panic!("Cannot summarize when dependencies are not recorded.")
                }
            });

            let hashing_timer = cx.profiler().incr_result_hashing();
556 557 558
            let current_fingerprint = hash_result.map(|hash_result| {
                cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result))
            });
559 560 561 562 563 564 565 566 567

            let print_status = cfg!(debug_assertions) && cx.sess().opts.unstable_opts.dep_tasks;

            // Intern the new `DepNode` with the dependencies up-to-now.
            let (dep_node_index, prev_and_color) = data.current.intern_node(
                cx.profiler(),
                &data.previous,
                node,
                edges,
568
                current_fingerprint,
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
                print_status,
            );

            hashing_timer.finish_with_query_invocation_id(dep_node_index.into());

            if let Some((prev_index, color)) = prev_and_color {
                debug_assert!(
                    data.colors.get(prev_index).is_none(),
                    "DepGraph::with_task() - Duplicate DepNodeColor insertion for {key:?}",
                );

                data.colors.insert(prev_index, color);
            }

            dep_node_index
        } else {
            // Incremental compilation is turned off. We just execute the task
            // without tracking. We still provide a dep-node index that uniquely
            // identifies the task so that we have a cheap way of referring to
            // the query for self-profiling.
            self.next_virtual_depnode_index()
        }
    }
592
}
593

594 595 596 597 598
impl<K: DepKind> DepGraphData<K> {
    #[inline]
    pub fn dep_node_index_of_opt(&self, dep_node: &DepNode<K>) -> Option<DepNodeIndex> {
        if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
            self.current.prev_index_to_index.lock()[prev_index]
599
        } else {
600 601 602 603 604 605
            self.current
                .new_node_to_index
                .get_shard_by_value(dep_node)
                .lock()
                .get(dep_node)
                .copied()
606
        }
607 608
    }

609
    #[inline]
610
    pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
        self.dep_node_index_of_opt(dep_node).is_some()
    }

    fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> {
        if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
            self.colors.get(prev_index)
        } else {
            // This is a node that did not exist in the previous compilation session.
            None
        }
    }

    /// Returns true if the given node has been marked as green during the
    /// current compilation session. Used in various assertions
    pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
        self.node_color(dep_node).map_or(false, |c| c.is_green())
627 628
    }

629
    #[inline]
630
    pub fn prev_fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
631 632 633 634 635 636 637 638 639 640 641
        self.previous.fingerprint_of(dep_node)
    }

    pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode<K>) {
        self.debug_loaded_from_disk.lock().insert(dep_node);
    }
}

impl<K: DepKind> DepGraph<K> {
    #[inline]
    pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
642
        self.data.as_ref().and_then(|data| data.dep_node_index_of_opt(dep_node)).is_some()
643 644
    }

A
Alexander Regueiro 已提交
645
    /// Checks whether a previous work product exists for `v` and, if
646
    /// so, return the path that leads to it. Used to skip doing work.
647
    pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
M
Mark Rousskov 已提交
648
        self.data.as_ref().and_then(|data| data.previous_work_products.get(v).cloned())
649 650
    }

651 652
    /// Access the map of work-products created during the cached run. Only
    /// used during saving of the dep-graph.
653 654
    pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> {
        &self.data.as_ref().unwrap().previous_work_products
655
    }
656

657 658 659 660
    pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode<K>) -> bool {
        self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node)
    }

661
    #[inline(always)]
662
    pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F)
M
Mark Rousskov 已提交
663 664
    where
        F: FnOnce() -> String,
665
    {
666
        let dep_node_debug = &self.data.as_ref().unwrap().dep_node_debug;
667

668
        if dep_node_debug.borrow().contains_key(&dep_node) {
M
Mark Rousskov 已提交
669
            return;
670
        }
671
        let debug_str = self.with_ignore(debug_str_gen);
672
        dep_node_debug.borrow_mut().insert(dep_node, debug_str);
673 674
    }

675
    pub fn dep_node_debug_str(&self, dep_node: DepNode<K>) -> Option<String> {
M
Mark Rousskov 已提交
676
        self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned()
677
    }
678

C
Camille GILLOT 已提交
679
    fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> {
680
        if let Some(ref data) = self.data {
681
            return data.node_color(dep_node);
682 683 684
        }

        None
685 686
    }

687 688 689 690 691 692 693 694 695 696
    pub fn try_mark_green<Qcx: QueryContext<DepKind = K>>(
        &self,
        qcx: Qcx,
        dep_node: &DepNode<K>,
    ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
        self.data().and_then(|data| data.try_mark_green(qcx, dep_node))
    }
}

impl<K: DepKind> DepGraphData<K> {
C
Camille GILLOT 已提交
697 698
    /// Try to mark a node index for the node dep_node.
    ///
699 700 701
    /// A node will have an index, when it's already been marked green, or when we can mark it
    /// green. This function will mark the current task as a reader of the specified node, when
    /// a node index can be found for that node.
702
    pub fn try_mark_green<Qcx: QueryContext<DepKind = K>>(
703
        &self,
704
        qcx: Qcx,
705
        dep_node: &DepNode<K>,
706
    ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
707
        debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
708

709
        // Return None if the dep node didn't exist in the previous session
710
        let prev_index = self.previous.node_to_index_opt(dep_node)?;
711

712
        match self.colors.get(prev_index) {
713 714 715
            Some(DepNodeColor::Green(dep_node_index)) => return Some((prev_index, dep_node_index)),
            Some(DepNodeColor::Red) => return None,
            None => {}
716
        }
717

718
        let backtrace = backtrace_printer(qcx.dep_context().sess(), self, prev_index);
719 720 721 722 723

        // This DepNode and the corresponding query invocation existed
        // in the previous compilation session too, so we can try to
        // mark it as green by recursively marking all of its
        // dependencies green.
C
Camille GILLOT 已提交
724
        let ret = self
725
            .try_mark_previous_green(qcx, prev_index, &dep_node)
726 727
            .map(|dep_node_index| (prev_index, dep_node_index));

C
Camille GILLOT 已提交
728
        // We succeeded, no backtrace.
C
Camille GILLOT 已提交
729
        backtrace.disable();
C
Camille GILLOT 已提交
730
        return ret;
731
    }
732

733
    #[instrument(skip(self, qcx, parent_dep_node_index), level = "debug")]
734
    fn try_mark_parent_green<Qcx: QueryContext<DepKind = K>>(
735
        &self,
736
        qcx: Qcx,
737 738 739
        parent_dep_node_index: SerializedDepNodeIndex,
        dep_node: &DepNode<K>,
    ) -> Option<()> {
740 741
        let dep_dep_node_color = self.colors.get(parent_dep_node_index);
        let dep_dep_node = &self.previous.index_to_node(parent_dep_node_index);
742 743 744 745 746 747

        match dep_dep_node_color {
            Some(DepNodeColor::Green(_)) => {
                // This dependency has been marked as green before, we are
                // still fine and can continue with checking the other
                // dependencies.
N
Nilstrieb 已提交
748
                debug!("dependency {dep_dep_node:?} was immediately green");
749 750 751 752 753 754 755
                return Some(());
            }
            Some(DepNodeColor::Red) => {
                // We found a dependency the value of which has changed
                // compared to the previous compilation session. We cannot
                // mark the DepNode as green and also don't need to bother
                // with checking any of the other dependencies.
N
Nilstrieb 已提交
756
                debug!("dependency {dep_dep_node:?} was immediately red");
757 758 759 760 761 762 763
                return None;
            }
            None => {}
        }

        // We don't know the state of this dependency. If it isn't
        // an eval_always node, let's try to mark it green recursively.
764
        if !qcx.dep_context().is_eval_always(dep_dep_node.kind) {
765
            debug!(
N
Nilstrieb 已提交
766 767
                "state of dependency {:?} ({}) is unknown, trying to mark it green",
                dep_dep_node, dep_dep_node.hash,
768 769
            );

770
            let node_index = self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node);
N
Nilstrieb 已提交
771

772
            if node_index.is_some() {
N
Nilstrieb 已提交
773
                debug!("managed to MARK dependency {dep_dep_node:?} as green",);
774 775 776 777 778
                return Some(());
            }
        }

        // We failed to mark it green, so we try to force the query.
N
Nilstrieb 已提交
779
        debug!("trying to force dependency {dep_dep_node:?}");
780
        if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
781
            // The DepNode could not be forced.
N
Nilstrieb 已提交
782
            debug!("dependency {dep_dep_node:?} could not be forced");
783 784 785
            return None;
        }

786
        let dep_dep_node_color = self.colors.get(parent_dep_node_index);
787 788 789

        match dep_dep_node_color {
            Some(DepNodeColor::Green(_)) => {
N
Nilstrieb 已提交
790
                debug!("managed to FORCE dependency {dep_dep_node:?} to green");
791 792 793
                return Some(());
            }
            Some(DepNodeColor::Red) => {
N
Nilstrieb 已提交
794
                debug!("dependency {dep_dep_node:?} was red after forcing",);
795 796 797 798 799
                return None;
            }
            None => {}
        }

800
        if let None = qcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
801 802 803 804 805 806 807 808 809 810 811 812 813
            panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
        }

        // If the query we just forced has resulted in
        // some kind of compilation error, we cannot rely on
        // the dep-node color having been properly updated.
        // This means that the query system has reached an
        // invalid state. We let the compiler continue (by
        // returning `None`) so it can emit error messages
        // and wind down, but rely on the fact that this
        // invalid state will not be persisted to the
        // incremental compilation cache because of
        // compilation errors being present.
N
Nilstrieb 已提交
814
        debug!("dependency {dep_dep_node:?} resulted in compilation error",);
815 816 817
        return None;
    }

A
Alexander Regueiro 已提交
818
    /// Try to mark a dep-node which existed in the previous compilation session as green.
819
    #[instrument(skip(self, qcx, prev_dep_node_index), level = "debug")]
820
    fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>(
821
        &self,
822
        qcx: Qcx,
823
        prev_dep_node_index: SerializedDepNodeIndex,
824
        dep_node: &DepNode<K>,
825
    ) -> Option<DepNodeIndex> {
826
        #[cfg(not(parallel_compiler))]
827
        {
828
            debug_assert!(!self.dep_node_exists(dep_node));
829
            debug_assert!(self.colors.get(prev_dep_node_index).is_none());
830 831
        }

832
        // We never try to mark eval_always nodes as green
833
        debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
834

835
        debug_assert_eq!(self.previous.index_to_node(prev_dep_node_index), *dep_node);
836

837
        let prev_deps = self.previous.edge_targets_from(prev_dep_node_index);
838

839
        for &dep_dep_node_index in prev_deps {
840 841
            let backtrace = backtrace_printer(qcx.dep_context().sess(), self, dep_dep_node_index);
            let success = self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node);
C
Camille GILLOT 已提交
842 843
            backtrace.disable();
            success?;
844 845 846 847
        }

        // If we got here without hitting a `return` that means that all
        // dependencies of this DepNode could be marked as green. Therefore we
J
John Kåre Alsaker 已提交
848
        // can also mark this DepNode as green.
849

J
John Kåre Alsaker 已提交
850 851
        // There may be multiple threads trying to mark the same dep node green concurrently

C
Camille GILLOT 已提交
852 853
        // We allocating an entry for the node in the current dependency graph and
        // adding all the appropriate edges imported from the previous graph
854
        let dep_node_index = self.current.promote_node_and_deps_to_current(
855
            qcx.dep_context().profiler(),
856
            &self.previous,
C
Camille GILLOT 已提交
857 858
            prev_dep_node_index,
        );
859

860
        // ... emitting any stored diagnostic ...
J
John Kåre Alsaker 已提交
861

862 863
        // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
        // Maybe store a list on disk and encode this fact in the DepNodeState
864
        let side_effects = qcx.load_side_effects(prev_dep_node_index);
865 866

        #[cfg(not(parallel_compiler))]
M
Mark Rousskov 已提交
867
        debug_assert!(
868
            self.colors.get(prev_dep_node_index).is_none(),
M
Mark Rousskov 已提交
869
            "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \
870
                      insertion for {dep_node:?}"
M
Mark Rousskov 已提交
871
        );
872

873
        if !side_effects.is_empty() {
J
John Kåre Alsaker 已提交
874
            qcx.dep_context().dep_graph().with_query_deserialization(|| {
875
                self.emit_side_effects(qcx, dep_node_index, side_effects)
876
            });
877 878
        }

879
        // ... and finally storing a "Green" entry in the color map.
J
John Kåre Alsaker 已提交
880
        // Multiple threads can all write the same color here
881
        self.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
882

N
Nilstrieb 已提交
883
        debug!("successfully marked {dep_node:?} as green");
884
        Some(dep_node_index)
885 886
    }

887 888
    /// Atomically emits some loaded diagnostics.
    /// This may be called concurrently on multiple threads for the same dep node.
889 890
    #[cold]
    #[inline(never)]
891
    fn emit_side_effects<Qcx: QueryContext<DepKind = K>>(
892
        &self,
893
        qcx: Qcx,
894
        dep_node_index: DepNodeIndex,
895
        side_effects: QuerySideEffects,
896
    ) {
897
        let mut processed = self.processed_side_effects.lock();
898

899
        if processed.insert(dep_node_index) {
900
            // We were the first to insert the node in the set so this thread
901
            // must process side effects
902 903

            // Promote the previous diagnostics to the current session.
904
            qcx.store_side_effects(dep_node_index, side_effects.clone());
905

906
            let handle = qcx.dep_context().sess().diagnostic();
907

908 909
            for mut diagnostic in side_effects.diagnostics {
                handle.emit_diagnostic(&mut diagnostic);
910 911 912
            }
        }
    }
913
}
914

915
impl<K: DepKind> DepGraph<K> {
916 917
    /// Returns true if the given node has been marked as red during the
    /// current compilation session. Used in various assertions
C
Camille GILLOT 已提交
918 919 920 921
    pub fn is_red(&self, dep_node: &DepNode<K>) -> bool {
        self.node_color(dep_node) == Some(DepNodeColor::Red)
    }

922 923
    /// Returns true if the given node has been marked as green during the
    /// current compilation session. Used in various assertions
924
    pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
925
        self.node_color(dep_node).map_or(false, |c| c.is_green())
926
    }
927

928 929 930 931 932 933 934 935
    /// This method loads all on-disk cacheable query results into memory, so
    /// they can be written out to the new cache file again. Most query results
    /// will already be in memory but in the case where we marked something as
    /// green but then did not need the value, that value will never have been
    /// loaded from disk.
    ///
    /// This method will only load queries that will end up in the disk cache.
    /// Other queries will not be executed.
936
    pub fn exec_cache_promotions<Tcx: DepContext<DepKind = K>>(&self, tcx: Tcx) {
937
        let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
938

J
John Kåre Alsaker 已提交
939 940 941 942
        let data = self.data.as_ref().unwrap();
        for prev_index in data.colors.values.indices() {
            match data.colors.get(prev_index) {
                Some(DepNodeColor::Green(_)) => {
943
                    let dep_node = data.previous.index_to_node(prev_index);
C
Camille GILLOT 已提交
944
                    tcx.try_load_from_on_disk_cache(dep_node);
945
                }
M
Mark Rousskov 已提交
946
                None | Some(DepNodeColor::Red) => {
J
John Kåre Alsaker 已提交
947 948 949 950 951
                    // We can skip red nodes because a node can only be marked
                    // as red if the query result was recomputed and thus is
                    // already in memory.
                }
            }
952 953
        }
    }
954

955
    pub fn print_incremental_info(&self) {
C
Camille GILLOT 已提交
956 957 958 959 960
        if let Some(data) = &self.data {
            data.current.encoder.borrow().print_incremental_info(
                data.current.total_read_count.load(Relaxed),
                data.current.total_duplicate_read_count.load(Relaxed),
            )
961
        }
C
Camille GILLOT 已提交
962
    }
963

964 965 966 967
    pub fn encode(&self, profiler: &SelfProfilerRef) -> FileEncodeResult {
        if let Some(data) = &self.data {
            data.current.encoder.steal().finish(profiler)
        } else {
968
            Ok(0)
969
        }
970 971
    }

C
Camille GILLOT 已提交
972
    pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex {
973 974 975
        let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
        DepNodeIndex::from_u32(index)
    }
976 977 978 979 980 981 982 983 984 985
}

/// A "work product" is an intermediate result that we save into the
/// incremental directory for later re-use. The primary example are
/// the object files that we save for each partition at code
/// generation time.
///
/// Each work product is associated with a dep-node, representing the
/// process that produced the work-product. If that dep-node is found
/// to be dirty when we load up, then we will delete the work-product
N
Niko Matsakis 已提交
986
/// at load time. If the work-product is found to be clean, then we
987 988 989 990 991 992 993 994 995 996 997
/// will keep a record in the `previous_work_products` list.
///
/// In addition, work products have an associated hash. This hash is
/// an extra hash that can be used to decide if the work-product from
/// a previous compilation can be re-used (in addition to the dirty
/// edges check).
///
/// As the primary example, consider the object files we generate for
/// each partition. In the first run, we create partitions based on
/// the symbols that need to be compiled. For each partition P, we
/// hash the symbols in P and create a `WorkProduct` record associated
I
Irina Popa 已提交
998
/// with `DepNode::CodegenUnit(P)`; the hash is the set of symbols
999 1000
/// in P.
///
I
Irina Popa 已提交
1001
/// The next time we compile, if the `DepNode::CodegenUnit(P)` is
1002 1003 1004 1005 1006 1007 1008
/// judged to be clean (which means none of the things we read to
/// generate the partition were found to be dirty), it will be loaded
/// into previous work products. We will then regenerate the set of
/// symbols in the partition P and hash them (note that new symbols
/// may be added -- for example, new monomorphizations -- even if
/// nothing in P changed!). We will compare that hash against the
/// previous hash. If it matches up, we can reuse the object file.
M
Matthew Jasper 已提交
1009
#[derive(Clone, Debug, Encodable, Decodable)]
1010
pub struct WorkProduct {
1011
    pub cgu_name: String,
1012 1013 1014 1015 1016 1017
    /// Saved files associated with this CGU. In each key/value pair, the value is the path to the
    /// saved file and the key is some identifier for the type of file being saved.
    ///
    /// By convention, file extensions are currently used as identifiers, i.e. the key "o" maps to
    /// the object file's path, and "dwo" to the dwarf object file's path.
    pub saved_files: FxHashMap<String, String>,
1018
}
1019

1020 1021
// Index type for `DepNodeData`'s edges.
rustc_index::newtype_index! {
1022
    struct EdgeIndex {}
1023 1024
}

1025 1026 1027
/// `CurrentDepGraph` stores the dependency graph for the current session. It
/// will be populated as we run queries or tasks. We never remove nodes from the
/// graph: they are only added.
1028
///
C
Camille GILLOT 已提交
1029
/// The nodes in it are identified by a `DepNodeIndex`. We avoid keeping the nodes
1030
/// in memory. This is important, because these graph structures are some of the
C
Camille GILLOT 已提交
1031
/// largest in the compiler.
1032
///
C
Camille GILLOT 已提交
1033
/// For this reason, we avoid storing `DepNode`s more than once as map
1034 1035
/// keys. The `new_node_to_index` map only contains nodes not in the previous
/// graph, and we map nodes in the previous graph to indices via a two-step
C
Camille GILLOT 已提交
1036
/// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
1037 1038
/// and the `prev_index_to_index` vector (which is more compact and faster than
/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
1039
///
1040 1041 1042
/// This struct uses three locks internally. The `data`, `new_node_to_index`,
/// and `prev_index_to_index` fields are locked separately. Operations that take
/// a `DepNodeIndex` typically just access the `data` field.
1043
///
1044
/// We only need to manipulate at most two locks simultaneously:
1045 1046 1047
/// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When
/// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index`
/// first, and `data` second.
C
Camille GILLOT 已提交
1048 1049
pub(super) struct CurrentDepGraph<K: DepKind> {
    encoder: Steal<GraphEncoder<K>>,
1050 1051
    new_node_to_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>,
    prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>,
1052

1053 1054 1055 1056 1057
    /// This is used to verify that fingerprints do not change between the creation of a node
    /// and its recomputation.
    #[cfg(debug_assertions)]
    fingerprints: Lock<FxHashMap<DepNode<K>, Fingerprint>>,

1058 1059
    /// Used to trap when a specific edge is added to the graph.
    /// This is used for debug purposes and is only active with `debug_assertions`.
C
Camille GILLOT 已提交
1060 1061
    #[cfg(debug_assertions)]
    forbidden_edge: Option<EdgeFilter<K>>,
1062

A
Alexander Regueiro 已提交
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
    /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of
    /// their edges. This has the beneficial side-effect that multiple anonymous
    /// nodes can be coalesced into one without changing the semantics of the
    /// dependency graph. However, the merging of nodes can lead to a subtle
    /// problem during red-green marking: The color of an anonymous node from
    /// the current session might "shadow" the color of the node with the same
    /// ID from the previous session. In order to side-step this problem, we make
    /// sure that anonymous `NodeId`s allocated in different sessions don't overlap.
    /// This is implemented by mixing a session-key into the ID fingerprint of
    /// each anon node. The session-key is just a random number generated when
    /// the `DepGraph` is created.
1074
    anon_id_seed: Fingerprint,
1075

1076 1077
    /// These are simple counters that are for profiling and
    /// debugging and only active with `debug_assertions`.
1078 1079
    total_read_count: AtomicU64,
    total_duplicate_read_count: AtomicU64,
1080 1081 1082 1083 1084 1085

    /// The cached event id for profiling node interning. This saves us
    /// from having to look up the event id every time we intern a node
    /// which may incur too much overhead.
    /// This will be None if self-profiling is disabled.
    node_intern_event_id: Option<EventId>,
1086 1087
}

1088
impl<K: DepKind> CurrentDepGraph<K> {
C
Camille GILLOT 已提交
1089
    fn new(
1090
        profiler: &SelfProfilerRef,
C
Camille GILLOT 已提交
1091 1092 1093 1094 1095
        prev_graph_node_count: usize,
        encoder: FileEncoder,
        record_graph: bool,
        record_stats: bool,
    ) -> CurrentDepGraph<K> {
1096 1097 1098
        use std::time::{SystemTime, UNIX_EPOCH};

        let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
M
Mark Rousskov 已提交
1099
        let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64;
1100 1101
        let mut stable_hasher = StableHasher::new();
        nanos.hash(&mut stable_hasher);
1102
        let anon_id_seed = stable_hasher.finish();
1103

C
Camille GILLOT 已提交
1104 1105 1106 1107 1108 1109 1110
        #[cfg(debug_assertions)]
        let forbidden_edge = match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
            Ok(s) => match EdgeFilter::new(&s) {
                Ok(f) => Some(f),
                Err(err) => panic!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
            },
            Err(_) => None,
1111 1112
        };

1113 1114 1115 1116
        // We store a large collection of these in `prev_index_to_index` during
        // non-full incremental builds, and want to ensure that the element size
        // doesn't inadvertently increase.
        static_assert_size!(Option<DepNodeIndex>, 4);
1117

C
Camille GILLOT 已提交
1118 1119
        let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200;

1120 1121 1122 1123
        let node_intern_event_id = profiler
            .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node")
            .map(EventId::from_label);

1124
        CurrentDepGraph {
C
Camille GILLOT 已提交
1125 1126 1127 1128 1129 1130
            encoder: Steal::new(GraphEncoder::new(
                encoder,
                prev_graph_node_count,
                record_graph,
                record_stats,
            )),
1131
            new_node_to_index: Sharded::new(|| {
M
Mark Rousskov 已提交
1132 1133 1134 1135 1136
                FxHashMap::with_capacity_and_hasher(
                    new_node_count_estimate / sharded::SHARDS,
                    Default::default(),
                )
            }),
1137
            prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)),
1138
            anon_id_seed,
C
Camille GILLOT 已提交
1139
            #[cfg(debug_assertions)]
1140
            forbidden_edge,
1141 1142
            #[cfg(debug_assertions)]
            fingerprints: Lock::new(Default::default()),
1143 1144
            total_read_count: AtomicU64::new(0),
            total_duplicate_read_count: AtomicU64::new(0),
1145
            node_intern_event_id,
1146 1147 1148
        }
    }

C
Camille GILLOT 已提交
1149
    #[cfg(debug_assertions)]
1150
    fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode<K>, fingerprint: Fingerprint) {
C
Camille GILLOT 已提交
1151 1152 1153
        if let Some(forbidden_edge) = &self.forbidden_edge {
            forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
        }
1154 1155 1156 1157 1158 1159 1160 1161
        match self.fingerprints.lock().entry(key) {
            Entry::Vacant(v) => {
                v.insert(fingerprint);
            }
            Entry::Occupied(o) => {
                assert_eq!(*o.get(), fingerprint, "Unstable fingerprints for {:?}", key);
            }
        }
C
Camille GILLOT 已提交
1162 1163 1164 1165
    }

    /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it.
    /// Assumes that this is a node that has no equivalent in the previous dep-graph.
1166
    #[inline(always)]
1167
    fn intern_new_node(
1168
        &self,
C
Camille GILLOT 已提交
1169
        profiler: &SelfProfilerRef,
C
Camille GILLOT 已提交
1170
        key: DepNode<K>,
1171
        edges: EdgesVec,
C
Camille GILLOT 已提交
1172
        current_fingerprint: Fingerprint,
1173
    ) -> DepNodeIndex {
1174 1175
        let dep_node_index = match self.new_node_to_index.get_shard_by_value(&key).lock().entry(key)
        {
1176 1177
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => {
C
Camille GILLOT 已提交
1178 1179
                let dep_node_index =
                    self.encoder.borrow().send(profiler, key, current_fingerprint, edges);
1180 1181 1182
                entry.insert(dep_node_index);
                dep_node_index
            }
1183 1184 1185 1186 1187 1188
        };

        #[cfg(debug_assertions)]
        self.record_edge(dep_node_index, key, current_fingerprint);

        dep_node_index
1189 1190
    }

C
Camille GILLOT 已提交
1191
    fn intern_node(
1192
        &self,
C
Camille GILLOT 已提交
1193
        profiler: &SelfProfilerRef,
C
Camille GILLOT 已提交
1194
        prev_graph: &SerializedDepGraph<K>,
C
Camille GILLOT 已提交
1195
        key: DepNode<K>,
1196
        edges: EdgesVec,
C
Camille GILLOT 已提交
1197
        fingerprint: Option<Fingerprint>,
C
Camille GILLOT 已提交
1198 1199 1200 1201
        print_status: bool,
    ) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) {
        let print_status = cfg!(debug_assertions) && print_status;

1202 1203 1204 1205
        // Get timer for profiling `DepNode` interning
        let _node_intern_timer =
            self.node_intern_event_id.map(|eid| profiler.generic_activity_with_event_id(eid));

C
Camille GILLOT 已提交
1206 1207
        if let Some(prev_index) = prev_graph.node_to_index_opt(&key) {
            // Determine the color and index of the new `DepNode`.
C
Camille GILLOT 已提交
1208 1209
            if let Some(fingerprint) = fingerprint {
                if fingerprint == prev_graph.fingerprint_by_index(prev_index) {
C
Camille GILLOT 已提交
1210
                    if print_status {
1211
                        eprintln!("[task::green] {key:?}");
C
Camille GILLOT 已提交
1212
                    }
1213

C
Camille GILLOT 已提交
1214
                    // This is a green node: it existed in the previous compilation,
C
Camille GILLOT 已提交
1215 1216 1217 1218 1219 1220 1221
                    // its query was re-executed, and it has the same result as before.
                    let mut prev_index_to_index = self.prev_index_to_index.lock();

                    let dep_node_index = match prev_index_to_index[prev_index] {
                        Some(dep_node_index) => dep_node_index,
                        None => {
                            let dep_node_index =
C
Camille GILLOT 已提交
1222
                                self.encoder.borrow().send(profiler, key, fingerprint, edges);
C
Camille GILLOT 已提交
1223 1224 1225 1226
                            prev_index_to_index[prev_index] = Some(dep_node_index);
                            dep_node_index
                        }
                    };
1227

C
Camille GILLOT 已提交
1228
                    #[cfg(debug_assertions)]
1229
                    self.record_edge(dep_node_index, key, fingerprint);
C
Camille GILLOT 已提交
1230 1231 1232
                    (dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index))))
                } else {
                    if print_status {
1233
                        eprintln!("[task::red] {key:?}");
C
Camille GILLOT 已提交
1234
                    }
1235

C
Camille GILLOT 已提交
1236 1237 1238 1239 1240 1241 1242 1243
                    // This is a red node: it existed in the previous compilation, its query
                    // was re-executed, but it has a different result from before.
                    let mut prev_index_to_index = self.prev_index_to_index.lock();

                    let dep_node_index = match prev_index_to_index[prev_index] {
                        Some(dep_node_index) => dep_node_index,
                        None => {
                            let dep_node_index =
C
Camille GILLOT 已提交
1244
                                self.encoder.borrow().send(profiler, key, fingerprint, edges);
C
Camille GILLOT 已提交
1245 1246 1247 1248
                            prev_index_to_index[prev_index] = Some(dep_node_index);
                            dep_node_index
                        }
                    };
1249

C
Camille GILLOT 已提交
1250
                    #[cfg(debug_assertions)]
1251
                    self.record_edge(dep_node_index, key, fingerprint);
C
Camille GILLOT 已提交
1252 1253 1254 1255
                    (dep_node_index, Some((prev_index, DepNodeColor::Red)))
                }
            } else {
                if print_status {
1256
                    eprintln!("[task::unknown] {key:?}");
C
Camille GILLOT 已提交
1257
                }
1258

C
Camille GILLOT 已提交
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
                // This is a red node, effectively: it existed in the previous compilation
                // session, its query was re-executed, but it doesn't compute a result hash
                // (i.e. it represents a `no_hash` query), so we have no way of determining
                // whether or not the result was the same as before.
                let mut prev_index_to_index = self.prev_index_to_index.lock();

                let dep_node_index = match prev_index_to_index[prev_index] {
                    Some(dep_node_index) => dep_node_index,
                    None => {
                        let dep_node_index =
C
Camille GILLOT 已提交
1269
                            self.encoder.borrow().send(profiler, key, Fingerprint::ZERO, edges);
C
Camille GILLOT 已提交
1270 1271 1272 1273 1274 1275
                        prev_index_to_index[prev_index] = Some(dep_node_index);
                        dep_node_index
                    }
                };

                #[cfg(debug_assertions)]
1276
                self.record_edge(dep_node_index, key, Fingerprint::ZERO);
C
Camille GILLOT 已提交
1277
                (dep_node_index, Some((prev_index, DepNodeColor::Red)))
1278
            }
C
Camille GILLOT 已提交
1279 1280
        } else {
            if print_status {
1281
                eprintln!("[task::new] {key:?}");
C
Camille GILLOT 已提交
1282 1283
            }

C
Camille GILLOT 已提交
1284
            let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
C
Camille GILLOT 已提交
1285 1286

            // This is a new node: it didn't exist in the previous compilation session.
C
Camille GILLOT 已提交
1287
            let dep_node_index = self.intern_new_node(profiler, key, edges, fingerprint);
C
Camille GILLOT 已提交
1288 1289

            (dep_node_index, None)
1290 1291 1292
        }
    }

C
Camille GILLOT 已提交
1293
    fn promote_node_and_deps_to_current(
1294
        &self,
C
Camille GILLOT 已提交
1295
        profiler: &SelfProfilerRef,
C
Camille GILLOT 已提交
1296
        prev_graph: &SerializedDepGraph<K>,
1297 1298 1299 1300 1301 1302 1303 1304 1305
        prev_index: SerializedDepNodeIndex,
    ) -> DepNodeIndex {
        self.debug_assert_not_in_new_nodes(prev_graph, prev_index);

        let mut prev_index_to_index = self.prev_index_to_index.lock();

        match prev_index_to_index[prev_index] {
            Some(dep_node_index) => dep_node_index,
            None => {
C
Camille GILLOT 已提交
1306
                let key = prev_graph.index_to_node(prev_index);
1307 1308 1309 1310 1311 1312 1313
                let edges = prev_graph
                    .edge_targets_from(prev_index)
                    .iter()
                    .map(|i| prev_index_to_index[*i].unwrap())
                    .collect();
                let fingerprint = prev_graph.fingerprint_by_index(prev_index);
                let dep_node_index = self.encoder.borrow().send(profiler, key, fingerprint, edges);
1314
                prev_index_to_index[prev_index] = Some(dep_node_index);
C
Camille GILLOT 已提交
1315
                #[cfg(debug_assertions)]
1316
                self.record_edge(dep_node_index, key, fingerprint);
1317
                dep_node_index
1318
            }
1319 1320 1321 1322 1323 1324
        }
    }

    #[inline]
    fn debug_assert_not_in_new_nodes(
        &self,
C
Camille GILLOT 已提交
1325
        prev_graph: &SerializedDepGraph<K>,
1326 1327 1328 1329 1330 1331 1332
        prev_index: SerializedDepNodeIndex,
    ) {
        let node = &prev_graph.index_to_node(prev_index);
        debug_assert!(
            !self.new_node_to_index.get_shard_by_value(node).lock().contains_key(node),
            "node from previous graph present in new node collection"
        );
1333
    }
J
John Kåre Alsaker 已提交
1334 1335
}

1336
/// The capacity of the `reads` field `SmallVec`
1337
const TASK_DEPS_READS_CAP: usize = 8;
1338
type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>;
1339

1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
#[derive(Debug, Clone, Copy)]
pub enum TaskDepsRef<'a, K: DepKind> {
    /// New dependencies can be added to the
    /// `TaskDeps`. This is used when executing a 'normal' query
    /// (no `eval_always` modifier)
    Allow(&'a Lock<TaskDeps<K>>),
    /// New dependencies are ignored. This is used when
    /// executing an `eval_always` query, since there's no
    /// need to track dependencies for a query that's always
    /// re-executed. This is also used for `dep_graph.with_ignore`
    Ignore,
    /// Any attempt to add new dependencies will cause a panic.
    /// This is used when decoding a query result from disk,
    /// to ensure that the decoding process doesn't itself
    /// require the execution of any queries.
    Forbid,
}

#[derive(Debug)]
pub struct TaskDeps<K: DepKind> {
1360
    #[cfg(debug_assertions)]
1361
    node: Option<DepNode<K>>,
1362
    reads: EdgesVec,
J
John Kåre Alsaker 已提交
1363
    read_set: FxHashSet<DepNodeIndex>,
C
Camille GILLOT 已提交
1364
    phantom_data: PhantomData<DepNode<K>>,
1365 1366
}

1367
impl<K: DepKind> Default for TaskDeps<K> {
1368 1369 1370 1371 1372 1373
    fn default() -> Self {
        Self {
            #[cfg(debug_assertions)]
            node: None,
            reads: EdgesVec::new(),
            read_set: FxHashSet::default(),
C
Camille GILLOT 已提交
1374
            phantom_data: PhantomData,
1375 1376
        }
    }
J
John Kåre Alsaker 已提交
1377 1378
}

1379 1380 1381
// A data structure that stores Option<DepNodeColor> values as a contiguous
// array, using one u32 per entry.
struct DepNodeColorMap {
1382
    values: IndexVec<SerializedDepNodeIndex, AtomicU32>,
1383 1384 1385 1386 1387 1388 1389 1390
}

const COMPRESSED_NONE: u32 = 0;
const COMPRESSED_RED: u32 = 1;
const COMPRESSED_FIRST_GREEN: u32 = 2;

impl DepNodeColorMap {
    fn new(size: usize) -> DepNodeColorMap {
M
Mark Rousskov 已提交
1391
        DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() }
1392 1393
    }

1394
    #[inline]
1395
    fn get(&self, index: SerializedDepNodeIndex) -> Option<DepNodeColor> {
1396
        match self.values[index].load(Ordering::Acquire) {
1397 1398
            COMPRESSED_NONE => None,
            COMPRESSED_RED => Some(DepNodeColor::Red),
M
Mark Rousskov 已提交
1399 1400 1401
            value => {
                Some(DepNodeColor::Green(DepNodeIndex::from_u32(value - COMPRESSED_FIRST_GREEN)))
            }
1402 1403 1404
        }
    }

1405
    #[inline]
1406
    fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) {
M
Mark Rousskov 已提交
1407 1408 1409 1410 1411 1412 1413
        self.values[index].store(
            match color {
                DepNodeColor::Red => COMPRESSED_RED,
                DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN,
            },
            Ordering::Release,
        )
1414 1415
    }
}
C
Camille GILLOT 已提交
1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438

fn backtrace_printer<'a, K: DepKind>(
    sess: &'a rustc_session::Session,
    graph: &'a DepGraphData<K>,
    node: SerializedDepNodeIndex,
) -> OnDrop<impl Fn() + 'a> {
    OnDrop(
        #[inline(never)]
        #[cold]
        move || {
            let node = graph.previous.index_to_node(node);
            // Do not try to rely on DepNode's Debug implementation, since it may panic.
            let diag = rustc_errors::Diagnostic::new(
                rustc_errors::Level::FailureNote,
                &format!(
                    "encountered while trying to mark dependency green: {:?}({})",
                    node.kind, node.hash
                ),
            );
            sess.diagnostic().force_print_diagnostic(diag);
        },
    )
}