forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgraph.rs
205 lines (183 loc) · 8.21 KB
/
graph.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use hir::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
use session::config::OutputType;
use std::cell::{Ref, RefCell};
use std::rc::Rc;
use std::sync::Arc;
use super::dep_node::{DepNode, WorkProductId};
use super::query::DepGraphQuery;
use super::raii;
use super::safe::DepGraphSafe;
use super::thread::{DepGraphThreadData, DepMessage};
#[derive(Clone)]
pub struct DepGraph {
data: Rc<DepGraphData>
}
struct DepGraphData {
/// We send messages to the thread to let it build up the dep-graph
/// from the current run.
thread: DepGraphThreadData,
/// When we load, there may be `.o` files, cached mir, or other such
/// 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.
previous_work_products: RefCell<FxHashMap<Arc<WorkProductId>, WorkProduct>>,
/// Work-products that we generate in this run.
work_products: RefCell<FxHashMap<Arc<WorkProductId>, WorkProduct>>,
}
impl DepGraph {
pub fn new(enabled: bool) -> DepGraph {
DepGraph {
data: Rc::new(DepGraphData {
thread: DepGraphThreadData::new(enabled),
previous_work_products: RefCell::new(FxHashMap()),
work_products: RefCell::new(FxHashMap()),
})
}
}
/// True if we are actually building the full dep-graph.
#[inline]
pub fn is_fully_enabled(&self) -> bool {
self.data.thread.is_fully_enabled()
}
pub fn query(&self) -> DepGraphQuery<DefId> {
self.data.thread.query()
}
pub fn in_ignore<'graph>(&'graph self) -> Option<raii::IgnoreTask<'graph>> {
raii::IgnoreTask::new(&self.data.thread)
}
pub fn in_task<'graph>(&'graph self, key: DepNode<DefId>) -> Option<raii::DepTask<'graph>> {
raii::DepTask::new(&self.data.thread, key)
}
pub fn with_ignore<OP,R>(&self, op: OP) -> R
where OP: FnOnce() -> R
{
let _task = self.in_ignore();
op()
}
/// 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
/// dep-graph -- see the [README] for more details on the
/// dep-graph). To this end, the task function gets exactly two
/// 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.
///
/// [README]: README.md
pub fn with_task<C, A, R>(&self, key: DepNode<DefId>, cx: C, arg: A, task: fn(C, A) -> R) -> R
where C: DepGraphSafe, A: DepGraphSafe
{
let _task = self.in_task(key);
task(cx, arg)
}
pub fn read(&self, v: DepNode<DefId>) {
if self.data.thread.is_enqueue_enabled() {
self.data.thread.enqueue(DepMessage::Read(v));
}
}
pub fn write(&self, v: DepNode<DefId>) {
if self.data.thread.is_enqueue_enabled() {
self.data.thread.enqueue(DepMessage::Write(v));
}
}
/// Indicates that a previous work product exists for `v`. This is
/// invoked during initial start-up based on what nodes are clean
/// (and what files exist in the incr. directory).
pub fn insert_previous_work_product(&self, v: &Arc<WorkProductId>, data: WorkProduct) {
debug!("insert_previous_work_product({:?}, {:?})", v, data);
self.data.previous_work_products.borrow_mut()
.insert(v.clone(), data);
}
/// Indicates that we created the given work-product in this run
/// for `v`. This record will be preserved and loaded in the next
/// run.
pub fn insert_work_product(&self, v: &Arc<WorkProductId>, data: WorkProduct) {
debug!("insert_work_product({:?}, {:?})", v, data);
self.data.work_products.borrow_mut()
.insert(v.clone(), data);
}
/// Check whether a previous work product exists for `v` and, if
/// so, return the path that leads to it. Used to skip doing work.
pub fn previous_work_product(&self, v: &Arc<WorkProductId>) -> Option<WorkProduct> {
self.data.previous_work_products.borrow()
.get(v)
.cloned()
}
/// Access the map of work-products created during this run. Only
/// used during saving of the dep-graph.
pub fn work_products(&self) -> Ref<FxHashMap<Arc<WorkProductId>, WorkProduct>> {
self.data.work_products.borrow()
}
/// Access the map of work-products created during the cached run. Only
/// used during saving of the dep-graph.
pub fn previous_work_products(&self) -> Ref<FxHashMap<Arc<WorkProductId>, WorkProduct>> {
self.data.previous_work_products.borrow()
}
}
/// 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
/// at load time. If the work-product is found to be clean, then we
/// 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
/// with `DepNode::TransPartition(P)`; the hash is the set of symbols
/// in P.
///
/// The next time we compile, if the `DepNode::TransPartition(P)` is
/// 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.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct WorkProduct {
/// Extra hash used to decide if work-product is still suitable;
/// note that this is *not* a hash of the work-product itself.
/// See documentation on `WorkProduct` type for an example.
pub input_hash: u64,
/// Saved files associated with this CGU
pub saved_files: Vec<(OutputType, String)>,
}