diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index e379f2aa10b4..223bed5d635e 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -163,6 +163,8 @@ macro_rules! arena_types { [] where_predicate: rustc_hir::WherePredicate<$tcx>, // HIR query types + [few] hir_map: rustc::hir::map::Map<$tcx>, + [few] hir_definitions: rustc::hir::map::definitions::Definitions, [] hir_owner: rustc::hir::HirOwner<$tcx>, [] hir_owner_items: rustc::hir::HirOwnerItems<$tcx>, ], $tcx); diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index a192cf52969f..0ac8f403cb7c 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -209,6 +209,12 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { FxHashMap>, Svh, ) { + // Insert bodies into the map + for (id, body) in self.krate.bodies.iter() { + let bodies = &mut self.owner_items_map.get_mut(&id.hir_id.owner).unwrap().bodies; + assert!(bodies.insert(id.hir_id.local_id, body).is_none()); + } + self.hir_body_nodes.sort_unstable_by_key(|bn| bn.0); let node_hashes = self.hir_body_nodes.iter().fold( diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs index f176f9243437..ef000f23d8ba 100644 --- a/src/librustc/hir/map/hir_id_validator.rs +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -1,15 +1,15 @@ -use crate::hir::map::Map; -use rustc_data_structures::fx::FxHashSet; +use crate::hir::map::EarlyMap; +/*use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc_hir::intravisit; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{HirId, ItemLocalId}; +use rustc_hir::{HirId, ItemLocalId};*/ -pub fn check_crate(hir_map: &Map<'_>, sess: &rustc_session::Session) { +pub fn check_crate(hir_map: &EarlyMap<'_>, sess: &rustc_session::Session) { hir_map.dep_graph.assert_ignored(); - + /* let errors = Lock::new(Vec::new()); par_iter(&hir_map.krate.modules).for_each(|(module_id, _)| { @@ -25,23 +25,23 @@ pub fn check_crate(hir_map: &Map<'_>, sess: &rustc_session::Session) { if !errors.is_empty() { let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); sess.delay_span_bug(rustc_span::DUMMY_SP, &message); - } + }*/ } - +/* struct HirIdValidator<'a, 'hir> { - hir_map: &'a Map<'hir>, + hir_map: &'a EarlyMap<'hir>, owner_def_index: Option, hir_ids_seen: FxHashSet, errors: &'a Lock>, } struct OuterVisitor<'a, 'hir> { - hir_map: &'a Map<'hir>, + hir_map: &'a EarlyMap<'hir>, errors: &'a Lock>, } impl<'a, 'hir> OuterVisitor<'a, 'hir> { - fn new_inner_visitor(&self, hir_map: &'a Map<'hir>) -> HirIdValidator<'a, 'hir> { + fn new_inner_visitor(&self, hir_map: &'a EarlyMap<'hir>) -> HirIdValidator<'a, 'hir> { HirIdValidator { hir_map, owner_def_index: None, @@ -133,7 +133,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { } impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { - type Map = Map<'hir>; + type Map = EarlyMap<'hir>; fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { intravisit::NestedVisitorMap::OnlyBodies(self.hir_map) @@ -173,3 +173,4 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { // different owner. } } +*/ diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 16b4047bd152..6b22ac01a067 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -8,6 +8,7 @@ use crate::dep_graph::{DepGraph, DepKind, DepNode, DepNodeIndex}; use crate::hir::{HirOwner, HirOwnerItems}; use crate::middle::cstore::CrateStoreDyn; use crate::ty::query::Providers; +use crate::ty::TyCtxt; use rustc_ast::ast::{self, Name, NodeId}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; @@ -138,9 +139,8 @@ impl<'hir> Entry<'hir> { pub(super) type HirEntryMap<'hir> = IndexVec>>>; /// Represents a mapping from `NodeId`s to AST elements and their parent `NodeId`s. -#[derive(Clone)] -pub struct Map<'hir> { - krate: &'hir Crate<'hir>, +pub struct EarlyMap<'hir> { + pub krate: &'hir Crate<'hir>, pub dep_graph: DepGraph, @@ -150,12 +150,34 @@ pub struct Map<'hir> { pub(super) owner_map: FxHashMap>, pub(super) owner_items_map: FxHashMap>, - map: HirEntryMap<'hir>, + pub(super) map: HirEntryMap<'hir>, - definitions: Definitions, + pub(crate) definitions: &'hir Definitions, /// The reverse mapping of `node_to_hir_id`. - hir_to_node_id: FxHashMap, + pub(super) hir_to_node_id: FxHashMap, +} + +/// Represents a mapping from `NodeId`s to AST elements and their parent `NodeId`s. +pub struct Map<'hir> { + pub(super) tcx: TyCtxt<'hir>, + + pub(super) krate: &'hir Crate<'hir>, + + pub dep_graph: DepGraph, + + /// The SVH of the local crate. + pub crate_hash: Svh, + + pub(super) owner_map: FxHashMap>, + pub(super) owner_items_map: FxHashMap>, + + pub(super) map: HirEntryMap<'hir>, + + pub(super) definitions: &'hir Definitions, + + /// The reverse mapping of `node_to_hir_id`. + pub(super) hir_to_node_id: FxHashMap, } /// An iterator that walks up the ancestor tree of a given `HirId`. @@ -406,11 +428,11 @@ impl<'hir> Map<'hir> { } pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { - self.read(id.hir_id); - - // N.B., intentionally bypass `self.krate()` so that we - // do not trigger a read of the whole krate here - self.krate.body(id) + self.tcx + .hir_owner_items(DefId::local(id.hir_id.owner)) + .bodies + .get(&id.hir_id.local_id) + .unwrap() } pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { @@ -966,45 +988,6 @@ impl<'hir> Map<'hir> { attrs.unwrap_or(&[]) } - /// Returns an iterator that yields all the hir ids in the map. - fn all_ids<'a>(&'a self) -> impl Iterator + 'a { - // This code is a bit awkward because the map is implemented as 2 levels of arrays, - // see the comment on `HirEntryMap`. - // Iterate over all the indices and return a reference to - // local maps and their index given that they exist. - self.map.iter_enumerated().flat_map(move |(owner, local_map)| { - // Iterate over each valid entry in the local map. - local_map.iter_enumerated().filter_map(move |(i, entry)| { - entry.map(move |_| { - // Reconstruct the `HirId` based on the 3 indices we used to find it. - HirId { owner, local_id: i } - }) - }) - }) - } - - /// Returns an iterator that yields the node id's with paths that - /// match `parts`. (Requires `parts` is non-empty.) - /// - /// For example, if given `parts` equal to `["bar", "quux"]`, then - /// the iterator will produce node id's for items with paths - /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and - /// any other such items it can find in the map. - pub fn nodes_matching_suffix<'a>( - &'a self, - parts: &'a [String], - ) -> impl Iterator + 'a { - let nodes = NodesMatchingSuffix { - map: self, - item_name: parts.last().unwrap(), - in_which: &parts[..parts.len() - 1], - }; - - self.all_ids() - .filter(move |hir| nodes.matches_suffix(*hir)) - .map(move |hir| self.hir_to_node_id(hir)) - } - pub fn span(&self, hir_id: HirId) -> Span { self.read(hir_id); // reveals span from node match self.find_entry(hir_id).map(|entry| entry.node) { @@ -1087,82 +1070,6 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub struct NodesMatchingSuffix<'a> { - map: &'a Map<'a>, - item_name: &'a String, - in_which: &'a [String], -} - -impl<'a> NodesMatchingSuffix<'a> { - /// Returns `true` only if some suffix of the module path for parent - /// matches `self.in_which`. - /// - /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; - /// returns true if parent's path ends with the suffix - /// `x_0::x_1::...::x_k`. - fn suffix_matches(&self, parent: HirId) -> bool { - let mut cursor = parent; - for part in self.in_which.iter().rev() { - let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) { - None => return false, - Some((node_id, name)) => (node_id, name), - }; - if mod_name.as_str() != *part { - return false; - } - cursor = self.map.get_parent_item(mod_id); - } - return true; - - // Finds the first mod in parent chain for `id`, along with - // that mod's name. - // - // If `id` itself is a mod named `m` with parent `p`, then - // returns `Some(id, m, p)`. If `id` has no mod in its parent - // chain, then returns `None`. - fn find_first_mod_parent(map: &Map<'_>, mut id: HirId) -> Option<(HirId, Name)> { - loop { - if let Node::Item(item) = map.find(id)? { - if item_is_mod(&item) { - return Some((id, item.ident.name)); - } - } - let parent = map.get_parent_item(id); - if parent == id { - return None; - } - id = parent; - } - - fn item_is_mod(item: &Item<'_>) -> bool { - match item.kind { - ItemKind::Mod(_) => true, - _ => false, - } - } - } - } - - // We are looking at some node `n` with a given name and parent - // id; do their names match what I am seeking? - fn matches_names(&self, parent_of_n: HirId, name: Name) -> bool { - name.as_str() == *self.item_name && self.suffix_matches(parent_of_n) - } - - fn matches_suffix(&self, hir: HirId) -> bool { - let name = match self.map.find_entry(hir).map(|entry| entry.node) { - Some(Node::Item(n)) => n.name(), - Some(Node::ForeignItem(n)) => n.name(), - Some(Node::TraitItem(n)) => n.name(), - Some(Node::ImplItem(n)) => n.name(), - Some(Node::Variant(n)) => n.name(), - Some(Node::Field(n)) => n.name(), - _ => return false, - }; - self.matches_names(self.map.get_parent_item(hir), name) - } -} - trait Named { fn name(&self) -> Name; } @@ -1211,7 +1118,7 @@ pub fn map_crate<'hir>( krate: &'hir Crate<'hir>, dep_graph: DepGraph, definitions: Definitions, -) -> Map<'hir> { +) -> EarlyMap<'hir> { let _prof_timer = sess.prof.generic_activity("build_hir_map"); // Build the reverse mapping of `node_to_hir_id`. @@ -1233,7 +1140,7 @@ pub fn map_crate<'hir>( collector.finalize_and_compute_crate_hash(crate_disambiguator, cstore, cmdline_args) }; - let map = Map { + let map = EarlyMap { krate, dep_graph, crate_hash, @@ -1241,7 +1148,7 @@ pub fn map_crate<'hir>( owner_map, owner_items_map: owner_items_map.into_iter().map(|(k, v)| (k, &*v)).collect(), hir_to_node_id, - definitions, + definitions: arena.alloc(definitions), }; sess.time("validate_HIR_map", || { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 57af8d250b31..d7999ee5f515 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -7,6 +7,7 @@ pub mod map; use crate::ty::query::Providers; use crate::ty::TyCtxt; +use rustc_data_structures::cold_path; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::print; @@ -68,7 +69,17 @@ impl<'hir> print::PpAnn for Hir<'hir> { impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn hir(self) -> Hir<'tcx> { - Hir { tcx: self, map: &self.hir_map } + let map = self.late_hir_map.load(); + let map = if unlikely!(map.is_none()) { + cold_path(|| { + let map = self.hir_map(LOCAL_CRATE); + self.late_hir_map.store(Some(map)); + map + }) + } else { + map.unwrap() + }; + Hir { tcx: self, map } } pub fn parent_module(self, id: HirId) -> DefId { @@ -81,6 +92,35 @@ pub fn provide(providers: &mut Providers<'_>) { let hir = tcx.hir(); hir.local_def_id(hir.get_module_parent_node(hir.as_local_hir_id(id).unwrap())) }; - providers.hir_crate = |tcx, _| tcx.hir_map.untracked_krate(); + providers.hir_crate = |tcx, _| tcx.hir_map(LOCAL_CRATE).untracked_krate(); + providers.hir_map = |tcx, id| { + assert_eq!(id, LOCAL_CRATE); + let early = tcx.hir_map.steal(); + tcx.arena.alloc(map::Map { + tcx, + krate: early.krate, + + dep_graph: early.dep_graph, + + crate_hash: early.crate_hash, + + owner_map: early.owner_map, + owner_items_map: early.owner_items_map, + + map: early.map, + + definitions: early.definitions, + + hir_to_node_id: early.hir_to_node_id, + }) + }; + providers.hir_owner = |tcx, id| { + assert_eq!(id.krate, LOCAL_CRATE); + *tcx.hir().map.owner_map.get(&id.index).unwrap() + }; + providers.hir_owner_items = |tcx, id| { + assert_eq!(id.krate, LOCAL_CRATE); + *tcx.hir().map.owner_items_map.get(&id.index).unwrap() + }; map::provide(providers); } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index cf7cb30a056d..b843bc17d2c6 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -55,6 +55,12 @@ rustc_queries! { desc { "get the crate HIR" } } + query hir_map(_: CrateNum) -> &'tcx map::Map<'tcx> { + eval_always + no_hash + desc { "index HIR" } + } + query hir_owner(key: DefId) -> &'tcx HirOwner<'tcx> { eval_always } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6fab55e9fd93..cff93015d047 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -5,6 +5,7 @@ use crate::dep_graph::DepGraph; use crate::dep_graph::{self, DepConstructor}; use crate::hir::exports::Export; use crate::hir::map as hir_map; +use crate::hir::map::definitions::Definitions; use crate::hir::map::{DefPathData, DefPathHash}; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; @@ -52,7 +53,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{ hash_stable_hashmap, HashStable, StableHasher, StableVec, }; -use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; +use rustc_data_structures::sync::{self, AtomicCell, Lock, Lrc, WorkerLocal}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE}; @@ -971,8 +972,11 @@ pub struct GlobalCtxt<'tcx> { /// Export map produced by name resolution. export_map: FxHashMap>>, - /// This should usually be accessed with the `tcx.hir()` method. - pub(crate) hir_map: hir_map::Map<'tcx>, + /// These should usually be accessed with the `tcx.hir()` method. + pub(crate) hir_map: Steal>, + pub(crate) late_hir_map: AtomicCell>>, + pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>, + pub(crate) definitions: &'tcx Definitions, /// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate /// as well as all upstream crates. Only populated in incremental mode. @@ -1116,7 +1120,7 @@ impl<'tcx> TyCtxt<'tcx> { extern_providers: ty::query::Providers<'tcx>, arena: &'tcx WorkerLocal>, resolutions: ty::ResolverOutputs, - hir: hir_map::Map<'tcx>, + hir: hir_map::EarlyMap<'tcx>, on_disk_query_result_cache: query::OnDiskCache<'tcx>, crate_name: &str, output_filenames: &OutputFilenames, @@ -1129,6 +1133,7 @@ impl<'tcx> TyCtxt<'tcx> { let common_lifetimes = CommonLifetimes::new(&interners); let common_consts = CommonConsts::new(&interners, &common_types); let dep_graph = hir.dep_graph.clone(); + let definitions = hir.definitions; let cstore = resolutions.cstore; let crates = cstore.crates_untracked(); let max_cnum = crates.iter().map(|c| c.as_usize()).max().unwrap_or(0); @@ -1139,7 +1144,7 @@ impl<'tcx> TyCtxt<'tcx> { let def_path_tables = crates .iter() .map(|&cnum| (cnum, cstore.def_path_table(cnum))) - .chain(iter::once((LOCAL_CRATE, hir.definitions().def_path_table()))); + .chain(iter::once((LOCAL_CRATE, definitions.def_path_table()))); // Precompute the capacity of the hashmap so we don't have to // re-allocate when populating it. @@ -1159,11 +1164,11 @@ impl<'tcx> TyCtxt<'tcx> { 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 hir_id = definitions.node_to_hir_id(k); let map = trait_map.entry(hir_id.owner).or_default(); let v = v .into_iter() - .map(|tc| tc.map_import_ids(|id| hir.definitions().node_to_hir_id(id))) + .map(|tc| tc.map_import_ids(|id| definitions.node_to_hir_id(id))) .collect(); map.insert(hir_id.local_id, StableVec::new(v)); } @@ -1185,28 +1190,33 @@ impl<'tcx> TyCtxt<'tcx> { .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(); + let exports: Vec<_> = v + .into_iter() + .map(|e| e.map_id(|id| definitions.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)) + .map(|id| definitions.local_def_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)) + .map(|(id, sp)| (definitions.local_def_id(id), sp)) .collect(), glob_map: resolutions .glob_map .into_iter() - .map(|(id, names)| (hir.local_def_id_from_node_id(id), names)) + .map(|(id, names)| (definitions.local_def_id(id), names)) .collect(), extern_prelude: resolutions.extern_prelude, - hir_map: hir, + untracked_crate: hir.krate, + hir_map: Steal::new(hir), + late_hir_map: AtomicCell::new(None), + definitions, def_path_hash_to_def_id, queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache), rcache: Default::default(), @@ -1286,7 +1296,7 @@ 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) + self.definitions.def_path_hash(def_id.index) } else { self.cstore.def_path_hash(def_id) } @@ -1333,9 +1343,9 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.hir_map.untracked_krate(); + let krate = self.gcx.untracked_crate; - StableHashingContext::new(self.sess, krate, self.hir().definitions(), &*self.cstore) + StableHashingContext::new(self.sess, krate, self.definitions, &*self.cstore) } // This method makes sure that we have a DepNode and a Fingerprint for diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 667c00a3df16..b6976221ef7d 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -1,5 +1,6 @@ use crate::dep_graph::{self, DepConstructor, DepNode, DepNodeParams}; use crate::hir::exports::Export; +use crate::hir::map; use crate::hir::{HirOwner, HirOwnerItems}; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap;