diff --git a/Cargo.lock b/Cargo.lock index 6b5499ec6f351..a1a6840ce28e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3021,6 +3021,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index e8c3914e695ad..c140d515d0c1a 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -31,6 +31,8 @@ macro_rules! arena_types { rustc::hir::def_id::DefId, rustc::ty::subst::SubstsRef<$tcx> )>, + [few] lowered_hir: rustc::hir::LoweredHir, + [few] hir_map: rustc::hir::map::Map<$tcx>, [few, decode] mir_keys: rustc::util::nodemap::DefIdSet, [decode] specialization_graph: rustc::traits::specialization_graph::Graph, [] region_scope_tree: rustc::middle::region::ScopeTree, diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3d5e7dd0af121..bb973800d1741 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -304,8 +304,7 @@ macro_rules! define_dep_nodes { pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> 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() + tcx.def_path_hash_to_def_id()?.get(&def_path_hash).cloned() } else { None } @@ -439,6 +438,12 @@ pub trait RecoverKey<'tcx>: Sized { fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; } +impl RecoverKey<'tcx> for () { + fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option { + Some(()) + } +} + impl RecoverKey<'tcx> for CrateNum { fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { dep_node.extract_def_id(tcx).map(|id| id.krate) @@ -533,6 +538,18 @@ impl<'tcx> DepNodeParams<'tcx> for CrateNum { } } +impl<'tcx> DepNodeParams<'tcx> for () { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, _: TyCtxt<'_>) -> Fingerprint { + Fingerprint::ZERO + } + + fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + "".to_string() + } +} + impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { const CAN_RECONSTRUCT_QUERY_KEY: bool = false; diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index b8c6c1e372382..b97e9c565e047 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -79,14 +79,14 @@ struct DepGraphData { loaded_from_cache: Lock>, } -pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option +pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint where R: for<'a> HashStable>, { let mut stable_hasher = StableHasher::new(); result.hash_stable(hcx, &mut stable_hasher); - Some(stable_hasher.finish()) + stable_hasher.finish() } impl DepGraph { @@ -193,7 +193,7 @@ impl DepGraph { cx: C, arg: A, task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) where C: DepGraphSafe + StableHashingContextProvider<'a>, @@ -229,7 +229,8 @@ impl DepGraph { |data, key, fingerprint, _| { data.borrow_mut().alloc_node(key, SmallVec::new(), fingerprint) }, - hash_result::) + Some(hash_result::) + ) } fn with_task_impl<'a, C, A, R>( @@ -244,7 +245,7 @@ impl DepGraph { DepNode, Fingerprint, Option) -> DepNodeIndex, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) where C: DepGraphSafe + StableHashingContextProvider<'a>, @@ -252,16 +253,13 @@ impl DepGraph { if let Some(ref data) = self.data { let task_deps = create_task(key).map(|deps| Lock::new(deps)); - // In incremental mode, hash the result of the task. We don't - // do anything with the hash yet, but we are computing it - // anyway so that - // - we make sure that the infrastructure works and - // - we can get an idea of the runtime cost. - let mut hcx = cx.get_stable_hashing_context(); - - if cfg!(debug_assertions) { - profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone())) - }; + let hcx = hash_result.as_ref().map(|_| { + let hcx = cx.get_stable_hashing_context(); + if cfg!(debug_assertions) { + profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone())) + }; + hcx + }); let result = if no_tcx { task(cx, arg) @@ -279,10 +277,12 @@ impl DepGraph { }; if cfg!(debug_assertions) { - profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd) + hcx.as_ref().map(|hcx| profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd)); }; - let current_fingerprint = hash_result(&mut hcx, &result); + let current_fingerprint = hash_result.map(|hash_result| { + hash_result(&mut hcx.unwrap(), &result) + }); let dep_node_index = finish_task_and_alloc_depnode( &data.current, @@ -291,7 +291,9 @@ impl DepGraph { task_deps.map(|lock| lock.into_inner()), ); - let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks; + let print_status = cfg!(debug_assertions) && ty::tls::with_opt(|tcx| { + tcx.map(|tcx| tcx.sess.opts.debugging_opts.dep_tasks).unwrap_or(false) + }); // Determine the color of the new DepNode. if let Some(prev_index) = data.previous.node_to_index_opt(&key) { @@ -378,7 +380,7 @@ impl DepGraph { cx: C, arg: A, task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) where C: DepGraphSafe + StableHashingContextProvider<'a>, @@ -674,8 +676,6 @@ impl DepGraph { } } else { match dep_dep_node.kind { - DepKind::Hir | - DepKind::HirBody | DepKind::CrateMetadata => { if dep_dep_node.extract_def_id(tcx).is_none() { // If the node does not exist anymore, we @@ -719,7 +719,7 @@ impl DepGraph { None => { if !tcx.sess.has_errors() { bug!("try_mark_previous_green() - Forcing the DepNode \ - should have set its color") + should have set its color - dep node {:?}", dep_dep_node) } else { // If the query we just forced has resulted // in some kind of compilation error, we diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 63f60d0ab9528..c218a3a84a1fd 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -8,8 +8,6 @@ use crate::dep_graph::{DepGraph, DepNode, DepKind, DepNodeIndex}; use crate::hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId}; -use crate::middle::cstore::CrateStoreDyn; - use rustc_target::spec::abi::Abi; use rustc_data_structures::svh::Svh; use rustc_data_structures::indexed_vec::IndexVec; @@ -27,6 +25,7 @@ use crate::util::common::time; use std::result::Result::Err; use crate::ty::query::Providers; +use crate::ty::TyCtxt; pub mod blocks; mod collector; @@ -1135,45 +1134,47 @@ impl Named for StructField { fn name(&self) -> Name { self.ident.name } } impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } } impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } } -pub fn map_crate<'hir>(sess: &crate::session::Session, - cstore: &CrateStoreDyn, - forest: &'hir Forest, - definitions: &'hir Definitions) - -> Map<'hir> { +pub fn map_crate(tcx: TyCtxt<'_>) -> Map<'_> { + // FIXME: Error handling here? + let hir = tcx.lowered_hir(); + // Build the reverse mapping of `node_to_hir_id`. - let hir_to_node_id = definitions.node_to_hir_id.iter_enumerated() + let hir_to_node_id = hir.defs.node_to_hir_id.iter_enumerated() .map(|(node_id, &hir_id)| (hir_id, node_id)).collect(); let (map, crate_hash) = { - let hcx = crate::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore); - - let mut collector = NodeCollector::root(sess, - &forest.krate, - &forest.dep_graph, - &definitions, - &hir_to_node_id, - hcx); - intravisit::walk_crate(&mut collector, &forest.krate); - - let crate_disambiguator = sess.local_crate_disambiguator(); - let cmdline_args = sess.opts.dep_tracking_hash(); + let hcx = tcx.create_stable_hashing_context(); + let krate = hir.forest.untracked_krate(); + + let mut collector = NodeCollector::root( + tcx.sess, + krate, + &tcx.dep_graph, + &hir.defs, + &hir_to_node_id, + hcx + ); + intravisit::walk_crate(&mut collector, krate); + + let crate_disambiguator = tcx.sess.local_crate_disambiguator(); + let cmdline_args = tcx.sess.opts.dep_tracking_hash(); collector.finalize_and_compute_crate_hash( crate_disambiguator, - cstore, + tcx.cstore, cmdline_args ) }; let map = Map { - forest, - dep_graph: forest.dep_graph.clone(), + forest: &hir.forest, + dep_graph: tcx.dep_graph.clone(), crate_hash, map, hir_to_node_id, - definitions, + definitions: &hir.defs, }; - time(sess, "validate hir map", || { + time(tcx.sess, "validate hir map", || { hir_id_validator::check_crate(&map); }); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e7b37d40b4b2f..4355cdeb3137e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -13,7 +13,9 @@ pub use self::UnsafeSource::*; use crate::hir::def::{Res, DefKind}; use crate::hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX}; use crate::hir::ptr::P; -use crate::util::nodemap::{NodeMap, FxHashSet}; +use crate::hir::map::definitions::DefPathHash; +use crate::hir::def::Export; +use crate::util::nodemap::NodeMap; use crate::mir::mono::Linkage; use errors::FatalError; @@ -32,6 +34,8 @@ use crate::ty::query::Providers; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stable_hasher::StableVec; use rustc_macros::HashStable; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; @@ -66,6 +70,35 @@ pub mod print; pub mod ptr; pub mod upvars; +pub struct LoweredHir { + pub forest: map::Forest, + pub defs: map::Definitions, + + /// Export map produced by name resolution. + pub export_map: FxHashMap>>, + + pub maybe_unused_trait_imports: FxHashSet, + pub maybe_unused_extern_crates: Vec<(DefId, Span)>, + + /// A map of glob use to a set of names it actually imports. Currently only + /// used in save-analysis. + pub glob_map: FxHashMap>, + /// Extern prelude entries. The value is `true` if the entry was introduced + /// via `extern crate` item and not `--extern` option or compiler built-in. + pub extern_prelude: FxHashMap, + + /// A map from DefPathHash -> DefId. Includes DefIds from the local crate + /// as well as all upstream crates. Only populated in incremental mode. + pub def_path_hash_to_def_id: Option>, + + /// Map indicating what traits are in scope for places where this + /// is relevant; generated by resolve. + pub trait_map: FxHashMap>>, + +} + /// Uniquely identifies a node in the HIR of the current crate. It is /// composed of the `owner`, which is the `DefIndex` of the directly enclosing /// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"), diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 442a90ab3f845..5c5aea76cadb3 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -31,6 +31,24 @@ use syntax_pos::symbol::InternedString; // as they will raise an fatal error on query cycles instead. rustc_queries! { Other { + query prepare_outputs(_: ()) -> Result, ErrorReported> { + no_hash + eval_always + desc { "preparing outputs" } + } + + query lower_ast_to_hir(_: ()) -> Result<&'tcx hir::LoweredHir, ErrorReported> { + no_hash + eval_always + desc { "lowering AST to HIR" } + } + + query hir_map(_: CrateNum) -> &'tcx hir::map::Map<'tcx> { + no_hash + eval_always + desc { "indexing HIR" } + } + /// Records the type of every item. query type_of(key: DefId) -> Ty<'tcx> { cache_on_disk_if { key.is_local() } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 82c53be3ec70f..f30ebe6576a32 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -482,6 +482,15 @@ impl BorrowckMode { } } +#[derive(Clone)] +pub struct InputsAndOutputs { + pub input: Input, + pub input_path: Option, + pub output_dir: Option, + pub output_file: Option, +} + +#[derive(Clone)] pub enum Input { /// Loads source from file File(PathBuf), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 16fc46b66d9f4..456d603cea8ce 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -4,12 +4,12 @@ use crate::arena::Arena; use crate::dep_graph::DepGraph; use crate::dep_graph::{self, DepNode, DepConstructor}; use crate::session::Session; -use crate::session::config::{BorrowckMode, OutputFilenames}; +use crate::session::config::{BorrowckMode, InputsAndOutputs}; use crate::session::config::CrateType; use crate::middle; use crate::hir::{TraitCandidate, HirId, ItemKind, ItemLocalId, Node}; -use crate::hir::def::{Res, DefKind, Export}; -use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; +use crate::hir::def::{Res, DefKind}; +use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use crate::hir::map as hir_map; use crate::hir::map::DefPathHash; use crate::lint::{self, Lint}; @@ -44,7 +44,7 @@ use crate::ty::{BoundVar, BindingMode}; use crate::ty::CanonicalPolyFnSig; use crate::util::common::ErrorReported; use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet}; -use crate::util::nodemap::{FxHashMap, FxHashSet}; +use crate::util::nodemap::FxHashMap; use errors::DiagnosticBuilder; use rustc_data_structures::interner::HashInterner; use smallvec::SmallVec; @@ -53,7 +53,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableVec}; use arena::SyncDroplessArena; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal}; +use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal, AtomicOnce, OneThread}; use std::any::Any; use std::borrow::Borrow; use std::cmp::Ordering; @@ -64,7 +64,6 @@ use std::mem; use std::ops::{Deref, Bound}; use std::iter; use std::sync::mpsc; -use std::sync::Arc; use rustc_target::spec::abi; use rustc_macros::HashStable; use syntax::ast; @@ -990,7 +989,7 @@ pub struct GlobalCtxt<'tcx> { interners: CtxtInterners<'tcx>, - cstore: &'tcx CrateStoreDyn, + pub cstore: &'tcx CrateStoreDyn, pub sess: &'tcx Session, @@ -1008,32 +1007,19 @@ pub struct GlobalCtxt<'tcx> { /// Common consts, pre-interned for your convenience. pub consts: CommonConsts<'tcx>, - /// Map indicating what traits are in scope for places where this - /// is relevant; generated by resolve. - trait_map: FxHashMap>>, + pub io: InputsAndOutputs, - /// Export map produced by name resolution. - export_map: FxHashMap>>, + pub ast_crate: Steal, - hir_map: hir_map::Map<'tcx>, + /// This stores a `Lrc>>)>`, but that type depends on + /// librustc_resolve, so it cannot be used here. + pub boxed_resolver: Steal>>, - /// A map from DefPathHash -> DefId. Includes DefIds from the local crate - /// as well as all upstream crates. Only populated in incremental mode. - pub def_path_hash_to_def_id: Option>, + lowered_hir: AtomicOnce<&'tcx hir::LoweredHir>, + hir_map: AtomicOnce<&'tcx hir_map::Map<'tcx>>, pub queries: query::Queries<'tcx>, - maybe_unused_trait_imports: FxHashSet, - maybe_unused_extern_crates: Vec<(DefId, Span)>, - /// A map of glob use to a set of names it actually imports. Currently only - /// used in save-analysis. - glob_map: FxHashMap>, - /// Extern prelude entries. The value is `true` if the entry was introduced - /// via `extern crate` item and not `--extern` option or compiler built-in. - pub extern_prelude: FxHashMap, - // Internal cache for metadata decoding. No need to track deps on this. pub rcache: Lock>>, @@ -1069,8 +1055,6 @@ pub struct GlobalCtxt<'tcx> { /// when satisfying the query for a particular codegen unit. Internally in /// the query it'll send data along this channel to get processed later. pub tx_to_llvm_workers: Lock>>, - - output_filenames: Arc, } impl<'tcx> TyCtxt<'tcx> { @@ -1082,9 +1066,25 @@ impl<'tcx> TyCtxt<'tcx> { } } + pub fn def_path_hash_to_def_id(self) -> Option<&'tcx FxHashMap> { + self.lowered_hir().def_path_hash_to_def_id.as_ref() + } + + #[inline(always)] + pub fn lowered_hir(self) -> &'tcx hir::LoweredHir { + self.lowered_hir.get_or_init(|| { + // FIXME: The ignore here is only sound because all queries + // used to compute LoweredHir are eval_always + self.dep_graph.with_ignore(|| self.lower_ast_to_hir(()).unwrap()) + }) + } + #[inline(always)] pub fn hir(self) -> &'tcx hir_map::Map<'tcx> { - &self.hir_map + self.hir_map.get_or_init(|| { + // We can use `with_ignore` here because the hir map does its own tracking + self.dep_graph.with_ignore(|| self.hir_map(LOCAL_CRATE)) + }) } pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal> { @@ -1168,12 +1168,13 @@ impl<'tcx> TyCtxt<'tcx> { local_providers: ty::query::Providers<'tcx>, extern_providers: ty::query::Providers<'tcx>, arenas: &'tcx AllArenas, - resolutions: ty::Resolutions, - hir: hir_map::Map<'tcx>, + dep_graph: DepGraph, + ast_crate: ast::Crate, + boxed_resolver: Box, on_disk_query_result_cache: query::OnDiskCache<'tcx>, crate_name: &str, tx: mpsc::Sender>, - output_filenames: &OutputFilenames, + io: InputsAndOutputs, ) -> GlobalCtxt<'tcx> { let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| { s.fatal(&err); @@ -1188,50 +1189,10 @@ impl<'tcx> TyCtxt<'tcx> { let common_types = CommonTypes::new(&interners); let common_lifetimes = CommonLifetimes::new(&interners); let common_consts = CommonConsts::new(&interners, &common_types); - let dep_graph = hir.dep_graph.clone(); let max_cnum = cstore.crates_untracked().iter().map(|c| c.as_usize()).max().unwrap_or(0); let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1); providers[LOCAL_CRATE] = local_providers; - let def_path_hash_to_def_id = if s.opts.build_dep_graph() { - let upstream_def_path_tables: Vec<(CrateNum, Lrc<_>)> = cstore - .crates_untracked() - .iter() - .map(|&cnum| (cnum, cstore.def_path_table(cnum))) - .collect(); - - let def_path_tables = || { - upstream_def_path_tables - .iter() - .map(|&(cnum, ref rc)| (cnum, &**rc)) - .chain(iter::once((LOCAL_CRATE, hir.definitions().def_path_table()))) - }; - - // Precompute the capacity of the hashmap so we don't have to - // re-allocate when populating it. - let capacity = def_path_tables().map(|(_, t)| t.size()).sum::(); - - let mut map: FxHashMap<_, _> = FxHashMap::with_capacity_and_hasher( - capacity, - ::std::default::Default::default() - ); - - for (cnum, def_path_table) in def_path_tables() { - def_path_table.add_def_path_hashes_to(cnum, &mut map); - } - - Some(map) - } else { - None - }; - - let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (k, v) in resolutions.trait_map { - let hir_id = hir.node_to_hir_id(k); - let map = trait_map.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, StableVec::new(v)); - } - GlobalCtxt { sess: s, cstore, @@ -1242,29 +1203,10 @@ impl<'tcx> TyCtxt<'tcx> { types: common_types, lifetimes: common_lifetimes, consts: common_consts, - trait_map, - export_map: resolutions.export_map.into_iter().map(|(k, v)| { - let exports: Vec<_> = v.into_iter().map(|e| { - e.map_id(|id| hir.node_to_hir_id(id)) - }).collect(); - (k, exports) - }).collect(), - maybe_unused_trait_imports: - resolutions.maybe_unused_trait_imports - .into_iter() - .map(|id| hir.local_def_id_from_node_id(id)) - .collect(), - maybe_unused_extern_crates: - resolutions.maybe_unused_extern_crates - .into_iter() - .map(|(id, sp)| (hir.local_def_id_from_node_id(id), sp)) - .collect(), - glob_map: resolutions.glob_map.into_iter().map(|(id, names)| { - (hir.local_def_id_from_node_id(id), names) - }).collect(), - extern_prelude: resolutions.extern_prelude, - hir_map: hir, - def_path_hash_to_def_id, + ast_crate: Steal::new(ast_crate), + boxed_resolver: Steal::new(OneThread::new(boxed_resolver)), + lowered_hir: AtomicOnce::new(), + hir_map: AtomicOnce::new(), queries: query::Queries::new( providers, extern_providers, @@ -1280,7 +1222,7 @@ impl<'tcx> TyCtxt<'tcx> { allocation_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), tx_to_llvm_workers: Lock::new(tx), - output_filenames: Arc::new(output_filenames.clone()), + io, } } @@ -1358,7 +1300,8 @@ impl<'tcx> TyCtxt<'tcx> { /// be a non-local `DefPath`. pub fn def_path(self, id: DefId) -> hir_map::DefPath { if id.is_local() { - self.hir().def_path(id) + // FIXME: This is used in some panic path? Don't use hir() + self.lowered_hir().defs.def_path(id.index) } else { self.cstore.def_path(id) } @@ -1377,7 +1320,9 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn def_path_hash(self, def_id: DefId) -> hir_map::DefPathHash { if def_id.is_local() { - self.hir().definitions().def_path_hash(def_id.index) + // This is used when creating dep nodes, which happens when executing queries, + // so we can't use hir() here + self.lowered_hir().defs.def_path_hash(def_id.index) } else { self.cstore.def_path_hash(def_id) } @@ -1416,12 +1361,18 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.hir_map.forest.untracked_krate(); + let hir = self.lowered_hir(); + + // FIXME: This is used when executing the hir query, can't use hir() here. + // Also used when dealing with query cycles + let krate = hir.forest.untracked_krate(); - StableHashingContext::new(self.sess, - krate, - self.hir().definitions(), - self.cstore) + StableHashingContext::new( + self.sess, + krate, + &hir.defs, + self.cstore, + ) } // This method makes sure that we have a DepNode and a Fingerprint for @@ -1439,7 +1390,7 @@ impl<'tcx> TyCtxt<'tcx> { self, crate_hash, |_, x| x, // No transformation needed - dep_graph::hash_result, + Some(dep_graph::hash_result), ); } } @@ -2892,8 +2843,12 @@ fn ptr_eq(t: *const T, u: *const U) -> bool { } pub fn provide(providers: &mut ty::query::Providers<'_>) { - providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id); - providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]); + providers.in_scope_traits_map = |tcx, id| { + tcx.lowered_hir().trait_map.get(&id) + }; + providers.module_exports = |tcx, id| { + tcx.lowered_hir().export_map.get(&id).map(|v| &v[..]) + }; providers.crate_name = |tcx, id| { assert_eq!(id, LOCAL_CRATE); tcx.crate_name @@ -2907,15 +2862,15 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { tcx.arena.alloc(middle::lang_items::collect(tcx)) }; providers.maybe_unused_trait_import = |tcx, id| { - tcx.maybe_unused_trait_imports.contains(&id) + tcx.lowered_hir().maybe_unused_trait_imports.contains(&id) }; providers.maybe_unused_extern_crates = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - &tcx.maybe_unused_extern_crates[..] + &tcx.lowered_hir().maybe_unused_extern_crates[..] }; providers.names_imported_by_glob_use = |tcx, id| { assert_eq!(id.krate, LOCAL_CRATE); - Lrc::new(tcx.glob_map.get(&id).cloned().unwrap_or_default()) + Lrc::new(tcx.lowered_hir().glob_map.get(&id).cloned().unwrap_or_default()) }; providers.stability_index = |tcx, cnum| { @@ -2946,7 +2901,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { }; providers.output_filenames = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.output_filenames.clone() + tcx.prepare_outputs(()).unwrap() }; providers.features_query = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index b921272856e28..1bda0ceba7bf4 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -43,10 +43,7 @@ pub(crate) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { // Don't use this method to compute query results, instead use the methods on TyCtxt fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value; - fn hash_result( - hcx: &mut StableHashingContext<'_>, - result: &Self::Value - ) -> Option; + fn hash_result() -> Option, &Self::Value) -> Fingerprint>; fn handle_cycle_error(tcx: TyCtxt<'tcx>, error: CycleError<'tcx>) -> Self::Value; } diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index 30a3e53dddfbb..24e8ea94c2f06 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -64,6 +64,15 @@ impl Key for CrateNum { } } +impl Key for () { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl Key for DefIndex { fn query_crate(&self) -> CrateNum { LOCAL_CRATE diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 56c9474170cad..be667cb6806d0 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -646,7 +646,7 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { let def_path_hash = DefPathHash::decode(self)?; // Using the DefPathHash, we can lookup the new DefId - Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]) + Ok(self.tcx().def_path_hash_to_def_id().unwrap()[&def_path_hash]) } } @@ -664,8 +664,7 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { // Use the DefPathHash to map to the current DefId. let def_id = self.tcx() - .def_path_hash_to_def_id - .as_ref() + .def_path_hash_to_def_id() .unwrap()[&def_path_hash]; debug_assert!(def_id.is_local()); diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 0c9e31e1ff28e..7e96d7fba179c 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -2,12 +2,13 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepNodeIndex, DepNode, DepKind, SerializedDepNodeIndex}; +use crate::dep_graph::{DepNodeIndex, DepNode, DepConstructor, DepKind, SerializedDepNodeIndex}; use crate::ty::tls; use crate::ty::{self, TyCtxt}; use crate::ty::query::Query; use crate::ty::query::config::{QueryConfig, QueryDescription}; use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo}; +use crate::hir::def_id::LOCAL_CRATE; use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; @@ -514,7 +515,7 @@ impl<'tcx> TyCtxt<'tcx> { debug!("BEGIN verify_ich({:?})", dep_node); let mut hcx = self.create_stable_hashing_context(); - let new_hash = Q::hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO); + let new_hash = Q::hash_result().map(|h| h(&mut hcx, result)).unwrap_or(Fingerprint::ZERO); debug!("END verify_ich({:?})", dep_node); let old_hash = self.dep_graph.fingerprint_of(dep_node_index); @@ -530,6 +531,10 @@ impl<'tcx> TyCtxt<'tcx> { job: JobOwner<'_, 'tcx, Q>, dep_node: DepNode, ) -> (Q::Value, DepNodeIndex) { + if self.dep_graph.is_fully_enabled() { + debug_assert_eq!(dep_node, Q::to_dep_node(self, &key)); + } + // If the following assertion triggers, it can have two reasons: // 1. Something is wrong with DepNode creation, either here or // in DepGraph::try_mark_green() @@ -551,13 +556,13 @@ impl<'tcx> TyCtxt<'tcx> { tcx, key, Q::compute, - Q::hash_result) + Q::hash_result()) } else { tcx.dep_graph.with_task(dep_node, tcx, key, Q::compute, - Q::hash_result) + Q::hash_result()) } }) }); @@ -679,14 +684,14 @@ 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$(, $modifiers:ident)*][$hcx:expr, $result:expr]) => {{ + ([no_hash$(, $modifiers:ident)*]) => {{ None }}; - ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { - hash_result!([$($modifiers),*][$($args)*]) + ([$other:ident$(, $modifiers:ident)*]) => { + hash_result!([$($modifiers),*]) }; } @@ -998,11 +1003,10 @@ macro_rules! define_queries_inner { }) } - fn hash_result( - _hcx: &mut StableHashingContext<'_>, - _result: &Self::Value - ) -> Option { - hash_result!([$($modifiers)*][_hcx, _result]) + fn hash_result() -> Option, &Self::Value + ) -> Fingerprint> { + hash_result!([$($modifiers)*]) } fn handle_cycle_error( @@ -1220,14 +1224,28 @@ pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool { ($query:ident, $key:expr) => { force_ex!(tcx, $query, $key) } }; + let force_hir_map = || { + tcx.force_query::>( + LOCAL_CRATE, + DUMMY_SP, + DepNode::new(tcx, DepConstructor::hir_map(LOCAL_CRATE)), + ); + }; + rustc_dep_node_force!([dep_node, tcx] + // Created by the Hir map query + DepKind::AllLocalTraitImpls | + DepKind::Krate => force_hir_map(), + DepKind::HirBody | + DepKind::Hir => { + // Ensure the def_id exists + def_id!(); + force_hir_map(); + } + // These are inputs that are expected to be pre-allocated and that // should therefore always be red or green already - DepKind::AllLocalTraitImpls | - DepKind::Krate | DepKind::CrateMetadata | - DepKind::HirBody | - DepKind::Hir | // This are anonymous nodes DepKind::TraitSelect | diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 21c19e167cfbe..c146be126ad59 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -112,7 +112,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'tcx>, cgu_name: InternedString) { tcx, cgu_name, module_codegen, - dep_graph::hash_result, + Some(dep_graph::hash_result), ); let time_to_codegen = start_time.elapsed(); diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index acddb3448ca60..79cbe26e73e83 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -18,6 +18,7 @@ lazy_static = "1" serialize = { path = "../libserialize" } graphviz = { path = "../libgraphviz" } cfg-if = "0.1.2" +crossbeam-utils = { version = "0.6.5", features = ["nightly"] } stable_deref_trait = "1.0.0" rayon = { version = "0.2.0", package = "rustc-rayon" } rayon-core = { version = "0.2.0", package = "rustc-rayon-core" } diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 73247c1469efd..469f778551239 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -21,6 +21,7 @@ use std::collections::HashMap; use std::hash::{Hash, BuildHasher}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; +use crate::cold_path; use crate::owning_ref::{Erased, OwningRef}; pub fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) @@ -67,6 +68,59 @@ cfg_if! { use std::ops::Add; use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe}; + #[derive(Debug)] + pub struct AtomicCell(Cell); + + impl AtomicCell { + #[inline] + pub fn new(v: T) -> Self { + AtomicCell(Cell::new(v)) + } + } + + impl AtomicCell { + pub fn into_inner(self) -> T { + self.0.into_inner() + } + + #[inline] + pub fn load(&self) -> T { + self.0.get() + } + + #[inline] + pub fn store(&self, val: T) { + self.0.set(val) + } + + pub fn swap(&self, val: T) -> T { + self.0.replace(val) + } + } + + impl AtomicCell { + pub fn compare_exchange(&self, + current: T, + new: T) + -> Result { + let read = self.0.get(); + if read == current { + self.0.set(new); + Ok(read) + } else { + Err(read) + } + } + } + + impl + Copy> AtomicCell { + pub fn fetch_add(&self, val: T) -> T { + let old = self.0.get(); + self.0.set(old + val); + old + } + } + #[derive(Debug)] pub struct Atomic(Cell); @@ -77,7 +131,7 @@ cfg_if! { } } - impl Atomic { + impl Atomic { pub fn into_inner(self) -> T { self.0.into_inner() } @@ -95,7 +149,9 @@ cfg_if! { pub fn swap(&self, val: T, _: Ordering) -> T { self.0.replace(val) } + } + impl Atomic { pub fn compare_exchange(&self, current: T, new: T, @@ -271,6 +327,8 @@ cfg_if! { pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; + pub use crossbeam_utils::atomic::AtomicCell; + pub use std::sync::Arc as Lrc; pub use std::sync::Weak as Weak; @@ -516,6 +574,34 @@ impl Once { } } +/// A type whose inner value can be written once and then will stay read-only +pub struct AtomicOnce(AtomicCell>); + +impl AtomicOnce { + /// Creates an AtomicOnce value which is uninitialized + #[inline] + pub fn new() -> Self { + AtomicOnce(AtomicCell::new(None)) + } + + /// Gets the inner value. If the value is not already initalized. + /// It will be initalized by the closure. The closure may be called + /// concurrently by many threads. + #[inline(always)] + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> T { + let value = self.0.load(); + if unlikely!(value.is_none()) { + cold_path(|| { + let value = f(); + self.0.store(Some(value)); + value + }) + } else { + value.unwrap() + } + } +} + #[derive(Debug)] pub struct Lock(InnerLock); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e615f8a484692..c6a1b216accb2 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -268,11 +268,10 @@ pub fn run_compiler( if ppm.needs_ast_map(&opt_uii) { pretty::visit_crate(sess, &mut compiler.parse()?.peek_mut(), ppm); compiler.global_ctxt()?.peek_mut().enter(|tcx| { - let expanded_crate = compiler.expansion()?.take().0; pretty::print_after_hir_lowering( tcx, compiler.input(), - &expanded_crate, + &tcx.ast_crate.borrow(), ppm, opt_uii.clone(), compiler.output_file().as_ref().map(|p| &**p), @@ -312,7 +311,10 @@ pub fn run_compiler( return sess.compile_status(); } - compiler.prepare_outputs()?; + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + tcx.prepare_outputs(())?; + Ok(()) + })?; if sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1 @@ -320,7 +322,10 @@ pub fn run_compiler( return sess.compile_status(); } - compiler.global_ctxt()?; + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + tcx.lower_ast_to_hir(())?; + Ok(()) + })?; if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json { @@ -328,19 +333,18 @@ pub fn run_compiler( } if sess.opts.debugging_opts.save_analysis { - let expanded_crate = &compiler.expansion()?.peek().0; - let crate_name = compiler.crate_name()?.peek().clone(); compiler.global_ctxt()?.peek_mut().enter(|tcx| { let result = tcx.analysis(LOCAL_CRATE); + let crate_name = &tcx.crate_name.as_str(); time(sess, "save analysis", || { save::process_crate( tcx, - &expanded_crate, - &crate_name, + &tcx.ast_crate.borrow(), + crate_name, &compiler.input(), None, - DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), &crate_name) + DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), crate_name) ) }); @@ -349,8 +353,10 @@ pub fn run_compiler( // (needed by the RLS) })?; } else { - // Drop AST after creating GlobalCtxt to free memory - mem::drop(compiler.expansion()?.take()); + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + // Drop AST after lowering HIR to free memory + mem::drop(tcx.ast_crate.steal()); + }); } compiler.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?; @@ -360,7 +366,10 @@ pub fn run_compiler( } if sess.opts.debugging_opts.save_analysis { - mem::drop(compiler.expansion()?.take()); + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + // Drop AST after lowering HIR to free memory + mem::drop(tcx.ast_crate.steal()); + }); } compiler.ongoing_codegen()?; diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index 674b2b60e44a2..8fef6338ec0d0 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -4,7 +4,7 @@ use crate::profile; pub use crate::passes::BoxedResolver; use rustc::lint; -use rustc::session::config::{self, Input}; +use rustc::session::config::{self, Input, InputsAndOutputs}; use rustc::session::{DiagnosticOutput, Session}; use rustc::util::common::ErrorReported; use rustc_codegen_utils::codegen_backend::CodegenBackend; @@ -29,10 +29,7 @@ pub struct Compiler { pub(crate) sess: Lrc, codegen_backend: Lrc>, source_map: Lrc, - pub(crate) input: Input, - pub(crate) input_path: Option, - pub(crate) output_dir: Option, - pub(crate) output_file: Option, + pub(crate) io: InputsAndOutputs, pub(crate) queries: Queries, pub(crate) cstore: Lrc, pub(crate) crate_name: Option, @@ -52,13 +49,13 @@ impl Compiler { &self.source_map } pub fn input(&self) -> &Input { - &self.input + &self.io.input } pub fn output_dir(&self) -> &Option { - &self.output_dir + &self.io.output_dir } pub fn output_file(&self) -> &Option { - &self.output_file + &self.io.output_file } } @@ -104,10 +101,12 @@ where codegen_backend, source_map, cstore, - input: config.input, - input_path: config.input_path, - output_dir: config.output_dir, - output_file: config.output_file, + io: InputsAndOutputs { + input: config.input, + input_path: config.input_path, + output_dir: config.output_dir, + output_file: config.output_file, + }, queries: Default::default(), crate_name: config.crate_name, }; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 9a5eb2b93d574..64aff184addfb 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -16,7 +16,7 @@ use rustc::traits; use rustc::util::common::{time, ErrorReported}; use rustc::util::profiling::ProfileCategory; use rustc::session::{CompileResult, CrateDisambiguator, Session}; -use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType}; +use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType, InputsAndOutputs}; use rustc::session::search_paths::PathKind; use rustc_allocator as allocator; use rustc_borrowck as borrowck; @@ -25,8 +25,9 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_codegen_utils::link::filename_for_metadata; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::StableHasher; -use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter}; +use rustc_data_structures::stable_hasher::{StableHasher, StableVec}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{self, Lrc, Lock, OneThread, ParallelIterator, par_iter}; use rustc_incremental; use rustc_incremental::DepGraphFuture; use rustc_metadata::creader::CrateLoader; @@ -63,7 +64,7 @@ use std::iter; use std::path::{Path, PathBuf}; use std::sync::mpsc; use std::cell::RefCell; -use std::rc::Rc; +use std::sync::Arc; use std::mem; use std::ops::Generator; @@ -167,8 +168,8 @@ pub fn configure_and_expand( } pub struct ExpansionResult { - pub defs: Steal, - pub resolutions: Steal, + pub defs: hir::map::Definitions, + pub resolutions: Resolutions, } impl ExpansionResult { @@ -176,8 +177,8 @@ impl ExpansionResult { resolver: Resolver<'_>, ) -> Self { ExpansionResult { - defs: Steal::new(resolver.definitions), - resolutions: Steal::new(Resolutions { + defs: resolver.definitions, + resolutions: Resolutions { export_map: resolver.export_map, trait_map: resolver.trait_map, glob_map: resolver.glob_map, @@ -186,7 +187,7 @@ impl ExpansionResult { extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { (ident.name, entry.introduced_by_item) }).collect(), - }), + }, } } @@ -194,8 +195,8 @@ impl ExpansionResult { resolver: &Resolver<'_>, ) -> Self { ExpansionResult { - defs: Steal::new(resolver.definitions.clone()), - resolutions: Steal::new(Resolutions { + defs: resolver.definitions.clone(), + resolutions: Resolutions { export_map: resolver.export_map.clone(), trait_map: resolver.trait_map.clone(), glob_map: resolver.glob_map.clone(), @@ -204,20 +205,19 @@ impl ExpansionResult { extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { (ident.name, entry.introduced_by_item) }).collect(), - }), + }, } } } impl BoxedResolver { pub fn to_expansion_result( - mut resolver: Rc>>, + resolver: &mut Lrc>>, ) -> ExpansionResult { - if let Some(resolver) = Rc::get_mut(&mut resolver) { + if let Some(resolver) = Lrc::get_mut(resolver) { mem::replace(resolver, None).unwrap().into_inner().complete() } else { - let resolver = &*resolver; - resolver.as_ref().unwrap().borrow_mut().access(|resolver| { + (**resolver).as_ref().unwrap().lock().access(|resolver| { ExpansionResult::from_resolver_ref(resolver) }) } @@ -548,26 +548,43 @@ fn configure_and_expand_inner<'a>( Ok((krate, resolver)) } -pub fn lower_to_hir( - sess: &Session, - cstore: &CStore, - resolver: &mut Resolver<'_>, - dep_graph: &DepGraph, - krate: &ast::Crate, -) -> Result { +fn lower_ast_to_hir( + tcx: TyCtxt<'_>, + _: (), +) -> Result<&'_ hir::LoweredHir> { + tcx.prepare_outputs(())?; + + let sess = tcx.sess; + + let boxed_resolver: Box = OneThread::into_inner(tcx.boxed_resolver.steal()); + let mut boxed_resolver: Box>>> = + boxed_resolver.downcast().unwrap(); + // Lower ast -> hir - let hir_forest = time(sess, "lowering ast -> hir", || { - let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver); + let forest = time(sess, "lowering ast -> hir", || { + (**boxed_resolver).as_ref().unwrap().lock().access(|resolver| { + let hir_crate = lower_crate( + sess, + tcx.cstore, + &tcx.dep_graph, + &tcx.ast_crate.borrow(), + resolver, + ); - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_hir_stats(&hir_crate); - } + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_hir_stats(&hir_crate); + } - hir::map::Forest::new(hir_crate, &dep_graph) + hir::map::Forest::new(hir_crate, &tcx.dep_graph) + }) }); time(sess, "early lint checks", || { - lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new()) + lint::check_ast_crate( + sess, + &tcx.ast_crate.borrow(), + false,rustc_lint::BuiltinCombinedEarlyLintPass::new() + ) }); // Discard hygiene data, which isn't required after lowering to HIR. @@ -575,7 +592,76 @@ pub fn lower_to_hir( syntax::ext::hygiene::clear_markings(); } - Ok(hir_forest) + let ExpansionResult { + defs, + resolutions, + } = BoxedResolver::to_expansion_result(&mut *boxed_resolver); + + let def_path_hash_to_def_id = if tcx.sess.opts.build_dep_graph() { + let upstream_def_path_tables: Vec<(CrateNum, Lrc<_>)> = tcx.cstore + .crates_untracked() + .iter() + .map(|&cnum| (cnum, tcx.cstore.def_path_table(cnum))) + .collect(); + + let def_path_tables = || { + upstream_def_path_tables + .iter() + .map(|&(cnum, ref rc)| (cnum, &**rc)) + .chain(iter::once((LOCAL_CRATE, defs.def_path_table()))) + }; + + // Precompute the capacity of the hashmap so we don't have to + // re-allocate when populating it. + let capacity = def_path_tables().map(|(_, t)| t.size()).sum::(); + + let mut map: FxHashMap<_, _> = FxHashMap::with_capacity_and_hasher( + capacity, + ::std::default::Default::default() + ); + + for (cnum, def_path_table) in def_path_tables() { + def_path_table.add_def_path_hashes_to(cnum, &mut map); + } + + Some(map) + } else { + None + }; + + let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); + for (k, v) in resolutions.trait_map { + let hir_id = defs.node_to_hir_id(k); + let map = trait_map.entry(hir_id.owner).or_default(); + map.insert(hir_id.local_id, StableVec::new(v)); + } + + Ok(tcx.arena.alloc(hir::LoweredHir { + forest, + export_map: resolutions.export_map.into_iter().map(|(k, v)| { + let exports: Vec<_> = v.into_iter().map(|e| { + e.map_id(|id| defs.node_to_hir_id(id)) + }).collect(); + (k, exports) + }).collect(), + maybe_unused_trait_imports: + resolutions.maybe_unused_trait_imports + .into_iter() + .map(|id| defs.local_def_id(id)) + .collect(), + maybe_unused_extern_crates: + resolutions.maybe_unused_extern_crates + .into_iter() + .map(|(id, sp)| (defs.local_def_id(id), sp)) + .collect(), + glob_map: resolutions.glob_map.into_iter().map(|(id, names)| { + (defs.local_def_id(id), names) + }).collect(), + defs, + extern_prelude: resolutions.extern_prelude, + def_path_hash_to_def_id, + trait_map, + })) } // Returns all the paths that correspond to generated files. @@ -697,33 +783,31 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[Pa } } -pub fn prepare_outputs( - sess: &Session, - compiler: &Compiler, - krate: &ast::Crate, - crate_name: &str -) -> Result { - // FIXME: rustdoc passes &[] instead of &krate.attrs here +fn prepare_outputs( + tcx: TyCtxt<'_>, + _: (), +) -> Result> { + // FIXME: rustdoc passes &[] instead of &tcx.ast_krate.borrow().attrs here let outputs = util::build_output_filenames( - &compiler.input, - &compiler.output_dir, - &compiler.output_file, - &krate.attrs, - sess + &tcx.io.input, + &tcx.io.output_dir, + &tcx.io.output_file, + &tcx.ast_crate.borrow().attrs, + tcx.sess ); let output_paths = generated_output_paths( - sess, + tcx.sess, &outputs, - compiler.output_file.is_some(), - &crate_name, + tcx.io.output_file.is_some(), + &tcx.crate_name.as_str(), ); // Ensure the source file isn't accidentally overwritten during compilation. - if let Some(ref input_path) = compiler.input_path { - if sess.opts.will_create_output_file() { + if let Some(ref input_path) = tcx.io.input_path { + if tcx.sess.opts.will_create_output_file() { if output_contains_path(&output_paths, input_path) { - sess.err(&format!( + tcx.sess.err(&format!( "the input file \"{}\" would be overwritten by the generated \ executable", input_path.display() @@ -731,7 +815,7 @@ pub fn prepare_outputs( return Err(ErrorReported); } if let Some(dir_path) = output_conflicts_with_dir(&output_paths) { - sess.err(&format!( + tcx.sess.err(&format!( "the generated executable for the input file \"{}\" conflicts with the \ existing directory \"{}\"", input_path.display(), @@ -742,25 +826,28 @@ pub fn prepare_outputs( } } - write_out_deps(sess, &outputs, &output_paths); + write_out_deps(tcx.sess, &outputs, &output_paths); - let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) - && sess.opts.output_types.len() == 1; + let only_dep_info = tcx.sess.opts.output_types.contains_key(&OutputType::DepInfo) + && tcx.sess.opts.output_types.len() == 1; if !only_dep_info { - if let Some(ref dir) = compiler.output_dir { + if let Some(ref dir) = tcx.io.output_dir { if fs::create_dir_all(dir).is_err() { - sess.err("failed to find or create the directory specified by --out-dir"); + tcx.sess.err("failed to find or create the directory specified by --out-dir"); return Err(ErrorReported); } } } - Ok(outputs) + Ok(Arc::new(outputs)) } pub fn default_provide(providers: &mut ty::query::Providers<'_>) { providers.analysis = analysis; + providers.hir_map = hir_map; + providers.lower_ast_to_hir = lower_ast_to_hir; + providers.prepare_outputs = prepare_outputs; proc_macro_decls::provide(providers); plugin::build::provide(providers); hir::provide(providers); @@ -806,10 +893,10 @@ impl BoxedGlobalCtxt { pub fn create_global_ctxt( compiler: &Compiler, - mut hir_forest: hir::map::Forest, - defs: hir::map::Definitions, - resolutions: Resolutions, - outputs: OutputFilenames, + dep_graph: DepGraph, + ast_krate: ast::Crate, + boxed_resolver: Box>>>, + io: InputsAndOutputs, tx: mpsc::Sender>, crate_name: &str, ) -> BoxedGlobalCtxt { @@ -825,11 +912,6 @@ pub fn create_global_ctxt( let global_ctxt: Option>; let arenas = AllArenas::new(); - // Construct the HIR map - let hir_map = time(sess, "indexing hir", || { - hir::map::map_crate(sess, cstore, &mut hir_forest, &defs) - }); - let query_result_on_disk_cache = time(sess, "load query result cache", || { rustc_incremental::load_query_result_cache(sess) }); @@ -848,12 +930,13 @@ pub fn create_global_ctxt( local_providers, extern_providers, &arenas, - resolutions, - hir_map, + dep_graph, + ast_krate, + boxed_resolver, query_result_on_disk_cache, &crate_name, tx, - &outputs + io, ); global_ctxt = Some(gcx); @@ -876,6 +959,20 @@ pub fn create_global_ctxt( result } +fn hir_map<'tcx>( + tcx: TyCtxt<'tcx>, + cnum: CrateNum, +) -> &'tcx hir::map::Map<'tcx> { + assert_eq!(cnum, LOCAL_CRATE); + + // Construct the HIR map + let hir_map = time(tcx.sess, "indexing hir", || { + hir::map::map_crate(tcx) + }); + + tcx.arena.alloc(hir_map) +} + /// Runs the resolution, type-checking, region checking and other /// miscellaneous analysis passes on the crate. fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 570509ffb2b8c..113e28035d758 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -2,14 +2,14 @@ use crate::interface::{Compiler, Result}; use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo}; use rustc_incremental::DepGraphFuture; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, Lock}; use rustc::session::config::{Input, OutputFilenames, OutputType}; use rustc::session::Session; use rustc::util::common::{time, ErrorReported}; use rustc::util::profiling::ProfileCategory; use rustc::lint; use rustc::hir; -use rustc::hir::def_id::LOCAL_CRATE; + use rustc::hir::def_id::LOCAL_CRATE; use rustc::ty; use rustc::ty::steal::Steal; use rustc::dep_graph::DepGraph; @@ -18,7 +18,7 @@ use rustc_plugin::registry::Registry; use serialize::json; use std::cell::{Ref, RefMut, RefCell}; use std::ops::Deref; -use std::rc::Rc; +use std::sync::Arc; use std::sync::mpsc; use std::any::Any; use std::mem; @@ -88,14 +88,12 @@ pub(crate) struct Queries { parse: Query, crate_name: Query, register_plugins: Query<(ast::Crate, PluginInfo)>, - expansion: Query<(ast::Crate, Rc>>)>, + expansion: Query<(ast::Crate, Lrc>>)>, dep_graph: Query, - lower_to_hir: Query<(Steal, ExpansionResult)>, - prepare_outputs: Query, codegen_channel: Query<(Steal>>, Steal>>)>, global_ctxt: Query, - ongoing_codegen: Query>, + ongoing_codegen: Query<(Box, Arc)>, link: Query<()>, } @@ -112,7 +110,7 @@ impl Compiler { pub fn parse(&self) -> Result<&Query> { self.queries.parse.compute(|| { - passes::parse(self.session(), &self.input).map_err( + passes::parse(self.session(), self.input()).map_err( |mut parse_error| { parse_error.emit(); ErrorReported @@ -145,7 +143,7 @@ impl Compiler { None => rustc_codegen_utils::link::find_crate_name( Some(self.session()), &krate.attrs, - &self.input + self.input(), ), }; Ok(result) @@ -154,7 +152,7 @@ impl Compiler { pub fn expansion( &self - ) -> Result<&Query<(ast::Crate, Rc>>)>> { + ) -> Result<&Query<(ast::Crate, Lrc>>)>> { self.queries.expansion.compute(|| { let crate_name = self.crate_name()?.peek().clone(); let (krate, plugin_info) = self.register_plugins()?.take(); @@ -164,7 +162,7 @@ impl Compiler { krate, &crate_name, plugin_info, - ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver))))) + ).map(|(krate, resolver)| (krate, Lrc::new(Some(Lock::new(resolver))))) }) } @@ -185,36 +183,6 @@ impl Compiler { }) } - pub fn lower_to_hir(&self) -> Result<&Query<(Steal, ExpansionResult)>> { - self.queries.lower_to_hir.compute(|| { - let expansion_result = self.expansion()?; - let (krate, resolver) = expansion_result.take(); - let resolver_ref = &*resolver; - let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| { - passes::lower_to_hir( - self.session(), - self.cstore(), - resolver, - &*self.dep_graph()?.peek(), - &krate - ) - })?); - expansion_result.give((krate, Rc::new(None))); - Ok((hir, BoxedResolver::to_expansion_result(resolver))) - }) - } - - pub fn prepare_outputs(&self) -> Result<&Query> { - self.queries.prepare_outputs.compute(|| { - self.lower_to_hir()?; - let krate = self.expansion()?; - let krate = krate.peek(); - let crate_name = self.crate_name()?; - let crate_name = crate_name.peek(); - passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name) - }) - } - pub fn codegen_channel(&self) -> Result<&Query<(Steal>>, Steal>>)>> { self.queries.codegen_channel.compute(|| { @@ -226,38 +194,37 @@ impl Compiler { pub fn global_ctxt(&self) -> Result<&Query> { self.queries.global_ctxt.compute(|| { let crate_name = self.crate_name()?.peek().clone(); - let outputs = self.prepare_outputs()?.peek().clone(); - let hir = self.lower_to_hir()?; - let hir = hir.peek(); - let (ref hir_forest, ref expansion) = *hir; + let expansion_result = self.expansion()?; + let (krate, resolver) = expansion_result.take(); let tx = self.codegen_channel()?.peek().0.steal(); Ok(passes::create_global_ctxt( self, - hir_forest.steal(), - expansion.defs.steal(), - expansion.resolutions.steal(), - outputs, + self.dep_graph()?.peek().clone(), + krate, + Box::new(resolver), + self.io.clone(), tx, &crate_name)) }) } - pub fn ongoing_codegen(&self) -> Result<&Query>> { + pub fn ongoing_codegen(&self) -> Result<&Query<(Box, Arc)>> { self.queries.ongoing_codegen.compute(|| { let rx = self.codegen_channel()?.peek().1.steal(); - let outputs = self.prepare_outputs()?; self.global_ctxt()?.peek_mut().enter(|tcx| { tcx.analysis(LOCAL_CRATE).ok(); // Don't do code generation if there were any errors self.session().compile_status()?; - Ok(passes::start_codegen( + let outputs = tcx.prepare_outputs(())?; + + Ok((passes::start_codegen( &***self.codegen_backend(), tcx, rx, - &*outputs.peek() - )) + &outputs, + ), outputs)) }) }) } @@ -266,13 +233,13 @@ impl Compiler { self.queries.link.compute(|| { let sess = self.session(); - let ongoing_codegen = self.ongoing_codegen()?.take(); + let (ongoing_codegen, outputs) = self.ongoing_codegen()?.take(); self.codegen_backend().join_codegen_and_link( ongoing_codegen, sess, &*self.dep_graph()?.peek(), - &*self.prepare_outputs()?.peek(), + &outputs, ).map_err(|_| ErrorReported)?; Ok(()) @@ -280,7 +247,10 @@ impl Compiler { } pub fn compile(&self) -> Result<()> { - self.prepare_outputs()?; + self.global_ctxt()?.peek_mut().enter(|tcx| { + tcx.prepare_outputs(())?; + Ok(()) + })?; if self.session().opts.output_types.contains_key(&OutputType::DepInfo) && self.session().opts.output_types.len() == 1 @@ -288,10 +258,13 @@ impl Compiler { return Ok(()) } - self.global_ctxt()?; - // Drop AST after creating GlobalCtxt to free memory - mem::drop(self.expansion()?.take()); + self.global_ctxt()?.peek_mut().enter(|tcx| { + tcx.lower_ast_to_hir(())?; + // Drop AST after lowering HIR to free memory + mem::drop(tcx.ast_crate.steal()); + Ok(()) + })?; self.ongoing_codegen()?; diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index ffc66ec16de13..4cfa9c07e95a0 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -154,7 +154,8 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { // If the extern crate isn't in the extern prelude, // there is no way it can be written as an `use`. let orig_name = extern_crate.orig_name.unwrap_or(item.ident.name); - if !tcx.extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) { + if !tcx.lowered_hir() + .extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) { continue; } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c391baabee06b..e3bafd3435019 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -25,9 +25,8 @@ use parking_lot::ReentrantMutex; use std::cell::RefCell; use std::mem; -use rustc_data_structures::sync::{self, Lrc}; +use rustc_data_structures::sync::{self, Lrc, Lock}; use std::sync::Arc; -use std::rc::Rc; use crate::visit_ast::RustdocVisitor; use crate::config::{Options as RustdocOptions, RenderOptions}; @@ -45,7 +44,7 @@ pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'tcx> { pub tcx: TyCtxt<'tcx>, - pub resolver: Rc>>, + pub resolver: Lrc>>, /// The stack of module NodeIds up till this point pub crate_name: Option, pub cstore: Lrc, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 63545ab45bf64..46a697d654cc7 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -77,28 +77,29 @@ pub fn run(options: Options) -> i32 { let display_warnings = options.display_warnings; let tests = interface::run_compiler(config, |compiler| -> Result<_, ErrorReported> { - let lower_to_hir = compiler.lower_to_hir()?; - - let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate()); - opts.display_warnings |= options.display_warnings; - let mut collector = Collector::new( - compiler.crate_name()?.peek().to_string(), - options.cfgs, - options.libs, - options.codegen_options, - options.externs, - false, - opts, - options.maybe_sysroot, - Some(compiler.source_map().clone()), - None, - options.linker, - options.edition, - options.persist_doctests, - ); - let mut global_ctxt = compiler.global_ctxt()?.take(); + global_ctxt.enter(|tcx| { + let lower_to_hir = tcx.lower_ast_to_hir(())?; + + let mut opts = scrape_test_config(lower_to_hir.forest.krate()); + opts.display_warnings |= options.display_warnings; + let mut collector = Collector::new( + compiler.crate_name()?.peek().to_string(), + options.cfgs, + options.libs, + options.codegen_options, + options.externs, + false, + opts, + options.maybe_sysroot, + Some(compiler.source_map().clone()), + None, + options.linker, + options.edition, + options.persist_doctests, + ); + let krate = tcx.hir().krate(); let mut hir_collector = HirCollector { sess: compiler.session(), @@ -110,9 +111,8 @@ pub fn run(options: Options) -> i32 { hir_collector.visit_testable("".to_string(), &krate.attrs, |this| { intravisit::walk_crate(this, krate); }); - }); - - Ok(collector.tests) + Ok(collector.tests) + }) }).expect("compiler aborted in rustdoc!"); test_args.insert(0, "rustdoctest".to_string());