@@ -14,9 +14,11 @@ use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph};
1414use rustc:: session:: Session ;
1515use rustc:: ty:: TyCtxt ;
1616use rustc:: ty:: maps:: OnDiskCache ;
17+ use rustc:: util:: common:: time;
1718use rustc_serialize:: Decodable as RustcDecodable ;
1819use rustc_serialize:: opaque:: Decoder ;
1920use std:: path:: Path ;
21+ use std;
2022
2123use super :: data:: * ;
2224use super :: fs:: * ;
@@ -39,7 +41,9 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
3941 }
4042
4143 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 {
4347 // Decode the list of work_products
4448 let mut work_product_decoder = Decoder :: new ( & work_products_data[ ..] , start_pos) ;
4549 let work_products: Vec < SerializedWorkProduct > =
@@ -74,27 +78,50 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
7478 }
7579}
7680
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+ } ,
80113 Ok ( None ) => {
81114 // The file either didn't exist or was produced by an incompatible
82115 // compiler version. Neither is an error.
116+ LoadResult :: DataOutOfDate
83117 }
84118 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+ }
88123 }
89124 }
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
98125}
99126
100127fn delete_dirty_work_product ( tcx : TyCtxt ,
@@ -103,41 +130,73 @@ fn delete_dirty_work_product(tcx: TyCtxt,
103130 work_product:: delete_workproduct_files ( tcx. sess , & swp. work_product ) ;
104131}
105132
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+ }
111146 }
147+ }
112148
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.
125155
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+ }
129162
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+ }
133191
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" ) ;
136194
137- PreviousDepGraph :: new ( dep_graph)
138- } else {
139- empty
140- }
195+ LoadResult :: Ok { data : PreviousDepGraph :: new ( dep_graph) }
196+ }
197+ }
198+ } )
199+ } ) )
141200}
142201
143202pub 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
146205 return OnDiskCache :: new_empty ( sess. codemap ( ) ) ;
147206 }
148207
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 ( ) )
153211 }
154212}
0 commit comments