diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 363879cbb1d19..0ae3c75fcc2cb 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -111,17 +111,6 @@ cfg_if! { type Profiler = measureme::Profiler; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] -pub enum ProfileCategory { - Parsing, - Expansion, - TypeChecking, - BorrowChecking, - Codegen, - Linking, - Other, -} - bitflags::bitflags! { struct EventFilter: u32 { const GENERIC_ACTIVITIES = 1 << 0; diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index e17396422f13f..9430446c12d02 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -41,7 +41,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_middle::dep_graph::debug::{DepNodeFilter, EdgeFilter}; -use rustc_middle::dep_graph::{DepGraphQuery, DepKind, DepNode, DepNodeExt}; +use rustc_middle::dep_graph::{dep_kind, DepGraphQuery, DepNode, DepNodeExt}; use rustc_middle::hir::map::Map; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{sym, Symbol}; @@ -120,7 +120,7 @@ impl IfThisChanged<'tcx> { if self.tcx.sess.check_name(attr, sym::rustc_if_this_changed) { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { - None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner), + None => DepNode::from_def_path_hash(def_path_hash, &dep_kind::hir_owner), Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) { Ok(n) => n, Err(()) => { diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index e7c054653accb..e5da621b2908c 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -190,7 +190,11 @@ impl Parse for List { } /// A named group containing queries. +/// +/// For now, the name is not used any more, but the capability remains interesting for future +/// developments of the query system. struct Group { + #[allow(unused)] name: Ident, queries: List, } @@ -417,12 +421,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut query_stream = quote! {}; let mut query_description_stream = quote! {}; let mut dep_node_def_stream = quote! {}; - let mut dep_node_force_stream = quote! {}; - let mut try_load_from_on_disk_cache_stream = quote! {}; - let mut cached_queries = quote! {}; for group in groups.0 { - let mut group_stream = quote! {}; for mut query in group.queries.0 { let modifiers = process_modifiers(&mut query); let name = &query.name; @@ -433,28 +433,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { _ => quote! { #result_full }, }; - if modifiers.cache.is_some() { - cached_queries.extend(quote! { - #name, - }); - - try_load_from_on_disk_cache_stream.extend(quote! { - ::rustc_middle::dep_graph::DepKind::#name => { - if <#arg as DepNodeParams>>::can_reconstruct_query_key() { - debug_assert!($tcx.dep_graph - .node_color($dep_node) - .map(|c| c.is_green()) - .unwrap_or(false)); - - let key = <#arg as DepNodeParams>>::recover($tcx, $dep_node).unwrap(); - if queries::#name::cache_on_disk($tcx, &key, None) { - let _ = $tcx.#name(key); - } - } - } - }); - } - let mut attributes = Vec::new(); // Pass on the fatal_cycle modifier @@ -481,13 +459,17 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { if modifiers.eval_always { attributes.push(quote! { eval_always }); }; + // Pass on the cache modifier + if modifiers.cache.is_some() { + attributes.push(quote! { cached }); + }; let attribute_stream = quote! {#(#attributes),*}; let doc_comments = query.doc_comments.iter(); // Add the query to the group - group_stream.extend(quote! { + query_stream.extend(quote! { #(#doc_comments)* - [#attribute_stream] fn #name: #name(#arg) #result, + [#attribute_stream] fn #name(#arg) #result, }); // Create a dep node for the query @@ -495,37 +477,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] #name(#arg), }); - // Add a match arm to force the query given the dep node - dep_node_force_stream.extend(quote! { - ::rustc_middle::dep_graph::DepKind::#name => { - if <#arg as DepNodeParams>>::can_reconstruct_query_key() { - if let Some(key) = <#arg as DepNodeParams>>::recover($tcx, $dep_node) { - force_query::, _>( - $tcx, - key, - DUMMY_SP, - *$dep_node - ); - return true; - } - } - } - }); - add_query_description_impl(&query, modifiers, &mut query_description_stream); } - let name = &group.name; - query_stream.extend(quote! { - #name { #group_stream }, - }); } - dep_node_force_stream.extend(quote! { - ::rustc_middle::dep_graph::DepKind::Null => { - bug!("Cannot force dep node: {:?}", $dep_node) - } - }); - TokenStream::from(quote! { macro_rules! rustc_query_append { ([$($macro:tt)*][$($other:tt)*]) => { @@ -546,30 +501,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { ); } } - macro_rules! rustc_dep_node_force { - ([$dep_node:expr, $tcx:expr] $($other:tt)*) => { - match $dep_node.kind { - $($other)* - - #dep_node_force_stream - } - } - } - macro_rules! rustc_cached_queries { - ($($macro:tt)*) => { - $($macro)*(#cached_queries); - } - } #query_description_stream - - macro_rules! rustc_dep_node_try_load_from_on_disk_cache { - ($dep_node:expr, $tcx:expr) => { - match $dep_node.kind { - #try_load_from_on_disk_cache_stream - _ => (), - } - } - } }) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b01a55b48da66..8106da25b9856 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1598,7 +1598,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let def_path_hash = self.def_path_hash(CRATE_DEF_INDEX); let dep_node = - DepNode::from_def_path_hash(def_path_hash, dep_graph::DepKind::CrateMetadata); + DepNode::from_def_path_hash(def_path_hash, &dep_graph::dep_kind::CrateMetadata); dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node); assert!(dep_node_index != DepNodeIndex::INVALID); diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index a61b9af9bace4..495ed6482abc7 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -60,16 +60,86 @@ use crate::traits::query::{ }; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use rustc_middle::ty::query; 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::query::QueryAccessors; +use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; use rustc_span::symbol::Symbol; use std::hash::Hash; pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; +pub trait DepKindTrait: std::fmt::Debug + Sync { + fn index(&self) -> DepKindIndex; + + fn can_reconstruct_query_key(&self) -> bool; + + fn is_anon(&self) -> bool; + + fn is_eval_always(&self) -> bool; + + fn has_params(&self) -> bool; + + fn encode_query_results<'a, 'tcx>( + &self, + tcx: TyCtxt<'tcx>, + encoder: &mut query::on_disk_cache::CacheEncoder<'a, 'tcx, opaque::Encoder>, + query_result_index: &mut query::on_disk_cache::EncodedQueryResultIndex, + ); + + /// The red/green evaluation system will try to mark a specific DepNode in the + /// dependency graph as green by recursively trying to mark the dependencies of + /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` + /// where we don't know if it is red or green and we therefore actually have + /// to recompute its value in order to find out. Since the only piece of + /// information that we have at that point is the `DepNode` we are trying to + /// re-evaluate, we need some way to re-run a query from just that. This is what + /// `force_from_dep_node()` implements. + /// + /// In the general case, a `DepNode` consists of a `DepKind` and an opaque + /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint + /// is usually constructed by computing a stable hash of the query-key that the + /// `DepNode` corresponds to. Consequently, it is not in general possible to go + /// back from hash to query-key (since hash functions are not reversible). For + /// this reason `force_from_dep_node()` is expected to fail from time to time + /// because we just cannot find out, from the `DepNode` alone, what the + /// corresponding query-key is and therefore cannot re-run the query. + /// + /// The system deals with this case letting `try_mark_green` fail which forces + /// the root query to be re-evaluated. + /// + /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. + /// Fortunately, we can use some contextual information that will allow us to + /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we + /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a + /// valid `DefPathHash`. Since we also always build a huge table that maps every + /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have + /// everything we need to re-run the query. + /// + /// Take the `mir_promoted` query as an example. Like many other queries, it + /// just has a single parameter: the `DefId` of the item it will compute the + /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` + /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` + /// is actually a `DefPathHash`, and can therefore just look up the corresponding + /// `DefId` in `tcx.def_path_hash_to_def_id`. + /// + /// When you implement a new query, it will likely have a corresponding new + /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As + /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter, + /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just + /// add it to the "We don't have enough information to reconstruct..." group in + /// the match below. + fn force_from_dep_node(&self, tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool; + + fn query_stats(&self, tcx: TyCtxt<'_>) -> Option; + + fn try_load_from_on_disk_cache(&self, tcx: TyCtxt<'_>, dep_node: &DepNode); +} + // erase!() just makes tokens go away. It's used to specify which macro argument // is repeated (i.e., which sub-expression of the macro we are in) but don't need // to actually use any of the arguments. @@ -103,75 +173,190 @@ macro_rules! contains_eval_always_attr { ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); } -macro_rules! define_dep_nodes { +macro_rules! encode_query_results { + ([][$name:ident][$($args:expr),*]) => {{}}; + ([cached $($rest:tt)*][$name:ident][$($args:expr),*]) => {{ + let ret = query::on_disk_cache::encode_query_results::< + query::queries::$name<'_> + >($($args),*); + match ret { Ok(()) => (), Err(_) => () } + }}; + ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$name:ident][$($args:expr),*]) => { + encode_query_results!([$($($modifiers)*)*][$name][$($args),*]) + }; +} + +macro_rules! define_dep_kinds { (<$tcx:tt> $( [$($attrs:tt)*] - $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* + $name:ident $(( $tuple_arg_ty:ty $(,)? ))* ,)* ) => ( - #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] - #[allow(non_camel_case_types)] - pub enum DepKind { - $($variant),* - } + $(impl DepKindTrait for dep_kind::$name { + #[inline] + fn index(&self) -> DepKindIndex { + DepKindIndex::$name + } - impl DepKind { + #[inline] #[allow(unreachable_code)] - pub fn can_reconstruct_query_key<$tcx>(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - if contains_anon_attr!($($attrs)*) { - return false; - } - - // tuple args - $({ - return <$tuple_arg_ty as DepNodeParams>> - ::can_reconstruct_query_key(); - })* - - true - } - )* + #[allow(unused_lifetimes)] // inside `tuple_arg_ty` + fn can_reconstruct_query_key<$tcx>(&self) -> bool { + if contains_anon_attr!($($attrs)*) { + return false; } + + // tuple args + $({ + return <$tuple_arg_ty as DepNodeParams>> + ::can_reconstruct_query_key(); + })* + + true } - pub fn is_anon(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_anon_attr!($($attrs)*) } - )* - } + #[inline] + fn is_anon(&self) -> bool { + contains_anon_attr!($($attrs)*) } - pub fn is_eval_always(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) } - )* - } + #[inline] + fn is_eval_always(&self) -> bool { + contains_eval_always_attr!($($attrs)*) } + #[inline] #[allow(unreachable_code)] - pub fn has_params(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - // tuple args - $({ - erase!($tuple_arg_ty); - return true; - })* - - false - } - )* + fn has_params(&self) -> bool { + // tuple args + $({ + erase!($tuple_arg_ty); + return true; + })* + + false + } + + #[inline] + fn encode_query_results<'a, 'tcx>( + &self, + _tcx: TyCtxt<'tcx>, + _encoder: &mut query::on_disk_cache::CacheEncoder<'a, 'tcx, opaque::Encoder>, + _query_result_index: &mut query::on_disk_cache::EncodedQueryResultIndex, + ) { + encode_query_results!([$($attrs)*][$name][_tcx, _encoder, _query_result_index]); + } + + #[inline] + fn force_from_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool { + use rustc_query_system::query::force_query; + use rustc_middle::ty::query::queries; + #[allow(unused_parens)] + #[allow(unused_lifetimes)] + type Key<$tcx> = ($($tuple_arg_ty),*); + + // We must avoid ever having to call `force_from_dep_node()` for a + // `DepNode::codegen_unit`: + // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we + // would always end up having to evaluate the first caller of the + // `codegen_unit` query that *is* reconstructible. This might very well be + // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just + // to re-trigger calling the `codegen_unit` query with the right key. At + // that point we would already have re-done all the work we are trying to + // avoid doing in the first place. + // The solution is simple: Just explicitly call the `codegen_unit` query for + // each CGU, right after partitioning. This way `try_mark_green` will always + // hit the cache instead of having to go through `force_from_dep_node`. + // This assertion makes sure, we actually keep applying the solution above. + debug_assert!( + dep_node.kind != &dep_kind::codegen_unit, + "calling force_from_dep_node() on DepKind::codegen_unit" + ); + + if !self.can_reconstruct_query_key() { + return false; + } + + debug_assert!( as DepNodeParams>>::can_reconstruct_query_key()); + + if let Some(key) = as DepNodeParams>>::recover(tcx, dep_node) { + force_query::, _>( + tcx, + key, + rustc_span::DUMMY_SP, + *dep_node + ); + return true; + } + + false + } + + #[inline] + fn query_stats(&self, tcx: TyCtxt<'_>) -> Option { + let ret = query::stats::stats::< + query::Query<'_>, + as QueryAccessors>>::Cache, + >( + stringify!($name), + &tcx.queries.$name, + ); + Some(ret) + } + + #[inline] + fn try_load_from_on_disk_cache<'tcx>(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) { + use rustc_query_system::query::QueryDescription; + use rustc_middle::ty::query::queries; + #[allow(unused_parens)] + #[allow(unused_lifetimes)] + type Key<$tcx> = ($($tuple_arg_ty),*); + + if ! as DepNodeParams>>::can_reconstruct_query_key() { + return; + } + + debug_assert!(tcx.dep_graph + .node_color(dep_node) + .map(|c| c.is_green()) + .unwrap_or(false)); + + let key = as DepNodeParams>>::recover(tcx, dep_node).unwrap(); + if queries::$name::cache_on_disk(tcx, &key, None) { + let _ = tcx.$name(key); } } + })* + ) +} + +rustc_dep_node_append!([define_dep_kinds!][ <'tcx> ]); + +macro_rules! define_dep_nodes { + (<$tcx:tt> + $( + [$($attrs:tt)*] + $name:ident $(( $tuple_arg_ty:ty $(,)? ))* + ,)* + ) => ( + pub mod dep_kind { + $( + #[allow(non_camel_case_types)] + #[derive(Debug)] + pub struct $name; + )* } + /// This enum serves as an index into the `DEP_KINDS` array. + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] + #[allow(non_camel_case_types)] + pub enum DepKindIndex { + $($name),* + } + + crate static DEP_KINDS: &[DepKind] = &[ $(&dep_kind::$name),* ]; + pub struct DepConstructor; #[allow(non_camel_case_types)] @@ -179,105 +364,22 @@ macro_rules! define_dep_nodes { $( #[inline(always)] #[allow(unreachable_code, non_snake_case)] - pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode { + pub fn $name(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode { // tuple args $({ erase!($tuple_arg_ty); - return DepNode::construct(_tcx, DepKind::$variant, &arg) + return DepNode::construct(_tcx, &dep_kind::$name, &arg) })* - return DepNode::construct(_tcx, DepKind::$variant, &()) + return DepNode::construct(_tcx, &dep_kind::$name, &()) } )* } - pub type DepNode = rustc_query_system::dep_graph::DepNode; - - pub trait DepNodeExt: Sized { - /// Construct a DepNode from the given DepKind and DefPathHash. This - /// method will assert that the given DepKind actually requires a - /// single DefId/DefPathHash parameter. - fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; - - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option; - - /// Used in testing - fn from_label_string(label: &str, def_path_hash: DefPathHash) - -> Result; - - /// Used in testing - fn has_label_string(label: &str) -> bool; - } - - impl DepNodeExt for DepNode { - /// Construct a DepNode from the given DepKind and DefPathHash. This - /// method will assert that the given DepKind actually requires a - /// single DefId/DefPathHash parameter. - fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { - debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); - DepNode { - kind, - hash: def_path_hash.0, - } - } - - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a 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.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(self.hash); - tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() - } else { - None - } - } - - /// Used in testing - fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result { - let kind = match label { - $( - stringify!($variant) => DepKind::$variant, - )* - _ => return Err(()), - }; - - if !kind.can_reconstruct_query_key() { - return Err(()); - } - - if kind.has_params() { - Ok(DepNode::from_def_path_hash(def_path_hash, kind)) - } else { - Ok(DepNode::new_no_params(kind)) - } - } - - /// Used in testing - fn has_label_string(label: &str) -> bool { - match label { - $( - stringify!($variant) => true, - )* - _ => false, - } + fn dep_kind_from_label_string(label: &str) -> Result { + match label { + $(stringify!($name) => Ok(&dep_kind::$name),)* + _ => Err(()), } } @@ -286,7 +388,7 @@ macro_rules! define_dep_nodes { #[allow(dead_code, non_upper_case_globals)] pub mod label_strs { $( - pub const $variant: &str = stringify!($variant); + pub const $name: &str = stringify!($name); )* } ); @@ -304,6 +406,324 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [] CompileCodegenUnit(Symbol), ]); +impl DepKindTrait for dep_kind::Null { + #[inline] + fn index(&self) -> DepKindIndex { + DepKindIndex::Null + } + + #[inline] + fn can_reconstruct_query_key(&self) -> bool { + true + } + + #[inline] + fn is_anon(&self) -> bool { + false + } + + #[inline] + fn is_eval_always(&self) -> bool { + false + } + + #[inline] + fn has_params(&self) -> bool { + false + } + + #[inline] + fn encode_query_results<'a, 'tcx>( + &self, + _tcx: TyCtxt<'tcx>, + _encoder: &mut query::on_disk_cache::CacheEncoder<'a, 'tcx, opaque::Encoder>, + _query_result_index: &mut query::on_disk_cache::EncodedQueryResultIndex, + ) { + } + + #[inline] + fn force_from_dep_node(&self, _tcx: TyCtxt<'tcx>, _dep_node: &DepNode) -> bool { + // Forcing this makes no sense. + bug!("force_from_dep_node: encountered {:?}", _dep_node); + } + + #[inline] + fn query_stats(&self, _tcx: TyCtxt<'_>) -> Option { + None + } + + #[inline] + fn try_load_from_on_disk_cache<'tcx>(&self, _tcx: TyCtxt<'tcx>, _dep_node: &DepNode) {} +} + +impl DepKindTrait for dep_kind::CrateMetadata { + #[inline] + fn index(&self) -> DepKindIndex { + DepKindIndex::CrateMetadata + } + + #[inline] + fn can_reconstruct_query_key(&self) -> bool { + >>::can_reconstruct_query_key() + } + + #[inline] + fn is_anon(&self) -> bool { + false + } + + #[inline] + fn is_eval_always(&self) -> bool { + true + } + + #[inline] + fn has_params(&self) -> bool { + true + } + + #[inline] + fn encode_query_results<'a, 'tcx>( + &self, + _tcx: TyCtxt<'tcx>, + _encoder: &mut query::on_disk_cache::CacheEncoder<'a, 'tcx, opaque::Encoder>, + _query_result_index: &mut query::on_disk_cache::EncodedQueryResultIndex, + ) { + } + + #[inline] + fn force_from_dep_node(&self, _tcx: TyCtxt<'tcx>, _dep_node: &DepNode) -> bool { + // These are inputs that are expected to be pre-allocated and that + // should therefore always be red or green already. + if !self.can_reconstruct_query_key() { + return false; + } + + bug!("force_from_dep_node: encountered {:?}", _dep_node); + } + + #[inline] + fn query_stats(&self, _tcx: TyCtxt<'_>) -> Option { + None + } + + #[inline] + fn try_load_from_on_disk_cache<'tcx>(&self, _tcx: TyCtxt<'tcx>, _dep_node: &DepNode) {} +} + +impl DepKindTrait for dep_kind::TraitSelect { + #[inline] + fn index(&self) -> DepKindIndex { + DepKindIndex::TraitSelect + } + + #[inline] + fn can_reconstruct_query_key(&self) -> bool { + false + } + + #[inline] + fn is_anon(&self) -> bool { + true + } + + #[inline] + fn is_eval_always(&self) -> bool { + false + } + + #[inline] + fn has_params(&self) -> bool { + false + } + + #[inline] + fn encode_query_results<'a, 'tcx>( + &self, + _tcx: TyCtxt<'tcx>, + _encoder: &mut query::on_disk_cache::CacheEncoder<'a, 'tcx, opaque::Encoder>, + _query_result_index: &mut query::on_disk_cache::EncodedQueryResultIndex, + ) { + } + + #[inline] + fn force_from_dep_node(&self, _tcx: TyCtxt<'tcx>, _dep_node: &DepNode) -> bool { + // These are anonymous nodes. + if !self.can_reconstruct_query_key() { + return false; + } + + bug!("force_from_dep_node: encountered {:?}", _dep_node); + } + + #[inline] + fn query_stats(&self, _tcx: TyCtxt<'_>) -> Option { + None + } + + #[inline] + fn try_load_from_on_disk_cache<'tcx>(&self, _tcx: TyCtxt<'tcx>, _dep_node: &DepNode) {} +} + +impl DepKindTrait for dep_kind::CompileCodegenUnit { + #[inline] + fn index(&self) -> DepKindIndex { + DepKindIndex::CompileCodegenUnit + } + + #[inline] + fn can_reconstruct_query_key(&self) -> bool { + >>::can_reconstruct_query_key() + } + + #[inline] + fn is_anon(&self) -> bool { + false + } + + #[inline] + fn is_eval_always(&self) -> bool { + false + } + + #[inline] + #[allow(unreachable_code)] + fn has_params(&self) -> bool { + true + } + + #[inline] + fn encode_query_results<'a, 'tcx>( + &self, + _tcx: TyCtxt<'tcx>, + _encoder: &mut query::on_disk_cache::CacheEncoder<'a, 'tcx, opaque::Encoder>, + _query_result_index: &mut query::on_disk_cache::EncodedQueryResultIndex, + ) { + } + + #[inline] + fn force_from_dep_node(&self, _tcx: TyCtxt<'tcx>, _dep_node: &DepNode) -> bool { + // We don't have enough information to reconstruct the query key of these. + if !self.can_reconstruct_query_key() { + return false; + } + + bug!("force_from_dep_node: encountered {:?}", _dep_node); + } + + #[inline] + fn query_stats(&self, _tcx: TyCtxt<'_>) -> Option { + None + } + + #[inline] + fn try_load_from_on_disk_cache<'tcx>(&self, _tcx: TyCtxt<'tcx>, _dep_node: &DepNode) {} +} + +pub type DepKind = &'static dyn DepKindTrait; + +impl PartialEq for &dyn DepKindTrait { + fn eq(&self, other: &Self) -> bool { + self.index() == other.index() + } +} +impl Eq for &dyn DepKindTrait {} + +impl Hash for &dyn DepKindTrait { + fn hash(&self, hasher: &mut H) { + self.index().hash(hasher) + } +} + +impl Encodable for &dyn DepKindTrait { + fn encode(&self, enc: &mut E) -> Result<(), E::Error> { + self.index().encode(enc) + } +} + +impl Decodable for &dyn DepKindTrait { + fn decode(dec: &mut D) -> Result { + let idx = DepKindIndex::decode(dec)?; + let dk = DEP_KINDS[idx as usize]; + debug_assert!(dk.index() == idx); + Ok(dk) + } +} + +pub type DepNode = rustc_query_system::dep_graph::DepNode; + +pub trait DepNodeExt: Sized { + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option; + + /// Used in testing + fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result; + + /// Used in testing + fn has_label_string(label: &str) -> bool; +} + +impl DepNodeExt for DepNode { + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { + debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); + DepNode { kind, hash: def_path_hash.0 } + } + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a 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.can_reconstruct_query_key() { + let def_path_hash = DefPathHash(self.hash); + tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() + } else { + None + } + } + + /// Used in testing + fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result { + let kind = dep_kind_from_label_string(label)?; + + if !kind.can_reconstruct_query_key() { + Err(()) + } else if kind.has_params() { + Ok(DepNode::from_def_path_hash(def_path_hash, kind)) + } else { + Ok(DepNode::new_no_params(kind)) + } + } + + /// Used in testing + fn has_label_string(label: &str) -> bool { + dep_kind_from_label_string(label).is_ok() + } +} + impl<'tcx> DepNodeParams> for DefId { #[inline] fn can_reconstruct_query_key() -> bool { diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 6697524279874..fcb124ace01a4 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -1,5 +1,4 @@ use crate::ich::StableHashingContext; -use crate::ty::query::try_load_from_on_disk_cache; use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; @@ -9,13 +8,15 @@ use rustc_hir::def_id::LocalDefId; mod dep_node; -pub(crate) use rustc_query_system::dep_graph::DepNodeParams; pub use rustc_query_system::dep_graph::{ debug, hash_result, DepContext, DepNodeColor, DepNodeIndex, SerializedDepNodeIndex, WorkProduct, WorkProductId, }; -pub use dep_node::{label_strs, DepConstructor, DepKind, DepNode, DepNodeExt}; +crate use dep_node::DEP_KINDS; +pub use dep_node::{ + dep_kind, label_strs, DepConstructor, DepKind, DepKindIndex, DepKindTrait, DepNode, DepNodeExt, +}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph; pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; @@ -24,14 +25,14 @@ pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph; impl rustc_query_system::dep_graph::DepKind for DepKind { - const NULL: Self = DepKind::Null; + const NULL: Self = &dep_kind::Null; fn is_eval_always(&self) -> bool { - DepKind::is_eval_always(self) + DepKindTrait::is_eval_always(*self) } fn has_params(&self) -> bool { - DepKind::has_params(self) + DepKindTrait::has_params(*self) } fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -83,7 +84,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { } fn can_reconstruct_query_key(&self) -> bool { - DepKind::can_reconstruct_query_key(self) + DepKindTrait::can_reconstruct_query_key(*self) } } @@ -104,14 +105,18 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool { + let index = dep_node.kind.index(); + // FIXME: This match is just a workaround for incremental bugs and should // be removed. https://github.com/rust-lang/rust/issues/62649 is one such // bug that must be fixed before removing this. - match dep_node.kind { - DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => { + match index { + DepKindIndex::hir_owner + | DepKindIndex::hir_owner_nodes + | DepKindIndex::CrateMetadata => { if let Some(def_id) = dep_node.extract_def_id(*self) { if def_id_corresponds_to_hir_dep_node(*self, def_id.expect_local()) { - if dep_node.kind == DepKind::CrateMetadata { + if index == DepKindIndex::CrateMetadata { // The `DefPath` has corresponding node, // and that node should have been marked // either red or green in `data.colors`. @@ -147,7 +152,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); - ty::query::force_from_dep_node(*self, dep_node) + dep_node.kind.force_from_dep_node(*self, dep_node) } fn has_errors_or_delayed_span_bugs(&self) -> bool { @@ -160,7 +165,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // Interactions with on_disk_cache fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { - try_load_from_on_disk_cache(*self, dep_node) + dep_node.kind.try_load_from_on_disk_cache(*self, dep_node) } fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index aaf6a8570437c..52f25780ead07 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -50,22 +50,6 @@ impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::Predicate } } -pub trait OpaqueEncoder: Encoder { - fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder; - fn encoder_position(&self) -> usize; -} - -impl OpaqueEncoder for rustc_serialize::opaque::Encoder { - #[inline] - fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder { - self - } - #[inline] - fn encoder_position(&self) -> usize { - self.position() - } -} - pub trait TyEncoder<'tcx>: Encoder { const CLEAR_CROSS_CRATE: bool; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ab92e5b745bcd..ba3934fedae64 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -45,6 +45,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; +use rustc_serialize::opaque; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Session; @@ -1323,10 +1324,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn serialize_query_result_cache(self, encoder: &mut E) -> Result<(), E::Error> - where - E: ty::codec::OpaqueEncoder, - { + pub fn serialize_query_result_cache(self, encoder: &mut opaque::Encoder) -> Result<(), !> { self.queries.on_disk_cache.serialize(self, encoder) } diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index d3a7412ef14e7..c2420c60f34ec 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{self, DepKind, DepNode, DepNodeParams}; +use crate::dep_graph; use crate::hir::exports::Export; use crate::hir::map; use crate::infer::canonical::{self, Canonical}; @@ -34,7 +34,6 @@ use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_data_structures::profiling::ProfileCategory::*; use rustc_data_structures::stable_hasher::StableVec; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; @@ -65,7 +64,7 @@ mod plumbing; pub(crate) use rustc_query_system::query::CycleError; use rustc_query_system::query::*; -mod stats; +crate mod stats; pub use self::stats::print_stats; #[cfg(parallel_compiler)] @@ -84,7 +83,7 @@ use rustc_query_system::query::QueryAccessors; pub use rustc_query_system::query::QueryConfig; pub(crate) use rustc_query_system::query::QueryDescription; -mod on_disk_cache; +pub mod on_disk_cache; pub use self::on_disk_cache::OnDiskCache; mod profiling_support; @@ -104,93 +103,6 @@ pub use self::profiling_support::{IntoSelfProfilingString, QueryKeyStringBuilder rustc_query_append! { [define_queries!][<'tcx>] } -/// The red/green evaluation system will try to mark a specific DepNode in the -/// dependency graph as green by recursively trying to mark the dependencies of -/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` -/// where we don't know if it is red or green and we therefore actually have -/// to recompute its value in order to find out. Since the only piece of -/// information that we have at that point is the `DepNode` we are trying to -/// re-evaluate, we need some way to re-run a query from just that. This is what -/// `force_from_dep_node()` implements. -/// -/// In the general case, a `DepNode` consists of a `DepKind` and an opaque -/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint -/// is usually constructed by computing a stable hash of the query-key that the -/// `DepNode` corresponds to. Consequently, it is not in general possible to go -/// back from hash to query-key (since hash functions are not reversible). For -/// this reason `force_from_dep_node()` is expected to fail from time to time -/// because we just cannot find out, from the `DepNode` alone, what the -/// corresponding query-key is and therefore cannot re-run the query. -/// -/// The system deals with this case letting `try_mark_green` fail which forces -/// the root query to be re-evaluated. -/// -/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. -/// Fortunately, we can use some contextual information that will allow us to -/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we -/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a -/// valid `DefPathHash`. Since we also always build a huge table that maps every -/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have -/// everything we need to re-run the query. -/// -/// Take the `mir_promoted` query as an example. Like many other queries, it -/// just has a single parameter: the `DefId` of the item it will compute the -/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` -/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` -/// is actually a `DefPathHash`, and can therefore just look up the corresponding -/// `DefId` in `tcx.def_path_hash_to_def_id`. -/// -/// When you implement a new query, it will likely have a corresponding new -/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As -/// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter, -/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just -/// add it to the "We don't have enough information to reconstruct..." group in -/// the match below. -pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool { - // We must avoid ever having to call `force_from_dep_node()` for a - // `DepNode::codegen_unit`: - // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we - // would always end up having to evaluate the first caller of the - // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just - // to re-trigger calling the `codegen_unit` query with the right key. At - // that point we would already have re-done all the work we are trying to - // avoid doing in the first place. - // The solution is simple: Just explicitly call the `codegen_unit` query for - // each CGU, right after partitioning. This way `try_mark_green` will always - // hit the cache instead of having to go through `force_from_dep_node`. - // This assertion makes sure, we actually keep applying the solution above. - debug_assert!( - dep_node.kind != DepKind::codegen_unit, - "calling force_from_dep_node() on DepKind::codegen_unit" - ); - - if !dep_node.kind.can_reconstruct_query_key() { - return false; - } - - rustc_dep_node_force!([dep_node, tcx] - // These are inputs that are expected to be pre-allocated and that - // should therefore always be red or green already. - DepKind::CrateMetadata | - - // These are anonymous nodes. - DepKind::TraitSelect | - - // We don't have enough information to reconstruct the query key of - // these. - DepKind::CompileCodegenUnit => { - bug!("force_from_dep_node: encountered {:?}", dep_node) - } - ); - - false -} - -pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) { - rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx) -} - mod sealed { use super::{DefId, LocalDefId}; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 173e9a31928b5..dd654ffce36d1 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -1,7 +1,7 @@ use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use crate::mir::{self, interpret}; -use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder}; +use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use crate::ty::context::TyCtxt; use crate::ty::{self, Ty}; use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder, FingerprintEncoder}; @@ -97,7 +97,7 @@ struct Footer { expn_data: FxHashMap, } -type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; +pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; type EncodedDiagnostics = Vec; @@ -105,7 +105,7 @@ type EncodedDiagnostics = Vec; struct SourceFileIndex(u32); #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)] -struct AbsoluteBytePos(u32); +pub struct AbsoluteBytePos(u32); impl AbsoluteBytePos { fn new(pos: usize) -> AbsoluteBytePos { @@ -176,10 +176,11 @@ impl<'sess> OnDiskCache<'sess> { } } - pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(), E::Error> - where - E: OpaqueEncoder, - { + crate fn serialize<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + encoder: &mut opaque::Encoder, + ) -> Result<(), !> { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -225,22 +226,10 @@ impl<'sess> OnDiskCache<'sess> { let enc = &mut encoder; let qri = &mut query_result_index; - macro_rules! encode_queries { - ($($query:ident,)*) => { - $( - encode_query_results::, _>( - tcx, - enc, - qri - )?; - )* - } + for dk in rustc_middle::dep_graph::DEP_KINDS { + dk.encode_query_results(tcx, enc, qri) } - - rustc_cached_queries!(encode_queries!); - - Ok(()) - })?; + }); // Encode diagnostics. let diagnostics_index: EncodedDiagnosticsIndex = self @@ -348,7 +337,7 @@ impl<'sess> OnDiskCache<'sess> { } /// Loads a diagnostic emitted during the previous compilation session. - pub fn load_diagnostics( + crate fn load_diagnostics( &self, tcx: TyCtxt<'_>, dep_node_index: SerializedDepNodeIndex, @@ -364,7 +353,7 @@ impl<'sess> OnDiskCache<'sess> { /// the next compilation session. #[inline(never)] #[cold] - pub fn store_diagnostics( + crate fn store_diagnostics( &self, dep_node_index: DepNodeIndex, diagnostics: ThinVec, @@ -393,7 +382,7 @@ impl<'sess> OnDiskCache<'sess> { /// 1:1 relationship between query-key and `DepNode`. #[inline(never)] #[cold] - pub fn store_diagnostics_for_anon_node( + crate fn store_diagnostics_for_anon_node( &self, dep_node_index: DepNodeIndex, diagnostics: ThinVec, @@ -763,8 +752,25 @@ impl<'a, 'tcx> Decodable> for &'tcx [Span] { //- ENCODING ------------------------------------------------------------------- +/// This trait is a hack to work around specialization bug #55243. +pub trait OpaqueEncoder: Encoder { + fn opaque(&mut self) -> &mut opaque::Encoder; + fn encoder_position(&self) -> usize; +} + +impl OpaqueEncoder for opaque::Encoder { + #[inline] + fn opaque(&mut self) -> &mut opaque::Encoder { + self + } + #[inline] + fn encoder_position(&self) -> usize { + self.position() + } +} + /// An encoder that can write the incr. comp. cache. -struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> { +pub struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> { tcx: TyCtxt<'tcx>, encoder: &'a mut E, type_shorthands: FxHashMap, usize>, @@ -955,7 +961,7 @@ where struct IntEncodedWithFixedSize(u64); impl IntEncodedWithFixedSize { - pub const ENCODED_SIZE: usize = 8; + const ENCODED_SIZE: usize = 8; } impl Encodable for IntEncodedWithFixedSize { @@ -987,15 +993,14 @@ impl<'a> Decodable> for IntEncodedWithFixedSize { } } -fn encode_query_results<'a, 'tcx, Q, E>( +pub fn encode_query_results<'a, 'tcx, Q>( tcx: TyCtxt<'tcx>, - encoder: &mut CacheEncoder<'a, 'tcx, E>, + encoder: &mut CacheEncoder<'a, 'tcx, opaque::Encoder>, query_result_index: &mut EncodedQueryResultIndex, -) -> Result<(), E::Error> +) -> Result<(), !> where Q: super::QueryDescription> + super::QueryAccessors>, - Q::Value: Encodable>, - E: 'a + OpaqueEncoder, + Q::Value: Encodable>, { let _timer = tcx .sess diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index 1a8aacc486986..fef586b4b3f1f 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -242,25 +242,15 @@ macro_rules! hash_result { }; } -macro_rules! define_queries { - (<$tcx:tt> $($category:tt { - $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)* - },)*) => { - define_queries_inner! { <$tcx> - $($( $(#[$attr])* category<$category> [$($modifiers)*] fn $name: $node($($K)*) -> $V,)*)* - } - } -} - macro_rules! query_helper_param_ty { (DefId) => { impl IntoQueryParam }; ($K:ty) => { $K }; } -macro_rules! define_queries_inner { +macro_rules! define_queries { (<$tcx:tt> - $($(#[$attr:meta])* category<$category:tt> - [$($modifiers:tt)*] fn $name:ident: $node:ident($($K:tt)*) -> $V:ty,)*) => { + $($(#[$attr:meta])* + [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { use std::mem; use crate::{ @@ -268,7 +258,6 @@ macro_rules! define_queries_inner { rustc_data_structures::stable_hasher::StableHasher, ich::StableHashingContext }; - use rustc_data_structures::profiling::ProfileCategory; define_queries_struct! { tcx: $tcx, @@ -362,13 +351,12 @@ macro_rules! define_queries_inner { as QueryStorage >::Stored; const NAME: &'static str = stringify!($name); - const CATEGORY: ProfileCategory = $category; } impl<$tcx> QueryAccessors> for queries::$name<$tcx> { const ANON: bool = is_anon!([$($modifiers)*]); const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]); - const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$node; + const DEP_KIND: dep_graph::DepKind = &dep_graph::dep_kind::$name; type Cache = query_storage!([$($modifiers)*][$($K)*, $V]); @@ -527,7 +515,7 @@ macro_rules! define_queries_struct { providers: IndexVec, fallback_extern_providers: Box, - $($(#[$attr])* $name: QueryState< + $($(#[$attr])* pub(crate) $name: QueryState< crate::dep_graph::DepKind, as QueryContext>::Query, as QueryAccessors>>::Cache, diff --git a/compiler/rustc_middle/src/ty/query/stats.rs b/compiler/rustc_middle/src/ty/query/stats.rs index 877f88d380a39..430175efab6a7 100644 --- a/compiler/rustc_middle/src/ty/query/stats.rs +++ b/compiler/rustc_middle/src/ty/query/stats.rs @@ -1,10 +1,9 @@ -use crate::ty::query::queries; +use crate::dep_graph::{self, DepKind}; use crate::ty::TyCtxt; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_query_system::query::{QueryAccessors, QueryCache, QueryContext, QueryState}; +use rustc_query_system::query::{QueryCache, QueryState}; use std::any::type_name; -use std::hash::Hash; use std::mem; #[cfg(debug_assertions)] use std::sync::atomic::Ordering; @@ -26,7 +25,7 @@ impl KeyStats for DefId { } #[derive(Clone)] -struct QueryStats { +pub struct QueryStats { name: &'static str, cache_hits: usize, key_size: usize, @@ -37,9 +36,8 @@ struct QueryStats { local_def_id_keys: Option, } -fn stats(name: &'static str, map: &QueryState) -> QueryStats +crate fn stats(name: &'static str, map: &QueryState) -> QueryStats where - D: Copy + Clone + Eq + Hash, Q: Clone, C: QueryCache, { @@ -65,7 +63,15 @@ where } pub fn print_stats(tcx: TyCtxt<'_>) { - let queries = query_stats(tcx); + let mut queries = Vec::new(); + + for dk in dep_graph::DEP_KINDS { + if let Some(fragment) = dk.query_stats(tcx) { + queries.push(fragment) + } + } + + let queries = queries; if cfg!(debug_assertions) { let hits: usize = queries.iter().map(|s| s.cache_hits).sum(); @@ -118,28 +124,3 @@ pub fn print_stats(tcx: TyCtxt<'_>) { println!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total); } } - -macro_rules! print_stats { - (<$tcx:tt> $($category:tt { - $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)* - },)*) => { - fn query_stats(tcx: TyCtxt<'_>) -> Vec { - let mut queries = Vec::new(); - - $($( - queries.push(stats::< - crate::dep_graph::DepKind, - as QueryContext>::Query, - as QueryAccessors>>::Cache, - >( - stringify!($name), - &tcx.queries.$name, - )); - )*)* - - queries - } - } -} - -rustc_query_append! { [print_stats!][<'tcx>] } diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index e8d02692f37ba..c6bd4eee3df23 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -59,7 +59,7 @@ pub trait DepContext: Copy { } /// Describe the different families of dependency nodes. -pub trait DepKind: Copy + fmt::Debug + Eq + Ord + Hash { +pub trait DepKind: Copy + fmt::Debug + Eq + Hash { const NULL: Self; /// Return whether this kind always require evaluation. diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index 6c9849e8708b7..0f0684b354791 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -5,7 +5,6 @@ use crate::dep_graph::SerializedDepNodeIndex; use crate::query::caches::QueryCache; use crate::query::plumbing::CycleError; use crate::query::{QueryContext, QueryState}; -use rustc_data_structures::profiling::ProfileCategory; use rustc_data_structures::fingerprint::Fingerprint; use std::borrow::Cow; @@ -14,7 +13,6 @@ use std::hash::Hash; pub trait QueryConfig { const NAME: &'static str; - const CATEGORY: ProfileCategory; type Key: Eq + Hash + Clone + Debug; type Value; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b838602e76ca3..635370fd4c0aa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -31,7 +31,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; +use rustc_middle::dep_graph::{dep_kind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fast_reject; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -972,7 +972,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { OP: FnOnce(&mut Self) -> R, { let (result, dep_node) = - self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self)); + self.tcx().dep_graph.with_anon_task(&dep_kind::TraitSelect, || op(self)); self.tcx().dep_graph.read_index(dep_node); (result, dep_node) }