@@ -14,9 +14,11 @@ use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph};
14
14
use rustc:: session:: Session ;
15
15
use rustc:: ty:: TyCtxt ;
16
16
use rustc:: ty:: maps:: OnDiskCache ;
17
+ use rustc:: util:: common:: time;
17
18
use rustc_serialize:: Decodable as RustcDecodable ;
18
19
use rustc_serialize:: opaque:: Decoder ;
19
20
use std:: path:: Path ;
21
+ use std;
20
22
21
23
use super :: data:: * ;
22
24
use super :: fs:: * ;
@@ -39,7 +41,9 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
39
41
}
40
42
41
43
let work_products_path = work_products_path ( tcx. sess ) ;
42
- if let Some ( ( work_products_data, start_pos) ) = load_data ( tcx. sess , & work_products_path) {
44
+ let load_result = load_data ( tcx. sess . opts . debugging_opts . incremental_info , & work_products_path) ;
45
+
46
+ if let LoadResult :: Ok { data : ( work_products_data, start_pos) } = load_result {
43
47
// Decode the list of work_products
44
48
let mut work_product_decoder = Decoder :: new ( & work_products_data[ ..] , start_pos) ;
45
49
let work_products: Vec < SerializedWorkProduct > =
@@ -74,27 +78,50 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
74
78
}
75
79
}
76
80
77
- fn load_data ( sess : & Session , path : & Path ) -> Option < ( Vec < u8 > , usize ) > {
78
- match file_format:: read_file ( sess, path) {
79
- Ok ( Some ( data_and_pos) ) => return Some ( data_and_pos) ,
81
+ pub enum LoadResult < T > {
82
+ Ok { data : T } ,
83
+ DataOutOfDate ,
84
+ Error { message : String } ,
85
+ }
86
+
87
+
88
+ impl LoadResult < PreviousDepGraph > {
89
+ pub fn open ( self , sess : & Session ) -> PreviousDepGraph {
90
+ match self {
91
+ LoadResult :: Error { message } => {
92
+ sess. fatal ( & message) /* never returns */
93
+ } ,
94
+ LoadResult :: DataOutOfDate => {
95
+ if let Err ( err) = delete_all_session_dir_contents ( sess) {
96
+ sess. err ( & format ! ( "Failed to delete invalidated or incompatible \
97
+ incremental compilation session directory contents `{}`: {}.",
98
+ dep_graph_path( sess) . display( ) , err) ) ;
99
+ }
100
+ PreviousDepGraph :: new ( SerializedDepGraph :: new ( ) )
101
+ }
102
+ LoadResult :: Ok { data } => data
103
+ }
104
+ }
105
+ }
106
+
107
+
108
+ fn load_data ( report_incremental_info : bool , path : & Path ) -> LoadResult < ( Vec < u8 > , usize ) > {
109
+ match file_format:: read_file ( report_incremental_info, path) {
110
+ Ok ( Some ( data_and_pos) ) => LoadResult :: Ok {
111
+ data : data_and_pos
112
+ } ,
80
113
Ok ( None ) => {
81
114
// The file either didn't exist or was produced by an incompatible
82
115
// compiler version. Neither is an error.
116
+ LoadResult :: DataOutOfDate
83
117
}
84
118
Err ( err) => {
85
- sess. err (
86
- & format ! ( "could not load dep-graph from `{}`: {}" ,
87
- path. display( ) , err) ) ;
119
+ LoadResult :: Error {
120
+ message : format ! ( "could not load dep-graph from `{}`: {}" ,
121
+ path. display( ) , err)
122
+ }
88
123
}
89
124
}
90
-
91
- if let Err ( err) = delete_all_session_dir_contents ( sess) {
92
- sess. err ( & format ! ( "could not clear incompatible incremental \
93
- compilation session directory `{}`: {}",
94
- path. display( ) , err) ) ;
95
- }
96
-
97
- None
98
125
}
99
126
100
127
fn delete_dirty_work_product ( tcx : TyCtxt ,
@@ -103,41 +130,73 @@ fn delete_dirty_work_product(tcx: TyCtxt,
103
130
work_product:: delete_workproduct_files ( tcx. sess , & swp. work_product ) ;
104
131
}
105
132
106
- pub fn load_dep_graph ( sess : & Session ) -> PreviousDepGraph {
107
- let empty = PreviousDepGraph :: new ( SerializedDepGraph :: new ( ) ) ;
108
-
109
- if sess. opts . incremental . is_none ( ) {
110
- return empty
133
+ /// Either a result that has already be computed or a
134
+ /// handle that will let us wait until it is computed
135
+ /// by a background thread.
136
+ pub enum MaybeAsync < T > {
137
+ Sync ( T ) ,
138
+ Async ( std:: thread:: JoinHandle < T > )
139
+ }
140
+ impl < T > MaybeAsync < T > {
141
+ pub fn open ( self ) -> std:: thread:: Result < T > {
142
+ match self {
143
+ MaybeAsync :: Sync ( result) => Ok ( result) ,
144
+ MaybeAsync :: Async ( handle) => handle. join ( )
145
+ }
111
146
}
147
+ }
112
148
113
- if let Some ( ( bytes, start_pos) ) = load_data ( sess, & dep_graph_path ( sess) ) {
114
- let mut decoder = Decoder :: new ( & bytes, start_pos) ;
115
- let prev_commandline_args_hash = u64:: decode ( & mut decoder)
116
- . expect ( "Error reading commandline arg hash from cached dep-graph" ) ;
117
-
118
- if prev_commandline_args_hash != sess. opts . dep_tracking_hash ( ) {
119
- if sess. opts . debugging_opts . incremental_info {
120
- println ! ( "[incremental] completely ignoring cache because of \
121
- differing commandline arguments") ;
122
- }
123
- // We can't reuse the cache, purge it.
124
- debug ! ( "load_dep_graph_new: differing commandline arg hashes" ) ;
149
+ /// Launch a thread and load the dependency graph in the background.
150
+ pub fn load_dep_graph ( sess : & Session , time_passes : bool ) ->
151
+ MaybeAsync < LoadResult < PreviousDepGraph > >
152
+ {
153
+ // Since `sess` isn't `Sync`, we perform all accesses to `sess`
154
+ // before we fire the background thread.
125
155
126
- delete_all_session_dir_contents ( sess)
127
- . expect ( "Failed to delete invalidated incr. comp. session \
128
- directory contents.") ;
156
+ if sess. opts . incremental . is_none ( ) {
157
+ // No incremental compilation.
158
+ return MaybeAsync :: Sync ( LoadResult :: Ok {
159
+ data : PreviousDepGraph :: new ( SerializedDepGraph :: new ( ) )
160
+ } ) ;
161
+ }
129
162
130
- // No need to do any further work
131
- return empty
132
- }
163
+ // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
164
+ // Fortunately, we just checked that this isn't the case.
165
+ let path = dep_graph_path_from ( & sess. incr_comp_session_dir ( ) ) ;
166
+ let report_incremental_info = sess. opts . debugging_opts . incremental_info ;
167
+ let expected_hash = sess. opts . dep_tracking_hash ( ) ;
168
+
169
+ MaybeAsync :: Async ( std:: thread:: spawn ( move || {
170
+ time ( time_passes, "background load prev dep-graph" , move || {
171
+ match load_data ( report_incremental_info, & path) {
172
+ LoadResult :: DataOutOfDate => LoadResult :: DataOutOfDate ,
173
+ LoadResult :: Error { message } => LoadResult :: Error { message } ,
174
+ LoadResult :: Ok { data : ( bytes, start_pos) } => {
175
+
176
+ let mut decoder = Decoder :: new ( & bytes, start_pos) ;
177
+ let prev_commandline_args_hash = u64:: decode ( & mut decoder)
178
+ . expect ( "Error reading commandline arg hash from cached dep-graph" ) ;
179
+
180
+ if prev_commandline_args_hash != expected_hash {
181
+ if report_incremental_info {
182
+ println ! ( "[incremental] completely ignoring cache because of \
183
+ differing commandline arguments") ;
184
+ }
185
+ // We can't reuse the cache, purge it.
186
+ debug ! ( "load_dep_graph_new: differing commandline arg hashes" ) ;
187
+
188
+ // No need to do any further work
189
+ return LoadResult :: DataOutOfDate ;
190
+ }
133
191
134
- let dep_graph = SerializedDepGraph :: decode ( & mut decoder)
135
- . expect ( "Error reading cached dep-graph" ) ;
192
+ let dep_graph = SerializedDepGraph :: decode ( & mut decoder)
193
+ . expect ( "Error reading cached dep-graph" ) ;
136
194
137
- PreviousDepGraph :: new ( dep_graph)
138
- } else {
139
- empty
140
- }
195
+ LoadResult :: Ok { data : PreviousDepGraph :: new ( dep_graph) }
196
+ }
197
+ }
198
+ } )
199
+ } ) )
141
200
}
142
201
143
202
pub fn load_query_result_cache < ' sess > ( sess : & ' sess Session ) -> OnDiskCache < ' sess > {
@@ -146,9 +205,8 @@ pub fn load_query_result_cache<'sess>(sess: &'sess Session) -> OnDiskCache<'sess
146
205
return OnDiskCache :: new_empty ( sess. codemap ( ) ) ;
147
206
}
148
207
149
- if let Some ( ( bytes, start_pos) ) = load_data ( sess, & query_cache_path ( sess) ) {
150
- OnDiskCache :: new ( sess, bytes, start_pos)
151
- } else {
152
- OnDiskCache :: new_empty ( sess. codemap ( ) )
208
+ match load_data ( sess. opts . debugging_opts . incremental_info , & query_cache_path ( sess) ) {
209
+ LoadResult :: Ok { data : ( bytes, start_pos) } => OnDiskCache :: new ( sess, bytes, start_pos) ,
210
+ _ => OnDiskCache :: new_empty ( sess. codemap ( ) )
153
211
}
154
212
}
0 commit comments