diff --git a/Cargo.lock b/Cargo.lock index 96526f7e9e7da..048b46df02b3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3545,6 +3545,7 @@ dependencies = [ "portable-atomic", "rustc-hash 2.1.1", "rustc-rayon", + "rustc-rayon-core", "rustc-stable-hash", "rustc_arena", "rustc_graphviz", diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index e7afaff3b428f..741b153ebebd3 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -7,6 +7,7 @@ // Note: please avoid adding other feature gates where possible #![feature(rustc_private)] // Note: please avoid adding other feature gates where possible +#![recursion_limit = "256"] #![warn(rust_2018_idioms)] #![warn(unreachable_pub)] #![warn(unused_lifetimes)] @@ -43,6 +44,7 @@ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::sync::{DynSend, downcast_box_any_dyn_send}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; @@ -207,7 +209,7 @@ impl CodegenBackend for CraneliftCodegenBackend { tcx: TyCtxt<'_>, metadata: EncodedMetadata, need_metadata_module: bool, - ) -> Box { + ) -> Box { info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); let config = self.config.clone().unwrap_or_else(|| { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) @@ -226,11 +228,13 @@ impl CodegenBackend for CraneliftCodegenBackend { fn join_codegen( &self, - ongoing_codegen: Box, + ongoing_codegen: Box, sess: &Session, outputs: &OutputFilenames, ) -> (CodegenResults, FxIndexMap) { - ongoing_codegen.downcast::().unwrap().join(sess, outputs) + downcast_box_any_dyn_send::(ongoing_codegen) + .unwrap() + .join(sess, outputs) } } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index bfa23174a19d9..a4292d1978649 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -104,7 +104,7 @@ use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods}; use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::sync::IntoDynSyncSend; +use rustc_data_structures::sync::{DynSend, IntoDynSyncSend, downcast_box_any_dyn_send}; use rustc_errors::DiagCtxtHandle; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -230,12 +230,12 @@ impl CodegenBackend for GccCodegenBackend { providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true) } - fn codegen_crate( + fn codegen_crate<'tcx>( &self, - tcx: TyCtxt<'_>, + tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool, - ) -> Box { + ) -> Box { let target_cpu = target_cpu(tcx.sess); let res = codegen_crate( self.clone(), @@ -250,12 +250,11 @@ impl CodegenBackend for GccCodegenBackend { fn join_codegen( &self, - ongoing_codegen: Box, + ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames, ) -> (CodegenResults, FxIndexMap) { - ongoing_codegen - .downcast::>() + downcast_box_any_dyn_send::>( ongoing_codegen) .expect("Expected GccCodegenBackend's OngoingCodegen, found Box") .join(sess) } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 425381b0ffab7..6f244c6292617 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -19,6 +19,7 @@ #![feature(rustdoc_internals)] #![feature(slice_as_array)] #![feature(try_blocks)] +#![recursion_limit = "256"] // tidy-alphabetical-end use std::any::Any; @@ -39,6 +40,7 @@ use rustc_codegen_ssa::back::write::{ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::sync::{DynSend, downcast_box_any_dyn_send}; use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -347,7 +349,7 @@ impl CodegenBackend for LlvmCodegenBackend { tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool, - ) -> Box { + ) -> Box { Box::new(rustc_codegen_ssa::base::codegen_crate( LlvmCodegenBackend(()), tcx, @@ -359,14 +361,15 @@ impl CodegenBackend for LlvmCodegenBackend { fn join_codegen( &self, - ongoing_codegen: Box, + ongoing_codegen: Box, sess: &Session, outputs: &OutputFilenames, ) -> (CodegenResults, FxIndexMap) { - let (codegen_results, work_products) = ongoing_codegen - .downcast::>() - .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box") - .join(sess); + let (codegen_results, work_products) = downcast_box_any_dyn_send::< + rustc_codegen_ssa::back::write::OngoingCodegen, + >(ongoing_codegen) + .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box") + .join(sess); if sess.opts.unstable_opts.llvm_time_trace { sess.time("llvm_dump_timing_file", || { diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 65fd843e7a59e..510f7fd91b949 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -36,7 +36,7 @@ pub trait BackendTypes { type DIVariable: Copy; } -pub trait CodegenBackend { +pub trait CodegenBackend: DynSync + DynSend { /// Locale resources for diagnostic messages - a string the content of the Fluent resource. /// Called before `init` so that all other functions are able to emit translatable diagnostics. fn locale_resource(&self) -> &'static str; @@ -73,16 +73,16 @@ pub trait CodegenBackend { tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool, - ) -> Box; + ) -> Box; - /// This is called on the returned `Box` from [`codegen_crate`](Self::codegen_crate) + /// This is called on the returned `Box` from [`codegen_crate`](Self::codegen_crate) /// /// # Panics /// - /// Panics when the passed `Box` was not returned by [`codegen_crate`](Self::codegen_crate). + /// Panics when the passed `Box` was not returned by [`codegen_crate`](Self::codegen_crate). fn join_codegen( &self, - ongoing_codegen: Box, + ongoing_codegen: Box, sess: &Session, outputs: &OutputFilenames, ) -> (CodegenResults, FxIndexMap); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index fcaf2750507dd..e90e0b7d99ded 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -15,6 +15,7 @@ jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "12.0.1" rustc-hash = "2.0.0" rustc-rayon = { version = "0.5.1", features = ["indexmap"] } +rustc-rayon-core = { version = "0.5.0" } rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 64c64bfa3c296..7d24ded7afaac 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -1,4 +1,5 @@ use std::alloc::Allocator; +use std::any::Any; #[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")] @@ -51,9 +52,20 @@ macro_rules! already_send { // These structures are already `Send`. already_send!( - [std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File] - [rustc_arena::DroplessArena][crate::memmap::Mmap][crate::profiling::SelfProfiler] - [crate::owned_slice::OwnedSlice] + [std::backtrace::Backtrace] + [std::io::Stdout] + [std::io::Stderr] + [std::io::Error] + [std::fs::File] + [std::sync::Condvar] + [jobserver_crate::Client] + [jobserver_crate::HelperThread] + [jobserver_crate::Acquired] + [Box] + [rustc_arena::DroplessArena] + [crate::memmap::Mmap] + [crate::profiling::SelfProfiler] + [crate::owned_slice::OwnedSlice] ); macro_rules! impl_dyn_send { @@ -64,10 +76,14 @@ macro_rules! impl_dyn_send { impl_dyn_send!( [std::sync::atomic::AtomicPtr where T] - [std::sync::Mutex where T: ?Sized+ DynSend] + [std::sync::Mutex where T: ?Sized + DynSend] + [std::sync::RwLock where T: ?Sized + DynSend] [std::sync::mpsc::Sender where T: DynSend] + [std::sync::mpsc::Receiver where T: DynSend] [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::OnceLock where T: DynSend] [std::sync::LazyLock where T: DynSend, F: DynSend] + [std::thread::JoinHandle where T] [std::collections::HashSet where K: DynSend, S: DynSend] [std::collections::HashMap where K: DynSend, V: DynSend, S: DynSend] [std::collections::BTreeMap where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend] @@ -119,9 +135,9 @@ macro_rules! already_sync { // These structures are already `Sync`. already_sync!( [std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8] - [std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File] - [jobserver_crate::Client][crate::memmap::Mmap][crate::profiling::SelfProfiler] - [crate::owned_slice::OwnedSlice] + [std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::sync::Condvar] + [std::io::Error][std::fs::File][jobserver_crate::Client][crate::memmap::Mmap] + [crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice] ); // Use portable AtomicU64 for targets without native 64-bit atomics @@ -142,7 +158,9 @@ impl_dyn_sync!( [std::sync::OnceLock where T: DynSend + DynSync] [std::sync::Mutex where T: ?Sized + DynSend] [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::RwLock where T: ?Sized + DynSend + DynSync] [std::sync::LazyLock where T: DynSend + DynSync, F: DynSend] + [std::sync::mpsc::SyncSender where T: DynSend] [std::collections::HashSet where K: DynSync, S: DynSync] [std::collections::HashMap where K: DynSync, V: DynSync, S: DynSync] [std::collections::BTreeMap where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync] @@ -224,3 +242,15 @@ impl std::ops::DerefMut for IntoDynSyncSend { &mut self.0 } } + +#[inline] +pub fn downcast_box_any_dyn_send(this: Box) -> Result, ()> { + if ::is::(&*this) { + unsafe { + let (raw, alloc): (*mut (dyn Any + DynSend), _) = Box::into_raw_with_allocator(this); + Ok(Box::from_raw_in(raw as *mut T, alloc)) + } + } else { + Err(()) + } +} diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 616a18a72ab7e..d864df294b753 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -50,6 +50,10 @@ pub use self::worker_local::{Registry, WorkerLocal}; pub use crate::marker::*; mod freeze; + +mod task; +pub use task::{Task, task}; + mod lock; mod parallel; mod vec; diff --git a/compiler/rustc_data_structures/src/sync/task.rs b/compiler/rustc_data_structures/src/sync/task.rs new file mode 100644 index 0000000000000..5bdc38352f9e8 --- /dev/null +++ b/compiler/rustc_data_structures/src/sync/task.rs @@ -0,0 +1,101 @@ +use std::any::Any; +use std::mem; +use std::panic::{self, AssertUnwindSafe}; +use std::sync::Arc; + +use parking_lot::{Condvar, Mutex}; + +use crate::jobserver; +use crate::sync::{DynSend, FromDyn, IntoDynSyncSend, mode}; + +enum TaskState { + Unexecuted(Box T + DynSend>), + Running, + Joined, + Result(Result>>), +} + +struct TaskData { + state: Mutex>, + waiter: Condvar, +} + +#[must_use] +pub struct Task { + data: Arc>, +} + +/// This attempts to run a closure in a background thread. It returns a `Task` type which +/// you must call `join` on to ensure that the closure runs. +pub fn task(f: impl FnOnce() -> T + DynSend + 'static) -> Task { + let task = Task { + data: Arc::new(TaskData { + state: Mutex::new(TaskState::Unexecuted(Box::new(f))), + waiter: Condvar::new(), + }), + }; + + if mode::is_dyn_thread_safe() { + let data = FromDyn::from(Arc::clone(&task.data)); + + // Try to execute the task on a separate thread. + rayon::spawn(move || { + let data = data.into_inner(); + let mut state = data.state.lock(); + if matches!(*state, TaskState::Unexecuted(..)) { + if let TaskState::Unexecuted(f) = mem::replace(&mut *state, TaskState::Running) { + drop(state); + let result = panic::catch_unwind(AssertUnwindSafe(f)); + + let unblock = { + let mut state = data.state.lock(); + let unblock = matches!(*state, TaskState::Joined); + *state = TaskState::Result(result.map_err(|e| IntoDynSyncSend(e))); + unblock + }; + + if unblock { + rayon_core::mark_unblocked(&rayon_core::Registry::current()); + } + + data.waiter.notify_one(); + } + } + }); + } + + task +} + +#[inline] +fn unwind(result: Result>>) -> T { + match result { + Ok(r) => r, + Err(err) => panic::resume_unwind(err.0), + } +} + +impl Task { + pub fn join(self) -> T { + let mut state_guard = self.data.state.lock(); + + match mem::replace(&mut *state_guard, TaskState::Joined) { + TaskState::Unexecuted(f) => f(), + TaskState::Result(result) => unwind(result), + TaskState::Running => { + rayon_core::mark_blocked(); + jobserver::release_thread(); + + self.data.waiter.wait(&mut state_guard); + + jobserver::acquire_thread(); + + match mem::replace(&mut *state_guard, TaskState::Joined) { + TaskState::Result(result) => unwind(result), + _ => panic!(), + } + } + TaskState::Joined => panic!(), + } + } +} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 37755e7d61db1..938f1ad9f8e0e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -380,13 +380,14 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) } } - Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)) + Some(Linker::codegen_and_build_linker(tcx, compiler)) }); // Linking is done outside the `compiler.enter()` so that the // `GlobalCtxt` within `Queries` can be freed as early as possible. if let Some(linker) = linker { - linker.link(sess, codegen_backend); + let _timer = sess.timer("waiting for linking"); + linker.join(); } }) } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 3f87b1a547be5..1e39340abdee1 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -37,8 +37,8 @@ pub type Result = result::Result; /// Can be used to run `rustc_interface` queries. /// Created by passing [`Config`] to [`run_compiler`]. pub struct Compiler { - pub sess: Session, - pub codegen_backend: Box, + pub sess: Arc, + pub codegen_backend: Arc, pub(crate) override_queries: Option, pub(crate) current_gcx: CurrentGcx, } @@ -494,8 +494,8 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se util::check_abi_required_features(&sess); let compiler = Compiler { - sess, - codegen_backend, + sess: Arc::new(sess), + codegen_backend: Arc::from(codegen_backend), override_queries: config.override_queries, current_gcx, }; diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 67e0be93523d9..f3529a527c25e 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -4,6 +4,7 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(try_blocks)] +#![recursion_limit = "256"] // tidy-alphabetical-end mod callbacks; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 93013c8b3f612..7cc20e25543f8 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -9,7 +9,7 @@ use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal}; +use rustc_data_structures::sync::{AppendOnlyIndexVec, DynSend, FreezeLock, WorkerLocal}; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; @@ -1072,7 +1072,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { pub(crate) fn start_codegen<'tcx>( codegen_backend: &dyn CodegenBackend, tcx: TyCtxt<'tcx>, -) -> Box { +) -> Box { // Hook for tests. if let Some((def_id, _)) = tcx.entry_fn(()) && tcx.has_attr(def_id, sym::rustc_delayed_bug_from_inside_query) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index c8914c9be9c01..3baf4d6f56a77 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -1,9 +1,12 @@ use std::any::Any; use std::sync::Arc; +use std::sync::mpsc::Receiver; use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::jobserver; use rustc_data_structures::svh::Svh; +use rustc_data_structures::sync::{DynSend, Task, join, task}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::TyCtxt; @@ -11,24 +14,24 @@ use rustc_session::Session; use rustc_session::config::{self, OutputFilenames, OutputType}; use crate::errors::FailedWritingFile; +use crate::interface::Compiler; use crate::passes; pub struct Linker { + dep_graph_serialized_rx: Receiver<()>, dep_graph: DepGraph, output_filenames: Arc, // Only present when incr. comp. is enabled. crate_hash: Option, - ongoing_codegen: Box, + ongoing_codegen: Box, } impl Linker { - pub fn codegen_and_build_linker( - tcx: TyCtxt<'_>, - codegen_backend: &dyn CodegenBackend, - ) -> Linker { - let ongoing_codegen = passes::start_codegen(codegen_backend, tcx); + pub fn codegen_and_build_linker(tcx: TyCtxt<'_>, compiler: &Compiler) -> Task<()> { + let ongoing_codegen = passes::start_codegen(&*compiler.codegen_backend, tcx); - Linker { + let linker = Linker { + dep_graph_serialized_rx: tcx.dep_graph_serialized_rx.lock().take().unwrap(), dep_graph: tcx.dep_graph.clone(), output_filenames: Arc::clone(tcx.output_filenames(())), crate_hash: if tcx.needs_crate_hash() { @@ -37,10 +40,15 @@ impl Linker { None }, ongoing_codegen, - } + }; + + let sess = Arc::clone(&compiler.sess); + let codegen_backend = Arc::clone(&compiler.codegen_backend); + + task(move || linker.link(&sess, &*codegen_backend)) } - pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) { + fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) { let (codegen_results, work_products) = sess.time("finish_ongoing_codegen", || { codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames) }); @@ -53,37 +61,53 @@ impl Linker { rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products) }); - let prof = sess.prof.clone(); - prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph)); - - // Now that we won't touch anything in the incremental compilation directory - // any more, we can finalize it (which involves renaming it) - rustc_incremental::finalize_session_directory(sess, self.crate_hash); - - if !sess - .opts - .output_types - .keys() - .any(|&i| i == OutputType::Exe || i == OutputType::Metadata) - { - return; - } - - if sess.opts.unstable_opts.no_link { - let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT); - CodegenResults::serialize_rlink( - sess, - &rlink_file, - &codegen_results, - &*self.output_filenames, - ) - .unwrap_or_else(|error| { - sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error }) - }); - return; - } - - let _timer = sess.prof.verbose_generic_activity("link_crate"); - codegen_backend.link(sess, codegen_results, &self.output_filenames) + let dep_graph_serialized_rx = self.dep_graph_serialized_rx; + + join( + || { + if !sess + .opts + .output_types + .keys() + .any(|&i| i == OutputType::Exe || i == OutputType::Metadata) + { + return; + } + + if sess.opts.unstable_opts.no_link { + let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT); + CodegenResults::serialize_rlink( + sess, + &rlink_file, + &codegen_results, + &*self.output_filenames, + ) + .unwrap_or_else(|error| { + sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error }) + }); + return; + } + + let _timer = sess.prof.verbose_generic_activity("link_crate"); + codegen_backend.link(sess, codegen_results, &self.output_filenames) + }, + || { + let dep_graph_serialized_rx = dep_graph_serialized_rx; + + // Wait for the dep graph to be serialized before finalizing the session directory. + if !dep_graph_serialized_rx.try_recv().is_ok() { + jobserver::release_thread(); + dep_graph_serialized_rx.recv().unwrap(); + jobserver::acquire_thread(); + } + + sess.prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph)); + + // Now that we won't touch anything in the incremental compilation directory + // any more, we can finalize it (which involves renaming it) + rustc_incremental::finalize_session_directory(sess, self.crate_hash); + }, + ) + .0 } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 618a65a018644..2695e1947d926 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -12,6 +12,7 @@ use std::ffi::OsStr; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::{Bound, Deref}; +use std::sync::mpsc::{Receiver, SyncSender, sync_channel}; use std::sync::{Arc, OnceLock}; use std::{fmt, iter, mem}; @@ -1365,6 +1366,9 @@ pub struct GlobalCtxt<'tcx> { pub dep_graph: DepGraph, + pub dep_graph_serialized_rx: Lock>>, + dep_graph_serialized_tx: SyncSender<()>, + pub prof: SelfProfilerRef, /// Common types, pre-interned for your convenience. @@ -1604,6 +1608,8 @@ impl<'tcx> TyCtxt<'tcx> { let common_lifetimes = CommonLifetimes::new(&interners); let common_consts = CommonConsts::new(&interners, &common_types, s, &untracked); + let (tx, rx) = sync_channel(1); + let gcx = gcx_cell.get_or_init(|| GlobalCtxt { sess: s, crate_types, @@ -1612,6 +1618,8 @@ impl<'tcx> TyCtxt<'tcx> { hir_arena, interners, dep_graph, + dep_graph_serialized_rx: Lock::new(Some(rx)), + dep_graph_serialized_tx: tx, hooks, prof: s.prof.clone(), types: common_types, @@ -2236,9 +2244,12 @@ impl<'tcx> TyCtxt<'tcx> { self.save_dep_graph(); self.query_key_hash_verify_all(); + // Finish the dep graph encoding before we signal `dep_graph_serialized`. if let Err((path, error)) = self.dep_graph.finish_encoding() { self.sess.dcx().emit_fatal(crate::error::FailedWritingFile { path: &path, error }); } + + self.dep_graph_serialized_tx.send(()).ok(); } } diff --git a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs index 656cfca1ed1d4..948aa09bad1b0 100644 --- a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs +++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs @@ -2,6 +2,7 @@ #![feature(rustc_private)] #![deny(warnings)] +#![recursion_limit = "256"] extern crate rustc_codegen_ssa; extern crate rustc_data_structures; @@ -20,6 +21,7 @@ use std::any::Any; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenResults, CrateInfo}; use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::sync::{DynSend, downcast_box_any_dyn_send}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -38,7 +40,7 @@ impl CodegenBackend for TheBackend { tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, _need_metadata_module: bool, - ) -> Box { + ) -> Box { Box::new(CodegenResults { modules: vec![], allocator_module: None, @@ -50,12 +52,11 @@ impl CodegenBackend for TheBackend { fn join_codegen( &self, - ongoing_codegen: Box, + ongoing_codegen: Box, _sess: &Session, _outputs: &OutputFilenames, ) -> (CodegenResults, FxIndexMap) { - let codegen_results = ongoing_codegen - .downcast::() + let codegen_results = downcast_box_any_dyn_send::(ongoing_codegen) .expect("in join_codegen: ongoing_codegen is not a CodegenResults"); (*codegen_results, FxIndexMap::default()) } diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index ffc19b138a573..fcc5452f98b62 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -80,8 +80,8 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path let krate = rustc_interface::passes::parse(&compiler.sess); let linker = rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { let _ = tcx.analysis(()); - Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend) + Linker::codegen_and_build_linker(tcx, compiler) }); - linker.link(&compiler.sess, &*compiler.codegen_backend); + linker.join(); }); }