From 81241cbf3ae39db6188b7965b34e444f48e7ebbd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 28 Jun 2021 21:12:01 +0200 Subject: [PATCH 1/2] Move OnDiskCache to rustc_query_impl. --- Cargo.lock | 4 + .../rustc_incremental/src/persist/load.rs | 10 +- compiler/rustc_interface/src/interface.rs | 3 +- compiler/rustc_interface/src/passes.rs | 8 +- compiler/rustc_macros/src/query.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 60 ++++- compiler/rustc_middle/src/ty/mod.rs | 2 +- .../src/ty/{query/mod.rs => query.rs} | 25 +-- compiler/rustc_query_impl/Cargo.toml | 6 +- compiler/rustc_query_impl/src/lib.rs | 10 +- .../src}/on_disk_cache.rs | 210 ++++++++---------- compiler/rustc_query_impl/src/plumbing.rs | 76 ++++--- 14 files changed, 226 insertions(+), 197 deletions(-) rename compiler/rustc_middle/src/ty/{query/mod.rs => query.rs} (93%) rename compiler/{rustc_middle/src/ty/query => rustc_query_impl/src}/on_disk_cache.rs (95%) diff --git a/Cargo.lock b/Cargo.lock index b261a00f4f3ab..753853e6acde4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4242,12 +4242,16 @@ version = "0.0.0" dependencies = [ "measureme", "rustc-rayon-core", + "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_index", + "rustc_macros", "rustc_middle", "rustc_query_system", "rustc_serialize", + "rustc_session", "rustc_span", "tracing", ] diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index ee62089b23760..437d5596447d7 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; -use rustc_middle::ty::query::OnDiskCache; +use rustc_middle::ty::OnDiskCache; use rustc_serialize::opaque::Decoder; use rustc_serialize::Decodable; use rustc_session::Session; @@ -198,7 +198,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { /// If we are not in incremental compilation mode, returns `None`. /// Otherwise, tries to load the query result cache from disk, /// creating an empty cache if it could not be loaded. -pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option> { +pub fn load_query_result_cache<'a, C: OnDiskCache<'a>>(sess: &'a Session) -> Option { if sess.opts.incremental.is_none() { return None; } @@ -210,9 +210,7 @@ pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option> &query_cache_path(sess), sess.is_nightly_build(), ) { - LoadResult::Ok { data: (bytes, start_pos) } => { - Some(OnDiskCache::new(sess, bytes, start_pos)) - } - _ => Some(OnDiskCache::new_empty(sess.source_map())), + LoadResult::Ok { data: (bytes, start_pos) } => Some(C::new(sess, bytes, start_pos)), + _ => Some(C::new_empty(sess.source_map())), } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 086c49c73972f..8393826aa1285 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -12,6 +12,7 @@ use rustc_errors::{ErrorReported, Handler}; use rustc_lint::LintStore; use rustc_middle::ty; use rustc_parse::new_parser_from_source_str; +use rustc_query_impl::QueryCtxt; use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; use rustc_session::early_error; use rustc_session::lint; @@ -233,7 +234,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 { - icx.tcx.queries.try_print_query_stack(icx.tcx, icx.query, handler, num_frames) + QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames) } else { 0 } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 958a4ab68020a..5db027fb5b473 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -26,7 +26,7 @@ use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; -use rustc_query_impl::Queries as TcxQueries; +use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_serialize::json; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; @@ -819,7 +819,9 @@ pub fn create_global_ctxt<'tcx>( callback(sess, &mut local_providers, &mut extern_providers); } - let queries = queries.get_or_init(|| TcxQueries::new(local_providers, extern_providers)); + let queries = queries.get_or_init(|| { + TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache) + }); let gcx = sess.time("setup_global_ctxt", || { global_ctxt.get_or_init(move || { @@ -830,7 +832,7 @@ pub fn create_global_ctxt<'tcx>( resolver_outputs, krate, dep_graph, - query_result_on_disk_cache, + queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), queries.as_dyn(), &crate_name, outputs, diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 291e7ef045e4f..dcd36d61bc6a0 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -367,7 +367,7 @@ fn add_query_description_impl( tcx: QueryCtxt<'tcx>, id: SerializedDepNodeIndex ) -> Option { - tcx.on_disk_cache.as_ref()?.try_load_query_result(*tcx, id) + tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id) } } }; diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 70b3efa1d1690..5373169bda7ab 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -131,7 +131,10 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { impl CStore { pub fn from_tcx(tcx: TyCtxt<'_>) -> &CStore { - tcx.cstore_as_any().downcast_ref::().expect("`tcx.cstore` is not a `CStore`") + tcx.cstore_untracked() + .as_any() + .downcast_ref::() + .expect("`tcx.cstore` is not a `CStore`") } fn alloc_new_crate_num(&mut self) -> CrateNum { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1651853a55205..cb99ae19ee72e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -724,7 +724,7 @@ rustc_queries! { cache_on_disk_if { true } load_cached(tcx, id) { let typeck_results: Option> = tcx - .on_disk_cache.as_ref() + .on_disk_cache().as_ref() .and_then(|c| c.try_load_query_result(*tcx, id)); typeck_results.map(|x| &*tcx.arena.alloc(x)) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f52686c9b5f2e..47cc328f6c8bb 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,7 +1,7 @@ //! Type context book-keeping. use crate::arena::Arena; -use crate::dep_graph::DepGraph; +use crate::dep_graph::{DepGraph, DepNode}; use crate::hir::place::Place as HirPlace; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; @@ -14,7 +14,7 @@ use crate::mir::interpret::{self, AllocId, Allocation, ConstValue, Scalar}; use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::thir::Thir; use crate::traits; -use crate::ty::query::{self, OnDiskCache, TyCtxtAt}; +use crate::ty::query::{self, TyCtxtAt}; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; use crate::ty::TyKind::*; use crate::ty::{ @@ -52,8 +52,8 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Limit; use rustc_session::Session; -use rustc_span::def_id::StableCrateId; -use rustc_span::source_map::MultiSpan; +use rustc_span::def_id::{DefPathHash, StableCrateId}; +use rustc_span::source_map::{MultiSpan, SourceMap}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; @@ -71,6 +71,40 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; +pub trait OnDiskCache<'tcx> { + /// Creates a new `OnDiskCache` instance from the serialized data in `data`. + fn new(sess: &'tcx Session, data: Vec, start_pos: usize) -> Self + where + Self: Sized; + + fn new_empty(source_map: &'tcx SourceMap) -> Self + where + Self: Sized; + + /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation + /// session, if it still exists. This is used during incremental compilation to + /// turn a deserialized `DefPathHash` into its current `DefId`. + fn def_path_hash_to_def_id( + &self, + tcx: TyCtxt<'tcx>, + def_path_hash: DefPathHash, + ) -> Option; + + /// If the given `dep_node`'s hash still exists in the current compilation, + /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. + /// + /// Normally, `store_foreign_def_id_hash` can be called directly by + /// the dependency graph when we construct a `DepNode`. However, + /// when we re-use a deserialized `DepNode` from the previous compilation + /// session, we only have the `DefPathHash` available. This method is used + /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written + /// out for usage in the next compilation session. + fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode); + fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash); + + fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult; +} + /// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s /// except through the error-reporting functions on a [`tcx`][TyCtxt]. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] @@ -993,7 +1027,7 @@ pub struct GlobalCtxt<'tcx> { /// Do not access this directly. It is only meant to be used by /// `DepGraph::try_mark_green()` and the query infrastructure. /// This is `None` if we are not incremental compilation mode - pub on_disk_cache: Option>, + pub on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, pub queries: &'tcx dyn query::QueryEngine<'tcx>, pub query_caches: query::QueryCaches<'tcx>, @@ -1141,7 +1175,7 @@ impl<'tcx> TyCtxt<'tcx> { resolutions: ty::ResolverOutputs, krate: &'tcx hir::Crate<'tcx>, dep_graph: DepGraph, - on_disk_cache: Option>, + on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, crate_name: &str, output_filenames: OutputFilenames, @@ -1308,10 +1342,16 @@ impl<'tcx> TyCtxt<'tcx> { self.untracked_resolutions.cstore.encode_metadata(self) } - // Note that this is *untracked* and should only be used within the query - // system if the result is otherwise tracked through queries - pub fn cstore_as_any(self) -> &'tcx dyn Any { - self.untracked_resolutions.cstore.as_any() + /// Note that this is *untracked* and should only be used within the query + /// system if the result is otherwise tracked through queries + pub fn cstore_untracked(self) -> &'tcx ty::CrateStoreDyn { + &*self.untracked_resolutions.cstore + } + + /// Note that this is *untracked* and should only be used within the query + /// system if the result is otherwise tracked through queries + pub fn definitions_untracked(self) -> &'tcx hir::definitions::Definitions { + &self.untracked_resolutions.definitions } #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bfc942e6f10ff..a6aff42479069 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -59,7 +59,7 @@ pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Uneval pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt, - Lift, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, + Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, }; pub use self::instance::{Instance, InstanceDef}; pub use self::list::List; diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query.rs similarity index 93% rename from compiler/rustc_middle/src/ty/query/mod.rs rename to compiler/rustc_middle/src/ty/query.rs index 2ed9ede8951c9..38ed82933fe94 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -38,14 +38,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; -use rustc_errors::{ErrorReported, Handler}; +use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; -use rustc_serialize::opaque; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::utils::NativeLibKind; use rustc_session::Limits; @@ -63,9 +62,6 @@ use std::sync::Arc; pub(crate) use rustc_query_system::query::QueryJobId; use rustc_query_system::query::*; -pub mod on_disk_cache; -pub use self::on_disk_cache::OnDiskCache; - #[derive(Copy, Clone)] pub struct TyCtxtAt<'tcx> { pub tcx: TyCtxt<'tcx>, @@ -235,28 +231,13 @@ macro_rules! define_callbacks { } pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync { + fn as_any(&'tcx self) -> &'tcx dyn std::any::Any; + #[cfg(parallel_compiler)] unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry); - fn encode_query_results( - &'tcx self, - tcx: TyCtxt<'tcx>, - encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, - query_result_index: &mut on_disk_cache::EncodedQueryResultIndex, - ) -> opaque::FileEncodeResult; - - fn exec_cache_promotions(&'tcx self, tcx: TyCtxt<'tcx>); - fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool; - fn try_print_query_stack( - &'tcx self, - tcx: TyCtxt<'tcx>, - query: Option>, - handler: &Handler, - num_frames: Option, - ) -> usize; - $($(#[$attr])* fn $name( &'tcx self, diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 5be06dfdc7797..6a1768b92dbbb 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -11,10 +11,14 @@ doctest = false measureme = "9.0.0" rustc-rayon-core = "0.3.1" tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_query_system = { path = "../rustc_query_system" } -rustc_span = { path = "../rustc_span" } rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 1d831affd1dee..5022bf265328a 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -1,12 +1,16 @@ //! Support for serializing the dep-graph and reloading it. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(min_specialization)] +#![feature(once_cell)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#[macro_use] +extern crate rustc_macros; #[macro_use] extern crate rustc_middle; #[macro_use] @@ -14,13 +18,12 @@ extern crate tracing; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::{DiagnosticBuilder, Handler}; +use rustc_errors::DiagnosticBuilder; use rustc_middle::dep_graph; use rustc_middle::ich::StableHashingContext; use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values}; use rustc_middle::ty::query::{Providers, QueryEngine}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_serialize::opaque; use rustc_span::Span; #[macro_use] @@ -42,7 +45,8 @@ use rustc_query_system::query::QueryAccessors; pub use rustc_query_system::query::QueryConfig; pub(crate) use rustc_query_system::query::QueryDescription; -use rustc_middle::ty::query::on_disk_cache; +mod on_disk_cache; +pub use on_disk_cache::OnDiskCache; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs similarity index 95% rename from compiler/rustc_middle/src/ty/query/on_disk_cache.rs rename to compiler/rustc_query_impl/src/on_disk_cache.rs index 0ac80ebd6367b..b024668d63646 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -1,9 +1,4 @@ -use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; -use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use crate::mir::{self, interpret}; -use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; -use crate::ty::context::TyCtxt; -use crate::ty::{self, Ty}; +use crate::QueryCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; use rustc_data_structures::thin_vec::ThinVec; @@ -12,6 +7,11 @@ use rustc_errors::Diagnostic; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; +use rustc_middle::mir::{self, interpret}; +use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; use rustc_query_system::query::QueryContext; use rustc_serialize::{ @@ -185,9 +185,8 @@ impl EncodedSourceFileId { } } -impl<'sess> OnDiskCache<'sess> { - /// Creates a new `OnDiskCache` instance from the serialized data in `data`. - pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { +impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { + fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> Self { debug_assert!(sess.opts.incremental.is_some()); // Wrap in a scope so we can borrow `data`. @@ -228,7 +227,7 @@ impl<'sess> OnDiskCache<'sess> { } } - pub fn new_empty(source_map: &'sess SourceMap) -> Self { + fn new_empty(source_map: &'sess SourceMap) -> Self { Self { serialized_data: Vec::new(), file_index_to_stable_id: Default::default(), @@ -249,11 +248,7 @@ impl<'sess> OnDiskCache<'sess> { } } - pub fn serialize<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - encoder: &mut FileEncoder, - ) -> FileEncodeResult { + fn serialize(&self, tcx: TyCtxt<'sess>, encoder: &mut FileEncoder) -> FileEncodeResult { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -288,7 +283,7 @@ impl<'sess> 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.queries.exec_cache_promotions(tcx); + tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx)); let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone(); let hygiene_encode_context = HygieneEncodeContext::default(); @@ -311,7 +306,7 @@ impl<'sess> OnDiskCache<'sess> { tcx.sess.time("encode_query_results", || -> FileEncodeResult { let enc = &mut encoder; let qri = &mut query_result_index; - tcx.queries.encode_query_results(tcx, enc, qri) + QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri) })?; // Encode diagnostics. @@ -411,6 +406,88 @@ impl<'sess> OnDiskCache<'sess> { }) } + fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> Option { + let mut cache = self.def_path_hash_to_def_id_cache.lock(); + match cache.entry(hash) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + debug!("def_path_hash_to_def_id({:?})", hash); + // Check if the `DefPathHash` corresponds to a definition in the current + // crate + if let Some(def_id) = + tcx.definitions_untracked().local_def_path_hash_to_def_id(hash) + { + let def_id = def_id.to_def_id(); + e.insert(Some(def_id)); + return Some(def_id); + } + // This `raw_def_id` represents the `DefId` of this `DefPathHash` in + // the *previous* compliation session. The `DefPathHash` includes the + // owning crate, so if the corresponding definition still exists in the + // current compilation session, the crate is guaranteed to be the same + // (otherwise, we would compute a different `DefPathHash`). + let raw_def_id = self.get_raw_def_id(&hash)?; + debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); + // If the owning crate no longer exists, the corresponding definition definitely + // no longer exists. + let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?; + debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); + // If our `DefPathHash` corresponded to a definition in the local crate, + // we should have either found it in `local_def_path_hash_to_def_id`, or + // never attempted to load it in the first place. Any query result or `DepNode` + // that references a local `DefId` should depend on some HIR-related `DepNode`. + // If a local definition is removed/modified such that its old `DefPathHash` + // no longer has a corresponding definition, that HIR-related `DepNode` should + // end up red. This should prevent us from ever calling + // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any + // queries involved. + debug_assert_ne!(krate, LOCAL_CRATE); + // Try to find a definition in the current session, using the previous `DefIndex` + // as an initial guess. + let opt_def_id = + tcx.cstore_untracked().def_path_hash_to_def_id(krate, raw_def_id.index, hash); + debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); + e.insert(opt_def_id); + opt_def_id + } + } + } + + fn register_reused_dep_node(&self, tcx: TyCtxt<'sess>, dep_node: &DepNode) { + // For reused dep nodes, we only need to store the mapping if the node + // is one whose query key we can reconstruct from the hash. We use the + // mapping to aid that reconstruction in the next session. While we also + // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, + // they're already registered during `DefId` encoding. + if dep_node.kind.can_reconstruct_query_key() { + let hash = DefPathHash(dep_node.hash.into()); + + // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to + // `latest_foreign_def_path_hashes`, since the `RawDefId` might have + // changed in the current compilation session (e.g. we've added/removed crates, + // or added/removed definitions before/after the target definition). + if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { + if !def_id.is_local() { + self.store_foreign_def_id_hash(def_id, hash); + } + } + } + } + + fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { + // We may overwrite an existing entry, but it will have the same value, + // so it's fine + self.latest_foreign_def_path_hashes + .lock() + .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); + } +} + +impl<'sess> OnDiskCache<'sess> { + pub fn as_dyn(&self) -> &dyn rustc_middle::ty::OnDiskCache<'sess> { + self as _ + } + /// Loads a diagnostic emitted during the previous compilation session. pub fn load_diagnostics( &self, @@ -449,44 +526,6 @@ impl<'sess> OnDiskCache<'sess> { cnum_map.get(&stable_crate_id).copied() } - pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { - // We may overwrite an existing entry, but it will have the same value, - // so it's fine - self.latest_foreign_def_path_hashes - .lock() - .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); - } - - /// If the given `dep_node`'s hash still exists in the current compilation, - /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. - /// - /// Normally, `store_foreign_def_id_hash` can be called directly by - /// the dependency graph when we construct a `DepNode`. However, - /// when we re-use a deserialized `DepNode` from the previous compilation - /// session, we only have the `DefPathHash` available. This method is used - /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written - /// out for usage in the next compilation session. - pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) { - // For reused dep nodes, we only need to store the mapping if the node - // is one whose query key we can reconstruct from the hash. We use the - // mapping to aid that reconstruction in the next session. While we also - // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, - // they're already registered during `DefId` encoding. - if dep_node.kind.can_reconstruct_query_key() { - let hash = DefPathHash(dep_node.hash.into()); - - // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to - // `latest_foreign_def_path_hashes`, since the `RawDefId` might have - // changed in the current compilation session (e.g. we've added/removed crates, - // or added/removed definitions before/after the target definition). - if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { - if !def_id.is_local() { - self.store_foreign_def_id_hash(def_id, hash); - } - } - } - } - /// Returns the cached query result if there is something in the cache for /// the given `SerializedDepNodeIndex`; otherwise returns `None`. pub fn try_load_query_result<'tcx, T>( @@ -579,63 +618,6 @@ impl<'sess> OnDiskCache<'sess> { .collect() }) } - - /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation - /// session, if it still exists. This is used during incremental compilation to - /// turn a deserialized `DefPathHash` into its current `DefId`. - pub(crate) fn def_path_hash_to_def_id( - &self, - tcx: TyCtxt<'tcx>, - hash: DefPathHash, - ) -> Option { - let mut cache = self.def_path_hash_to_def_id_cache.lock(); - match cache.entry(hash) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - debug!("def_path_hash_to_def_id({:?})", hash); - // Check if the `DefPathHash` corresponds to a definition in the current - // crate - if let Some(def_id) = - tcx.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash) - { - let def_id = def_id.to_def_id(); - e.insert(Some(def_id)); - return Some(def_id); - } - // This `raw_def_id` represents the `DefId` of this `DefPathHash` in - // the *previous* compliation session. The `DefPathHash` includes the - // owning crate, so if the corresponding definition still exists in the - // current compilation session, the crate is guaranteed to be the same - // (otherwise, we would compute a different `DefPathHash`). - let raw_def_id = self.get_raw_def_id(&hash)?; - debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); - // If the owning crate no longer exists, the corresponding definition definitely - // no longer exists. - let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?; - debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); - // If our `DefPathHash` corresponded to a definition in the local crate, - // we should have either found it in `local_def_path_hash_to_def_id`, or - // never attempted to load it in the first place. Any query result or `DepNode` - // that references a local `DefId` should depend on some HIR-related `DepNode`. - // If a local definition is removed/modified such that its old `DefPathHash` - // no longer has a corresponding definition, that HIR-related `DepNode` should - // end up red. This should prevent us from ever calling - // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any - // queries involved. - debug_assert_ne!(krate, LOCAL_CRATE); - // Try to find a definition in the current session, using the previous `DefIndex` - // as an initial guess. - let opt_def_id = tcx.untracked_resolutions.cstore.def_path_hash_to_def_id( - krate, - raw_def_id.index, - hash, - ); - debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); - e.insert(opt_def_id); - opt_def_id - } - } - } } //- DECODING ------------------------------------------------------------------- @@ -776,7 +758,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { } } -crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); +rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); // This ensures that the `Decodable::decode` specialization for `Vec` is used // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt @@ -827,7 +809,7 @@ impl<'a, 'tcx> Decodable> for ExpnId { rustc_span::hygiene::register_local_expn_id(data, hash) } else { let index_guess = decoder.foreign_expn_data[&hash]; - decoder.tcx.untracked_resolutions.cstore.expn_hash_to_expn_id(krate, index_guess, hash) + decoder.tcx.cstore_untracked().expn_hash_to_expn_id(krate, index_guess, hash) }; #[cfg(debug_assertions)] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 5907a587e1690..6ed82ebfdb357 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -2,9 +2,8 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use super::queries; +use crate::{on_disk_cache, queries, Queries}; use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; -use rustc_middle::ty::query::on_disk_cache; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::HasDepContext; @@ -12,14 +11,16 @@ use rustc_query_system::query::{QueryContext, QueryDescription, QueryJobId, Quer use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::Diagnostic; +use rustc_errors::{Diagnostic, Handler}; use rustc_serialize::opaque; use rustc_span::def_id::LocalDefId; +use std::any::Any; + #[derive(Copy, Clone)] pub struct QueryCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - pub queries: &'tcx super::Queries<'tcx>, + pub queries: &'tcx Queries<'tcx>, } impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { @@ -83,14 +84,15 @@ impl QueryContext for QueryCtxt<'tcx> { // Interactions with on_disk_cache fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { - self.on_disk_cache + self.queries + .on_disk_cache .as_ref() .map(|c| c.load_diagnostics(**self, prev_dep_node_index)) .unwrap_or_default() } fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec) { - if let Some(c) = self.on_disk_cache.as_ref() { + if let Some(c) = self.queries.on_disk_cache.as_ref() { c.store_diagnostics(dep_node_index, diagnostics) } } @@ -100,7 +102,7 @@ impl QueryContext for QueryCtxt<'tcx> { dep_node_index: DepNodeIndex, diagnostics: ThinVec, ) { - if let Some(c) = self.on_disk_cache.as_ref() { + if let Some(c) = self.queries.on_disk_cache.as_ref() { c.store_diagnostics_for_anon_node(dep_node_index, diagnostics) } } @@ -137,6 +139,22 @@ impl QueryContext for QueryCtxt<'tcx> { } impl<'tcx> QueryCtxt<'tcx> { + #[inline] + pub fn from_tcx(tcx: TyCtxt<'tcx>) -> Self { + let queries = tcx.queries.as_any(); + let queries = unsafe { + let queries = std::mem::transmute::<&dyn Any, &dyn Any>(queries); + let queries = queries.downcast_ref().unwrap(); + let queries = std::mem::transmute::<&Queries<'_>, &Queries<'_>>(queries); + queries + }; + QueryCtxt { tcx, queries } + } + + crate fn on_disk_cache(self) -> Option<&'tcx on_disk_cache::OnDiskCache<'tcx>> { + self.queries.on_disk_cache.as_ref() + } + pub(super) fn encode_query_results( self, encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, @@ -158,6 +176,15 @@ 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) + } } /// This struct stores metadata about each Query. @@ -462,6 +489,8 @@ macro_rules! define_queries_struct { local_providers: Box, extern_providers: Box, + pub on_disk_cache: Option>, + $($(#[$attr])* $name: QueryState< crate::dep_graph::DepKind, query_keys::$name<$tcx>, @@ -472,10 +501,12 @@ macro_rules! define_queries_struct { pub fn new( local_providers: Providers, extern_providers: Providers, + on_disk_cache: Option>, ) -> Self { Queries { local_providers: Box::new(local_providers), extern_providers: Box::new(extern_providers), + on_disk_cache, $($name: Default::default()),* } } @@ -501,43 +532,22 @@ macro_rules! define_queries_struct { } impl QueryEngine<'tcx> for Queries<'tcx> { + fn as_any(&'tcx self) -> &'tcx dyn std::any::Any { + let this = unsafe { std::mem::transmute::<&Queries<'_>, &Queries<'_>>(self) }; + this as _ + } + #[cfg(parallel_compiler)] unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry) { let tcx = QueryCtxt { tcx, queries: self }; rustc_query_system::query::deadlock(tcx, registry) } - fn encode_query_results( - &'tcx self, - tcx: TyCtxt<'tcx>, - encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, - query_result_index: &mut on_disk_cache::EncodedQueryResultIndex, - ) -> opaque::FileEncodeResult { - let tcx = QueryCtxt { tcx, queries: self }; - tcx.encode_query_results(encoder, query_result_index) - } - - fn exec_cache_promotions(&'tcx self, tcx: TyCtxt<'tcx>) { - let tcx = QueryCtxt { tcx, queries: self }; - tcx.dep_graph.exec_cache_promotions(tcx) - } - fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool { let qcx = QueryCtxt { tcx, queries: self }; tcx.dep_graph.try_mark_green(qcx, dep_node).is_some() } - fn try_print_query_stack( - &'tcx self, - tcx: TyCtxt<'tcx>, - query: Option>, - handler: &Handler, - num_frames: Option, - ) -> usize { - let qcx = QueryCtxt { tcx, queries: self }; - rustc_query_system::query::print_query_stack(qcx, query, handler, num_frames) - } - $($(#[$attr])* #[inline(always)] fn $name( From 5b921505ef0892e4d83d0e2743e3e2eecd03d461 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 28 Jun 2021 21:33:47 +0200 Subject: [PATCH 2/2] Remove deadlock virtual call. --- compiler/rustc_interface/src/util.rs | 4 +++- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/query.rs | 3 --- compiler/rustc_query_impl/src/plumbing.rs | 11 +++++------ 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 4f51ce620427b..8b41a0ff17693 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -10,6 +10,8 @@ use rustc_errors::registry::Registry; use rustc_metadata::dynamic_lib::DynamicLibrary; #[cfg(parallel_compiler)] use rustc_middle::ty::tls; +#[cfg(parallel_compiler)] +use rustc_query_impl::QueryCtxt; use rustc_resolve::{self, Resolver}; use rustc_session as session; use rustc_session::config::{self, CrateType}; @@ -176,7 +178,7 @@ unsafe fn handle_deadlock() { thread::spawn(move || { tls::enter_context(icx, |_| { rustc_span::set_session_globals_then(session_globals, || { - tls::with(|tcx| tcx.queries.deadlock(tcx, ®istry)) + tls::with(|tcx| QueryCtxt::from_tcx(tcx).deadlock(®istry)) }) }); }); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 47cc328f6c8bb..b84058011066f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -71,7 +71,7 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -pub trait OnDiskCache<'tcx> { +pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. fn new(sess: &'tcx Session, data: Vec, start_pos: usize) -> Self where diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 38ed82933fe94..15a8888ee65ed 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -233,9 +233,6 @@ macro_rules! define_callbacks { pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync { fn as_any(&'tcx self) -> &'tcx dyn std::any::Any; - #[cfg(parallel_compiler)] - unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry); - fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool; $($(#[$attr])* diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 6ed82ebfdb357..58c1b57dbb949 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -155,6 +155,11 @@ impl<'tcx> QueryCtxt<'tcx> { self.queries.on_disk_cache.as_ref() } + #[cfg(parallel_compiler)] + pub unsafe fn deadlock(self, registry: &rustc_rayon_core::Registry) { + rustc_query_system::query::deadlock(self, registry) + } + pub(super) fn encode_query_results( self, encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>, @@ -537,12 +542,6 @@ macro_rules! define_queries_struct { this as _ } - #[cfg(parallel_compiler)] - unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry) { - let tcx = QueryCtxt { tcx, queries: self }; - rustc_query_system::query::deadlock(tcx, registry) - } - fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool { let qcx = QueryCtxt { tcx, queries: self }; tcx.dep_graph.try_mark_green(qcx, dep_node).is_some()