@@ -14,12 +14,13 @@ use rbml::Error;
14
14
use rbml:: opaque:: Decoder ;
15
15
use rustc:: dep_graph:: DepNode ;
16
16
use rustc:: hir:: def_id:: DefId ;
17
+ use rustc:: session:: Session ;
17
18
use rustc:: ty:: TyCtxt ;
18
19
use rustc_data_structures:: fnv:: FnvHashSet ;
19
20
use rustc_serialize:: Decodable as RustcDecodable ;
20
21
use std:: io:: Read ;
21
- use std:: fs:: File ;
22
- use std:: path:: Path ;
22
+ use std:: fs:: { self , File } ;
23
+ use std:: path:: { Path } ;
23
24
24
25
use super :: data:: * ;
25
26
use super :: directory:: * ;
@@ -38,50 +39,73 @@ type CleanEdges = Vec<(DepNode<DefId>, DepNode<DefId>)>;
38
39
/// actually it doesn't matter all that much.) See `README.md` for
39
40
/// more general overview.
40
41
pub fn load_dep_graph < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
42
+ if tcx. sess . opts . incremental . is_none ( ) {
43
+ return ;
44
+ }
45
+
41
46
let _ignore = tcx. dep_graph . in_ignore ( ) ;
47
+ load_dep_graph_if_exists ( tcx) ;
48
+ dirty_clean:: check_dirty_clean_annotations ( tcx) ;
49
+ }
42
50
43
- if let Some ( dep_graph) = dep_graph_path ( tcx) {
44
- // FIXME(#32754) lock file?
45
- load_dep_graph_if_exists ( tcx, & dep_graph) ;
46
- dirty_clean:: check_dirty_clean_annotations ( tcx) ;
51
+ fn load_dep_graph_if_exists < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
52
+ let dep_graph_path = dep_graph_path ( tcx) . unwrap ( ) ;
53
+ let dep_graph_data = match load_data ( tcx. sess , & dep_graph_path) {
54
+ Some ( p) => p,
55
+ None => return // no file
56
+ } ;
57
+
58
+ let work_products_path = tcx_work_products_path ( tcx) . unwrap ( ) ;
59
+ let work_products_data = match load_data ( tcx. sess , & work_products_path) {
60
+ Some ( p) => p,
61
+ None => return // no file
62
+ } ;
63
+
64
+ match decode_dep_graph ( tcx, & dep_graph_data, & work_products_data) {
65
+ Ok ( ( ) ) => return ,
66
+ Err ( err) => bug ! ( "decoding error in dep-graph from `{}` and `{}`: {}" ,
67
+ dep_graph_path. display( ) ,
68
+ work_products_path. display( ) ,
69
+ err) ,
47
70
}
48
71
}
49
72
50
- pub fn load_dep_graph_if_exists < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > , path : & Path ) {
73
+ fn load_data ( sess : & Session , path : & Path ) -> Option < Vec < u8 > > {
51
74
if !path. exists ( ) {
52
- return ;
75
+ return None ;
53
76
}
54
77
55
78
let mut data = vec ! [ ] ;
56
79
match
57
80
File :: open ( path)
58
81
. and_then ( |mut file| file. read_to_end ( & mut data) )
59
82
{
60
- Ok ( _) => { }
83
+ Ok ( _) => {
84
+ Some ( data)
85
+ }
61
86
Err ( err) => {
62
- tcx . sess . err (
87
+ sess. err (
63
88
& format ! ( "could not load dep-graph from `{}`: {}" ,
64
89
path. display( ) , err) ) ;
65
- return ;
90
+ None
66
91
}
67
92
}
68
93
69
- match decode_dep_graph ( tcx, & data) {
70
- Ok ( dirty) => dirty,
71
- Err ( err) => {
72
- bug ! ( "decoding error in dep-graph from `{}`: {}" , path. display( ) , err) ;
73
- }
74
- }
75
94
}
76
95
96
+ /// Decode the dep graph and load the edges/nodes that are still clean
97
+ /// into `tcx.dep_graph`. On success, returns a hashset containing all
98
+ /// the paths of work-products from clean nodes (any work-products not
99
+ /// in this set can be deleted).
77
100
pub fn decode_dep_graph < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
78
- data : & [ u8 ] )
101
+ dep_graph_data : & [ u8 ] ,
102
+ work_products_data : & [ u8 ] )
79
103
-> Result < ( ) , Error >
80
104
{
81
105
// Deserialize the directory and dep-graph.
82
- let mut decoder = Decoder :: new ( data , 0 ) ;
83
- let directory = try!( DefIdDirectory :: decode ( & mut decoder ) ) ;
84
- let serialized_dep_graph = try!( SerializedDepGraph :: decode ( & mut decoder ) ) ;
106
+ let mut dep_graph_decoder = Decoder :: new ( dep_graph_data , 0 ) ;
107
+ let directory = try!( DefIdDirectory :: decode ( & mut dep_graph_decoder ) ) ;
108
+ let serialized_dep_graph = try!( SerializedDepGraph :: decode ( & mut dep_graph_decoder ) ) ;
85
109
86
110
debug ! ( "decode_dep_graph: directory = {:#?}" , directory) ;
87
111
debug ! ( "decode_dep_graph: serialized_dep_graph = {:#?}" , serialized_dep_graph) ;
@@ -121,12 +145,18 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
121
145
// Add nodes and edges that are not dirty into our main graph.
122
146
let dep_graph = tcx. dep_graph . clone ( ) ;
123
147
for ( source, target) in clean_edges. into_iter ( ) . chain ( clean_nodes) {
124
- let _task = dep_graph. in_task ( target. clone ( ) ) ;
125
- dep_graph. read ( source. clone ( ) ) ;
126
-
127
148
debug ! ( "decode_dep_graph: clean edge: {:?} -> {:?}" , source, target) ;
149
+
150
+ let _task = dep_graph. in_task ( target) ;
151
+ dep_graph. read ( source) ;
128
152
}
129
153
154
+ // Add in work-products that are still clean, and delete those that are
155
+ // dirty.
156
+ let mut work_product_decoder = Decoder :: new ( work_products_data, 0 ) ;
157
+ let work_products = try!( <Vec < SerializedWorkProduct > >:: decode ( & mut work_product_decoder) ) ;
158
+ reconcile_work_products ( tcx, work_products, & dirty_nodes) ;
159
+
130
160
Ok ( ( ) )
131
161
}
132
162
@@ -141,9 +171,9 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
141
171
match hash. node . map_def ( |& i| retraced. def_id ( i) ) {
142
172
Some ( dep_node) => {
143
173
let current_hash = hcx. hash ( & dep_node) . unwrap ( ) ;
144
- debug ! ( "initial_dirty_nodes: hash of {:?} is {:?}, was {:?}" ,
145
- dep_node, current_hash, hash. hash) ;
146
174
if current_hash != hash. hash {
175
+ debug ! ( "initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}" ,
176
+ dep_node, current_hash, hash. hash) ;
147
177
dirty_nodes. insert ( dep_node) ;
148
178
}
149
179
}
@@ -177,6 +207,8 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)],
177
207
clean_edges. push ( ( source, target) )
178
208
} else {
179
209
// source removed, target must be dirty
210
+ debug ! ( "compute_clean_edges: {:?} dirty because {:?} no longer exists" ,
211
+ target, serialized_source) ;
180
212
dirty_nodes. insert ( target) ;
181
213
}
182
214
} else {
@@ -213,3 +245,40 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)],
213
245
214
246
clean_edges
215
247
}
248
+
249
+ /// Go through the list of work-products produced in the previous run.
250
+ /// Delete any whose nodes have been found to be dirty or which are
251
+ /// otherwise no longer applicable.
252
+ fn reconcile_work_products < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
253
+ work_products : Vec < SerializedWorkProduct > ,
254
+ dirty_nodes : & DirtyNodes ) {
255
+ debug ! ( "reconcile_work_products({:?})" , work_products) ;
256
+ for swp in work_products {
257
+ let dep_node = DepNode :: WorkProduct ( swp. id . clone ( ) ) ;
258
+ if dirty_nodes. contains ( & dep_node) {
259
+ debug ! ( "reconcile_work_products: dep-node for {:?} is dirty" , swp) ;
260
+ delete_dirty_work_product ( tcx, swp) ;
261
+ } else {
262
+ let path = in_incr_comp_dir ( tcx. sess , & swp. work_product . file_name ) . unwrap ( ) ;
263
+ if path. exists ( ) {
264
+ tcx. dep_graph . insert_previous_work_product ( & swp. id , swp. work_product ) ;
265
+ } else {
266
+ debug ! ( "reconcile_work_products: file for {:?} does not exist" , swp) ;
267
+ }
268
+ }
269
+ }
270
+ }
271
+
272
+ fn delete_dirty_work_product ( tcx : TyCtxt ,
273
+ swp : SerializedWorkProduct ) {
274
+ debug ! ( "delete_dirty_work_product({:?})" , swp) ;
275
+ let path = in_incr_comp_dir ( tcx. sess , & swp. work_product . file_name ) . unwrap ( ) ;
276
+ match fs:: remove_file ( & path) {
277
+ Ok ( ( ) ) => { }
278
+ Err ( err) => {
279
+ tcx. sess . warn (
280
+ & format ! ( "file-system error deleting outdated file `{}`: {}" ,
281
+ path. display( ) , err) ) ;
282
+ }
283
+ }
284
+ }
0 commit comments