Avoid rehashing Fingerprint as a map key
This introduces a no-op `Unhasher` for map keys that are already hash- like, for example `Fingerprint` and its wrapper `DefPathHash`. For these we can directly produce the `u64` hash for maps. The first use of this is `def_path_hash_to_def_id: Option<UnhashMap<DefPathHash, DefId>>`.
This commit is contained in:
parent
130359cb05
commit
469ca379d6
4 changed files with 62 additions and 3 deletions
|
@ -3,9 +3,10 @@ use rustc_serialize::{
|
||||||
opaque::{self, EncodeResult},
|
opaque::{self, EncodeResult},
|
||||||
Decodable, Encodable,
|
Decodable, Encodable,
|
||||||
};
|
};
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
|
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
|
||||||
pub struct Fingerprint(u64, u64);
|
pub struct Fingerprint(u64, u64);
|
||||||
|
|
||||||
impl Fingerprint {
|
impl Fingerprint {
|
||||||
|
@ -76,6 +77,33 @@ impl ::std::fmt::Display for Fingerprint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Hash for Fingerprint {
|
||||||
|
#[inline]
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
state.write_fingerprint(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait FingerprintHasher {
|
||||||
|
fn write_fingerprint(&mut self, fingerprint: &Fingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Hasher> FingerprintHasher for H {
|
||||||
|
#[inline]
|
||||||
|
default fn write_fingerprint(&mut self, fingerprint: &Fingerprint) {
|
||||||
|
self.write_u64(fingerprint.0);
|
||||||
|
self.write_u64(fingerprint.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FingerprintHasher for crate::unhash::Unhasher {
|
||||||
|
#[inline]
|
||||||
|
fn write_fingerprint(&mut self, fingerprint: &Fingerprint) {
|
||||||
|
// `Unhasher` only wants a single `u64`
|
||||||
|
self.write_u64(fingerprint.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl stable_hasher::StableHasherResult for Fingerprint {
|
impl stable_hasher::StableHasherResult for Fingerprint {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn finish(hasher: stable_hasher::StableHasher) -> Self {
|
fn finish(hasher: stable_hasher::StableHasher) -> Self {
|
||||||
|
|
|
@ -103,6 +103,7 @@ pub use atomic_ref::AtomicRef;
|
||||||
pub mod frozen;
|
pub mod frozen;
|
||||||
pub mod tagged_ptr;
|
pub mod tagged_ptr;
|
||||||
pub mod temp_dir;
|
pub mod temp_dir;
|
||||||
|
pub mod unhash;
|
||||||
|
|
||||||
pub struct OnDrop<F: Fn()>(pub F);
|
pub struct OnDrop<F: Fn()>(pub F);
|
||||||
|
|
||||||
|
|
29
compiler/rustc_data_structures/src/unhash.rs
Normal file
29
compiler/rustc_data_structures/src/unhash.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::hash::{BuildHasherDefault, Hasher};
|
||||||
|
|
||||||
|
pub type UnhashMap<K, V> = HashMap<K, V, BuildHasherDefault<Unhasher>>;
|
||||||
|
pub type UnhashSet<V> = HashSet<V, BuildHasherDefault<Unhasher>>;
|
||||||
|
|
||||||
|
/// This no-op hasher expects only a single `write_u64` call. It's intended for
|
||||||
|
/// map keys that already have hash-like quality, like `Fingerprint`.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Unhasher {
|
||||||
|
value: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hasher for Unhasher {
|
||||||
|
#[inline]
|
||||||
|
fn finish(&self) -> u64 {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, _bytes: &[u8]) {
|
||||||
|
unimplemented!("use write_u64");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_u64(&mut self, value: u64) {
|
||||||
|
debug_assert_eq!(0, self.value, "Unhasher doesn't mix values!");
|
||||||
|
self.value = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ use rustc_data_structures::stable_hasher::{
|
||||||
hash_stable_hashmap, HashStable, StableHasher, StableVec,
|
hash_stable_hashmap, HashStable, StableHasher, StableVec,
|
||||||
};
|
};
|
||||||
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
|
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
|
||||||
|
use rustc_data_structures::unhash::UnhashMap;
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
@ -935,7 +936,7 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
|
|
||||||
/// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate
|
/// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate
|
||||||
/// as well as all upstream crates. Only populated in incremental mode.
|
/// as well as all upstream crates. Only populated in incremental mode.
|
||||||
pub def_path_hash_to_def_id: Option<FxHashMap<DefPathHash, DefId>>,
|
pub def_path_hash_to_def_id: Option<UnhashMap<DefPathHash, DefId>>,
|
||||||
|
|
||||||
pub queries: query::Queries<'tcx>,
|
pub queries: query::Queries<'tcx>,
|
||||||
|
|
||||||
|
@ -1104,7 +1105,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
let def_path_hash_to_def_id = if s.opts.build_dep_graph() {
|
let def_path_hash_to_def_id = if s.opts.build_dep_graph() {
|
||||||
let capacity = definitions.def_path_table().num_def_ids()
|
let capacity = definitions.def_path_table().num_def_ids()
|
||||||
+ crates.iter().map(|cnum| cstore.num_def_ids(*cnum)).sum::<usize>();
|
+ crates.iter().map(|cnum| cstore.num_def_ids(*cnum)).sum::<usize>();
|
||||||
let mut map = FxHashMap::with_capacity_and_hasher(capacity, Default::default());
|
let mut map = UnhashMap::with_capacity_and_hasher(capacity, Default::default());
|
||||||
|
|
||||||
map.extend(definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE));
|
map.extend(definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE));
|
||||||
for cnum in &crates {
|
for cnum in &crates {
|
||||||
|
|
Loading…
Add table
Reference in a new issue