Skip to content

Commit d7f4a86

Browse files
committed
Auto merge of #60246 - Zoxc:hir-map-vec, r=eddyb
Optimize HIR map Builds on #59042 cc @ljedrz r? @eddyb
2 parents b92d360 + d33db6e commit d7f4a86

File tree

4 files changed

+102
-60
lines changed

4 files changed

+102
-60
lines changed

src/librustc/hir/map/collector.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use super::*;
22
use crate::dep_graph::{DepGraph, DepKind, DepNodeIndex};
33
use crate::hir;
4+
use crate::hir::map::HirEntryMap;
45
use crate::hir::def_id::{LOCAL_CRATE, CrateNum};
56
use crate::hir::intravisit::{Visitor, NestedVisitorMap};
67
use rustc_data_structures::svh::Svh;
8+
use rustc_data_structures::indexed_vec::IndexVec;
79
use crate::ich::Fingerprint;
810
use crate::middle::cstore::CrateStore;
911
use crate::session::CrateDisambiguator;
@@ -12,6 +14,7 @@ use crate::util::nodemap::FxHashMap;
1214
use syntax::ast::NodeId;
1315
use syntax::source_map::SourceMap;
1416
use syntax_pos::Span;
17+
use std::iter::repeat;
1518

1619
use crate::ich::StableHashingContext;
1720
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
@@ -25,7 +28,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
2528
source_map: &'a SourceMap,
2629

2730
/// The node map
28-
map: FxHashMap<HirId, Entry<'hir>>,
31+
map: HirEntryMap<'hir>,
2932
/// The parent of this node
3033
parent_node: hir::HirId,
3134

@@ -142,11 +145,15 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
142145
);
143146
}
144147

148+
let (lo, hi) = definitions.def_index_counts_lo_hi();
149+
145150
let mut collector = NodeCollector {
146151
krate,
147152
source_map: sess.source_map(),
148-
map: FxHashMap::with_capacity_and_hasher(sess.current_node_id_count(),
149-
Default::default()),
153+
map: [
154+
repeat(None).take(lo).collect(),
155+
repeat(None).take(hi).collect(),
156+
],
150157
parent_node: hir::CRATE_HIR_ID,
151158
current_signature_dep_index: root_mod_sig_dep_index,
152159
current_full_dep_index: root_mod_full_dep_index,
@@ -171,7 +178,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
171178
crate_disambiguator: CrateDisambiguator,
172179
cstore: &dyn CrateStore,
173180
commandline_args_hash: u64)
174-
-> (FxHashMap<HirId, Entry<'hir>>, Svh)
181+
-> (HirEntryMap<'hir>, Svh)
175182
{
176183
self.hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
177184

@@ -224,7 +231,17 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
224231

225232
fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>) {
226233
debug!("hir_map: {:?} => {:?}", id, entry);
227-
self.map.insert(id, entry);
234+
let local_map = &mut self.map[id.owner.address_space().index()][id.owner.as_array_index()];
235+
let i = id.local_id.as_u32() as usize;
236+
if local_map.is_none() {
237+
*local_map = Some(IndexVec::with_capacity(i + 1));
238+
}
239+
let local_map = local_map.as_mut().unwrap();
240+
let len = local_map.len();
241+
if i >= len {
242+
local_map.extend(repeat(None).take(i - len + 1));
243+
}
244+
local_map[id.local_id] = Some(entry);
228245
}
229246

230247
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {

src/librustc/hir/map/mod.rs

+73-47
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::middle::cstore::CrateStoreDyn;
1111

1212
use rustc_target::spec::abi::Abi;
1313
use rustc_data_structures::svh::Svh;
14+
use rustc_data_structures::indexed_vec::IndexVec;
1415
use syntax::ast::{self, Name, NodeId};
1516
use syntax::source_map::Spanned;
1617
use syntax::ext::base::MacroKind;
@@ -161,6 +162,13 @@ impl Forest {
161162
}
162163
}
163164

165+
/// This type is effectively a `HashMap<HirId, Entry<'hir>>`,
166+
/// but is implemented by 3 layers of arrays.
167+
/// - the outer layer is `[A; 2]` and correspond to the 2 address spaces `DefIndex`es can be in
168+
/// - then we have `A = Vec<Option<B>>` mapping a `DefIndex`'s index to a inner value
169+
/// - which is `B = IndexVec<ItemLocalId, Option<Entry<'hir>>` which finally gives you the `Entry`.
170+
pub(super) type HirEntryMap<'hir> = [Vec<Option<IndexVec<ItemLocalId, Option<Entry<'hir>>>>>; 2];
171+
164172
/// Represents a mapping from `NodeId`s to AST elements and their parent `NodeId`s.
165173
#[derive(Clone)]
166174
pub struct Map<'hir> {
@@ -174,7 +182,7 @@ pub struct Map<'hir> {
174182
/// The SVH of the local crate.
175183
pub crate_hash: Svh,
176184

177-
map: FxHashMap<HirId, Entry<'hir>>,
185+
map: HirEntryMap<'hir>,
178186

179187
definitions: &'hir Definitions,
180188

@@ -183,6 +191,12 @@ pub struct Map<'hir> {
183191
}
184192

185193
impl<'hir> Map<'hir> {
194+
#[inline]
195+
fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> {
196+
let local_map = self.map[id.owner.address_space().index()].get(id.owner.as_array_index())?;
197+
local_map.as_ref()?.get(id.local_id)?.as_ref()
198+
}
199+
186200
/// Registers a read in the dependency graph of the AST node with
187201
/// the given `id`. This needs to be called each time a public
188202
/// function returns the HIR for a node -- in other words, when it
@@ -191,7 +205,7 @@ impl<'hir> Map<'hir> {
191205
/// read recorded). If the function just returns a DefId or
192206
/// NodeId, no actual content was returned, so no read is needed.
193207
pub fn read(&self, hir_id: HirId) {
194-
if let Some(entry) = self.map.get(&hir_id) {
208+
if let Some(entry) = self.lookup(hir_id) {
195209
self.dep_graph.read_index(entry.dep_node);
196210
} else {
197211
bug!("called `HirMap::read()` with invalid `HirId`: {:?}", hir_id)
@@ -378,12 +392,8 @@ impl<'hir> Map<'hir> {
378392
})
379393
}
380394

381-
fn entry_count(&self) -> usize {
382-
self.map.len()
383-
}
384-
385395
fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> {
386-
self.map.get(&id).cloned()
396+
self.lookup(id).cloned()
387397
}
388398

389399
pub fn krate(&self) -> &'hir Crate {
@@ -433,7 +443,7 @@ impl<'hir> Map<'hir> {
433443
/// item (possibly associated), a closure, or a `hir::AnonConst`.
434444
pub fn body_owner(&self, BodyId { hir_id }: BodyId) -> NodeId {
435445
let parent = self.get_parent_node_by_hir_id(hir_id);
436-
assert!(self.map.get(&parent).map_or(false, |e| e.is_body_owner(hir_id)));
446+
assert!(self.lookup(parent).map_or(false, |e| e.is_body_owner(hir_id)));
437447
self.hir_to_node_id(parent)
438448
}
439449

@@ -1004,6 +1014,34 @@ impl<'hir> Map<'hir> {
10041014
attrs.unwrap_or(&[])
10051015
}
10061016

1017+
/// Returns an iterator that yields all the hir ids in the map.
1018+
fn all_ids<'a>(&'a self) -> impl Iterator<Item = HirId> + 'a {
1019+
// This code is a bit awkward because the map is implemented as 3 levels of arrays,
1020+
// see the comment on `HirEntryMap`.
1021+
let map = &self.map;
1022+
1023+
// Look at both the def index address spaces
1024+
let spaces = [DefIndexAddressSpace::Low, DefIndexAddressSpace::High].iter().cloned();
1025+
spaces.flat_map(move |space| {
1026+
// Iterate over all the indices in the address space and return a reference to
1027+
// local maps and their index given that they exist.
1028+
let local_maps = map[space.index()].iter().enumerate().filter_map(|(i, local_map)| {
1029+
local_map.as_ref().map(|m| (i, m))
1030+
});
1031+
1032+
local_maps.flat_map(move |(array_index, local_map)| {
1033+
// Iterate over each valid entry in the local map
1034+
local_map.iter_enumerated().filter_map(move |(i, entry)| entry.map(move |_| {
1035+
// Reconstruct the HirId based on the 3 indices we used to find it
1036+
HirId {
1037+
owner: DefIndex::from_array_index(array_index, space),
1038+
local_id: i,
1039+
}
1040+
}))
1041+
})
1042+
})
1043+
}
1044+
10071045
/// Returns an iterator that yields the node id's with paths that
10081046
/// match `parts`. (Requires `parts` is non-empty.)
10091047
///
@@ -1012,13 +1050,16 @@ impl<'hir> Map<'hir> {
10121050
/// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
10131051
/// any other such items it can find in the map.
10141052
pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String])
1015-
-> NodesMatchingSuffix<'a, 'hir> {
1016-
NodesMatchingSuffix {
1053+
-> impl Iterator<Item = NodeId> + 'a {
1054+
let nodes = NodesMatchingSuffix {
10171055
map: self,
10181056
item_name: parts.last().unwrap(),
10191057
in_which: &parts[..parts.len() - 1],
1020-
idx: ast::CRATE_NODE_ID,
1021-
}
1058+
};
1059+
1060+
self.all_ids().filter(move |hir| nodes.matces_suffix(*hir)).map(move |hir| {
1061+
self.hir_to_node_id(hir)
1062+
})
10221063
}
10231064

10241065
pub fn span(&self, id: NodeId) -> Span {
@@ -1097,21 +1138,20 @@ impl<'hir> Map<'hir> {
10971138
}
10981139
}
10991140

1100-
pub struct NodesMatchingSuffix<'a, 'hir:'a> {
1101-
map: &'a Map<'hir>,
1141+
pub struct NodesMatchingSuffix<'a> {
1142+
map: &'a Map<'a>,
11021143
item_name: &'a String,
11031144
in_which: &'a [String],
1104-
idx: NodeId,
11051145
}
11061146

1107-
impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> {
1147+
impl<'a> NodesMatchingSuffix<'a> {
11081148
/// Returns `true` only if some suffix of the module path for parent
11091149
/// matches `self.in_which`.
11101150
///
11111151
/// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`;
11121152
/// returns true if parent's path ends with the suffix
11131153
/// `x_0::x_1::...::x_k`.
1114-
fn suffix_matches(&self, parent: NodeId) -> bool {
1154+
fn suffix_matches(&self, parent: HirId) -> bool {
11151155
let mut cursor = parent;
11161156
for part in self.in_which.iter().rev() {
11171157
let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
@@ -1121,7 +1161,7 @@ impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> {
11211161
if mod_name != &**part {
11221162
return false;
11231163
}
1124-
cursor = self.map.get_parent(mod_id);
1164+
cursor = self.map.get_parent_item(mod_id);
11251165
}
11261166
return true;
11271167

@@ -1131,14 +1171,14 @@ impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> {
11311171
// If `id` itself is a mod named `m` with parent `p`, then
11321172
// returns `Some(id, m, p)`. If `id` has no mod in its parent
11331173
// chain, then returns `None`.
1134-
fn find_first_mod_parent<'a>(map: &'a Map<'_>, mut id: NodeId) -> Option<(NodeId, Name)> {
1174+
fn find_first_mod_parent<'a>(map: &'a Map<'_>, mut id: HirId) -> Option<(HirId, Name)> {
11351175
loop {
1136-
if let Node::Item(item) = map.find(id)? {
1176+
if let Node::Item(item) = map.find_by_hir_id(id)? {
11371177
if item_is_mod(&item) {
11381178
return Some((id, item.ident.name))
11391179
}
11401180
}
1141-
let parent = map.get_parent(id);
1181+
let parent = map.get_parent_item(id);
11421182
if parent == id { return None }
11431183
id = parent;
11441184
}
@@ -1154,35 +1194,21 @@ impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> {
11541194

11551195
// We are looking at some node `n` with a given name and parent
11561196
// id; do their names match what I am seeking?
1157-
fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool {
1197+
fn matches_names(&self, parent_of_n: HirId, name: Name) -> bool {
11581198
name == &**self.item_name && self.suffix_matches(parent_of_n)
11591199
}
1160-
}
11611200

1162-
impl<'a, 'hir> Iterator for NodesMatchingSuffix<'a, 'hir> {
1163-
type Item = NodeId;
1164-
1165-
fn next(&mut self) -> Option<NodeId> {
1166-
loop {
1167-
let idx = self.idx;
1168-
if idx.as_usize() >= self.map.entry_count() {
1169-
return None;
1170-
}
1171-
self.idx = NodeId::from_u32(self.idx.as_u32() + 1);
1172-
let hir_idx = self.map.node_to_hir_id(idx);
1173-
let name = match self.map.find_entry(hir_idx).map(|entry| entry.node) {
1174-
Some(Node::Item(n)) => n.name(),
1175-
Some(Node::ForeignItem(n)) => n.name(),
1176-
Some(Node::TraitItem(n)) => n.name(),
1177-
Some(Node::ImplItem(n)) => n.name(),
1178-
Some(Node::Variant(n)) => n.name(),
1179-
Some(Node::Field(n)) => n.name(),
1180-
_ => continue,
1181-
};
1182-
if self.matches_names(self.map.get_parent(idx), name) {
1183-
return Some(idx)
1184-
}
1185-
}
1201+
fn matces_suffix(&self, hir: HirId) -> bool {
1202+
let name = match self.map.find_entry(hir).map(|entry| entry.node) {
1203+
Some(Node::Item(n)) => n.name(),
1204+
Some(Node::ForeignItem(n)) => n.name(),
1205+
Some(Node::TraitItem(n)) => n.name(),
1206+
Some(Node::ImplItem(n)) => n.name(),
1207+
Some(Node::Variant(n)) => n.name(),
1208+
Some(Node::Field(n)) => n.name(),
1209+
_ => return false,
1210+
};
1211+
self.matches_names(self.map.get_parent_item(hir), name)
11861212
}
11871213
}
11881214

src/librustc/session/mod.rs

-3
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,6 @@ impl Session {
408408
pub fn next_node_id(&self) -> NodeId {
409409
self.reserve_node_ids(1)
410410
}
411-
pub(crate) fn current_node_id_count(&self) -> usize {
412-
self.next_node_id.get().as_u32() as usize
413-
}
414411
pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler {
415412
&self.parse_sess.span_diagnostic
416413
}

src/librustc_driver/pretty.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -543,12 +543,12 @@ impl FromStr for UserIdentifiedItem {
543543
}
544544
}
545545

546-
enum NodesMatchingUII<'a, 'hir: 'a> {
546+
enum NodesMatchingUII<'a> {
547547
NodesMatchingDirect(option::IntoIter<ast::NodeId>),
548-
NodesMatchingSuffix(hir_map::NodesMatchingSuffix<'a, 'hir>),
548+
NodesMatchingSuffix(Box<dyn Iterator<Item = ast::NodeId> + 'a>),
549549
}
550550

551-
impl<'a, 'hir> Iterator for NodesMatchingUII<'a, 'hir> {
551+
impl<'a> Iterator for NodesMatchingUII<'a> {
552552
type Item = ast::NodeId;
553553

554554
fn next(&mut self) -> Option<ast::NodeId> {
@@ -576,10 +576,12 @@ impl UserIdentifiedItem {
576576

577577
fn all_matching_node_ids<'a, 'hir>(&'a self,
578578
map: &'a hir_map::Map<'hir>)
579-
-> NodesMatchingUII<'a, 'hir> {
579+
-> NodesMatchingUII<'a> {
580580
match *self {
581581
ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
582-
ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)),
582+
ItemViaPath(ref parts) => {
583+
NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts)))
584+
}
583585
}
584586
}
585587

0 commit comments

Comments
 (0)