diff options
Diffstat (limited to 'compiler/rustc_query_impl/src')
| -rw-r--r-- | compiler/rustc_query_impl/src/lib.rs | 24 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/on_disk_cache.rs | 25 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/plumbing.rs | 290 | ||||
| -rw-r--r-- | compiler/rustc_query_impl/src/stats.rs | 27 |
4 files changed, 134 insertions, 232 deletions
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index e50a8c191ad..9cd36a77b70 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -8,28 +8,25 @@ #![feature(once_cell)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_macros; #[macro_use] extern crate rustc_middle; -#[macro_use] -extern crate tracing; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::DiagnosticBuilder; -use rustc_middle::dep_graph; +use rustc_middle::arena::Arena; +use rustc_middle::dep_graph::{self, DepKindStruct, SerializedDepNodeIndex}; use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values}; -use rustc_middle::ty::query::{Providers, QueryEngine}; +use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_query_system::ich::StableHashingContext; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; #[macro_use] mod plumbing; pub use plumbing::QueryCtxt; -use plumbing::QueryStruct; use rustc_query_system::query::*; mod stats; @@ -41,9 +38,8 @@ use keys::Key; mod values; use self::values::Value; -use rustc_query_system::query::QueryAccessors; pub use rustc_query_system::query::QueryConfig; -pub(crate) use rustc_query_system::query::QueryDescription; +pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable}; mod on_disk_cache; pub use on_disk_cache::OnDiskCache; @@ -53,6 +49,14 @@ pub use self::profiling_support::alloc_self_profile_query_strings; mod util; +fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { + if def_id.is_top_level_module() { + "top-level module".to_string() + } else { + format!("module `{}`", tcx.def_path_str(def_id.to_def_id())) + } +} + rustc_query_append! { [define_queries!][<'tcx>] } impl<'tcx> Queries<'tcx> { diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 48eb488792d..552906aac31 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -219,7 +219,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { // Do this *before* we clone 'latest_foreign_def_path_hashes', since // loading existing queries may cause us to create new DepNodes, which // may in turn end up invoking `store_foreign_def_id_hash` - tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); + tcx.dep_graph.exec_cache_promotions(tcx); *self.serialized_data.write() = None; } @@ -358,23 +358,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { Ok(()) }) } - - fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> DefId { - debug!("def_path_hash_to_def_id({:?})", hash); - - let stable_crate_id = hash.stable_crate_id(); - - // If this is a DefPathHash from the local crate, we can look up the - // DefId in the tcx's `Definitions`. - if stable_crate_id == tcx.sess.local_stable_crate_id() { - tcx.definitions_untracked().local_def_path_hash_to_def_id(hash).to_def_id() - } else { - // If this is a DefPathHash from an upstream crate, let the CrateStore map - // it to a DefId. - let cnum = tcx.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id); - tcx.cstore_untracked().def_path_hash_to_def_id(cnum, hash) - } - } } impl<'sess> OnDiskCache<'sess> { @@ -764,7 +747,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId { // If we get to this point, then all of the query inputs were green, // which means that the definition with this hash is guaranteed to // still exist in the current compilation session. - Ok(d.tcx().on_disk_cache.as_ref().unwrap().def_path_hash_to_def_id(d.tcx(), def_path_hash)) + Ok(d.tcx().def_path_hash_to_def_id(def_path_hash)) } } @@ -1035,7 +1018,7 @@ pub fn encode_query_results<'a, 'tcx, CTX, Q>( ) -> FileEncodeResult where CTX: QueryContext + 'tcx, - Q: super::QueryDescription<CTX> + super::QueryAccessors<CTX>, + Q: super::QueryDescription<CTX>, Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>, { let _timer = tcx @@ -1050,7 +1033,7 @@ where if res.is_err() { return; } - if Q::cache_on_disk(tcx, &key, Some(value)) { + if Q::cache_on_disk(*tcx.dep_context(), &key) { let dep_node = SerializedDepNodeIndex::new(dep_node.index()); // Record position of the cache entry. diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 4d1e39db0ed..81a36e0d59e 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -2,20 +2,17 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::{on_disk_cache, queries, Queries}; -use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use crate::{on_disk_cache, Queries}; +use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::ty::tls::{self, ImplicitCtxt}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::HasDepContext; -use rustc_query_system::query::{ - QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects, -}; +use rustc_query_system::query::{QueryContext, QueryJobId, QueryMap, QuerySideEffects}; use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{Diagnostic, Handler}; use rustc_serialize::opaque; -use rustc_span::def_id::LocalDefId; use std::any::Any; @@ -53,36 +50,6 @@ impl QueryContext for QueryCtxt<'tcx> { self.queries.try_collect_active_jobs(**self) } - fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { - let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize]; - (cb.try_load_from_on_disk_cache)(*self, dep_node) - } - - fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool { - debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); - - // 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" - ); - - let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize]; - (cb.force_from_dep_node)(*self, dep_node) - } - // Interactions with on_disk_cache fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects { self.queries @@ -193,60 +160,6 @@ impl<'tcx> QueryCtxt<'tcx> { } } -/// This struct stores metadata about each Query. -/// -/// Information is retrieved by indexing the `QUERIES` array using the integer value -/// of the `DepKind`. Overall, this allows to implement `QueryContext` using this manual -/// jump table instead of large matches. -pub struct QueryStruct { - /// 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(crate) force_from_dep_node: fn(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool, - - /// Invoke a query to put the on-disk cached value in memory. - pub(crate) try_load_from_on_disk_cache: fn(QueryCtxt<'_>, &DepNode), -} - macro_rules! handle_cycle_error { ([][$tcx: expr, $error:expr]) => {{ $error.emit(); @@ -291,14 +204,30 @@ macro_rules! is_eval_always { } macro_rules! hash_result { - ([][$hcx:expr, $result:expr]) => {{ - dep_graph::hash_result($hcx, &$result) + ([]) => {{ + Some(dep_graph::hash_result) }}; - ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{ + ([(no_hash) $($rest:tt)*]) => {{ None }}; + ([$other:tt $($modifiers:tt)*]) => { + hash_result!([$($modifiers)*]) + }; +} + +macro_rules! get_provider { + ([][$tcx:expr, $name:ident, $key:expr]) => {{ + $tcx.queries.local_providers.$name + }}; + ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{ + if $key.query_crate_is_local() { + $tcx.queries.local_providers.$name + } else { + $tcx.queries.extern_providers.$name + } + }}; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - hash_result!([$($modifiers)*][$($args)*]) + get_provider!([$($modifiers)*][$($args)*]) }; } @@ -374,10 +303,8 @@ macro_rules! define_queries { const NAME: &'static str = stringify!($name); } - impl<$tcx> QueryAccessors<QueryCtxt<$tcx>> 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::$name; + impl<$tcx> QueryDescription<QueryCtxt<$tcx>> for queries::$name<$tcx> { + rustc_query_description! { $name<$tcx> } type Cache = query_storage::$name<$tcx>; @@ -396,32 +323,25 @@ macro_rules! define_queries { } #[inline] - fn compute_fn(tcx: QueryCtxt<'tcx>, key: &Self::Key) -> - fn(TyCtxt<'tcx>, Self::Key) -> Self::Value + fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) -> + QueryVtable<QueryCtxt<$tcx>, Self::Key, Self::Value> { - if key.query_crate_is_local() { - tcx.queries.local_providers.$name - } else { - tcx.queries.extern_providers.$name + let compute = get_provider!([$($modifiers)*][tcx, $name, key]); + let cache_on_disk = Self::cache_on_disk(tcx.tcx, key); + QueryVtable { + anon: is_anon!([$($modifiers)*]), + eval_always: is_eval_always!([$($modifiers)*]), + dep_kind: dep_graph::DepKind::$name, + hash_result: hash_result!([$($modifiers)*]), + handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]), + compute, + cache_on_disk, + try_load_from_disk: Self::TRY_LOAD_FROM_DISK, } } - - fn hash_result( - _hcx: &mut StableHashingContext<'_>, - _result: &Self::Value - ) -> Option<Fingerprint> { - hash_result!([$($modifiers)*][_hcx, _result]) - } - - fn handle_cycle_error( - tcx: QueryCtxt<'tcx>, - mut error: DiagnosticBuilder<'_>, - ) -> Self::Value { - handle_cycle_error!([$($modifiers)*][tcx, error]) - } })* - #[allow(non_upper_case_globals)] + #[allow(nonstandard_style)] pub mod query_callbacks { use super::*; use rustc_middle::dep_graph::DepNode; @@ -431,68 +351,100 @@ macro_rules! define_queries { use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. - pub const Null: QueryStruct = QueryStruct { - force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node), - try_load_from_on_disk_cache: |_, _| {}, - }; + pub fn Null() -> DepKindStruct { + DepKindStruct { + is_anon: false, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Unit, + force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), + try_load_from_on_disk_cache: None, + } + } - pub const TraitSelect: QueryStruct = QueryStruct { - force_from_dep_node: |_, _| false, - try_load_from_on_disk_cache: |_, _| {}, - }; + pub fn TraitSelect() -> DepKindStruct { + DepKindStruct { + is_anon: true, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Unit, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + } + } - pub const CompileCodegenUnit: QueryStruct = QueryStruct { - force_from_dep_node: |_, _| false, - try_load_from_on_disk_cache: |_, _| {}, - }; + pub fn CompileCodegenUnit() -> DepKindStruct { + DepKindStruct { + is_anon: false, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Opaque, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + } + } - pub const CompileMonoItem: QueryStruct = QueryStruct { - force_from_dep_node: |_, _| false, - try_load_from_on_disk_cache: |_, _| {}, - }; + pub fn CompileMonoItem() -> DepKindStruct { + DepKindStruct { + is_anon: false, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Opaque, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + } + } - $(pub const $name: QueryStruct = { - const is_anon: bool = is_anon!([$($modifiers)*]); + $(pub fn $name()-> DepKindStruct { + let is_anon = is_anon!([$($modifiers)*]); + let is_eval_always = is_eval_always!([$($modifiers)*]); - #[inline(always)] - fn fingerprint_style() -> FingerprintStyle { - <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>> - ::fingerprint_style() - } + let fingerprint_style = + <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::fingerprint_style(); - fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> { - <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node) + if is_anon || !fingerprint_style.reconstructible() { + return DepKindStruct { + is_anon, + is_eval_always, + fingerprint_style, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + } } - fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool { - force_query::<queries::$name<'_>, _>(tcx, dep_node) + #[inline(always)] + fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<query_keys::$name<'tcx>> { + <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node) } - fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) { - if is_anon { - return - } - - if !fingerprint_style().reconstructible() { - return + fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool { + if let Some(key) = recover(tcx, dep_node) { + let tcx = QueryCtxt::from_tcx(tcx); + force_query::<queries::$name<'_>, _>(tcx, key, dep_node); + true + } else { + false } + } - debug_assert!(tcx.dep_graph.is_green(dep_node)); + fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) { + debug_assert!(tcx.dep_graph.is_green(&dep_node)); - let key = recover(*tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); - if queries::$name::cache_on_disk(tcx, &key, None) { + let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); + if queries::$name::cache_on_disk(tcx, &key) { let _ = tcx.$name(key); } } - QueryStruct { - force_from_dep_node, - try_load_from_on_disk_cache, + DepKindStruct { + is_anon, + is_eval_always, + fingerprint_style, + force_from_dep_node: Some(force_from_dep_node), + try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache), } - };)* + })* } - static QUERY_CALLBACKS: &[QueryStruct] = &make_dep_kind_array!(query_callbacks); + pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] { + arena.alloc_from_iter(make_dep_kind_array!(query_callbacks)) + } } } @@ -504,7 +456,7 @@ macro_rules! define_queries_struct { input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Queries<$tcx> { local_providers: Box<Providers>, - extern_providers: Box<Providers>, + extern_providers: Box<ExternProviders>, pub on_disk_cache: Option<OnDiskCache<$tcx>>, @@ -517,7 +469,7 @@ macro_rules! define_queries_struct { impl<$tcx> Queries<$tcx> { pub fn new( local_providers: Providers, - extern_providers: Providers, + extern_providers: ExternProviders, on_disk_cache: Option<OnDiskCache<$tcx>>, ) -> Self { Queries { @@ -575,13 +527,3 @@ macro_rules! define_queries_struct { } }; } - -fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { - if def_id.is_top_level_module() { - "top-level module".to_string() - } else { - format!("module `{}`", tcx.def_path_str(def_id.to_def_id())) - } -} - -rustc_query_description! {} diff --git a/compiler/rustc_query_impl/src/stats.rs b/compiler/rustc_query_impl/src/stats.rs index fa48df3ed45..c3bbd51f3d3 100644 --- a/compiler/rustc_query_impl/src/stats.rs +++ b/compiler/rustc_query_impl/src/stats.rs @@ -5,8 +5,6 @@ use rustc_query_system::query::{QueryCache, QueryCacheStore}; use std::any::type_name; use std::mem; -#[cfg(debug_assertions)] -use std::sync::atomic::Ordering; trait KeyStats { fn key_stats(&self, stats: &mut QueryStats); @@ -27,7 +25,6 @@ impl KeyStats for DefId { #[derive(Clone)] struct QueryStats { name: &'static str, - cache_hits: usize, key_size: usize, key_type: &'static str, value_size: usize, @@ -42,10 +39,6 @@ where { let mut stats = QueryStats { name, - #[cfg(debug_assertions)] - cache_hits: map.cache_hits.load(Ordering::Relaxed), - #[cfg(not(debug_assertions))] - cache_hits: 0, key_size: mem::size_of::<C::Key>(), key_type: type_name::<C::Key>(), value_size: mem::size_of::<C::Value>(), @@ -63,12 +56,6 @@ where pub fn print_stats(tcx: TyCtxt<'_>) { let queries = query_stats(tcx); - if cfg!(debug_assertions) { - let hits: usize = queries.iter().map(|s| s.cache_hits).sum(); - let results: usize = queries.iter().map(|s| s.entry_count).sum(); - eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64); - } - let mut query_key_sizes = queries.clone(); query_key_sizes.sort_by_key(|q| q.key_size); eprintln!("\nLarge query keys:"); @@ -83,20 +70,6 @@ pub fn print_stats(tcx: TyCtxt<'_>) { eprintln!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type); } - if cfg!(debug_assertions) { - let mut query_cache_hits = queries.clone(); - query_cache_hits.sort_by_key(|q| q.cache_hits); - eprintln!("\nQuery cache hits:"); - for q in query_cache_hits.iter().rev() { - eprintln!( - " {} - {} ({}%)", - q.name, - q.cache_hits, - q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64 - ); - } - } - let mut query_value_count = queries.clone(); query_value_count.sort_by_key(|q| q.entry_count); eprintln!("\nQuery value count:"); |
