diff --git a/Cargo.lock b/Cargo.lock index 41275accbe962..030950d10e354 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4019,6 +4019,7 @@ dependencies = [ "rustc_plugin_impl", "rustc_privacy", "rustc_query_impl", + "rustc_query_system", "rustc_resolve", "rustc_serialize", "rustc_session", diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 571337a8dcbc6..fcdb630ba2209 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -55,7 +55,7 @@ use std::io::{BufWriter, Write}; pub fn assert_dep_graph(tcx: TyCtxt<'_>) { tcx.dep_graph.with_ignore(|| { if tcx.sess.opts.debugging_opts.dump_dep_graph { - tcx.dep_graph.with_query(dump_graph); + tcx.dep_graph.with_debug(dump_graph); } if !tcx.sess.opts.debugging_opts.query_dep_graph { @@ -207,7 +207,7 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou } return; } - tcx.dep_graph.with_query(|query| { + tcx.dep_graph.with_debug(|query| { for &(_, source_def_id, ref source_dep_node) in if_this_changed { let dependents = query.transitive_predecessors(source_dep_node); for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need { diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 07af2201f5fc2..367174798519e 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -42,6 +42,7 @@ rustc_lint = { path = "../rustc_lint" } rustc_errors = { path = "../rustc_errors" } rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_privacy = { path = "../rustc_privacy" } +rustc_query_system = { path = "../rustc_query_system" } rustc_query_impl = { path = "../rustc_query_impl" } rustc_resolve = { path = "../rustc_resolve" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 3c7908fae79be..44449d2dc0863 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -9,8 +9,9 @@ //! The functions in this file should fall back to the default set in their //! origin crate when the `TyCtxt` is not present in TLS. -use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; +use rustc_middle::dep_graph::DepNodeExt; use rustc_middle::ty::tls; +use rustc_query_system::dep_graph::DepNode; use std::fmt; /// This is a callback from `rustc_ast` as it cannot access the implicit state @@ -35,20 +36,6 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { }) } -/// This is a callback from `rustc_ast` as it cannot access the implicit state -/// in `rustc_middle` otherwise. It is used to when diagnostic messages are -/// emitted and stores them in the current query, if there is one. -fn track_diagnostic(diagnostic: &Diagnostic) { - tls::with_context_opt(|icx| { - if let Some(icx) = icx { - if let Some(diagnostics) = icx.diagnostics { - let mut diagnostics = diagnostics.lock(); - diagnostics.extend(Some(diagnostic.clone())); - } - } - }) -} - /// This is a callback from `rustc_hir` as it cannot access the implicit state /// in `rustc_middle` otherwise. fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -62,11 +49,32 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> write!(f, ")") } +fn dep_node_debug(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}(", node.kind)?; + + tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = node.extract_def_id(tcx) { + write!(f, "{}", tcx.def_path_debug_str(def_id)) + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) { + write!(f, "{}", s) + } else { + write!(f, "{}", node.hash) + } + } else { + write!(f, "{}", node.hash) + } + })?; + + write!(f, ")") +} + /// Sets up the callbacks in prior crates which we want to refer to the /// TyCtxt in. pub fn setup_callbacks() { rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); - TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_))); + rustc_query_system::dep_graph::NODE_DEBUG.swap(&(dep_node_debug as _)); + rustc_errors::TRACK_DIAGNOSTICS.swap(&(rustc_query_system::tls::track_diagnostic as fn(&_))); } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 81585f8f4e49c..5c43ca2a56a65 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -231,7 +231,7 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option) { // state if it was responsible for triggering the panic. let i = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { - QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames) + QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(handler, num_frames) } else { 0 } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index cffb087af187f..edeaf17a00c61 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -158,8 +158,11 @@ unsafe fn handle_deadlock() { let context = tls::get_tlv(); assert!(context != 0); - rustc_data_structures::sync::assert_sync::>(); - let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>); + rustc_data_structures::sync::assert_sync::>(); + let icx: &tls::ImplicitCtxt<'_> = &*(context as *const tls::ImplicitCtxt<'_>); + + // We do not need to copy the query ImplicitCtxt since this deadlock handler is not part of a + // normal query invocation. let session_globals = rustc_span::with_session_globals(|sg| sg as *const _); let session_globals = &*session_globals; diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 443af50c5ff2c..fa1ac68a890e7 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -504,6 +504,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { } } } + #[macro_export] macro_rules! rustc_dep_node_append { ([$($macro:tt)*][$($other:tt)*]) => { $($macro)*( diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index f310001077030..b52c29e9c5908 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -63,11 +63,9 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::DefPathHash; use rustc_hir::HirId; -use rustc_query_system::dep_graph::FingerprintStyle; +use rustc_query_system::dep_graph::dep_kind_from_label_string; +use rustc_query_system::dep_graph::{DepKind, DepNode, DepNodeParams, FingerprintStyle}; use rustc_span::symbol::Symbol; -use std::hash::Hash; - -pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; /// This struct stores metadata about each DepKind. /// @@ -130,69 +128,6 @@ pub struct DepKindStruct { pub try_load_from_on_disk_cache: Option, DepNode)>, } -impl DepKind { - #[inline(always)] - pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle { - // Only fetch the DepKindStruct once. - let data = tcx.query_kind(self); - if data.is_anon { - return FingerprintStyle::Opaque; - } - data.fingerprint_style - } -} - -macro_rules! define_dep_nodes { - (<$tcx:tt> - $( - [$($attrs:tt)*] - $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* - ,)* - ) => ( - #[macro_export] - macro_rules! make_dep_kind_array { - ($mod:ident) => {[ $($mod::$variant()),* ]}; - } - - /// This enum serves as an index into arrays built by `make_dep_kind_array`. - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] - #[allow(non_camel_case_types)] - pub enum DepKind { - $($variant),* - } - - fn dep_kind_from_label_string(label: &str) -> Result { - match label { - $(stringify!($variant) => Ok(DepKind::$variant),)* - _ => Err(()), - } - } - - /// Contains variant => str representations for constructing - /// DepNode groups for tests. - #[allow(dead_code, non_upper_case_globals)] - pub mod label_strs { - $( - pub const $variant: &str = stringify!($variant); - )* - } - ); -} - -rustc_dep_node_append!([define_dep_nodes!][ <'tcx> - // We use this for most things when incr. comp. is turned off. - [] Null, - - [anon] TraitSelect, - - // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below. - [] CompileCodegenUnit(Symbol), - - // WARNING: if `MonoItem` is changed, make sure you update `make_compile_mono_item` below. - // Only used by rustc_codegen_cranelift - [] CompileMonoItem(MonoItem), -]); - // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. // Be very careful changing this type signature! crate fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { @@ -205,16 +140,15 @@ crate fn make_compile_mono_item(tcx: TyCtxt<'tcx>, mono_item: &MonoItem<'tcx>) - DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item) } -pub type DepNode = rustc_query_system::dep_graph::DepNode; - -// We keep a lot of `DepNode`s in memory during compilation. It's not -// required that their size stay the same, but we don't want to change -// it inadvertently. This assert just ensures we're aware of any change. -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -static_assert_size!(DepNode, 18); - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -static_assert_size!(DepNode, 24); +#[inline(always)] +pub fn fingerprint_style(tcx: TyCtxt<'_>, kind: DepKind) -> FingerprintStyle { + // Only fetch the DepKindStruct once. + let data = tcx.query_kind(kind); + if data.is_anon { + return FingerprintStyle::Opaque; + } + data.fingerprint_style +} pub trait DepNodeExt: Sized { /// Construct a DepNode from the given DepKind and DefPathHash. This @@ -241,8 +175,7 @@ pub trait DepNodeExt: Sized { def_path_hash: DefPathHash, ) -> Result; - /// Used in testing - fn has_label_string(label: &str) -> bool; + fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle; } impl DepNodeExt for DepNode { @@ -250,7 +183,7 @@ impl DepNodeExt for DepNode { /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode { - debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash); + debug_assert_eq!(fingerprint_style(tcx, kind), FingerprintStyle::DefPathHash); DepNode { kind, hash: def_path_hash.0.into() } } @@ -265,7 +198,7 @@ impl DepNodeExt for DepNode { /// refers to something from the previous compilation session that /// has been removed. fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option { - if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash { + if fingerprint_style(tcx, self.kind) == FingerprintStyle::DefPathHash { Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))) } else { None @@ -280,7 +213,7 @@ impl DepNodeExt for DepNode { ) -> Result { let kind = dep_kind_from_label_string(label)?; - match kind.fingerprint_style(tcx) { + match fingerprint_style(tcx, kind) { FingerprintStyle::Opaque => Err(()), FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)), FingerprintStyle::DefPathHash => { @@ -289,9 +222,9 @@ impl DepNodeExt for DepNode { } } - /// Used in testing - fn has_label_string(label: &str) -> bool { - dep_kind_from_label_string(label).is_ok() + #[inline(always)] + fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle { + fingerprint_style(tcx, self.kind) } } diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 79d7ca32f3555..825424d5df99b 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -1,6 +1,5 @@ -use crate::ty::{self, TyCtxt}; +use crate::ty::TyCtxt; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::Lock; use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; @@ -8,68 +7,15 @@ use rustc_session::Session; mod dep_node; pub use rustc_query_system::dep_graph::{ - debug::DepNodeFilter, hash_result, DepContext, DepNodeColor, DepNodeIndex, - SerializedDepNodeIndex, WorkProduct, WorkProductId, + debug::DepNodeFilter, debug::EdgeFilter, hash_result, label_strs, DepContext, DepGraph, + DepGraphQuery, DepKind, DepNode, DepNodeColor, DepNodeIndex, SerializedDepGraph, + SerializedDepNodeIndex, TaskDeps, WorkProduct, WorkProductId, }; -pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt}; -crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; - -pub type DepGraph = rustc_query_system::dep_graph::DepGraph; -pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; -pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery; -pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph; -pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter; - -impl rustc_query_system::dep_graph::DepKind for DepKind { - const NULL: Self = DepKind::Null; - - fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}(", node.kind)?; - - ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(def_id) = node.extract_def_id(tcx) { - write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) { - write!(f, "{}", s)?; - } else { - write!(f, "{}", node.hash)?; - } - } else { - write!(f, "{}", node.hash)?; - } - Ok(()) - })?; - - write!(f, ")") - } - - fn with_deps(task_deps: Option<&Lock>, op: OP) -> R - where - OP: FnOnce() -> R, - { - ty::tls::with_context(|icx| { - let icx = ty::tls::ImplicitCtxt { task_deps, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }) - } - - fn read_deps(op: OP) - where - OP: for<'a> FnOnce(Option<&'a Lock>), - { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - op(icx.task_deps) - }) - } -} +crate use dep_node::{fingerprint_style, make_compile_codegen_unit, make_compile_mono_item}; +pub use dep_node::{DepKindStruct, DepNodeExt}; impl<'tcx> DepContext for TyCtxt<'tcx> { - type DepKind = DepKind; - #[inline] fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { TyCtxt::create_stable_hashing_context(*self) @@ -92,7 +38,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { #[inline(always)] fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle { - kind.fingerprint_style(*self) + fingerprint_style(*self, kind) } #[inline(always)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 0894b80507581..6aab0cc7425ed 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -64,6 +64,8 @@ extern crate rustc_macros; #[macro_use] extern crate rustc_data_structures; #[macro_use] +extern crate rustc_query_system; +#[macro_use] extern crate tracing; #[macro_use] extern crate smallvec; @@ -74,9 +76,6 @@ mod tests; #[macro_use] mod macros; -#[macro_use] -pub mod query; - #[macro_use] pub mod arena; #[macro_use] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8240273acad4c..52a33faef5ef1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1684,14 +1684,8 @@ nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } } pub mod tls { - use super::{ptr_eq, GlobalCtxt, TyCtxt}; - - use crate::dep_graph::{DepKind, TaskDeps}; - use crate::ty::query; - use rustc_data_structures::sync::{self, Lock}; - use rustc_data_structures::thin_vec::ThinVec; - use rustc_errors::Diagnostic; - use std::mem; + use super::{GlobalCtxt, TyCtxt}; + use rustc_data_structures::sync; #[cfg(not(parallel_compiler))] use std::cell::Cell; @@ -1705,30 +1699,18 @@ pub mod tls { /// you should also have access to an `ImplicitCtxt` through the functions /// in this module. #[derive(Clone)] - pub struct ImplicitCtxt<'a, 'tcx> { + pub struct ImplicitCtxt<'tcx> { /// The current `TyCtxt`. pub tcx: TyCtxt<'tcx>, - /// The current query job, if any. This is updated by `JobOwner::start` in - /// `ty::query::plumbing` when executing a query. - pub query: Option>, - - /// Where to store diagnostics for the current query job, if any. - /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. - pub diagnostics: Option<&'a Lock>>, - /// Used to prevent layout from recursing too deeply. pub layout_depth: usize, - - /// The current dep graph task. This is used to add dependencies to queries - /// when executing them. - pub task_deps: Option<&'a Lock>, } - impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { + impl<'tcx> ImplicitCtxt<'tcx> { pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self { let tcx = TyCtxt { gcx }; - ImplicitCtxt { tcx, query: None, diagnostics: None, layout_depth: 0, task_deps: None } + ImplicitCtxt { tcx, layout_depth: 0 } } } @@ -1776,9 +1758,9 @@ pub mod tls { /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. #[inline] - pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R + pub fn enter_context<'tcx, F, R>(context: &ImplicitCtxt<'tcx>, f: F) -> R where - F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, + F: FnOnce(&ImplicitCtxt<'tcx>) -> R, { set_tlv(context as *const _ as usize, || f(&context)) } @@ -1787,7 +1769,7 @@ pub mod tls { #[inline] pub fn with_context_opt(f: F) -> R where - F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, + F: for<'tcx> FnOnce(Option<&ImplicitCtxt<'tcx>>) -> R, { let context = get_tlv(); if context == 0 { @@ -1795,9 +1777,9 @@ pub mod tls { } else { // We could get an `ImplicitCtxt` pointer from another thread. // Ensure that `ImplicitCtxt` is `Sync`. - sync::assert_sync::>(); + sync::assert_sync::>(); - unsafe { f(Some(&*(context as *const ImplicitCtxt<'_, '_>))) } + unsafe { f(Some(&*(context as *const ImplicitCtxt<'_>))) } } } @@ -1806,28 +1788,11 @@ pub mod tls { #[inline] pub fn with_context(f: F) -> R where - F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, + F: for<'tcx> FnOnce(&ImplicitCtxt<'tcx>) -> R, { with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls"))) } - /// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument - /// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime - /// as the `TyCtxt` passed in. - /// This will panic if you pass it a `TyCtxt` which is different from the current - /// `ImplicitCtxt`'s `tcx` field. - #[inline] - pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R - where - F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R, - { - with_context(|context| unsafe { - assert!(ptr_eq(context.tcx.gcx, tcx.gcx)); - let context: &ImplicitCtxt<'_, '_> = mem::transmute(context); - f(context) - }) - } - /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. /// Panics if there is no `ImplicitCtxt` available. #[inline] @@ -2834,12 +2799,6 @@ impl InternIteratorElement for Result { } } -// We are comparing types with different invariant lifetimes, so `ptr::eq` -// won't work for us. -fn ptr_eq(t: *const T, u: *const U) -> bool { - t as *const () == u as *const () -} - pub fn provide(providers: &mut ty::query::Providers) { providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8ec5f4c79781f..dac82700b345a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -216,7 +216,7 @@ fn layout_of<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Result, LayoutError<'tcx>> { - ty::tls::with_related_context(tcx, move |icx| { + ty::tls::with_context(move |icx| { let (param_env, ty) = query.into_parts(); if !tcx.recursion_limit().value_within_limit(icx.layout_depth) { diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 6c1175ebdb4ee..32fdf86e720b9 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -60,7 +60,6 @@ use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; -pub(crate) use rustc_query_system::query::QueryJobId; use rustc_query_system::query::*; #[derive(Copy, Clone)] diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index b216d78da945c..8b4d2d4be1f42 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -13,6 +13,8 @@ extern crate rustc_macros; #[macro_use] extern crate rustc_middle; +#[macro_use] +extern crate rustc_query_system; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index a822ef1477808..df2dcfd33d0e0 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -3,17 +3,11 @@ //! manage the caches, and so forth. use crate::{on_disk_cache, queries, Queries}; -use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex}; -use rustc_middle::ty::tls::{self, ImplicitCtxt}; +use rustc_errors::Handler; +use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::HasDepContext; -use rustc_query_system::query::{ - QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects, -}; - -use rustc_data_structures::sync::Lock; -use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::{Diagnostic, Handler}; +use rustc_query_system::query::{QueryContext, QueryDescription, QueryMap, QuerySideEffects}; use rustc_serialize::opaque; use rustc_span::def_id::LocalDefId; @@ -35,7 +29,6 @@ impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { } impl HasDepContext for QueryCtxt<'tcx> { - type DepKind = rustc_middle::dep_graph::DepKind; type DepContext = TyCtxt<'tcx>; #[inline] @@ -45,11 +38,7 @@ impl HasDepContext for QueryCtxt<'tcx> { } impl QueryContext for QueryCtxt<'tcx> { - fn current_query_job(&self) -> Option> { - tls::with_related_context(**self, |icx| icx.query) - } - - fn try_collect_active_jobs(&self) -> Option> { + fn try_collect_active_jobs(&self) -> Option { self.queries.try_collect_active_jobs(**self) } @@ -77,36 +66,6 @@ impl QueryContext for QueryCtxt<'tcx> { c.store_side_effects_for_anon_node(dep_node_index, side_effects) } } - - /// Executes a job by changing the `ImplicitCtxt` to point to the - /// new query job while it executes. It returns the diagnostics - /// captured during execution and the actual result. - #[inline(always)] - fn start_query( - &self, - token: QueryJobId, - diagnostics: Option<&Lock>>, - compute: impl FnOnce() -> R, - ) -> R { - // The `TyCtxt` stored in TLS has the same global interner lifetime - // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes - // when accessing the `ImplicitCtxt`. - tls::with_related_context(**self, move |current_icx| { - // Update the `ImplicitCtxt` to point to our new query job. - let new_icx = ImplicitCtxt { - tcx: **self, - query: Some(token), - diagnostics, - layout_depth: current_icx.layout_depth, - task_deps: current_icx.task_deps, - }; - - // Use the `ImplicitCtxt` while we execute the query. - tls::enter_context(&new_icx, |_| { - rustc_data_structures::stack::ensure_sufficient_stack(compute) - }) - }) - } } impl<'tcx> QueryCtxt<'tcx> { @@ -153,13 +112,8 @@ impl<'tcx> QueryCtxt<'tcx> { Ok(()) } - pub fn try_print_query_stack( - self, - query: Option>, - handler: &Handler, - num_frames: Option, - ) -> usize { - rustc_query_system::query::print_query_stack(self, query, handler, num_frames) + pub fn try_print_query_stack(self, handler: &Handler, num_frames: Option) -> usize { + rustc_query_system::query::print_query_stack(self, handler, num_frames) } } @@ -299,7 +253,7 @@ macro_rules! define_queries { type Cache = query_storage::$name<$tcx>; #[inline(always)] - fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState + fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState where QueryCtxt<$tcx>: 'a { &tcx.queries.$name @@ -451,10 +405,7 @@ macro_rules! define_queries_struct { pub on_disk_cache: Option>, - $($(#[$attr])* $name: QueryState< - crate::dep_graph::DepKind, - query_keys::$name<$tcx>, - >,)* + $($(#[$attr])* $name: QueryState>,)* } impl<$tcx> Queries<$tcx> { @@ -474,7 +425,7 @@ macro_rules! define_queries_struct { pub(crate) fn try_collect_active_jobs( &$tcx self, tcx: TyCtxt<$tcx>, - ) -> Option> { + ) -> Option { let tcx = QueryCtxt { tcx, queries: self }; let mut jobs = QueryMap::default(); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_query_system/src/decl.rs similarity index 99% rename from compiler/rustc_middle/src/query/mod.rs rename to compiler/rustc_query_system/src/decl.rs index c6c0fdc885126..560d3275c2845 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_query_system/src/decl.rs @@ -52,7 +52,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_owner(key: LocalDefId) -> Option> { + query hir_owner(key: LocalDefId) -> Option> { desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -1139,7 +1139,7 @@ rustc_queries! { desc { "dylib dependency formats of crate" } } - query dependency_formats(_: ()) -> Lrc { + query dependency_formats(_: ()) -> Lrc { desc { "get the linkage format of all dependencies" } } diff --git a/compiler/rustc_query_system/src/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs index a544ac2c343ae..968ca20655db1 100644 --- a/compiler/rustc_query_system/src/dep_graph/debug.rs +++ b/compiler/rustc_query_system/src/dep_graph/debug.rs @@ -1,6 +1,6 @@ //! Code for debugging the dep-graph. -use super::{DepKind, DepNode, DepNodeIndex}; +use super::{DepNode, DepNodeIndex}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; use std::error::Error; @@ -28,7 +28,7 @@ impl DepNodeFilter { } /// Tests whether `node` meets the filter, returning true if so. - pub fn test(&self, node: &DepNode) -> bool { + pub fn test(&self, node: &DepNode) -> bool { let debug_str = format!("{:?}", node); self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f)) } @@ -36,14 +36,14 @@ impl DepNodeFilter { /// A filter like `F -> G` where `F` and `G` are valid dep-node /// filters. This can be used to test the source/target independently. -pub struct EdgeFilter { +pub struct EdgeFilter { pub source: DepNodeFilter, pub target: DepNodeFilter, - pub index_to_node: Lock>>, + pub index_to_node: Lock>, } -impl EdgeFilter { - pub fn new(test: &str) -> Result, Box> { +impl EdgeFilter { + pub fn new(test: &str) -> Result> { let parts: Vec<_> = test.split("->").collect(); if parts.len() != 2 { Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into()) @@ -57,7 +57,7 @@ impl EdgeFilter { } #[cfg(debug_assertions)] - pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { + pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { self.source.test(source) && self.target.test(target) } } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_kind.rs b/compiler/rustc_query_system/src/dep_graph/dep_kind.rs new file mode 100644 index 0000000000000..f7b134b45ea05 --- /dev/null +++ b/compiler/rustc_query_system/src/dep_graph/dep_kind.rs @@ -0,0 +1,69 @@ +use super::DepNode; + +macro_rules! define_dep_nodes { + (<$tcx:tt> + $( + [$($attrs:tt)*] + $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* + ,)* + ) => ( + #[macro_export] + macro_rules! make_dep_kind_array { + ($mod:ident) => {[ $($mod::$variant()),* ]}; + } + + /// This enum serves as an index into arrays built by `make_dep_kind_array`. + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] + #[allow(non_camel_case_types)] + pub enum DepKind { + $($variant),* + } + + pub fn dep_kind_from_label_string(label: &str) -> Result { + match label { + $(stringify!($variant) => Ok(DepKind::$variant),)* + _ => Err(()), + } + } + + /// Contains variant => str representations for constructing + /// DepNode groups for tests. + #[allow(dead_code, non_upper_case_globals)] + pub mod label_strs { + $( + pub const $variant: &str = stringify!($variant); + )* + } + ); +} + +rustc_dep_node_append!([define_dep_nodes!][ <'tcx> + // We use this for most things when incr. comp. is turned off. + [] Null, + + [anon] TraitSelect, + + // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit`. + [] CompileCodegenUnit(Symbol), + + // WARNING: if `MonoItem` is changed, make sure you update `make_compile_mono_item`. + // Only used by rustc_codegen_cranelift + [] CompileMonoItem(MonoItem), +]); + +// We keep a lot of `DepNode`s in memory during compilation. It's not +// required that their size stay the same, but we don't want to change +// it inadvertently. This assert just ensures we're aware of any change. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +static_assert_size!(DepNode, 18); + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +static_assert_size!(DepNode, 24); + +impl DepNode { + /// Used in testing + #[inline] + pub fn has_label_string(label: &str) -> bool { + dep_kind_from_label_string(label).is_ok() + } +} diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index c274c2cc26c15..dbf759bd03451 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -47,30 +47,32 @@ use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::AtomicRef; use std::fmt; use std::hash::Hash; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct DepNode { - pub kind: K, +#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable)] +pub struct DepNode { + pub kind: DepKind, pub hash: PackedFingerprint, } -impl DepNode { +impl DepNode { /// Creates a new, parameterless DepNode. This method will assert /// that the DepNode corresponding to the given DepKind actually /// does not require any parameters. - pub fn new_no_params(tcx: Ctxt, kind: K) -> DepNode + #[inline] + pub fn new_no_params(tcx: Ctxt, kind: DepKind) -> DepNode where - Ctxt: super::DepContext, + Ctxt: super::DepContext, { debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit); DepNode { kind, hash: Fingerprint::ZERO.into() } } - pub fn construct(tcx: Ctxt, kind: K, arg: &Key) -> DepNode + pub fn construct(tcx: Ctxt, kind: DepKind, arg: &Key) -> DepNode where - Ctxt: super::DepContext, + Ctxt: super::DepContext, Key: DepNodeParams, { let hash = arg.to_fingerprint(tcx); @@ -90,12 +92,20 @@ impl DepNode { } } -impl fmt::Debug for DepNode { +impl fmt::Debug for DepNode { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - K::debug_node(self, f) + (*NODE_DEBUG)(self, f) } } +pub static NODE_DEBUG: AtomicRef) -> fmt::Result> = + AtomicRef::new(&(default_node_debug as _)); + +fn default_node_debug(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}({})", node.kind, node.hash) +} + pub trait DepNodeParams: fmt::Debug + Sized { fn fingerprint_style() -> FingerprintStyle; @@ -117,7 +127,7 @@ pub trait DepNodeParams: fmt::Debug + Sized { /// `fingerprint_style()` is not `FingerprintStyle::Opaque`. /// It is always valid to return `None` here, in which case incremental /// compilation will treat the query as having changed instead of forcing it. - fn recover(tcx: Ctxt, dep_node: &DepNode) -> Option; + fn recover(tcx: Ctxt, dep_node: &DepNode) -> Option; } impl DepNodeParams for T @@ -145,7 +155,7 @@ where } #[inline(always)] - default fn recover(_: Ctxt, _: &DepNode) -> Option { + default fn recover(_: Ctxt, _: &DepNode) -> Option { None } } @@ -162,6 +172,7 @@ pub struct WorkProductId { } impl WorkProductId { + #[inline] pub fn from_cgu_name(cgu_name: &str) -> WorkProductId { let mut hasher = StableHasher::new(); cgu_name.len().hash(&mut hasher); diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index a8be1ca34c04f..cd31679709207 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,4 +1,3 @@ -use parking_lot::Mutex; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef}; @@ -6,8 +5,12 @@ use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::unlikely; use rustc_index::vec::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; + +use parking_lot::Mutex; use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use std::fmt::Debug; @@ -19,14 +22,14 @@ use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; use crate::ich::StableHashingContext; -use crate::query::{QueryContext, QuerySideEffects}; +use crate::query::{QueryContext, QueryJobId, QuerySideEffects}; #[cfg(debug_assertions)] use {super::debug::EdgeFilter, std::env}; #[derive(Clone)] -pub struct DepGraph { - data: Option>>, +pub struct DepGraph { + data: Option>, /// This field is used for assigning DepNodeIndices when running in /// non-incremental mode. Even in non-incremental mode we make sure that @@ -66,16 +69,16 @@ impl DepNodeColor { } } -struct DepGraphData { +struct DepGraphData { /// The new encoding of the dependency graph, optimized for red/green /// tracking. The `current` field is the dependency graph of only the /// current compilation session: We don't merge the previous dep-graph into /// current one anymore, but we do reference shared data to save space. - current: CurrentDepGraph, + current: CurrentDepGraph, /// The dep-graph from the previous compilation session. It contains all /// nodes and edges as well as all fingerprints of nodes that have them. - previous: SerializedDepGraph, + previous: SerializedDepGraph, colors: DepNodeColorMap, @@ -87,7 +90,7 @@ struct DepGraphData { /// this map. We can later look for and extract that data. previous_work_products: FxHashMap, - dep_node_debug: Lock, String>>, + dep_node_debug: Lock>, } pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint @@ -99,15 +102,15 @@ where stable_hasher.finish() } -impl DepGraph { +impl DepGraph { pub fn new( profiler: &SelfProfilerRef, - prev_graph: SerializedDepGraph, + prev_graph: SerializedDepGraph, prev_work_products: FxHashMap, encoder: FileEncoder, record_graph: bool, record_stats: bool, - ) -> DepGraph { + ) -> DepGraph { let prev_graph_node_count = prev_graph.node_count(); let current = CurrentDepGraph::new( @@ -121,7 +124,7 @@ impl DepGraph { // Instantiate a dependy-less node only once for anonymous queries. let _green_node_index = current.intern_new_node( profiler, - DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() }, + DepNode { kind: DepKind::Null, hash: current.anon_id_seed.into() }, smallvec![], Fingerprint::ZERO, ); @@ -140,7 +143,8 @@ impl DepGraph { } } - pub fn new_disabled() -> DepGraph { + #[inline] + pub fn new_disabled() -> DepGraph { DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } } @@ -150,15 +154,16 @@ impl DepGraph { self.data.is_some() } - pub fn with_query(&self, f: impl Fn(&DepGraphQuery)) { + pub fn with_debug(&self, f: impl Fn(&DepGraphQuery)) { if let Some(data) = &self.data { data.current.encoder.borrow().with_query(f) } } + #[inline] pub fn assert_ignored(&self) { if let Some(..) = self.data { - K::read_deps(|task_deps| { + crate::tls::read_deps(|task_deps| { assert!(task_deps.is_none(), "expected no task dependency tracking"); }) } @@ -168,7 +173,7 @@ impl DepGraph { where OP: FnOnce() -> R, { - K::with_deps(None, op) + crate::tls::with_deps(None, op) } /// Starts a new dep-graph task. Dep-graph tasks are specified @@ -198,16 +203,22 @@ impl DepGraph { /// `arg` parameter. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html - pub fn with_task, A: Debug, R>( + pub fn with_task( &self, - key: DepNode, + key: DepNode, cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) { if self.is_fully_enabled() { - self.with_task_impl(key, cx, arg, task, hash_result) + self.with_task_impl( + key, + cx, + arg, + |arg, task_deps| crate::tls::with_deps(task_deps, || task(cx, arg)), + hash_result, + ) } else { // Incremental compilation is turned off. We just execute the task // without tracking. We still provide a dep-node index that uniquely @@ -217,12 +228,45 @@ impl DepGraph { } } - fn with_task_impl, A: Debug, R>( + pub(crate) fn with_query( &self, - key: DepNode, + key: DepNode, cx: Ctxt, arg: A, - task: fn(Ctxt, A) -> R, + token: QueryJobId, + task: fn(Ctxt::DepContext, A) -> R, + hash_result: Option, &R) -> Fingerprint>, + ) -> (R, DepNodeIndex) { + let prof_timer = cx.dep_context().profiler().query_provider(); + let diagnostics = Lock::new(ThinVec::new()); + let (result, dep_node_index) = self.with_task_impl( + key, + cx, + arg, + |arg, task_deps| { + crate::tls::start_query(token, Some(&diagnostics), task_deps, || { + task(*cx.dep_context(), arg) + }) + }, + hash_result, + ); + let diagnostics = diagnostics.into_inner(); + let side_effects = QuerySideEffects { diagnostics }; + + prof_timer.finish_with_query_invocation_id(dep_node_index.into()); + + if unlikely!(!side_effects.is_empty()) { + cx.store_side_effects(dep_node_index, side_effects); + } + (result, dep_node_index) + } + + fn with_task_impl( + &self, + key: DepNode, + cx: Ctxt, + arg: A, + invoke: impl FnOnce(A, Option<&Lock>) -> R, hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) { // This function is only called when the graph is enabled. @@ -253,7 +297,7 @@ impl DepGraph { phantom_data: PhantomData, })) }; - let result = K::with_deps(task_deps.as_ref(), || task(cx, arg)); + let result = invoke(arg, task_deps.as_ref()); let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); let dcx = cx.dep_context(); @@ -293,10 +337,10 @@ impl DepGraph { /// Executes something within an "anonymous" task, that is, a task the /// `DepNode` of which is determined by the list of inputs it read from. - pub fn with_anon_task, OP, R>( + pub fn with_anon_task( &self, cx: Ctxt, - dep_kind: K, + dep_kind: DepKind, op: OP, ) -> (R, DepNodeIndex) where @@ -304,61 +348,104 @@ impl DepGraph { { debug_assert!(!cx.is_eval_always(dep_kind)); - if let Some(ref data) = self.data { - let task_deps = Lock::new(TaskDeps::default()); - let result = K::with_deps(Some(&task_deps), op); - let task_deps = task_deps.into_inner(); - let task_deps = task_deps.reads; - - let dep_node_index = match task_deps.len() { - 0 => { - // Because the dep-node id of anon nodes is computed from the sets of its - // dependencies we already know what the ID of this dependency-less node is - // going to be (i.e. equal to the precomputed - // `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating - // a `StableHasher` and sending the node through interning. - DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE - } - 1 => { - // When there is only one dependency, don't bother creating a node. - task_deps[0] - } - _ => { - // The dep node indices are hashed here instead of hashing the dep nodes of the - // dependencies. These indices may refer to different nodes per session, but this isn't - // a problem here because we that ensure the final dep node hash is per session only by - // combining it with the per session random number `anon_id_seed`. This hash only need - // to map the dependencies to a single value on a per session basis. - let mut hasher = StableHasher::new(); - task_deps.hash(&mut hasher); - - let target_dep_node = DepNode { - kind: dep_kind, - // Fingerprint::combine() is faster than sending Fingerprint - // through the StableHasher (at least as long as StableHasher - // is so slow). - hash: data.current.anon_id_seed.combine(hasher.finish()).into(), - }; - - data.current.intern_new_node( - cx.profiler(), - target_dep_node, - task_deps, - Fingerprint::ZERO, - ) - } - }; - - (result, dep_node_index) + if self.is_fully_enabled() { + self.with_anon_task_impl(*cx.dep_context(), dep_kind, |task_deps| { + crate::tls::with_deps(task_deps, op) + }) } else { (op(), self.next_virtual_depnode_index()) } } + /// Executes something within an "anonymous" task, that is, a task the + /// `DepNode` of which is determined by the list of inputs it read from. + pub(crate) fn with_anon_query( + &self, + dep_kind: DepKind, + cx: Ctxt, + arg: A, + token: QueryJobId, + task: fn(Ctxt::DepContext, A) -> R, + ) -> (R, DepNodeIndex) { + let dcx = *cx.dep_context(); + debug_assert!(!dcx.is_eval_always(dep_kind)); + + let prof_timer = dcx.profiler().query_provider(); + let diagnostics = Lock::new(ThinVec::new()); + + let (result, dep_node_index) = self.with_anon_task_impl(dcx, dep_kind, |task_deps| { + crate::tls::start_query(token, Some(&diagnostics), task_deps, || task(dcx, arg)) + }); + let diagnostics = diagnostics.into_inner(); + + prof_timer.finish_with_query_invocation_id(dep_node_index.into()); + + let side_effects = QuerySideEffects { diagnostics }; + if unlikely!(!side_effects.is_empty()) { + cx.store_side_effects_for_anon_node(dep_node_index, side_effects); + } + (result, dep_node_index) + } + + fn with_anon_task_impl( + &self, + cx: Ctxt, + dep_kind: DepKind, + invoke: impl FnOnce(Option<&Lock>) -> R, + ) -> (R, DepNodeIndex) { + debug_assert!(!cx.dep_context().is_eval_always(dep_kind)); + + let data = self.data.as_ref().unwrap(); + let task_deps = Lock::new(TaskDeps::default()); + let result = invoke(Some(&task_deps)); + let task_deps = task_deps.into_inner().reads; + + let dep_node_index = match task_deps.len() { + 0 => { + // Because the dep-node id of anon nodes is computed from the sets of its + // dependencies we already know what the ID of this dependency-less node is + // going to be (i.e. equal to the precomputed + // `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating + // a `StableHasher` and sending the node through interning. + DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE + } + 1 => { + // When there is only one dependency, don't bother creating a node. + task_deps[0] + } + _ => { + // The dep node indices are hashed here instead of hashing the dep nodes of the + // dependencies. These indices may refer to different nodes per session, but this isn't + // a problem here because we that ensure the final dep node hash is per session only by + // combining it with the per session random number `anon_id_seed`. This hash only need + // to map the dependencies to a single value on a per session basis. + let mut hasher = StableHasher::new(); + task_deps.hash(&mut hasher); + + let target_dep_node = DepNode { + kind: dep_kind, + // Fingerprint::combine() is faster than sending Fingerprint + // through the StableHasher (at least as long as StableHasher + // is so slow). + hash: data.current.anon_id_seed.combine(hasher.finish()).into(), + }; + + data.current.intern_new_node( + cx.profiler(), + target_dep_node, + task_deps, + Fingerprint::ZERO, + ) + } + }; + + (result, dep_node_index) + } + #[inline] pub fn read_index(&self, dep_node_index: DepNodeIndex) { if let Some(ref data) = self.data { - K::read_deps(|task_deps| { + crate::tls::read_deps(|task_deps| { if let Some(task_deps) = task_deps { let mut task_deps = task_deps.lock(); let task_deps = &mut *task_deps; @@ -401,12 +488,12 @@ impl DepGraph { } #[inline] - pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { + pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { self.dep_node_index_of_opt(dep_node).unwrap() } #[inline] - pub fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option { + pub fn dep_node_index_of_opt(&self, dep_node: &DepNode) -> Option { let data = self.data.as_ref().unwrap(); let current = &data.current; @@ -418,28 +505,31 @@ impl DepGraph { } #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { self.data.is_some() && self.dep_node_index_of_opt(dep_node).is_some() } - pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { + #[inline] + pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) } /// Checks whether a previous work product exists for `v` and, if /// so, return the path that leads to it. Used to skip doing work. + #[inline] pub fn previous_work_product(&self, v: &WorkProductId) -> Option { self.data.as_ref().and_then(|data| data.previous_work_products.get(v).cloned()) } /// Access the map of work-products created during the cached run. Only /// used during saving of the dep-graph. + #[inline] pub fn previous_work_products(&self) -> &FxHashMap { &self.data.as_ref().unwrap().previous_work_products } #[inline(always)] - pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) + pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) where F: FnOnce() -> String, { @@ -452,11 +542,13 @@ impl DepGraph { dep_node_debug.borrow_mut().insert(dep_node, debug_str); } - pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { + #[inline] + pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() } - fn node_color(&self, dep_node: &DepNode) -> Option { + #[inline] + fn node_color(&self, dep_node: &DepNode) -> Option { if let Some(ref data) = self.data { if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { return data.colors.get(prev_index); @@ -474,10 +566,10 @@ impl DepGraph { /// A node will have an index, when it's already been marked green, or when we can mark it /// green. This function will mark the current task as a reader of the specified node, when /// a node index can be found for that node. - pub fn try_mark_green>( + pub fn try_mark_green( &self, tcx: Ctxt, - dep_node: &DepNode, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind)); @@ -501,12 +593,12 @@ impl DepGraph { } } - fn try_mark_parent_green>( + fn try_mark_parent_green( &self, tcx: Ctxt, - data: &DepGraphData, + data: &DepGraphData, parent_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, + dep_node: &DepNode, ) -> Option<()> { let dep_dep_node_color = data.colors.get(parent_dep_node_index); let dep_dep_node = &data.previous.index_to_node(parent_dep_node_index); @@ -613,12 +705,12 @@ impl DepGraph { } /// Try to mark a dep-node which existed in the previous compilation session as green. - fn try_mark_previous_green>( + fn try_mark_previous_green( &self, tcx: Ctxt, - data: &DepGraphData, + data: &DepGraphData, prev_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, + dep_node: &DepNode, ) -> Option { debug!("try_mark_previous_green({:?}) - BEGIN", dep_node); @@ -683,10 +775,10 @@ impl DepGraph { /// This may be called concurrently on multiple threads for the same dep node. #[cold] #[inline(never)] - fn emit_side_effects>( + fn emit_side_effects( &self, tcx: Ctxt, - data: &DepGraphData, + data: &DepGraphData, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects, ) { @@ -709,13 +801,15 @@ impl DepGraph { // Returns true if the given node has been marked as red during the // current compilation session. Used in various assertions - pub fn is_red(&self, dep_node: &DepNode) -> bool { + #[inline] + pub fn is_red(&self, dep_node: &DepNode) -> bool { self.node_color(dep_node) == Some(DepNodeColor::Red) } // Returns true if the given node has been marked as green during the // current compilation session. Used in various assertions - pub fn is_green(&self, dep_node: &DepNode) -> bool { + #[inline] + pub fn is_green(&self, dep_node: &DepNode) -> bool { self.node_color(dep_node).map_or(false, |c| c.is_green()) } @@ -727,7 +821,7 @@ impl DepGraph { // // This method will only load queries that will end up in the disk cache. // Other queries will not be executed. - pub fn exec_cache_promotions>(&self, tcx: Ctxt) { + pub fn exec_cache_promotions(&self, tcx: Ctxt) { let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion"); let data = self.data.as_ref().unwrap(); @@ -755,6 +849,7 @@ impl DepGraph { } } + #[inline] pub fn encode(&self, profiler: &SelfProfilerRef) -> FileEncodeResult { if let Some(data) = &self.data { data.current.encoder.steal().finish(profiler) @@ -763,6 +858,7 @@ impl DepGraph { } } + #[inline] pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex { let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); DepNodeIndex::from_u32(index) @@ -835,15 +931,15 @@ rustc_index::newtype_index! { /// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When /// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index` /// first, and `data` second. -pub(super) struct CurrentDepGraph { - encoder: Steal>, - new_node_to_index: Sharded, DepNodeIndex>>, +pub(super) struct CurrentDepGraph { + encoder: Steal, + new_node_to_index: Sharded>, prev_index_to_index: Lock>>, /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. #[cfg(debug_assertions)] - forbidden_edge: Option>, + forbidden_edge: Option, /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of /// their edges. This has the beneficial side-effect that multiple anonymous @@ -870,14 +966,14 @@ pub(super) struct CurrentDepGraph { node_intern_event_id: Option, } -impl CurrentDepGraph { +impl CurrentDepGraph { fn new( profiler: &SelfProfilerRef, prev_graph_node_count: usize, encoder: FileEncoder, record_graph: bool, record_stats: bool, - ) -> CurrentDepGraph { + ) -> CurrentDepGraph { use std::time::{SystemTime, UNIX_EPOCH}; let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); @@ -929,7 +1025,8 @@ impl CurrentDepGraph { } #[cfg(debug_assertions)] - fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode) { + #[inline] + fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode) { if let Some(forbidden_edge) = &self.forbidden_edge { forbidden_edge.index_to_node.lock().insert(dep_node_index, key); } @@ -937,10 +1034,11 @@ impl CurrentDepGraph { /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it. /// Assumes that this is a node that has no equivalent in the previous dep-graph. + #[inline] fn intern_new_node( &self, profiler: &SelfProfilerRef, - key: DepNode, + key: DepNode, edges: EdgesVec, current_fingerprint: Fingerprint, ) -> DepNodeIndex { @@ -957,11 +1055,12 @@ impl CurrentDepGraph { } } + #[inline] fn intern_node( &self, profiler: &SelfProfilerRef, - prev_graph: &SerializedDepGraph, - key: DepNode, + prev_graph: &SerializedDepGraph, + key: DepNode, edges: EdgesVec, fingerprint: Option, print_status: bool, @@ -1059,10 +1158,11 @@ impl CurrentDepGraph { } } + #[inline] fn promote_node_and_deps_to_current( &self, profiler: &SelfProfilerRef, - prev_graph: &SerializedDepGraph, + prev_graph: &SerializedDepGraph, prev_index: SerializedDepNodeIndex, ) -> DepNodeIndex { self.debug_assert_not_in_new_nodes(prev_graph, prev_index); @@ -1094,7 +1194,7 @@ impl CurrentDepGraph { #[inline] fn debug_assert_not_in_new_nodes( &self, - prev_graph: &SerializedDepGraph, + prev_graph: &SerializedDepGraph, prev_index: SerializedDepNodeIndex, ) { let node = &prev_graph.index_to_node(prev_index); @@ -1109,24 +1209,13 @@ impl CurrentDepGraph { const TASK_DEPS_READS_CAP: usize = 8; type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; -pub struct TaskDeps { +#[derive(Default)] +pub struct TaskDeps { #[cfg(debug_assertions)] - node: Option>, + node: Option, reads: EdgesVec, read_set: FxHashSet, - phantom_data: PhantomData>, -} - -impl Default for TaskDeps { - fn default() -> Self { - Self { - #[cfg(debug_assertions)] - node: None, - reads: EdgesVec::new(), - read_set: FxHashSet::default(), - phantom_data: PhantomData, - } - } + phantom_data: PhantomData, } // A data structure that stores Option values as a contiguous @@ -1140,6 +1229,7 @@ const COMPRESSED_RED: u32 = 1; const COMPRESSED_FIRST_GREEN: u32 = 2; impl DepNodeColorMap { + #[inline] fn new(size: usize) -> DepNodeColorMap { DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() } } @@ -1155,6 +1245,7 @@ impl DepNodeColorMap { } } + #[inline] fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) { self.values[index].store( match color { diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 047fc9f10cc2f..3f5909574d014 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -1,31 +1,26 @@ pub mod debug; +mod dep_kind; mod dep_node; mod graph; mod query; mod serialized; -pub use dep_node::{DepNode, DepNodeParams, WorkProductId}; +pub use dep_kind::{dep_kind_from_label_string, label_strs, DepKind}; +pub use dep_node::{DepNode, DepNodeParams, WorkProductId, NODE_DEBUG}; pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; pub use query::DepGraphQuery; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::Lock; -use rustc_serialize::{opaque::FileEncoder, Encodable}; use rustc_session::Session; -use std::fmt; -use std::hash::Hash; - pub trait DepContext: Copy { - type DepKind: self::DepKind; - /// Create a hashing context for hashing new results. fn create_stable_hashing_context(&self) -> StableHashingContext<'_>; /// Access the DepGraph. - fn dep_graph(&self) -> &DepGraph; + fn dep_graph(&self) -> &DepGraph; /// Access the profiler. fn profiler(&self) -> &SelfProfilerRef; @@ -34,26 +29,24 @@ pub trait DepContext: Copy { fn sess(&self) -> &Session; /// Return whether this kind always require evaluation. - fn is_eval_always(&self, kind: Self::DepKind) -> bool; + fn is_eval_always(&self, kind: DepKind) -> bool; - fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle; + fn fingerprint_style(&self, kind: DepKind) -> FingerprintStyle; /// Try to force a dep node to execute and see if it's green. - fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool; + fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool; /// Load data from the on-disk cache. - fn try_load_from_on_disk_cache(&self, dep_node: DepNode); + fn try_load_from_on_disk_cache(&self, dep_node: DepNode); } pub trait HasDepContext: Copy { - type DepKind: self::DepKind; - type DepContext: self::DepContext; + type DepContext: self::DepContext; fn dep_context(&self) -> &Self::DepContext; } impl HasDepContext for T { - type DepKind = T::DepKind; type DepContext = Self; fn dep_context(&self) -> &Self::DepContext { @@ -81,21 +74,3 @@ impl FingerprintStyle { } } } - -/// Describe the different families of dependency nodes. -pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable + 'static { - const NULL: Self; - - /// Implementation of `std::fmt::Debug` for `DepNode`. - fn debug_node(node: &DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result; - - /// Execute the operation with provided dependencies. - fn with_deps(deps: Option<&Lock>>, op: OP) -> R - where - OP: FnOnce() -> R; - - /// Access dependencies from current implicit context. - fn read_deps(op: OP) - where - OP: for<'a> FnOnce(Option<&'a Lock>>); -} diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index 27b3b5e13667e..380b9c8d91518 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -2,16 +2,16 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING}; use rustc_index::vec::IndexVec; -use super::{DepKind, DepNode, DepNodeIndex}; +use super::{DepNode, DepNodeIndex}; -pub struct DepGraphQuery { - pub graph: Graph, ()>, - pub indices: FxHashMap, NodeIndex>, +pub struct DepGraphQuery { + pub graph: Graph, + pub indices: FxHashMap, pub dep_index_to_index: IndexVec>, } -impl DepGraphQuery { - pub fn new(prev_node_count: usize) -> DepGraphQuery { +impl DepGraphQuery { + pub fn new(prev_node_count: usize) -> DepGraphQuery { let node_count = prev_node_count + prev_node_count / 4; let edge_count = 6 * node_count; @@ -22,7 +22,7 @@ impl DepGraphQuery { DepGraphQuery { graph, indices, dep_index_to_index } } - pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) { + pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) { let source = self.graph.add_node(node); if index.index() >= self.dep_index_to_index.len() { self.dep_index_to_index.resize(index.index() + 1, None); @@ -40,11 +40,11 @@ impl DepGraphQuery { } } - pub fn nodes(&self) -> Vec<&DepNode> { + pub fn nodes(&self) -> Vec<&DepNode> { self.graph.all_nodes().iter().map(|n| &n.data).collect() } - pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { + pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { self.graph .all_edges() .iter() @@ -53,7 +53,7 @@ impl DepGraphQuery { .collect() } - fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { + fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(node) { self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect() } else { @@ -62,7 +62,7 @@ impl DepGraphQuery { } /// All nodes that can reach `node`. - pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, INCOMING) } } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 47197a1e492a3..9c0d3827999f7 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -35,9 +35,9 @@ rustc_index::newtype_index! { /// Data for use when recompiling the **current crate**. #[derive(Debug)] -pub struct SerializedDepGraph { +pub struct SerializedDepGraph { /// The set of all DepNodes in the graph - nodes: IndexVec>, + nodes: IndexVec, /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to /// the DepNode at the same index in the nodes vector. fingerprints: IndexVec, @@ -49,10 +49,11 @@ pub struct SerializedDepGraph { /// implicit in edge_list_indices. edge_list_data: Vec, /// Reciprocal map to `nodes`. - index: FxHashMap, SerializedDepNodeIndex>, + index: FxHashMap, } -impl Default for SerializedDepGraph { +impl Default for SerializedDepGraph { + #[inline] fn default() -> Self { SerializedDepGraph { nodes: Default::default(), @@ -64,7 +65,7 @@ impl Default for SerializedDepGraph { } } -impl SerializedDepGraph { +impl SerializedDepGraph { #[inline] pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] { let targets = self.edge_list_indices[source]; @@ -72,17 +73,17 @@ impl SerializedDepGraph { } #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { + pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { self.nodes[dep_node_index] } #[inline] - pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { self.index.get(dep_node).cloned() } #[inline] - pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { + pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { self.index.get(dep_node).map(|&node_index| self.fingerprints[node_index]) } @@ -91,16 +92,15 @@ impl SerializedDepGraph { self.fingerprints[dep_node_index] } + #[inline] pub fn node_count(&self) -> usize { self.index.len() } } -impl<'a, K: DepKind + Decodable>> Decodable> - for SerializedDepGraph -{ +impl<'a> Decodable> for SerializedDepGraph { #[instrument(level = "debug", skip(d))] - fn decode(d: &mut opaque::Decoder<'a>) -> Result, String> { + fn decode(d: &mut opaque::Decoder<'a>) -> Result { let start_position = d.position(); // The last 16 bytes are the node count and edge count. @@ -123,7 +123,7 @@ impl<'a, K: DepKind + Decodable>> Decodable = d.read_struct_field("node", Decodable::decode)?; + let dep_node: DepNode = d.read_struct_field("node", Decodable::decode)?; let _i: SerializedDepNodeIndex = nodes.push(dep_node); debug_assert_eq!(_i.index(), _index); @@ -155,28 +155,29 @@ impl<'a, K: DepKind + Decodable>> Decodable { - node: DepNode, +#[derive(Debug, Encodable)] +pub struct NodeInfo { + node: DepNode, fingerprint: Fingerprint, edges: SmallVec<[DepNodeIndex; 8]>, } -struct Stat { - kind: K, +struct Stat { + kind: DepKind, node_counter: u64, edge_counter: u64, } -struct EncoderState { +struct EncoderState { encoder: FileEncoder, total_node_count: usize, total_edge_count: usize, result: FileEncodeResult, - stats: Option>>, + stats: Option>, } -impl EncoderState { +impl EncoderState { + #[inline] fn new(encoder: FileEncoder, record_stats: bool) -> Self { Self { encoder, @@ -190,8 +191,8 @@ impl EncoderState { #[instrument(level = "debug", skip(self, record_graph))] fn encode_node( &mut self, - node: &NodeInfo, - record_graph: &Option>>, + node: &NodeInfo, + record_graph: &Option>, ) -> DepNodeIndex { let index = DepNodeIndex::new(self.total_node_count); self.total_node_count += 1; @@ -243,12 +244,13 @@ impl EncoderState { } } -pub struct GraphEncoder { - status: Lock>, - record_graph: Option>>, +pub struct GraphEncoder { + status: Lock, + record_graph: Option>, } -impl> GraphEncoder { +impl GraphEncoder { + #[inline] pub fn new( encoder: FileEncoder, prev_node_count: usize, @@ -261,7 +263,7 @@ impl> GraphEncoder { GraphEncoder { status, record_graph } } - pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { + pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { if let Some(record_graph) = &self.record_graph { f(&record_graph.lock()) } @@ -322,10 +324,11 @@ impl> GraphEncoder { } } + #[inline] pub(crate) fn send( &self, profiler: &SelfProfilerRef, - node: DepNode, + node: DepNode, fingerprint: Fingerprint, edges: SmallVec<[DepNodeIndex; 8]>, ) -> DepNodeIndex { @@ -334,6 +337,7 @@ impl> GraphEncoder { self.status.lock().encode_node(&node, &self.record_graph) } + #[inline] pub fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph"); self.status.into_inner().finish(profiler) diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 1b992cdb0c94b..bad3c8b7e0513 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -14,7 +14,12 @@ extern crate rustc_data_structures; #[macro_use] extern crate rustc_macros; +#[macro_use] +pub mod decl; + pub mod cache; pub mod dep_graph; pub mod ich; pub mod query; + +pub mod tls; diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 07b2e2b1080b8..70669bb004c41 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -1,5 +1,6 @@ //! Query configuration and description traits. +use crate::dep_graph::DepKind; use crate::dep_graph::DepNode; use crate::dep_graph::SerializedDepNodeIndex; use crate::ich::StableHashingContext; @@ -21,7 +22,7 @@ pub trait QueryConfig { pub(crate) struct QueryVtable { pub anon: bool, - pub dep_kind: CTX::DepKind, + pub dep_kind: DepKind, pub eval_always: bool, pub compute: fn(CTX::DepContext, K) -> V, @@ -32,7 +33,7 @@ pub(crate) struct QueryVtable { } impl QueryVtable { - pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode + pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode where K: crate::dep_graph::DepNodeParams, { @@ -55,7 +56,7 @@ impl QueryVtable { pub trait QueryAccessors: QueryConfig { const ANON: bool; const EVAL_ALWAYS: bool; - const DEP_KIND: CTX::DepKind; + const DEP_KIND: DepKind; const HASH_RESULT: Option< fn(hcx: &mut StableHashingContext<'_>, result: &Self::Value) -> Fingerprint, >; @@ -63,7 +64,7 @@ pub trait QueryAccessors: QueryConfig { type Cache: QueryCache; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(tcx: CTX) -> &'a QueryState + fn query_state<'a>(tcx: CTX) -> &'a QueryState where CTX: 'a; diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index bd67303099220..eda477c369d58 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,4 +1,5 @@ use crate::dep_graph::DepContext; +use crate::dep_graph::DepKind; use crate::query::plumbing::CycleError; use crate::query::{QueryContext, QueryStackFrame, SimpleDefKind}; @@ -13,7 +14,6 @@ use std::num::NonZeroU32; #[cfg(parallel_compiler)] use { - crate::dep_graph::DepKind, parking_lot::{Condvar, Mutex}, rustc_data_structures::fx::FxHashSet, rustc_data_structures::sync::Lock, @@ -33,7 +33,7 @@ pub struct QueryInfo { pub query: QueryStackFrame, } -pub type QueryMap = FxHashMap, QueryJobInfo>; +pub type QueryMap = FxHashMap; /// A value uniquely identifying an active query job within a shard in the query cache. #[derive(Copy, Clone, Eq, PartialEq, Hash)] @@ -41,7 +41,7 @@ pub struct QueryShardJobId(pub NonZeroU32); /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct QueryJobId { +pub struct QueryJobId { /// Which job within a shard is this pub job: QueryShardJobId, @@ -49,64 +49,64 @@ pub struct QueryJobId { pub shard: u16, /// What kind of query this job is. - pub kind: D, + pub kind: DepKind, } -impl QueryJobId -where - D: Copy + Clone + Eq + Hash, -{ - pub fn new(job: QueryShardJobId, shard: usize, kind: D) -> Self { +impl QueryJobId { + #[inline] + pub fn new(job: QueryShardJobId, shard: usize, kind: DepKind) -> Self { QueryJobId { job, shard: u16::try_from(shard).unwrap(), kind } } - fn query(self, map: &QueryMap) -> QueryStackFrame { + #[inline] + fn query(self, map: &QueryMap) -> QueryStackFrame { map.get(&self).unwrap().query.clone() } #[cfg(parallel_compiler)] - fn span(self, map: &QueryMap) -> Span { + #[inline] + fn span(self, map: &QueryMap) -> Span { map.get(&self).unwrap().job.span } #[cfg(parallel_compiler)] - fn parent(self, map: &QueryMap) -> Option> { + #[inline] + fn parent(self, map: &QueryMap) -> Option { map.get(&self).unwrap().job.parent } #[cfg(parallel_compiler)] - fn latch<'a>(self, map: &'a QueryMap) -> Option<&'a QueryLatch> { + #[inline] + fn latch<'a>(self, map: &'a QueryMap) -> Option<&'a QueryLatch> { map.get(&self).unwrap().job.latch.as_ref() } } -pub struct QueryJobInfo { +pub struct QueryJobInfo { pub query: QueryStackFrame, - pub job: QueryJob, + pub job: QueryJob, } /// Represents an active query job. #[derive(Clone)] -pub struct QueryJob { +pub struct QueryJob { pub id: QueryShardJobId, /// The span corresponding to the reason for which this query was required. pub span: Span, /// The parent query job which created this job and is implicitly waiting on it. - pub parent: Option>, + pub parent: Option, /// The latch that is used to wait on this job. #[cfg(parallel_compiler)] - latch: Option>, + latch: Option, } -impl QueryJob -where - D: Copy + Clone + Eq + Hash, -{ +impl QueryJob { /// Creates a new query job. - pub fn new(id: QueryShardJobId, span: Span, parent: Option>) -> Self { + #[inline] + pub fn new(id: QueryShardJobId, span: Span, parent: Option) -> Self { QueryJob { id, span, @@ -117,7 +117,8 @@ where } #[cfg(parallel_compiler)] - pub(super) fn latch(&mut self) -> QueryLatch { + #[inline] + pub(super) fn latch(&mut self) -> QueryLatch { if self.latch.is_none() { self.latch = Some(QueryLatch::new()); } @@ -128,6 +129,7 @@ where /// /// This does nothing for single threaded rustc, /// as there are no concurrent jobs which could be waiting on us + #[inline] pub fn signal_complete(self) { #[cfg(parallel_compiler)] { @@ -139,16 +141,13 @@ where } #[cfg(not(parallel_compiler))] -impl QueryJobId -where - D: Copy + Clone + Eq + Hash, -{ +impl QueryJobId { #[cold] #[inline(never)] pub(super) fn find_cycle_in_stack( &self, - query_map: QueryMap, - current_job: &Option>, + query_map: QueryMap, + current_job: &Option, span: Span, ) -> CycleError { // Find the waitee amongst `current_job` parents @@ -184,15 +183,15 @@ where } #[cfg(parallel_compiler)] -struct QueryWaiter { - query: Option>, +struct QueryWaiter { + query: Option, condvar: Condvar, span: Span, cycle: Lock>, } #[cfg(parallel_compiler)] -impl QueryWaiter { +impl QueryWaiter { fn notify(&self, registry: &rayon_core::Registry) { rayon_core::mark_unblocked(registry); self.condvar.notify_one(); @@ -200,19 +199,20 @@ impl QueryWaiter { } #[cfg(parallel_compiler)] -struct QueryLatchInfo { +struct QueryLatchInfo { complete: bool, - waiters: Vec>>, + waiters: Vec>, } #[cfg(parallel_compiler)] #[derive(Clone)] -pub(super) struct QueryLatch { - info: Lrc>>, +pub(super) struct QueryLatch { + info: Lrc>, } #[cfg(parallel_compiler)] -impl QueryLatch { +impl QueryLatch { + #[inline] fn new() -> Self { QueryLatch { info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), @@ -221,13 +221,10 @@ impl QueryLatch { } #[cfg(parallel_compiler)] -impl QueryLatch { +impl QueryLatch { /// Awaits for the query job to complete. - pub(super) fn wait_on( - &self, - query: Option>, - span: Span, - ) -> Result<(), CycleError> { + #[inline] + pub(super) fn wait_on(&self, query: Option, span: Span) -> Result<(), CycleError> { let waiter = Lrc::new(QueryWaiter { query, span, cycle: Lock::new(None), condvar: Condvar::new() }); self.wait_on_inner(&waiter); @@ -242,7 +239,8 @@ impl QueryLatch { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, waiter: &Lrc>) { + #[inline] + fn wait_on_inner(&self, waiter: &Lrc) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -264,6 +262,7 @@ impl QueryLatch { } /// Sets the latch and resumes all waiters on it + #[inline] fn set(&self) { let mut info = self.info.lock(); debug_assert!(!info.complete); @@ -276,7 +275,8 @@ impl QueryLatch { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. - fn extract_waiter(&self, waiter: usize) -> Lrc> { + #[inline] + fn extract_waiter(&self, waiter: usize) -> Lrc { let mut info = self.info.lock(); debug_assert!(!info.complete); // Remove the waiter from the list of waiters @@ -286,7 +286,7 @@ impl QueryLatch { /// A resumable waiter of a query. The usize is the index into waiters in the query's latch #[cfg(parallel_compiler)] -type Waiter = (QueryJobId, usize); +type Waiter = (QueryJobId, usize); /// Visits all the non-resumable and resumable waiters of a query. /// Only waiters in a query are visited. @@ -298,14 +298,9 @@ type Waiter = (QueryJobId, usize); /// required information to resume the waiter. /// If all `visit` calls returns None, this function also returns None. #[cfg(parallel_compiler)] -fn visit_waiters( - query_map: &QueryMap, - query: QueryJobId, - mut visit: F, -) -> Option>> +fn visit_waiters(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option> where - D: Copy + Clone + Eq + Hash, - F: FnMut(Span, QueryJobId) -> Option>>, + F: FnMut(Span, QueryJobId) -> Option>, { // Visit the parent query which is a non-resumable waiter since it's on the same stack if let Some(parent) = query.parent(query_map) { @@ -334,16 +329,13 @@ where /// If a cycle is detected, this initial value is replaced with the span causing /// the cycle. #[cfg(parallel_compiler)] -fn cycle_check( - query_map: &QueryMap, - query: QueryJobId, +fn cycle_check( + query_map: &QueryMap, + query: QueryJobId, span: Span, - stack: &mut Vec<(Span, QueryJobId)>, - visited: &mut FxHashSet>, -) -> Option>> -where - D: Copy + Clone + Eq + Hash, -{ + stack: &mut Vec<(Span, QueryJobId)>, + visited: &mut FxHashSet, +) -> Option> { if !visited.insert(query) { return if let Some(p) = stack.iter().position(|q| q.1 == query) { // We detected a query cycle, fix up the initial span and return Some @@ -378,14 +370,11 @@ where /// from `query` without going through any of the queries in `visited`. /// This is achieved with a depth first search. #[cfg(parallel_compiler)] -fn connected_to_root( - query_map: &QueryMap, - query: QueryJobId, - visited: &mut FxHashSet>, -) -> bool -where - D: Copy + Clone + Eq + Hash, -{ +fn connected_to_root( + query_map: &QueryMap, + query: QueryJobId, + visited: &mut FxHashSet, +) -> bool { // We already visited this or we're deliberately ignoring it if !visited.insert(query) { return false; @@ -404,10 +393,9 @@ where // Deterministically pick an query from a list #[cfg(parallel_compiler)] -fn pick_query<'a, D, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T +fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T where - D: Copy + Clone + Eq + Hash, - F: Fn(&T) -> (Span, QueryJobId), + F: Fn(&T) -> (Span, QueryJobId), { // Deterministically pick an entry point // FIXME: Sort this instead @@ -431,10 +419,10 @@ where /// If a cycle was not found, the starting query is removed from `jobs` and /// the function returns false. #[cfg(parallel_compiler)] -fn remove_cycle( - query_map: &QueryMap, - jobs: &mut Vec>, - wakelist: &mut Vec>>, +fn remove_cycle( + query_map: &QueryMap, + jobs: &mut Vec, + wakelist: &mut Vec>, ) -> bool { let mut visited = FxHashSet::default(); let mut stack = Vec::new(); @@ -489,7 +477,7 @@ fn remove_cycle( } } }) - .collect::, Option<(Span, QueryJobId)>)>>(); + .collect::)>>(); // Deterministically pick an entry point let (_, entry_point, usage) = pick_query(query_map, &entry_points, |e| (e.0, e.1)); @@ -544,7 +532,7 @@ pub fn deadlock(tcx: CTX, registry: &rayon_core::Registry) { let mut wakelist = Vec::new(); let query_map = tcx.try_collect_active_jobs().unwrap(); - let mut jobs: Vec> = query_map.keys().cloned().collect(); + let mut jobs: Vec = query_map.keys().cloned().collect(); let mut found_cycle = false; @@ -630,10 +618,11 @@ pub(crate) fn report_cycle<'a>( pub fn print_query_stack( tcx: CTX, - mut current_query: Option>, handler: &Handler, num_frames: Option, ) -> usize { + let mut current_query = crate::tls::current_query_job(); + // Be careful relying on global state here: this code is called from // a panic hook, which means that the global `Handler` may be in a weird // state if it was responsible for triggering the panic. diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index e2b0a65ab77b1..4a3ad12abbf63 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -16,7 +16,6 @@ pub use self::config::{QueryAccessors, QueryConfig, QueryDescription}; use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; -use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; use rustc_span::Span; @@ -117,10 +116,7 @@ impl QuerySideEffects { } pub trait QueryContext: HasDepContext { - /// Get the query information from the TLS context. - fn current_query_job(&self) -> Option>; - - fn try_collect_active_jobs(&self) -> Option>; + fn try_collect_active_jobs(&self) -> Option; /// Load side effects associated to the node in the previous session. fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects; @@ -134,14 +130,4 @@ pub trait QueryContext: HasDepContext { dep_node_index: DepNodeIndex, side_effects: QuerySideEffects, ); - - /// Executes a job by changing the `ImplicitCtxt` to point to the - /// new query job while it executes. It returns the diagnostics - /// captured during execution and the actual result. - fn start_query( - &self, - token: QueryJobId, - diagnostics: Option<&Lock>>, - compute: impl FnOnce() -> R, - ) -> R; } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 5506666b6a1bf..35c1523410762 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -2,21 +2,20 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams}; +use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams}; use crate::query::caches::QueryCache; use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt}; use crate::query::job::{ report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId, }; -use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame}; +use crate::query::{QueryContext, QueryMap, QueryStackFrame}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHasher}; #[cfg(parallel_compiler)] use rustc_data_structures::profiling::TimingGuard; use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded}; -use rustc_data_structures::sync::{Lock, LockGuard}; -use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::sync::LockGuard; use rustc_errors::{DiagnosticBuilder, FatalError}; use rustc_span::{Span, DUMMY_SP}; use std::cell::Cell; @@ -69,36 +68,35 @@ impl QueryCacheStore { } } -struct QueryStateShard { - active: FxHashMap>, +struct QueryStateShard { + active: FxHashMap, /// Used to generate unique ids for active jobs. jobs: u32, } -impl Default for QueryStateShard { - fn default() -> QueryStateShard { +impl Default for QueryStateShard { + fn default() -> QueryStateShard { QueryStateShard { active: Default::default(), jobs: 0 } } } -pub struct QueryState { - shards: Sharded>, +pub struct QueryState { + shards: Sharded>, } /// Indicates the state of a query for a given key in a query map. -enum QueryResult { +enum QueryResult { /// An already executing query. The query job can be used to await for its completion. - Started(QueryJob), + Started(QueryJob), /// The query panicked. Queries trying to wait on this will raise a fatal error which will /// silently panic. Poisoned, } -impl QueryState +impl QueryState where - D: Copy + Clone + Eq + Hash, K: Eq + Hash + Clone + Debug, { pub fn all_inactive(&self) -> bool { @@ -109,9 +107,9 @@ where pub fn try_collect_active_jobs( &self, tcx: CTX, - kind: D, + kind: DepKind, make_query: fn(CTX, K) -> QueryStackFrame, - jobs: &mut QueryMap, + jobs: &mut QueryMap, ) -> Option<()> { // We use try_lock_shards here since we are called from the // deadlock handler, and this shouldn't be locked. @@ -130,22 +128,21 @@ where } } -impl Default for QueryState { - fn default() -> QueryState { +impl Default for QueryState { + fn default() -> QueryState { QueryState { shards: Default::default() } } } /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -struct JobOwner<'tcx, D, K> +struct JobOwner<'tcx, K> where - D: Copy + Clone + Eq + Hash, K: Eq + Hash + Clone, { - state: &'tcx QueryState, + state: &'tcx QueryState, key: K, - id: QueryJobId, + id: QueryJobId, } #[cold] @@ -166,9 +163,8 @@ where cache.store_nocache(value) } -impl<'tcx, D, K> JobOwner<'tcx, D, K> +impl<'tcx, K> JobOwner<'tcx, K> where - D: Copy + Clone + Eq + Hash, K: Eq + Hash + Clone, { /// Either gets a `JobOwner` corresponding the query, allowing us to @@ -182,12 +178,12 @@ where #[inline(always)] fn try_start<'b, CTX>( tcx: &'b CTX, - state: &'b QueryState, + state: &'b QueryState, span: Span, key: K, lookup: QueryLookup, - dep_kind: CTX::DepKind, - ) -> TryGetJob<'b, CTX::DepKind, K> + dep_kind: DepKind, + ) -> TryGetJob<'b, K> where CTX: QueryContext, { @@ -202,7 +198,7 @@ where lock.jobs = id; let id = QueryShardJobId(NonZeroU32::new(id).unwrap()); - let job = tcx.current_query_job(); + let job = crate::tls::current_query_job(); let job = QueryJob::new(id, span, job); let key = entry.key().clone(); @@ -224,7 +220,7 @@ where // so we just return the error. return TryGetJob::Cycle(id.find_cycle_in_stack( tcx.try_collect_active_jobs().unwrap(), - &tcx.current_query_job(), + &crate::tls::current_query_job(), span, )); } @@ -242,7 +238,7 @@ where // With parallel queries we might just have to wait on some other // thread. - let result = latch.wait_on(tcx.current_query_job(), span); + let result = latch.wait_on(crate::tls::current_query_job(), span); match result { Ok(()) => TryGetJob::JobCompleted(query_blocked_prof_timer), @@ -295,9 +291,8 @@ where } } -impl<'tcx, D, K> Drop for JobOwner<'tcx, D, K> +impl<'tcx, K> Drop for JobOwner<'tcx, K> where - D: Copy + Clone + Eq + Hash, K: Eq + Hash + Clone, { #[inline(never)] @@ -329,13 +324,12 @@ pub(crate) struct CycleError { } /// The result of `try_start`. -enum TryGetJob<'tcx, D, K> +enum TryGetJob<'tcx, K> where - D: Copy + Clone + Eq + Hash, K: Eq + Hash + Clone, { /// The query is not yet started. Contains a guard to the cache eventually used to start it. - NotYetStarted(JobOwner<'tcx, D, K>), + NotYetStarted(JobOwner<'tcx, K>), /// The query was already completed. /// Returns the result of the query and its dep-node index @@ -375,12 +369,12 @@ where fn try_execute_query( tcx: CTX, - state: &QueryState, + state: &QueryState, cache: &QueryCacheStore, span: Span, key: C::Key, lookup: QueryLookup, - dep_node: Option>, + dep_node: Option, query: &QueryVtable, ) -> (C::Stored, Option) where @@ -388,14 +382,8 @@ where C::Key: Clone + DepNodeParams, CTX: QueryContext, { - match JobOwner::<'_, CTX::DepKind, C::Key>::try_start( - &tcx, - state, - span, - key.clone(), - lookup, - query.dep_kind, - ) { + match JobOwner::<'_, C::Key>::try_start(&tcx, state, span, key.clone(), lookup, query.dep_kind) + { TryGetJob::NotYetStarted(job) => { let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id); let result = job.complete(cache, result, dep_node_index); @@ -425,9 +413,9 @@ where fn execute_job( tcx: CTX, key: K, - mut dep_node_opt: Option>, + mut dep_node_opt: Option, query: &QueryVtable, - job_id: QueryJobId, + job_id: QueryJobId, ) -> (V, DepNodeIndex) where K: Clone + DepNodeParams, @@ -439,7 +427,8 @@ where // Fast path for when incr. comp. is off. if !dep_graph.is_fully_enabled() { let prof_timer = tcx.dep_context().profiler().query_provider(); - let result = tcx.start_query(job_id, None, || query.compute(*tcx.dep_context(), key)); + let result = + crate::tls::start_query(job_id, None, None, || query.compute(*tcx.dep_context(), key)); let dep_node_index = dep_graph.next_virtual_depnode_index(); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); return (result, dep_node_index); @@ -452,53 +441,31 @@ where // The diagnostics for this query will be promoted to the current session during // `try_mark_green()`, so we can ignore them here. - if let Some(ret) = tcx.start_query(job_id, None, || { + if let Some(ret) = crate::tls::start_query(job_id, None, None, || { try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query) }) { return ret; } } - let prof_timer = tcx.dep_context().profiler().query_provider(); - let diagnostics = Lock::new(ThinVec::new()); - - let (result, dep_node_index) = tcx.start_query(job_id, Some(&diagnostics), || { - if query.anon { - return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || { - query.compute(*tcx.dep_context(), key) - }); - } - + if query.anon { + dep_graph.with_anon_query(query.dep_kind, tcx, key, job_id, query.compute) + } else { // `to_dep_node` is expensive for some `DepKind`s. let dep_node = dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key)); - dep_graph.with_task(dep_node, *tcx.dep_context(), key, query.compute, query.hash_result) - }); - - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - let diagnostics = diagnostics.into_inner(); - let side_effects = QuerySideEffects { diagnostics }; - - if unlikely!(!side_effects.is_empty()) { - if query.anon { - tcx.store_side_effects_for_anon_node(dep_node_index, side_effects); - } else { - tcx.store_side_effects(dep_node_index, side_effects); - } + dep_graph.with_query(dep_node, tcx, key, job_id, query.compute, query.hash_result) } - - (result, dep_node_index) } fn try_load_from_disk_and_cache_in_memory( tcx: CTX, key: &K, - dep_node: &DepNode, + dep_node: &DepNode, query: &QueryVtable, ) -> Option<(V, DepNodeIndex)> where - K: Clone, + K: Clone + DepNodeParams, CTX: QueryContext, V: Debug, { @@ -562,7 +529,7 @@ where fn incremental_verify_ich( tcx: CTX::DepContext, result: &V, - dep_node: &DepNode, + dep_node: &DepNode, query: &QueryVtable, ) where CTX: QueryContext, @@ -629,7 +596,7 @@ fn ensure_must_run( tcx: CTX, key: &K, query: &QueryVtable, -) -> (bool, Option>) +) -> (bool, Option) where K: crate::dep_graph::DepNodeParams, CTX: QueryContext, @@ -707,7 +674,7 @@ where Some(result) } -pub fn force_query(tcx: CTX, key: Q::Key, dep_node: DepNode) +pub fn force_query(tcx: CTX, key: Q::Key, dep_node: DepNode) where Q: QueryDescription, Q::Key: DepNodeParams, diff --git a/compiler/rustc_query_system/src/tls.rs b/compiler/rustc_query_system/src/tls.rs new file mode 100644 index 0000000000000..498a87568e1e8 --- /dev/null +++ b/compiler/rustc_query_system/src/tls.rs @@ -0,0 +1,151 @@ +use crate::dep_graph::TaskDeps; +use crate::query::QueryJobId; +use rustc_data_structures::sync::{self, Lock}; +use rustc_data_structures::thin_vec::ThinVec; +use rustc_errors::Diagnostic; + +#[cfg(not(parallel_compiler))] +use std::cell::Cell; + +#[cfg(parallel_compiler)] +use rustc_rayon_core as rayon_core; + +/// This is the implicit state of rustc. It contains the current +/// query. It is updated when +/// executing a new query. +#[derive(Clone, Default)] +struct ImplicitCtxt<'a> { + /// The current query job, if any. This is updated by `JobOwner::start` in + /// `ty::query::plumbing` when executing a query. + query: Option, + + /// Where to store diagnostics for the current query job, if any. + /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. + diagnostics: Option<&'a Lock>>, + + /// The current dep graph task. This is used to add dependencies to queries + /// when executing them. + task_deps: Option<&'a Lock>, +} + +/// Sets Rayon's thread-local variable, which is preserved for Rayon jobs +/// to `value` during the call to `f`. It is restored to its previous value after. +/// This is used to set the pointer to the new `ImplicitCtxt`. +#[cfg(parallel_compiler)] +#[inline] +fn set_tlv R, R>(value: usize, f: F) -> R { + rayon_core::tlv::with(value, f) +} + +/// Gets Rayon's thread-local variable, which is preserved for Rayon jobs. +/// This is used to get the pointer to the current `ImplicitCtxt`. +#[cfg(parallel_compiler)] +#[inline] +pub fn get_tlv() -> usize { + rayon_core::tlv::get() +} + +#[cfg(not(parallel_compiler))] +thread_local! { + /// A thread local variable that stores a pointer to the current `ImplicitCtxt`. + static TLV: Cell = const { Cell::new(0) }; +} + +/// Sets TLV to `value` during the call to `f`. +/// It is restored to its previous value after. +/// This is used to set the pointer to the new `ImplicitCtxt`. +#[cfg(not(parallel_compiler))] +#[inline] +fn set_tlv R, R>(value: usize, f: F) -> R { + let old = get_tlv(); + let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old))); + TLV.with(|tlv| tlv.set(value)); + f() +} + +/// Gets the pointer to the current `ImplicitCtxt`. +#[cfg(not(parallel_compiler))] +#[inline] +fn get_tlv() -> usize { + TLV.with(|tlv| tlv.get()) +} + +/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. +#[inline] +fn enter_context<'a, F, R>(context: &ImplicitCtxt<'a>, f: F) -> R +where + F: FnOnce(&ImplicitCtxt<'a>) -> R, +{ + set_tlv(context as *const _ as usize, || f(&context)) +} + +/// Allows access to the current `ImplicitCtxt` in a closure if one is available. +#[inline] +fn with_context_opt(f: F) -> R +where + F: for<'a> FnOnce(Option<&ImplicitCtxt<'a>>) -> R, +{ + // We could get a `ImplicitCtxt` pointer from another thread. + // Ensure that `ImplicitCtxt` is `Sync`. + sync::assert_sync::>(); + + let context = get_tlv(); + let context = + if context == 0 { None } else { unsafe { Some(&*(context as *const ImplicitCtxt<'_>)) } }; + f(context) +} + +/// This is a callback from `rustc_ast` as it cannot access the implicit state +/// in `rustc_middle` otherwise. It is used to when diagnostic messages are +/// emitted and stores them in the current query, if there is one. +pub fn track_diagnostic(diagnostic: &Diagnostic) { + with_context_opt(|icx| { + if let Some(icx) = icx { + if let Some(ref diagnostics) = icx.diagnostics { + let mut diagnostics = diagnostics.lock(); + diagnostics.extend(Some(diagnostic.clone())); + } + } + }) +} + +pub fn with_deps(task_deps: Option<&Lock>, op: OP) -> R +where + OP: FnOnce() -> R, +{ + crate::tls::with_context_opt(|icx| { + let icx = crate::tls::ImplicitCtxt { task_deps, ..icx.cloned().unwrap_or_default() }; + + crate::tls::enter_context(&icx, |_| op()) + }) +} + +pub fn read_deps(op: OP) +where + OP: for<'a> FnOnce(Option<&'a Lock>), +{ + crate::tls::with_context_opt(|icx| op(icx.and_then(|icx| icx.task_deps))) +} + +/// Get the query information from the TLS context. +#[inline(always)] +pub fn current_query_job() -> Option { + with_context_opt(|icx| icx?.query) +} + +/// Executes a job by changing the `ImplicitCtxt` to point to the +/// new query job while it executes. It returns the diagnostics +/// captured during execution and the actual result. +#[inline(always)] +pub fn start_query( + token: QueryJobId, + diagnostics: Option<&Lock>>, + task_deps: Option<&Lock>, + compute: impl FnOnce() -> R, +) -> R { + // Update the `ImplicitCtxt` to point to our new query job. + let new_icx = ImplicitCtxt { query: Some(token), diagnostics, task_deps }; + + // Use the `ImplicitCtxt` while we execute the query. + enter_context(&new_icx, |_| rustc_data_structures::stack::ensure_sufficient_stack(compute)) +}