From 000d3c97eeb286a1a1e9c2fa2a1fc8874ed93731 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 7 May 2018 22:30:44 -0400 Subject: [PATCH] Make DepGraph::previous_work_products immutable Fixes #50501 --- src/librustc/dep_graph/graph.rs | 26 ++---- src/librustc_driver/driver.rs | 19 ++-- src/librustc_incremental/persist/load.rs | 112 ++++++++++++----------- 3 files changed, 74 insertions(+), 83 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 22ab1b15c8b8e..61a7404b08526 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -77,7 +77,7 @@ struct DepGraphData { /// 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: RwLock>, + previous_work_products: FxHashMap, /// Work-products that we generate in this run. work_products: RwLock>, @@ -90,7 +90,8 @@ struct DepGraphData { impl DepGraph { - pub fn new(prev_graph: PreviousDepGraph) -> DepGraph { + pub fn new(prev_graph: PreviousDepGraph, + prev_work_products: FxHashMap) -> DepGraph { // Pre-allocate the fingerprints array. We over-allocate a little so // that we hopefully don't have to re-allocate during this compilation // session. @@ -100,7 +101,7 @@ impl DepGraph { (prev_graph_node_count * 115) / 100); DepGraph { data: Some(Lrc::new(DepGraphData { - previous_work_products: RwLock::new(FxHashMap()), + previous_work_products: prev_work_products, work_products: RwLock::new(FxHashMap()), dep_node_debug: Lock::new(FxHashMap()), current: Lock::new(CurrentDepGraph::new()), @@ -460,19 +461,6 @@ impl DepGraph { self.data.as_ref().unwrap().previous.node_to_index(dep_node) } - /// 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: &WorkProductId, data: WorkProduct) { - debug!("insert_previous_work_product({:?}, {:?})", v, data); - self.data - .as_ref() - .unwrap() - .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. @@ -492,7 +480,7 @@ impl DepGraph { self.data .as_ref() .and_then(|data| { - data.previous_work_products.borrow().get(v).cloned() + data.previous_work_products.get(v).cloned() }) } @@ -504,8 +492,8 @@ impl DepGraph { /// 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) -> ReadGuard> { - self.data.as_ref().unwrap().previous_work_products.borrow() + pub fn previous_work_products(&self) -> &FxHashMap { + &self.data.as_ref().unwrap().previous_work_products } #[inline(always)] diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2fb811eba1e9a..1e74039503d51 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -980,15 +980,16 @@ where let dep_graph = match future_dep_graph { None => DepGraph::new_disabled(), Some(future) => { - let prev_graph = time(sess, "blocked while dep-graph loading finishes", || { - future - .open() - .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { - message: format!("could not decode incremental cache: {:?}", e), - }) - .open(sess) - }); - DepGraph::new(prev_graph) + let (prev_graph, prev_work_products) = + time(sess, "blocked while dep-graph loading finishes", || { + future + .open() + .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { + message: format!("could not decode incremental cache: {:?}", e), + }) + .open(sess) + }); + DepGraph::new(prev_graph, prev_work_products) } }; let hir_forest = time(sess, "lowering ast -> hir", || { diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 44d6e532f79bb..01186483a6839 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -10,7 +10,8 @@ //! Code to save/load the dep-graph from files. -use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph}; +use rustc_data_structures::fx::FxHashMap; +use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::ty::maps::OnDiskCache; @@ -32,65 +33,22 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.allocate_metadata_dep_nodes(); tcx.precompute_in_scope_traits_hashes(); - - if tcx.sess.incr_comp_session_dir_opt().is_none() { - // If we are only building with -Zquery-dep-graph but without an actual - // incr. comp. session directory, we exit here. Otherwise we'd fail - // when trying to load work products. - return - } - - let work_products_path = work_products_path(tcx.sess); - let load_result = load_data(tcx.sess.opts.debugging_opts.incremental_info, &work_products_path); - - if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { - // Decode the list of work_products - let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos); - let work_products: Vec = - RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| { - let msg = format!("Error decoding `work-products` from incremental \ - compilation session directory: {}", e); - tcx.sess.fatal(&msg[..]) - }); - - for swp in work_products { - let mut all_files_exist = true; - for &(_, ref file_name) in swp.work_product.saved_files.iter() { - let path = in_incr_comp_dir_sess(tcx.sess, file_name); - if !path.exists() { - all_files_exist = false; - - if tcx.sess.opts.debugging_opts.incremental_info { - eprintln!("incremental: could not find file for work \ - product: {}", path.display()); - } - } - } - - if all_files_exist { - debug!("reconcile_work_products: all files for {:?} exist", swp); - tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product); - } else { - debug!("reconcile_work_products: some file for {:?} does not exist", swp); - delete_dirty_work_product(tcx, swp); - } - } - } } +type WorkProductMap = FxHashMap; + pub enum LoadResult { Ok { data: T }, DataOutOfDate, Error { message: String }, } - -impl LoadResult { - pub fn open(self, sess: &Session) -> PreviousDepGraph { +impl LoadResult<(PreviousDepGraph, WorkProductMap)> { + pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) { match self { LoadResult::Error { message } => { sess.warn(&message); - PreviousDepGraph::new(SerializedDepGraph::new()) + (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap()) }, LoadResult::DataOutOfDate => { if let Err(err) = delete_all_session_dir_contents(sess) { @@ -98,7 +56,7 @@ impl LoadResult { incremental compilation session directory contents `{}`: {}.", dep_graph_path(sess).display(), err)); } - PreviousDepGraph::new(SerializedDepGraph::new()) + (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap()) } LoadResult::Ok { data } => data } @@ -125,10 +83,10 @@ fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec, } } -fn delete_dirty_work_product(tcx: TyCtxt, +fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) { debug!("delete_dirty_work_product({:?})", swp); - work_product::delete_workproduct_files(tcx.sess, &swp.work_product); + work_product::delete_workproduct_files(sess, &swp.work_product); } /// Either a result that has already be computed or a @@ -149,7 +107,7 @@ impl MaybeAsync { /// Launch a thread and load the dependency graph in the background. pub fn load_dep_graph(sess: &Session) -> - MaybeAsync> + MaybeAsync> { // Since `sess` isn't `Sync`, we perform all accesses to `sess` // before we fire the background thread. @@ -159,7 +117,7 @@ pub fn load_dep_graph(sess: &Session) -> if sess.opts.incremental.is_none() { // No incremental compilation. return MaybeAsync::Sync(LoadResult::Ok { - data: PreviousDepGraph::new(SerializedDepGraph::new()) + data: (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap()) }); } @@ -169,6 +127,50 @@ pub fn load_dep_graph(sess: &Session) -> let report_incremental_info = sess.opts.debugging_opts.incremental_info; let expected_hash = sess.opts.dep_tracking_hash(); + let mut prev_work_products = FxHashMap(); + + // If we are only building with -Zquery-dep-graph but without an actual + // incr. comp. session directory, we exit here. Otherwise we'd fail + // when trying to load work products. + if sess.incr_comp_session_dir_opt().is_some() { + let work_products_path = work_products_path(sess); + let load_result = load_data(report_incremental_info, &work_products_path); + + if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { + // Decode the list of work_products + let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos); + let work_products: Vec = + RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| { + let msg = format!("Error decoding `work-products` from incremental \ + compilation session directory: {}", e); + sess.fatal(&msg[..]) + }); + + for swp in work_products { + let mut all_files_exist = true; + for &(_, ref file_name) in swp.work_product.saved_files.iter() { + let path = in_incr_comp_dir_sess(sess, file_name); + if !path.exists() { + all_files_exist = false; + + if sess.opts.debugging_opts.incremental_info { + eprintln!("incremental: could not find file for work \ + product: {}", path.display()); + } + } + } + + if all_files_exist { + debug!("reconcile_work_products: all files for {:?} exist", swp); + prev_work_products.insert(swp.id, swp.work_product); + } else { + debug!("reconcile_work_products: some file for {:?} does not exist", swp); + delete_dirty_work_product(sess, swp); + } + } + } + } + MaybeAsync::Async(std::thread::spawn(move || { time_ext(time_passes, None, "background load prev dep-graph", move || { match load_data(report_incremental_info, &path) { @@ -195,7 +197,7 @@ pub fn load_dep_graph(sess: &Session) -> let dep_graph = SerializedDepGraph::decode(&mut decoder) .expect("Error reading cached dep-graph"); - LoadResult::Ok { data: PreviousDepGraph::new(dep_graph) } + LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) } } } })