9
9
// except according to those terms.
10
10
11
11
use hir:: def_id:: DefId ;
12
+ use rustc_data_structures:: fnv:: FnvHashMap ;
13
+ use std:: cell:: { Ref , RefCell } ;
12
14
use std:: rc:: Rc ;
15
+ use std:: sync:: Arc ;
13
16
14
- use super :: dep_node:: DepNode ;
17
+ use super :: dep_node:: { DepNode , WorkProductId } ;
15
18
use super :: query:: DepGraphQuery ;
16
19
use super :: raii;
17
20
use super :: thread:: { DepGraphThreadData , DepMessage } ;
18
21
19
22
#[ derive( Clone ) ]
20
23
pub struct DepGraph {
21
- data : Rc < DepGraphThreadData >
24
+ data : Rc < DepGraphData >
25
+ }
26
+
27
+ struct DepGraphData {
28
+ /// we send messages to the thread to let it build up the dep-graph
29
+ /// from the current run
30
+ thread : DepGraphThreadData ,
31
+
32
+ /// when we load, there may be `.o` files, cached mir, or other such
33
+ /// things available to us. If we find that they are not dirty, we
34
+ /// load the path to the file storing those work-products here into
35
+ /// this map. We can later look for and extract that data.
36
+ previous_work_products : RefCell < FnvHashMap < Arc < WorkProductId > , WorkProduct > > ,
37
+
38
+ /// work-products that we generate in this run
39
+ work_products : RefCell < FnvHashMap < Arc < WorkProductId > , WorkProduct > > ,
22
40
}
23
41
24
42
impl DepGraph {
25
43
pub fn new ( enabled : bool ) -> DepGraph {
26
44
DepGraph {
27
- data : Rc :: new ( DepGraphThreadData :: new ( enabled) )
45
+ data : Rc :: new ( DepGraphData {
46
+ thread : DepGraphThreadData :: new ( enabled) ,
47
+ previous_work_products : RefCell :: new ( FnvHashMap ( ) ) ,
48
+ work_products : RefCell :: new ( FnvHashMap ( ) )
49
+ } )
28
50
}
29
51
}
30
52
31
53
/// True if we are actually building a dep-graph. If this returns false,
32
54
/// then the other methods on this `DepGraph` will have no net effect.
33
55
#[ inline]
34
56
pub fn enabled ( & self ) -> bool {
35
- self . data . enabled ( )
57
+ self . data . thread . enabled ( )
36
58
}
37
59
38
60
pub fn query ( & self ) -> DepGraphQuery < DefId > {
39
- self . data . query ( )
61
+ self . data . thread . query ( )
40
62
}
41
63
42
64
pub fn in_ignore < ' graph > ( & ' graph self ) -> raii:: IgnoreTask < ' graph > {
43
- raii:: IgnoreTask :: new ( & self . data )
65
+ raii:: IgnoreTask :: new ( & self . data . thread )
44
66
}
45
67
46
68
pub fn in_task < ' graph > ( & ' graph self , key : DepNode < DefId > ) -> raii:: DepTask < ' graph > {
47
- raii:: DepTask :: new ( & self . data , key)
69
+ raii:: DepTask :: new ( & self . data . thread , key)
48
70
}
49
71
50
72
pub fn with_ignore < OP , R > ( & self , op : OP ) -> R
@@ -62,10 +84,84 @@ impl DepGraph {
62
84
}
63
85
64
86
pub fn read ( & self , v : DepNode < DefId > ) {
65
- self . data . enqueue ( DepMessage :: Read ( v) ) ;
87
+ self . data . thread . enqueue ( DepMessage :: Read ( v) ) ;
66
88
}
67
89
68
90
pub fn write ( & self , v : DepNode < DefId > ) {
69
- self . data . enqueue ( DepMessage :: Write ( v) ) ;
91
+ self . data . thread . enqueue ( DepMessage :: Write ( v) ) ;
92
+ }
93
+
94
+ /// Indicates that a previous work product exists for `v`. This is
95
+ /// invoked during initial start-up based on what nodes are clean
96
+ /// (and what files exist in the incr. directory).
97
+ pub fn insert_previous_work_product ( & self , v : & Arc < WorkProductId > , data : WorkProduct ) {
98
+ debug ! ( "insert_previous_work_product({:?}, {:?})" , v, data) ;
99
+ self . data . previous_work_products . borrow_mut ( )
100
+ . insert ( v. clone ( ) , data) ;
101
+ }
102
+
103
+ /// Indicates that we created the given work-product in this run
104
+ /// for `v`. This record will be preserved and loaded in the next
105
+ /// run.
106
+ pub fn insert_work_product ( & self , v : & Arc < WorkProductId > , data : WorkProduct ) {
107
+ debug ! ( "insert_work_product({:?}, {:?})" , v, data) ;
108
+ self . data . work_products . borrow_mut ( )
109
+ . insert ( v. clone ( ) , data) ;
70
110
}
111
+
112
+ /// Check whether a previous work product exists for `v` and, if
113
+ /// so, return the path that leads to it. Used to skip doing work.
114
+ pub fn previous_work_product ( & self , v : & Arc < WorkProductId > ) -> Option < WorkProduct > {
115
+ self . data . previous_work_products . borrow ( )
116
+ . get ( v)
117
+ . cloned ( )
118
+ }
119
+
120
+ /// Access the map of work-products created during this run. Only
121
+ /// used during saving of the dep-graph.
122
+ pub fn work_products ( & self ) -> Ref < FnvHashMap < Arc < WorkProductId > , WorkProduct > > {
123
+ self . data . work_products . borrow ( )
124
+ }
125
+ }
126
+
127
+ /// A "work product" is an intermediate result that we save into the
128
+ /// incremental directory for later re-use. The primary example are
129
+ /// the object files that we save for each partition at code
130
+ /// generation time.
131
+ ///
132
+ /// Each work product is associated with a dep-node, representing the
133
+ /// process that produced the work-product. If that dep-node is found
134
+ /// to be dirty when we load up, then we will delete the work-product
135
+ /// at load time. If the work-product is found to be clean, the we
136
+ /// will keep a record in the `previous_work_products` list.
137
+ ///
138
+ /// In addition, work products have an associated hash. This hash is
139
+ /// an extra hash that can be used to decide if the work-product from
140
+ /// a previous compilation can be re-used (in addition to the dirty
141
+ /// edges check).
142
+ ///
143
+ /// As the primary example, consider the object files we generate for
144
+ /// each partition. In the first run, we create partitions based on
145
+ /// the symbols that need to be compiled. For each partition P, we
146
+ /// hash the symbols in P and create a `WorkProduct` record associated
147
+ /// with `DepNode::TransPartition(P)`; the hash is the set of symbols
148
+ /// in P.
149
+ ///
150
+ /// The next time we compile, if the `DepNode::TransPartition(P)` is
151
+ /// judged to be clean (which means none of the things we read to
152
+ /// generate the partition were found to be dirty), it will be loaded
153
+ /// into previous work products. We will then regenerate the set of
154
+ /// symbols in the partition P and hash them (note that new symbols
155
+ /// may be added -- for example, new monomorphizations -- even if
156
+ /// nothing in P changed!). We will compare that hash against the
157
+ /// previous hash. If it matches up, we can reuse the object file.
158
+ #[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
159
+ pub struct WorkProduct {
160
+ /// extra hash used to decide if work-product is still suitable;
161
+ /// note that this is *not* a hash of the work-product itself.
162
+ /// See documentation on `WorkProduct` type for an example.
163
+ pub input_hash : u64 ,
164
+
165
+ /// filename storing this work-product (found in the incr. comp. directory)
166
+ pub file_name : String ,
71
167
}
0 commit comments