about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2020-09-01 18:27:02 -0700
committerJosh Stone <jistone@redhat.com>2020-09-01 18:27:02 -0700
commit469ca379d6dc0ade5ee08f14892c1549bb383e77 (patch)
tree51d82da09a15482edf3e98004004fab1d2f3588a
parent130359cb05246fcacdde61baa2613419ef6570c7 (diff)
downloadrust-469ca379d6dc0ade5ee08f14892c1549bb383e77.tar.gz
rust-469ca379d6dc0ade5ee08f14892c1549bb383e77.zip
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>>`.
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs30
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/unhash.rs29
-rw-r--r--compiler/rustc_middle/src/ty/context.rs5
4 files changed, 62 insertions, 3 deletions
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index f8d631ce01e..aba0bbbac80 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -3,9 +3,10 @@ use rustc_serialize::{
     opaque::{self, EncodeResult},
     Decodable, Encodable,
 };
+use std::hash::{Hash, Hasher};
 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);
 
 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 {
     #[inline]
     fn finish(hasher: stable_hasher::StableHasher) -> Self {
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 78b7e08ceed..de4e7a13424 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -103,6 +103,7 @@ pub use atomic_ref::AtomicRef;
 pub mod frozen;
 pub mod tagged_ptr;
 pub mod temp_dir;
+pub mod unhash;
 
 pub struct OnDrop<F: Fn()>(pub F);
 
diff --git a/compiler/rustc_data_structures/src/unhash.rs b/compiler/rustc_data_structures/src/unhash.rs
new file mode 100644
index 00000000000..48e21a9dab1
--- /dev/null
+++ b/compiler/rustc_data_structures/src/unhash.rs
@@ -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;
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 18ae744cb1e..5819c774bc2 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -34,6 +34,7 @@ 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::unhash::UnhashMap;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 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
     /// 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>,
 
@@ -1104,7 +1105,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let def_path_hash_to_def_id = if s.opts.build_dep_graph() {
             let capacity = definitions.def_path_table().num_def_ids()
                 + 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));
             for cnum in &crates {