1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use errors
::DiagnosticBuilder
;
12 use rustc_data_structures
::stable_hasher
::{HashStable
, StableHasher
,
13 StableHashingContextProvider
};
14 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
15 use rustc_data_structures
::indexed_vec
::{Idx, IndexVec}
;
16 use std
::cell
::{Ref, RefCell}
;
21 use util
::common
::{ProfileQueriesMsg, profq_msg}
;
25 use super::debug
::EdgeFilter
;
26 use super::dep_node
::{DepNode, DepKind, WorkProductId}
;
27 use super::query
::DepGraphQuery
;
29 use super::safe
::DepGraphSafe
;
30 use super::serialized
::{SerializedDepGraph, SerializedDepNodeIndex}
;
31 use super::prev
::PreviousDepGraph
;
35 data
: Option
<Rc
<DepGraphData
>>,
37 // A vector mapping depnodes from the current graph to their associated
38 // result value fingerprints. Do not rely on the length of this vector
39 // being the same as the number of nodes in the graph. The vector can
40 // contain an arbitrary number of zero-entries at the end.
41 fingerprints
: Rc
<RefCell
<IndexVec
<DepNodeIndex
, Fingerprint
>>>
45 newtype_index
!(DepNodeIndex
);
48 const INVALID
: DepNodeIndex
= DepNodeIndex(::std
::u32::MAX
);
51 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
52 pub enum DepNodeColor
{
58 pub fn is_green(self) -> bool
{
60 DepNodeColor
::Red
=> false,
61 DepNodeColor
::Green(_
) => true,
67 /// The new encoding of the dependency graph, optimized for red/green
68 /// tracking. The `current` field is the dependency graph of only the
69 /// current compilation session: We don't merge the previous dep-graph into
70 /// current one anymore.
71 current
: RefCell
<CurrentDepGraph
>,
73 /// The dep-graph from the previous compilation session. It contains all
74 /// nodes and edges as well as all fingerprints of nodes that have them.
75 previous
: PreviousDepGraph
,
77 colors
: RefCell
<FxHashMap
<DepNode
, DepNodeColor
>>,
79 /// When we load, there may be `.o` files, cached mir, or other such
80 /// things available to us. If we find that they are not dirty, we
81 /// load the path to the file storing those work-products here into
82 /// this map. We can later look for and extract that data.
83 previous_work_products
: RefCell
<FxHashMap
<WorkProductId
, WorkProduct
>>,
85 /// Work-products that we generate in this run.
86 work_products
: RefCell
<FxHashMap
<WorkProductId
, WorkProduct
>>,
88 dep_node_debug
: RefCell
<FxHashMap
<DepNode
, String
>>,
90 // Used for testing, only populated when -Zquery-dep-graph is specified.
91 loaded_from_cache
: RefCell
<FxHashMap
<DepNodeIndex
, bool
>>,
96 pub fn new(prev_graph
: PreviousDepGraph
) -> DepGraph
{
97 // Pre-allocate the fingerprints array. We over-allocate a little so
98 // that we hopefully don't have to re-allocate during this compilation
100 let fingerprints
= IndexVec
::from_elem_n(Fingerprint
::ZERO
,
101 (prev_graph
.node_count() * 115) / 100);
103 data
: Some(Rc
::new(DepGraphData
{
104 previous_work_products
: RefCell
::new(FxHashMap()),
105 work_products
: RefCell
::new(FxHashMap()),
106 dep_node_debug
: RefCell
::new(FxHashMap()),
107 current
: RefCell
::new(CurrentDepGraph
::new()),
108 previous
: prev_graph
,
109 colors
: RefCell
::new(FxHashMap()),
110 loaded_from_cache
: RefCell
::new(FxHashMap()),
112 fingerprints
: Rc
::new(RefCell
::new(fingerprints
)),
116 pub fn new_disabled() -> DepGraph
{
119 fingerprints
: Rc
::new(RefCell
::new(IndexVec
::new())),
123 /// True if we are actually building the full dep-graph.
125 pub fn is_fully_enabled(&self) -> bool
{
129 pub fn query(&self) -> DepGraphQuery
{
130 let current_dep_graph
= self.data
.as_ref().unwrap().current
.borrow();
131 let nodes
: Vec
<_
> = current_dep_graph
.nodes
.iter().cloned().collect();
132 let mut edges
= Vec
::new();
133 for (index
, edge_targets
) in current_dep_graph
.edges
.iter_enumerated() {
134 let from
= current_dep_graph
.nodes
[index
];
135 for &edge_target
in edge_targets
{
136 let to
= current_dep_graph
.nodes
[edge_target
];
137 edges
.push((from
, to
));
141 DepGraphQuery
::new(&nodes
[..], &edges
[..])
144 pub fn assert_ignored(&self)
146 if let Some(ref data
) = self.data
{
147 match data
.current
.borrow().task_stack
.last() {
148 Some(&OpenTask
::Ignore
) | None
=> {
151 _
=> panic
!("expected an ignore context")
156 pub fn with_ignore
<OP
,R
>(&self, op
: OP
) -> R
157 where OP
: FnOnce() -> R
159 let _task
= self.data
.as_ref().map(|data
| raii
::IgnoreTask
::new(&data
.current
));
163 /// Starts a new dep-graph task. Dep-graph tasks are specified
164 /// using a free function (`task`) and **not** a closure -- this
165 /// is intentional because we want to exercise tight control over
166 /// what state they have access to. In particular, we want to
167 /// prevent implicit 'leaks' of tracked state into the task (which
168 /// could then be read without generating correct edges in the
169 /// dep-graph -- see the module-level [README] for more details on
170 /// the dep-graph). To this end, the task function gets exactly two
171 /// pieces of state: the context `cx` and an argument `arg`. Both
172 /// of these bits of state must be of some type that implements
173 /// `DepGraphSafe` and hence does not leak.
175 /// The choice of two arguments is not fundamental. One argument
176 /// would work just as well, since multiple values can be
177 /// collected using tuples. However, using two arguments works out
178 /// to be quite convenient, since it is common to need a context
179 /// (`cx`) and some argument (e.g., a `DefId` identifying what
180 /// item to process).
182 /// For cases where you need some other number of arguments:
184 /// - If you only need one argument, just use `()` for the `arg`
186 /// - If you need 3+ arguments, use a tuple for the
189 /// [README]: https://github.com/rust-lang/rust/blob/master/src/librustc/dep_graph/README.md
190 pub fn with_task
<C
, A
, R
, HCX
>(&self,
196 where C
: DepGraphSafe
+ StableHashingContextProvider
<ContextType
=HCX
>,
199 self.with_task_impl(key
, cx
, arg
, task
,
200 |data
, key
| data
.borrow_mut().push_task(key
),
201 |data
, key
| data
.borrow_mut().pop_task(key
))
204 fn with_task_impl
<C
, A
, R
, HCX
>(&self,
209 push
: fn(&RefCell
<CurrentDepGraph
>, DepNode
),
210 pop
: fn(&RefCell
<CurrentDepGraph
>, DepNode
) -> DepNodeIndex
)
212 where C
: DepGraphSafe
+ StableHashingContextProvider
<ContextType
=HCX
>,
215 if let Some(ref data
) = self.data
{
216 debug_assert
!(!data
.colors
.borrow().contains_key(&key
));
218 push(&data
.current
, key
);
219 if cfg
!(debug_assertions
) {
220 profq_msg(ProfileQueriesMsg
::TaskBegin(key
.clone()))
223 // In incremental mode, hash the result of the task. We don't
224 // do anything with the hash yet, but we are computing it
226 // - we make sure that the infrastructure works and
227 // - we can get an idea of the runtime cost.
228 let mut hcx
= cx
.create_stable_hashing_context();
230 let result
= task(cx
, arg
);
231 if cfg
!(debug_assertions
) {
232 profq_msg(ProfileQueriesMsg
::TaskEnd
)
235 let dep_node_index
= pop(&data
.current
, key
);
237 let mut stable_hasher
= StableHasher
::new();
238 result
.hash_stable(&mut hcx
, &mut stable_hasher
);
240 let current_fingerprint
= stable_hasher
.finish();
242 // Store the current fingerprint
244 let mut fingerprints
= self.fingerprints
.borrow_mut();
246 if dep_node_index
.index() >= fingerprints
.len() {
247 fingerprints
.resize(dep_node_index
.index() + 1, Fingerprint
::ZERO
);
250 debug_assert
!(fingerprints
[dep_node_index
] == Fingerprint
::ZERO
,
251 "DepGraph::with_task() - Duplicate fingerprint \
252 insertion for {:?}", key
);
253 fingerprints
[dep_node_index
] = current_fingerprint
;
256 // Determine the color of the new DepNode.
258 let prev_fingerprint
= data
.previous
.fingerprint_of(&key
);
260 let color
= if Some(current_fingerprint
) == prev_fingerprint
{
261 DepNodeColor
::Green(dep_node_index
)
266 let old_value
= data
.colors
.borrow_mut().insert(key
, color
);
267 debug_assert
!(old_value
.is_none(),
268 "DepGraph::with_task() - Duplicate DepNodeColor \
269 insertion for {:?}", key
);
272 (result
, dep_node_index
)
274 if key
.kind
.fingerprint_needed_for_crate_hash() {
275 let mut hcx
= cx
.create_stable_hashing_context();
276 let result
= task(cx
, arg
);
277 let mut stable_hasher
= StableHasher
::new();
278 result
.hash_stable(&mut hcx
, &mut stable_hasher
);
279 let fingerprint
= stable_hasher
.finish();
281 let mut fingerprints
= self.fingerprints
.borrow_mut();
282 let dep_node_index
= DepNodeIndex
::new(fingerprints
.len());
283 fingerprints
.push(fingerprint
);
284 debug_assert
!(fingerprints
[dep_node_index
] == fingerprint
,
285 "DepGraph::with_task() - Assigned fingerprint to \
286 unexpected index for {:?}", key
);
287 (result
, dep_node_index
)
289 (task(cx
, arg
), DepNodeIndex
::INVALID
)
294 /// Execute something within an "anonymous" task, that is, a task the
295 /// DepNode of which is determined by the list of inputs it read from.
296 pub fn with_anon_task
<OP
,R
>(&self, dep_kind
: DepKind
, op
: OP
) -> (R
, DepNodeIndex
)
297 where OP
: FnOnce() -> R
299 if let Some(ref data
) = self.data
{
300 data
.current
.borrow_mut().push_anon_task();
302 let dep_node_index
= data
.current
304 .pop_anon_task(dep_kind
);
305 (result
, dep_node_index
)
307 (op(), DepNodeIndex
::INVALID
)
311 /// Execute something within an "eval-always" task which is a task
312 // that runs whenever anything changes.
313 pub fn with_eval_always_task
<C
, A
, R
, HCX
>(&self,
319 where C
: DepGraphSafe
+ StableHashingContextProvider
<ContextType
=HCX
>,
322 self.with_task_impl(key
, cx
, arg
, task
,
323 |data
, key
| data
.borrow_mut().push_eval_always_task(key
),
324 |data
, key
| data
.borrow_mut().pop_eval_always_task(key
))
328 pub fn read(&self, v
: DepNode
) {
329 if let Some(ref data
) = self.data
{
330 let mut current
= data
.current
.borrow_mut();
331 if let Some(&dep_node_index
) = current
.node_to_node_index
.get(&v
) {
332 current
.read_index(dep_node_index
);
334 bug
!("DepKind {:?} should be pre-allocated but isn't.", v
.kind
)
340 pub fn read_index(&self, dep_node_index
: DepNodeIndex
) {
341 if let Some(ref data
) = self.data
{
342 data
.current
.borrow_mut().read_index(dep_node_index
);
347 pub fn dep_node_index_of(&self, dep_node
: &DepNode
) -> DepNodeIndex
{
360 pub fn fingerprint_of(&self, dep_node_index
: DepNodeIndex
) -> Fingerprint
{
361 match self.fingerprints
.borrow().get(dep_node_index
) {
362 Some(&fingerprint
) => fingerprint
,
364 if let Some(ref data
) = self.data
{
365 let dep_node
= data
.current
.borrow().nodes
[dep_node_index
];
366 bug
!("Could not find current fingerprint for {:?}", dep_node
)
368 bug
!("Could not find current fingerprint for {:?}", dep_node_index
)
374 pub fn prev_fingerprint_of(&self, dep_node
: &DepNode
) -> Option
<Fingerprint
> {
375 self.data
.as_ref().unwrap().previous
.fingerprint_of(dep_node
)
379 pub fn prev_dep_node_index_of(&self, dep_node
: &DepNode
) -> SerializedDepNodeIndex
{
380 self.data
.as_ref().unwrap().previous
.node_to_index(dep_node
)
383 /// Indicates that a previous work product exists for `v`. This is
384 /// invoked during initial start-up based on what nodes are clean
385 /// (and what files exist in the incr. directory).
386 pub fn insert_previous_work_product(&self, v
: &WorkProductId
, data
: WorkProduct
) {
387 debug
!("insert_previous_work_product({:?}, {:?})", v
, data
);
391 .previous_work_products
393 .insert(v
.clone(), data
);
396 /// Indicates that we created the given work-product in this run
397 /// for `v`. This record will be preserved and loaded in the next
399 pub fn insert_work_product(&self, v
: &WorkProductId
, data
: WorkProduct
) {
400 debug
!("insert_work_product({:?}, {:?})", v
, data
);
406 .insert(v
.clone(), data
);
409 /// Check whether a previous work product exists for `v` and, if
410 /// so, return the path that leads to it. Used to skip doing work.
411 pub fn previous_work_product(&self, v
: &WorkProductId
) -> Option
<WorkProduct
> {
415 data
.previous_work_products
.borrow().get(v
).cloned()
419 /// Access the map of work-products created during this run. Only
420 /// used during saving of the dep-graph.
421 pub fn work_products(&self) -> Ref
<FxHashMap
<WorkProductId
, WorkProduct
>> {
422 self.data
.as_ref().unwrap().work_products
.borrow()
425 /// Access the map of work-products created during the cached run. Only
426 /// used during saving of the dep-graph.
427 pub fn previous_work_products(&self) -> Ref
<FxHashMap
<WorkProductId
, WorkProduct
>> {
428 self.data
.as_ref().unwrap().previous_work_products
.borrow()
432 pub fn register_dep_node_debug_str
<F
>(&self,
435 where F
: FnOnce() -> String
437 let dep_node_debug
= &self.data
.as_ref().unwrap().dep_node_debug
;
439 if dep_node_debug
.borrow().contains_key(&dep_node
) {
442 let debug_str
= debug_str_gen();
443 dep_node_debug
.borrow_mut().insert(dep_node
, debug_str
);
446 pub(super) fn dep_node_debug_str(&self, dep_node
: DepNode
) -> Option
<String
> {
447 self.data
.as_ref().and_then(|t
| t
.dep_node_debug
.borrow().get(&dep_node
).cloned())
450 pub fn edge_deduplication_data(&self) -> (u64, u64) {
451 let current_dep_graph
= self.data
.as_ref().unwrap().current
.borrow();
453 (current_dep_graph
.total_read_count
, current_dep_graph
.total_duplicate_read_count
)
456 pub fn serialize(&self) -> SerializedDepGraph
{
457 let mut fingerprints
= self.fingerprints
.borrow_mut();
458 let current_dep_graph
= self.data
.as_ref().unwrap().current
.borrow();
460 // Make sure we don't run out of bounds below.
461 if current_dep_graph
.nodes
.len() > fingerprints
.len() {
462 fingerprints
.resize(current_dep_graph
.nodes
.len(), Fingerprint
::ZERO
);
465 let nodes
: IndexVec
<_
, (DepNode
, Fingerprint
)> =
466 current_dep_graph
.nodes
.iter_enumerated().map(|(idx
, &dep_node
)| {
467 (dep_node
, fingerprints
[idx
])
470 let total_edge_count
: usize = current_dep_graph
.edges
.iter()
474 let mut edge_list_indices
= IndexVec
::with_capacity(nodes
.len());
475 let mut edge_list_data
= Vec
::with_capacity(total_edge_count
);
477 for (current_dep_node_index
, edges
) in current_dep_graph
.edges
.iter_enumerated() {
478 let start
= edge_list_data
.len() as u32;
479 // This should really just be a memcpy :/
480 edge_list_data
.extend(edges
.iter().map(|i
| SerializedDepNodeIndex
::new(i
.index())));
481 let end
= edge_list_data
.len() as u32;
483 debug_assert_eq
!(current_dep_node_index
.index(), edge_list_indices
.len());
484 edge_list_indices
.push((start
, end
));
487 debug_assert
!(edge_list_data
.len() <= ::std
::u32::MAX
as usize);
488 debug_assert_eq
!(edge_list_data
.len(), total_edge_count
);
497 pub fn node_color(&self, dep_node
: &DepNode
) -> Option
<DepNodeColor
> {
498 self.data
.as_ref().and_then(|data
| data
.colors
.borrow().get(dep_node
).cloned())
501 pub fn try_mark_green
<'tcx
>(&self,
502 tcx
: TyCtxt
<'_
, 'tcx
, 'tcx
>,
504 -> Option
<DepNodeIndex
> {
505 debug
!("try_mark_green({:?}) - BEGIN", dep_node
);
506 let data
= self.data
.as_ref().unwrap();
508 debug_assert
!(!data
.colors
.borrow().contains_key(dep_node
));
509 debug_assert
!(!data
.current
.borrow().node_to_node_index
.contains_key(dep_node
));
511 if dep_node
.kind
.is_input() {
512 // We should only hit try_mark_green() for inputs that do not exist
513 // anymore in the current compilation session. Existing inputs are
514 // eagerly marked as either red/green before any queries are
516 debug_assert
!(dep_node
.extract_def_id(tcx
).is_none());
517 debug
!("try_mark_green({:?}) - END - DepNode is deleted input", dep_node
);
521 let (prev_deps
, prev_dep_node_index
) = match data
.previous
.edges_from(dep_node
) {
523 // This DepNode and the corresponding query invocation existed
524 // in the previous compilation session too, so we can try to
525 // mark it as green by recursively marking all of its
526 // dependencies green.
530 // This DepNode did not exist in the previous compilation session,
531 // so we cannot mark it as green.
532 debug
!("try_mark_green({:?}) - END - DepNode does not exist in \
533 current compilation session anymore", dep_node
);
538 let mut current_deps
= Vec
::new();
540 for &dep_dep_node_index
in prev_deps
{
541 let dep_dep_node
= &data
.previous
.index_to_node(dep_dep_node_index
);
543 let dep_dep_node_color
= data
.colors
.borrow().get(dep_dep_node
).cloned();
544 match dep_dep_node_color
{
545 Some(DepNodeColor
::Green(node_index
)) => {
546 // This dependency has been marked as green before, we are
547 // still fine and can continue with checking the other
549 debug
!("try_mark_green({:?}) --- found dependency {:?} to \
550 be immediately green", dep_node
, dep_dep_node
);
551 current_deps
.push(node_index
);
553 Some(DepNodeColor
::Red
) => {
554 // We found a dependency the value of which has changed
555 // compared to the previous compilation session. We cannot
556 // mark the DepNode as green and also don't need to bother
557 // with checking any of the other dependencies.
558 debug
!("try_mark_green({:?}) - END - dependency {:?} was \
559 immediately red", dep_node
, dep_dep_node
);
563 // We don't know the state of this dependency. If it isn't
564 // an input node, let's try to mark it green recursively.
565 if !dep_dep_node
.kind
.is_input() {
566 debug
!("try_mark_green({:?}) --- state of dependency {:?} \
567 is unknown, trying to mark it green", dep_node
,
570 if let Some(node_index
) = self.try_mark_green(tcx
, dep_dep_node
) {
571 debug
!("try_mark_green({:?}) --- managed to MARK \
572 dependency {:?} as green", dep_node
, dep_dep_node
);
573 current_deps
.push(node_index
);
577 match dep_dep_node
.kind
{
580 DepKind
::CrateMetadata
=> {
581 if dep_node
.extract_def_id(tcx
).is_none() {
582 // If the node does not exist anymore, we
583 // just fail to mark green.
586 // If the node does exist, it should have
587 // been pre-allocated.
588 bug
!("DepNode {:?} should have been \
589 pre-allocated but wasn't.",
594 // For other kinds of inputs it's OK to be
600 // We failed to mark it green, so we try to force the query.
601 debug
!("try_mark_green({:?}) --- trying to force \
602 dependency {:?}", dep_node
, dep_dep_node
);
603 if ::ty
::maps
::force_from_dep_node(tcx
, dep_dep_node
) {
604 let dep_dep_node_color
= data
.colors
608 match dep_dep_node_color
{
609 Some(DepNodeColor
::Green(node_index
)) => {
610 debug
!("try_mark_green({:?}) --- managed to \
611 FORCE dependency {:?} to green",
612 dep_node
, dep_dep_node
);
613 current_deps
.push(node_index
);
615 Some(DepNodeColor
::Red
) => {
616 debug
!("try_mark_green({:?}) - END - \
617 dependency {:?} was red after forcing",
623 bug
!("try_mark_green() - Forcing the DepNode \
624 should have set its color")
628 // The DepNode could not be forced.
629 debug
!("try_mark_green({:?}) - END - dependency {:?} \
630 could not be forced", dep_node
, dep_dep_node
);
638 // If we got here without hitting a `return` that means that all
639 // dependencies of this DepNode could be marked as green. Therefore we
640 // can also mark this DepNode as green. We do so by...
642 // ... allocating an entry for it in the current dependency graph and
643 // adding all the appropriate edges imported from the previous graph ...
644 let dep_node_index
= data
.current
646 .alloc_node(*dep_node
, current_deps
);
648 // ... copying the fingerprint from the previous graph too, so we don't
649 // have to recompute it ...
651 let fingerprint
= data
.previous
.fingerprint_by_index(prev_dep_node_index
);
652 let mut fingerprints
= self.fingerprints
.borrow_mut();
654 if dep_node_index
.index() >= fingerprints
.len() {
655 fingerprints
.resize(dep_node_index
.index() + 1, Fingerprint
::ZERO
);
658 debug_assert
!(fingerprints
[dep_node_index
] == Fingerprint
::ZERO
,
659 "DepGraph::try_mark_green() - Duplicate fingerprint \
660 insertion for {:?}", dep_node
);
662 fingerprints
[dep_node_index
] = fingerprint
;
665 // ... emitting any stored diagnostic ...
667 let diagnostics
= tcx
.on_disk_query_result_cache
668 .load_diagnostics(tcx
, prev_dep_node_index
);
670 if diagnostics
.len() > 0 {
671 let handle
= tcx
.sess
.diagnostic();
673 // Promote the previous diagnostics to the current session.
674 tcx
.on_disk_query_result_cache
675 .store_diagnostics(dep_node_index
, diagnostics
.clone());
677 for diagnostic
in diagnostics
{
678 DiagnosticBuilder
::new_diagnostic(handle
, diagnostic
).emit();
683 // ... and finally storing a "Green" entry in the color map.
684 let old_color
= data
.colors
686 .insert(*dep_node
, DepNodeColor
::Green(dep_node_index
));
687 debug_assert
!(old_color
.is_none(),
688 "DepGraph::try_mark_green() - Duplicate DepNodeColor \
689 insertion for {:?}", dep_node
);
691 debug
!("try_mark_green({:?}) - END - successfully marked as green", dep_node
);
695 // Used in various assertions
696 pub fn is_green(&self, dep_node_index
: DepNodeIndex
) -> bool
{
697 let dep_node
= self.data
.as_ref().unwrap().current
.borrow().nodes
[dep_node_index
];
698 self.data
.as_ref().unwrap().colors
.borrow().get(&dep_node
).map(|&color
| {
700 DepNodeColor
::Red
=> false,
701 DepNodeColor
::Green(_
) => true,
706 // This method loads all on-disk cacheable query results into memory, so
707 // they can be written out to the new cache file again. Most query results
708 // will already be in memory but in the case where we marked something as
709 // green but then did not need the value, that value will never have been
712 // This method will only load queries that will end up in the disk cache.
713 // Other queries will not be executed.
714 pub fn exec_cache_promotions
<'a
, 'tcx
>(&self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) {
715 let green_nodes
: Vec
<DepNode
> = {
716 let data
= self.data
.as_ref().unwrap();
717 data
.colors
.borrow().iter().filter_map(|(dep_node
, color
)| match color
{
718 DepNodeColor
::Green(_
) => {
719 if dep_node
.cache_on_disk(tcx
) {
725 DepNodeColor
::Red
=> {
726 // We can skip red nodes because a node can only be marked
727 // as red if the query result was recomputed and thus is
728 // already in memory.
734 for dep_node
in green_nodes
{
735 dep_node
.load_from_on_disk_cache(tcx
);
739 pub fn mark_loaded_from_cache(&self, dep_node_index
: DepNodeIndex
, state
: bool
) {
740 debug
!("mark_loaded_from_cache({:?}, {})",
741 self.data
.as_ref().unwrap().current
.borrow().nodes
[dep_node_index
],
749 .insert(dep_node_index
, state
);
752 pub fn was_loaded_from_cache(&self, dep_node
: &DepNode
) -> Option
<bool
> {
753 let data
= self.data
.as_ref().unwrap();
754 let dep_node_index
= data
.current
.borrow().node_to_node_index
[dep_node
];
755 data
.loaded_from_cache
.borrow().get(&dep_node_index
).cloned()
759 /// A "work product" is an intermediate result that we save into the
760 /// incremental directory for later re-use. The primary example are
761 /// the object files that we save for each partition at code
764 /// Each work product is associated with a dep-node, representing the
765 /// process that produced the work-product. If that dep-node is found
766 /// to be dirty when we load up, then we will delete the work-product
767 /// at load time. If the work-product is found to be clean, then we
768 /// will keep a record in the `previous_work_products` list.
770 /// In addition, work products have an associated hash. This hash is
771 /// an extra hash that can be used to decide if the work-product from
772 /// a previous compilation can be re-used (in addition to the dirty
775 /// As the primary example, consider the object files we generate for
776 /// each partition. In the first run, we create partitions based on
777 /// the symbols that need to be compiled. For each partition P, we
778 /// hash the symbols in P and create a `WorkProduct` record associated
779 /// with `DepNode::TransPartition(P)`; the hash is the set of symbols
782 /// The next time we compile, if the `DepNode::TransPartition(P)` is
783 /// judged to be clean (which means none of the things we read to
784 /// generate the partition were found to be dirty), it will be loaded
785 /// into previous work products. We will then regenerate the set of
786 /// symbols in the partition P and hash them (note that new symbols
787 /// may be added -- for example, new monomorphizations -- even if
788 /// nothing in P changed!). We will compare that hash against the
789 /// previous hash. If it matches up, we can reuse the object file.
790 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
791 pub struct WorkProduct
{
792 pub cgu_name
: String
,
793 /// Saved files associated with this CGU
794 pub saved_files
: Vec
<(WorkProductFileKind
, String
)>,
797 #[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)]
798 pub enum WorkProductFileKind
{
804 pub(super) struct CurrentDepGraph
{
805 nodes
: IndexVec
<DepNodeIndex
, DepNode
>,
806 edges
: IndexVec
<DepNodeIndex
, Vec
<DepNodeIndex
>>,
807 node_to_node_index
: FxHashMap
<DepNode
, DepNodeIndex
>,
808 task_stack
: Vec
<OpenTask
>,
809 forbidden_edge
: Option
<EdgeFilter
>,
811 // Anonymous DepNodes are nodes the ID of which we compute from the list of
812 // their edges. This has the beneficial side-effect that multiple anonymous
813 // nodes can be coalesced into one without changing the semantics of the
814 // dependency graph. However, the merging of nodes can lead to a subtle
815 // problem during red-green marking: The color of an anonymous node from
816 // the current session might "shadow" the color of the node with the same
817 // ID from the previous session. In order to side-step this problem, we make
818 // sure that anon-node IDs allocated in different sessions don't overlap.
819 // This is implemented by mixing a session-key into the ID fingerprint of
820 // each anon node. The session-key is just a random number generated when
821 // the DepGraph is created.
822 anon_id_seed
: Fingerprint
,
824 total_read_count
: u64,
825 total_duplicate_read_count
: u64,
828 impl CurrentDepGraph
{
829 fn new() -> CurrentDepGraph
{
830 use std
::time
::{SystemTime, UNIX_EPOCH}
;
832 let duration
= SystemTime
::now().duration_since(UNIX_EPOCH
).unwrap();
833 let nanos
= duration
.as_secs() * 1_000_000_000 +
834 duration
.subsec_nanos() as u64;
835 let mut stable_hasher
= StableHasher
::new();
836 nanos
.hash(&mut stable_hasher
);
838 let forbidden_edge
= if cfg
!(debug_assertions
) {
839 match env
::var("RUST_FORBID_DEP_GRAPH_EDGE") {
841 match EdgeFilter
::new(&s
) {
843 Err(err
) => bug
!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err
),
853 nodes
: IndexVec
::new(),
854 edges
: IndexVec
::new(),
855 node_to_node_index
: FxHashMap(),
856 anon_id_seed
: stable_hasher
.finish(),
857 task_stack
: Vec
::new(),
860 total_duplicate_read_count
: 0,
864 pub(super) fn push_ignore(&mut self) {
865 self.task_stack
.push(OpenTask
::Ignore
);
868 pub(super) fn pop_ignore(&mut self) {
869 let popped_node
= self.task_stack
.pop().unwrap();
870 debug_assert_eq
!(popped_node
, OpenTask
::Ignore
);
873 pub(super) fn push_task(&mut self, key
: DepNode
) {
874 self.task_stack
.push(OpenTask
::Regular
{
877 read_set
: FxHashSet(),
881 pub(super) fn pop_task(&mut self, key
: DepNode
) -> DepNodeIndex
{
882 let popped_node
= self.task_stack
.pop().unwrap();
884 if let OpenTask
::Regular
{
889 assert_eq
!(node
, key
);
891 // If this is an input node, we expect that it either has no
892 // dependencies, or that it just depends on DepKind::CrateMetadata
893 // or DepKind::Krate. This happens for some "thin wrapper queries"
894 // like `crate_disambiguator` which sometimes have zero deps (for
895 // when called for LOCAL_CRATE) or they depend on a CrateMetadata
897 if cfg
!(debug_assertions
) {
898 if node
.kind
.is_input() && reads
.len() > 0 &&
899 // FIXME(mw): Special case for DefSpan until Spans are handled
900 // better in general.
901 node
.kind
!= DepKind
::DefSpan
&&
902 reads
.iter().any(|&i
| {
903 !(self.nodes
[i
].kind
== DepKind
::CrateMetadata
||
904 self.nodes
[i
].kind
== DepKind
::Krate
)
907 bug
!("Input node {:?} with unexpected reads: {:?}",
909 reads
.iter().map(|&i
| self.nodes
[i
]).collect
::<Vec
<_
>>())
913 self.alloc_node(node
, reads
)
915 bug
!("pop_task() - Expected regular task to be popped")
919 fn push_anon_task(&mut self) {
920 self.task_stack
.push(OpenTask
::Anon
{
922 read_set
: FxHashSet(),
926 fn pop_anon_task(&mut self, kind
: DepKind
) -> DepNodeIndex
{
927 let popped_node
= self.task_stack
.pop().unwrap();
929 if let OpenTask
::Anon
{
933 debug_assert
!(!kind
.is_input());
935 let mut fingerprint
= self.anon_id_seed
;
936 let mut hasher
= StableHasher
::new();
938 for &read
in reads
.iter() {
939 let read_dep_node
= self.nodes
[read
];
941 ::std
::mem
::discriminant(&read_dep_node
.kind
).hash(&mut hasher
);
943 // Fingerprint::combine() is faster than sending Fingerprint
944 // through the StableHasher (at least as long as StableHasher
946 fingerprint
= fingerprint
.combine(read_dep_node
.hash
);
949 fingerprint
= fingerprint
.combine(hasher
.finish());
951 let target_dep_node
= DepNode
{
956 if let Some(&index
) = self.node_to_node_index
.get(&target_dep_node
) {
959 self.alloc_node(target_dep_node
, reads
)
962 bug
!("pop_anon_task() - Expected anonymous task to be popped")
966 fn push_eval_always_task(&mut self, key
: DepNode
) {
967 self.task_stack
.push(OpenTask
::EvalAlways { node: key }
);
970 fn pop_eval_always_task(&mut self, key
: DepNode
) -> DepNodeIndex
{
971 let popped_node
= self.task_stack
.pop().unwrap();
973 if let OpenTask
::EvalAlways
{
976 debug_assert_eq
!(node
, key
);
977 let krate_idx
= self.node_to_node_index
[&DepNode
::new_no_params(DepKind
::Krate
)];
978 self.alloc_node(node
, vec
![krate_idx
])
980 bug
!("pop_eval_always_task() - Expected eval always task to be popped");
984 fn read_index(&mut self, source
: DepNodeIndex
) {
985 match self.task_stack
.last_mut() {
986 Some(&mut OpenTask
::Regular
{
991 self.total_read_count
+= 1;
992 if read_set
.insert(source
) {
995 if cfg
!(debug_assertions
) {
996 if let Some(ref forbidden_edge
) = self.forbidden_edge
{
997 let source
= self.nodes
[source
];
998 if forbidden_edge
.test(&source
, &target
) {
999 bug
!("forbidden edge {:?} -> {:?} created",
1006 self.total_duplicate_read_count
+= 1;
1009 Some(&mut OpenTask
::Anon
{
1013 if read_set
.insert(source
) {
1017 Some(&mut OpenTask
::Ignore
) |
1018 Some(&mut OpenTask
::EvalAlways { .. }
) | None
=> {
1024 fn alloc_node(&mut self,
1026 edges
: Vec
<DepNodeIndex
>)
1028 debug_assert_eq
!(self.edges
.len(), self.nodes
.len());
1029 debug_assert_eq
!(self.node_to_node_index
.len(), self.nodes
.len());
1030 debug_assert
!(!self.node_to_node_index
.contains_key(&dep_node
));
1031 let dep_node_index
= DepNodeIndex
::new(self.nodes
.len());
1032 self.nodes
.push(dep_node
);
1033 self.node_to_node_index
.insert(dep_node
, dep_node_index
);
1034 self.edges
.push(edges
);
1039 #[derive(Clone, Debug, PartialEq)]
1043 reads
: Vec
<DepNodeIndex
>,
1044 read_set
: FxHashSet
<DepNodeIndex
>,
1047 reads
: Vec
<DepNodeIndex
>,
1048 read_set
: FxHashSet
<DepNodeIndex
>,