From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_incremental/src/persist/load.rs | 235 +++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 compiler/rustc_incremental/src/persist/load.rs (limited to 'compiler/rustc_incremental/src/persist/load.rs') diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs new file mode 100644 index 000000000..1c5fd9169 --- /dev/null +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -0,0 +1,235 @@ +//! Code to save/load the dep-graph from files. + +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::memmap::Mmap; +use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; +use rustc_middle::ty::OnDiskCache; +use rustc_serialize::opaque::MemDecoder; +use rustc_serialize::Decodable; +use rustc_session::config::IncrementalStateAssertion; +use rustc_session::Session; +use std::path::Path; + +use super::data::*; +use super::file_format; +use super::fs::*; +use super::work_product; + +type WorkProductMap = FxHashMap; + +#[derive(Debug)] +/// Represents the result of an attempt to load incremental compilation data. +pub enum LoadResult { + /// Loading was successful. + Ok { + #[allow(missing_docs)] + data: T, + }, + /// The file either didn't exist or was produced by an incompatible compiler version. + DataOutOfDate, + /// An error occurred. + Error { + #[allow(missing_docs)] + message: String, + }, +} + +impl LoadResult { + /// Accesses the data returned in [`LoadResult::Ok`]. + pub fn open(self, sess: &Session) -> T { + // Check for errors when using `-Zassert-incremental-state` + match (sess.opts.assert_incr_state, &self) { + (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => { + sess.fatal( + "We asserted that the incremental cache should not be loaded, \ + but it was loaded.", + ); + } + ( + Some(IncrementalStateAssertion::Loaded), + LoadResult::Error { .. } | LoadResult::DataOutOfDate, + ) => { + sess.fatal( + "We asserted that an existing incremental cache directory should \ + be successfully loaded, but it was not.", + ); + } + _ => {} + }; + + match self { + LoadResult::Error { message } => { + sess.warn(&message); + Default::default() + } + LoadResult::DataOutOfDate => { + if let Err(err) = delete_all_session_dir_contents(sess) { + sess.err(&format!( + "Failed to delete invalidated or incompatible \ + incremental compilation session directory contents `{}`: {}.", + dep_graph_path(sess).display(), + err + )); + } + Default::default() + } + LoadResult::Ok { data } => data, + } + } +} + +fn load_data( + report_incremental_info: bool, + path: &Path, + nightly_build: bool, +) -> LoadResult<(Mmap, usize)> { + match file_format::read_file(report_incremental_info, path, nightly_build) { + Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, + Ok(None) => { + // The file either didn't exist or was produced by an incompatible + // compiler version. Neither is an error. + LoadResult::DataOutOfDate + } + Err(err) => LoadResult::Error { + message: format!("could not load dep-graph from `{}`: {}", path.display(), err), + }, + } +} + +fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) { + debug!("delete_dirty_work_product({:?})", swp); + work_product::delete_workproduct_files(sess, &swp.work_product); +} + +/// Either a result that has already be computed or a +/// handle that will let us wait until it is computed +/// by a background thread. +pub enum MaybeAsync { + Sync(T), + Async(std::thread::JoinHandle), +} + +impl MaybeAsync> { + /// Accesses the data returned in [`LoadResult::Ok`] in an asynchronous way if possible. + pub fn open(self) -> LoadResult { + match self { + MaybeAsync::Sync(result) => result, + MaybeAsync::Async(handle) => handle.join().unwrap_or_else(|e| LoadResult::Error { + message: format!("could not decode incremental cache: {:?}", e), + }), + } + } +} + +/// An asynchronous type for computing the dependency graph. +pub type DepGraphFuture = MaybeAsync>; + +/// Launch a thread and load the dependency graph in the background. +pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { + // Since `sess` isn't `Sync`, we perform all accesses to `sess` + // before we fire the background thread. + + let prof = sess.prof.clone(); + + if sess.opts.incremental.is_none() { + // No incremental compilation. + return MaybeAsync::Sync(LoadResult::Ok { data: Default::default() }); + } + + let _timer = sess.prof.generic_activity("incr_comp_prepare_load_dep_graph"); + + // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`. + // Fortunately, we just checked that this isn't the case. + let path = dep_graph_path(&sess); + let report_incremental_info = sess.opts.unstable_opts.incremental_info; + let expected_hash = sess.opts.dep_tracking_hash(false); + + let mut prev_work_products = FxHashMap::default(); + let nightly_build = sess.is_nightly_build(); + + // If we are only building with -Zquery-dep-graph but without an actual + // incr. comp. session directory, we skip this. 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, nightly_build); + + if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { + // Decode the list of work_products + let mut work_product_decoder = MemDecoder::new(&work_products_data[..], start_pos); + let work_products: Vec = + Decodable::decode(&mut work_product_decoder); + + for swp in work_products { + let all_files_exist = swp.work_product.saved_files.iter().all(|(_, path)| { + let exists = in_incr_comp_dir_sess(sess, path).exists(); + if !exists && sess.opts.unstable_opts.incremental_info { + eprintln!("incremental: could not find file for work product: {path}",); + } + exists + }); + + 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 || { + let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph"); + + match load_data(report_incremental_info, &path, nightly_build) { + LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, + LoadResult::Error { message } => LoadResult::Error { message }, + LoadResult::Ok { data: (bytes, start_pos) } => { + let mut decoder = MemDecoder::new(&bytes, start_pos); + let prev_commandline_args_hash = u64::decode(&mut decoder); + + if prev_commandline_args_hash != expected_hash { + if report_incremental_info { + eprintln!( + "[incremental] completely ignoring cache because of \ + differing commandline arguments" + ); + } + // We can't reuse the cache, purge it. + debug!("load_dep_graph_new: differing commandline arg hashes"); + + // No need to do any further work + return LoadResult::DataOutOfDate; + } + + let dep_graph = SerializedDepGraph::decode(&mut decoder); + + LoadResult::Ok { data: (dep_graph, prev_work_products) } + } + } + })) +} + +/// Attempts to load the query result cache from disk +/// +/// If we are not in incremental compilation mode, returns `None`. +/// Otherwise, tries to load the query result cache from disk, +/// creating an empty cache if it could not be loaded. +pub fn load_query_result_cache<'a, C: OnDiskCache<'a>>(sess: &'a Session) -> Option { + if sess.opts.incremental.is_none() { + return None; + } + + let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache"); + + match load_data( + sess.opts.unstable_opts.incremental_info, + &query_cache_path(sess), + sess.is_nightly_build(), + ) { + LoadResult::Ok { data: (bytes, start_pos) } => Some(C::new(sess, bytes, start_pos)), + _ => Some(C::new_empty(sess.source_map())), + } +} -- cgit v1.2.3