Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d7225dd

Browse files
committedMar 19, 2025
Auto merge of #138708 - fmease:revert-137701, r=<try>
[tentative] Revert "Convert `ShardedHashMap` to use `hashbrown::HashTable`" #138414 (comment) r? fmease
2 parents c4b38a5 + ff21e44 commit d7225dd

File tree

10 files changed

+66
-109
lines changed

10 files changed

+66
-109
lines changed
 

‎Cargo.lock

-2
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,6 @@ version = "0.15.2"
14911491
source = "registry+https://github.com/rust-lang/crates.io-index"
14921492
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
14931493
dependencies = [
1494-
"allocator-api2",
14951494
"foldhash",
14961495
"serde",
14971496
]
@@ -3502,7 +3501,6 @@ dependencies = [
35023501
"either",
35033502
"elsa",
35043503
"ena",
3505-
"hashbrown 0.15.2",
35063504
"indexmap",
35073505
"jobserver",
35083506
"libc",

‎compiler/rustc_data_structures/Cargo.toml

-5
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ thin-vec = "0.2.12"
2929
tracing = "0.1"
3030
# tidy-alphabetical-end
3131

32-
[dependencies.hashbrown]
33-
version = "0.15.2"
34-
default-features = false
35-
features = ["nightly"] # for may_dangle
36-
3732
[dependencies.parking_lot]
3833
version = "0.12"
3934

‎compiler/rustc_data_structures/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#![feature(dropck_eyepatch)]
2525
#![feature(extend_one)]
2626
#![feature(file_buffered)]
27+
#![feature(hash_raw_entry)]
2728
#![feature(macro_metavar_expr)]
2829
#![feature(map_try_insert)]
2930
#![feature(min_specialization)]

‎compiler/rustc_data_structures/src/marker.rs

-2
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ impl_dyn_send!(
7676
[crate::sync::RwLock<T> where T: DynSend]
7777
[crate::tagged_ptr::TaggedRef<'a, P, T> where 'a, P: Sync, T: Send + crate::tagged_ptr::Tag]
7878
[rustc_arena::TypedArena<T> where T: DynSend]
79-
[hashbrown::HashTable<T> where T: DynSend]
8079
[indexmap::IndexSet<V, S> where V: DynSend, S: DynSend]
8180
[indexmap::IndexMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend]
8281
[thin_vec::ThinVec<T> where T: DynSend]
@@ -154,7 +153,6 @@ impl_dyn_sync!(
154153
[crate::tagged_ptr::TaggedRef<'a, P, T> where 'a, P: Sync, T: Sync + crate::tagged_ptr::Tag]
155154
[parking_lot::lock_api::Mutex<R, T> where R: DynSync, T: ?Sized + DynSend]
156155
[parking_lot::lock_api::RwLock<R, T> where R: DynSync, T: ?Sized + DynSend + DynSync]
157-
[hashbrown::HashTable<T> where T: DynSync]
158156
[indexmap::IndexSet<V, S> where V: DynSync, S: DynSync]
159157
[indexmap::IndexMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync]
160158
[smallvec::SmallVec<A> where A: smallvec::Array + DynSync]

‎compiler/rustc_data_structures/src/sharded.rs

+17-78
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use std::borrow::Borrow;
2+
use std::collections::hash_map::RawEntryMut;
23
use std::hash::{Hash, Hasher};
3-
use std::{iter, mem};
4+
use std::iter;
45

56
use either::Either;
6-
use hashbrown::hash_table::{Entry, HashTable};
77

8-
use crate::fx::FxHasher;
8+
use crate::fx::{FxHashMap, FxHasher};
99
use crate::sync::{CacheAligned, Lock, LockGuard, Mode, is_dyn_thread_safe};
1010

1111
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
@@ -140,67 +140,17 @@ pub fn shards() -> usize {
140140
1
141141
}
142142

143-
pub type ShardedHashMap<K, V> = Sharded<HashTable<(K, V)>>;
143+
pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>;
144144

145145
impl<K: Eq, V> ShardedHashMap<K, V> {
146146
pub fn with_capacity(cap: usize) -> Self {
147-
Self::new(|| HashTable::with_capacity(cap))
147+
Self::new(|| FxHashMap::with_capacity_and_hasher(cap, rustc_hash::FxBuildHasher::default()))
148148
}
149149
pub fn len(&self) -> usize {
150150
self.lock_shards().map(|shard| shard.len()).sum()
151151
}
152152
}
153153

154-
impl<K: Eq + Hash, V> ShardedHashMap<K, V> {
155-
#[inline]
156-
pub fn get<Q>(&self, key: &Q) -> Option<V>
157-
where
158-
K: Borrow<Q>,
159-
Q: Hash + Eq,
160-
V: Clone,
161-
{
162-
let hash = make_hash(key);
163-
let shard = self.lock_shard_by_hash(hash);
164-
let (_, value) = shard.find(hash, |(k, _)| k.borrow() == key)?;
165-
Some(value.clone())
166-
}
167-
168-
#[inline]
169-
pub fn get_or_insert_with(&self, key: K, default: impl FnOnce() -> V) -> V
170-
where
171-
V: Copy,
172-
{
173-
let hash = make_hash(&key);
174-
let mut shard = self.lock_shard_by_hash(hash);
175-
176-
match table_entry(&mut shard, hash, &key) {
177-
Entry::Occupied(e) => e.get().1,
178-
Entry::Vacant(e) => {
179-
let value = default();
180-
e.insert((key, value));
181-
value
182-
}
183-
}
184-
}
185-
186-
#[inline]
187-
pub fn insert(&self, key: K, value: V) -> Option<V> {
188-
let hash = make_hash(&key);
189-
let mut shard = self.lock_shard_by_hash(hash);
190-
191-
match table_entry(&mut shard, hash, &key) {
192-
Entry::Occupied(e) => {
193-
let previous = mem::replace(&mut e.into_mut().1, value);
194-
Some(previous)
195-
}
196-
Entry::Vacant(e) => {
197-
e.insert((key, value));
198-
None
199-
}
200-
}
201-
}
202-
}
203-
204154
impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
205155
#[inline]
206156
pub fn intern_ref<Q: ?Sized>(&self, value: &Q, make: impl FnOnce() -> K) -> K
@@ -210,12 +160,13 @@ impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
210160
{
211161
let hash = make_hash(value);
212162
let mut shard = self.lock_shard_by_hash(hash);
163+
let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, value);
213164

214-
match table_entry(&mut shard, hash, value) {
215-
Entry::Occupied(e) => e.get().0,
216-
Entry::Vacant(e) => {
165+
match entry {
166+
RawEntryMut::Occupied(e) => *e.key(),
167+
RawEntryMut::Vacant(e) => {
217168
let v = make();
218-
e.insert((v, ()));
169+
e.insert_hashed_nocheck(hash, v, ());
219170
v
220171
}
221172
}
@@ -229,12 +180,13 @@ impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
229180
{
230181
let hash = make_hash(&value);
231182
let mut shard = self.lock_shard_by_hash(hash);
183+
let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, &value);
232184

233-
match table_entry(&mut shard, hash, &value) {
234-
Entry::Occupied(e) => e.get().0,
235-
Entry::Vacant(e) => {
185+
match entry {
186+
RawEntryMut::Occupied(e) => *e.key(),
187+
RawEntryMut::Vacant(e) => {
236188
let v = make(value);
237-
e.insert((v, ()));
189+
e.insert_hashed_nocheck(hash, v, ());
238190
v
239191
}
240192
}
@@ -251,30 +203,17 @@ impl<K: Eq + Hash + Copy + IntoPointer> ShardedHashMap<K, ()> {
251203
let hash = make_hash(&value);
252204
let shard = self.lock_shard_by_hash(hash);
253205
let value = value.into_pointer();
254-
shard.find(hash, |(k, ())| k.into_pointer() == value).is_some()
206+
shard.raw_entry().from_hash(hash, |entry| entry.into_pointer() == value).is_some()
255207
}
256208
}
257209

258210
#[inline]
259-
fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
211+
pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
260212
let mut state = FxHasher::default();
261213
val.hash(&mut state);
262214
state.finish()
263215
}
264216

265-
#[inline]
266-
fn table_entry<'a, K, V, Q>(
267-
table: &'a mut HashTable<(K, V)>,
268-
hash: u64,
269-
key: &Q,
270-
) -> Entry<'a, (K, V)>
271-
where
272-
K: Hash + Borrow<Q>,
273-
Q: ?Sized + Eq,
274-
{
275-
table.entry(hash, move |(k, _)| k.borrow() == key, |(k, _)| make_hash(k))
276-
}
277-
278217
/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
279218
/// ever used in combination with `get_shard_by_hash` on a single `Sharded`
280219
/// instance, then `hash` must be computed with `FxHasher`. Otherwise,

‎compiler/rustc_middle/src/mir/interpret/mod.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,12 @@ impl<'tcx> TyCtxt<'tcx> {
452452
}
453453
let id = self.alloc_map.reserve();
454454
debug!("creating alloc {:?} with id {id:?}", alloc_salt.0);
455-
let had_previous = self.alloc_map.to_alloc.insert(id, alloc_salt.0.clone()).is_some();
455+
let had_previous = self
456+
.alloc_map
457+
.to_alloc
458+
.lock_shard_by_value(&id)
459+
.insert(id, alloc_salt.0.clone())
460+
.is_some();
456461
// We just reserved, so should always be unique.
457462
assert!(!had_previous);
458463
dedup.insert(alloc_salt, id);
@@ -505,7 +510,7 @@ impl<'tcx> TyCtxt<'tcx> {
505510
/// local dangling pointers and allocations in constants/statics.
506511
#[inline]
507512
pub fn try_get_global_alloc(self, id: AllocId) -> Option<GlobalAlloc<'tcx>> {
508-
self.alloc_map.to_alloc.get(&id)
513+
self.alloc_map.to_alloc.lock_shard_by_value(&id).get(&id).cloned()
509514
}
510515

511516
#[inline]
@@ -524,16 +529,21 @@ impl<'tcx> TyCtxt<'tcx> {
524529
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
525530
/// call this function twice, even with the same `Allocation` will ICE the compiler.
526531
pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
527-
if let Some(old) = self.alloc_map.to_alloc.insert(id, GlobalAlloc::Memory(mem)) {
532+
if let Some(old) =
533+
self.alloc_map.to_alloc.lock_shard_by_value(&id).insert(id, GlobalAlloc::Memory(mem))
534+
{
528535
bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}");
529536
}
530537
}
531538

532539
/// Freezes an `AllocId` created with `reserve` by pointing it at a static item. Trying to
533540
/// call this function twice, even with the same `DefId` will ICE the compiler.
534541
pub fn set_nested_alloc_id_static(self, id: AllocId, def_id: LocalDefId) {
535-
if let Some(old) =
536-
self.alloc_map.to_alloc.insert(id, GlobalAlloc::Static(def_id.to_def_id()))
542+
if let Some(old) = self
543+
.alloc_map
544+
.to_alloc
545+
.lock_shard_by_value(&id)
546+
.insert(id, GlobalAlloc::Static(def_id.to_def_id()))
537547
{
538548
bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}");
539549
}

‎compiler/rustc_middle/src/ty/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2335,8 +2335,8 @@ macro_rules! sty_debug_print {
23352335
$(let mut $variant = total;)*
23362336

23372337
for shard in tcx.interners.type_.lock_shards() {
2338-
let types = shard.iter();
2339-
for &(InternedInSet(t), ()) in types {
2338+
let types = shard.keys();
2339+
for &InternedInSet(t) in types {
23402340
let variant = match t.internee {
23412341
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
23422342
ty::Float(..) | ty::Str | ty::Never => continue,

‎compiler/rustc_query_system/src/dep_graph/graph.rs

+20-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::assert_matches::assert_matches;
2+
use std::collections::hash_map::Entry;
23
use std::fmt::Debug;
34
use std::hash::Hash;
45
use std::marker::PhantomData;
@@ -8,7 +9,7 @@ use std::sync::atomic::{AtomicU32, Ordering};
89
use rustc_data_structures::fingerprint::Fingerprint;
910
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1011
use rustc_data_structures::profiling::{QueryInvocationId, SelfProfilerRef};
11-
use rustc_data_structures::sharded::{self, ShardedHashMap};
12+
use rustc_data_structures::sharded::{self, Sharded};
1213
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1314
use rustc_data_structures::sync::{AtomicU64, Lock};
1415
use rustc_data_structures::unord::UnordMap;
@@ -618,7 +619,7 @@ impl<D: Deps> DepGraphData<D> {
618619
if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) {
619620
self.current.prev_index_to_index.lock()[prev_index]
620621
} else {
621-
self.current.new_node_to_index.get(dep_node)
622+
self.current.new_node_to_index.lock_shard_by_value(dep_node).get(dep_node).copied()
622623
}
623624
}
624625

@@ -1047,7 +1048,7 @@ rustc_index::newtype_index! {
10471048
/// first, and `data` second.
10481049
pub(super) struct CurrentDepGraph<D: Deps> {
10491050
encoder: GraphEncoder<D>,
1050-
new_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
1051+
new_node_to_index: Sharded<FxHashMap<DepNode, DepNodeIndex>>,
10511052
prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>,
10521053

10531054
/// This is used to verify that fingerprints do not change between the creation of a node
@@ -1116,9 +1117,12 @@ impl<D: Deps> CurrentDepGraph<D> {
11161117
profiler,
11171118
previous,
11181119
),
1119-
new_node_to_index: ShardedHashMap::with_capacity(
1120-
new_node_count_estimate / sharded::shards(),
1121-
),
1120+
new_node_to_index: Sharded::new(|| {
1121+
FxHashMap::with_capacity_and_hasher(
1122+
new_node_count_estimate / sharded::shards(),
1123+
Default::default(),
1124+
)
1125+
}),
11221126
prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)),
11231127
anon_id_seed,
11241128
#[cfg(debug_assertions)]
@@ -1148,9 +1152,14 @@ impl<D: Deps> CurrentDepGraph<D> {
11481152
edges: EdgesVec,
11491153
current_fingerprint: Fingerprint,
11501154
) -> DepNodeIndex {
1151-
let dep_node_index = self
1152-
.new_node_to_index
1153-
.get_or_insert_with(key, || self.encoder.send(key, current_fingerprint, edges));
1155+
let dep_node_index = match self.new_node_to_index.lock_shard_by_value(&key).entry(key) {
1156+
Entry::Occupied(entry) => *entry.get(),
1157+
Entry::Vacant(entry) => {
1158+
let dep_node_index = self.encoder.send(key, current_fingerprint, edges);
1159+
entry.insert(dep_node_index);
1160+
dep_node_index
1161+
}
1162+
};
11541163

11551164
#[cfg(debug_assertions)]
11561165
self.record_edge(dep_node_index, key, current_fingerprint);
@@ -1248,7 +1257,7 @@ impl<D: Deps> CurrentDepGraph<D> {
12481257
) {
12491258
let node = &prev_graph.index_to_node(prev_index);
12501259
debug_assert!(
1251-
!self.new_node_to_index.get(node).is_some(),
1260+
!self.new_node_to_index.lock_shard_by_value(node).contains_key(node),
12521261
"node from previous graph present in new node collection"
12531262
);
12541263
}
@@ -1373,7 +1382,7 @@ fn panic_on_forbidden_read<D: Deps>(data: &DepGraphData<D>, dep_node_index: DepN
13731382
if dep_node.is_none() {
13741383
// Try to find it among the new nodes
13751384
for shard in data.current.new_node_to_index.lock_shards() {
1376-
if let Some((node, _)) = shard.iter().find(|(_, index)| *index == dep_node_index) {
1385+
if let Some((node, _)) = shard.iter().find(|(_, index)| **index == dep_node_index) {
13771386
dep_node = Some(*node);
13781387
break;
13791388
}

‎compiler/rustc_query_system/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![feature(assert_matches)]
44
#![feature(core_intrinsics)]
55
#![feature(dropck_eyepatch)]
6+
#![feature(hash_raw_entry)]
67
#![feature(let_chains)]
78
#![feature(min_specialization)]
89
// tidy-alphabetical-end

‎compiler/rustc_query_system/src/query/caches.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use std::fmt::Debug;
22
use std::hash::Hash;
33
use std::sync::OnceLock;
44

5-
use rustc_data_structures::sharded::ShardedHashMap;
5+
use rustc_data_structures::fx::FxHashMap;
6+
use rustc_data_structures::sharded::{self, Sharded};
67
pub use rustc_data_structures::vec_cache::VecCache;
78
use rustc_hir::def_id::LOCAL_CRATE;
89
use rustc_index::Idx;
@@ -35,7 +36,7 @@ pub trait QueryCache: Sized {
3536
/// In-memory cache for queries whose keys aren't suitable for any of the
3637
/// more specialized kinds of cache. Backed by a sharded hashmap.
3738
pub struct DefaultCache<K, V> {
38-
cache: ShardedHashMap<K, (V, DepNodeIndex)>,
39+
cache: Sharded<FxHashMap<K, (V, DepNodeIndex)>>,
3940
}
4041

4142
impl<K, V> Default for DefaultCache<K, V> {
@@ -54,14 +55,19 @@ where
5455

5556
#[inline(always)]
5657
fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> {
57-
self.cache.get(key)
58+
let key_hash = sharded::make_hash(key);
59+
let lock = self.cache.lock_shard_by_hash(key_hash);
60+
let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key);
61+
62+
if let Some((_, value)) = result { Some(*value) } else { None }
5863
}
5964

6065
#[inline]
6166
fn complete(&self, key: K, value: V, index: DepNodeIndex) {
67+
let mut lock = self.cache.lock_shard_by_value(&key);
6268
// We may be overwriting another value. This is all right, since the dep-graph
6369
// will check that the fingerprint matches.
64-
self.cache.insert(key, (value, index));
70+
lock.insert(key, (value, index));
6571
}
6672

6773
fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) {

0 commit comments

Comments
 (0)
Failed to load comments.