diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 82994f9170fe0..38877dee71106 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -59,6 +59,7 @@ #![feature(log_syntax)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] +#![feature(hash_raw_entry)] #![recursion_limit="512"] diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 214de35b6d0a9..52a784d3fc0be 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -14,12 +14,13 @@ use errors::Level; use errors::Diagnostic; use errors::FatalError; use errors::Handler; -use rustc_data_structures::fx::{FxHashMap}; +use rustc_data_structures::fx::{FxHasher, FxHashMap}; use rustc_data_structures::sync::{Lrc, Lock}; use rustc_data_structures::sharded::Sharded; use rustc_data_structures::thin_vec::ThinVec; #[cfg(not(parallel_compiler))] use rustc_data_structures::cold_path; +use std::hash::{Hash, Hasher}; use std::mem; use std::ptr; use std::collections::hash_map::Entry; @@ -82,8 +83,17 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<'a, 'tcx, Q> { let cache = Q::query_cache(tcx); loop { - let mut lock = cache.get_shard_by_value(key).lock(); - if let Some(value) = lock.results.get(key) { + // We compute the key's hash once and then use it for both the + // shard lookup and the hashmap lookup. This relies on the fact + // that both of them use `FxHasher`. + let mut state = FxHasher::default(); + key.hash(&mut state); + let key_hash = state.finish(); + + let mut lock = cache.get_shard_by_hash(key_hash).lock(); + if let Some((_, value)) = + lock.results.raw_entry().from_key_hashed_nocheck(key_hash, key) + { tcx.prof.query_cache_hit(Q::NAME); let result = (value.value.clone(), value.index); #[cfg(debug_assertions)] diff --git a/src/librustc_data_structures/sharded.rs b/src/librustc_data_structures/sharded.rs index 2f972eeccdcbd..a28a5e0f0415a 100644 --- a/src/librustc_data_structures/sharded.rs +++ b/src/librustc_data_structures/sharded.rs @@ -60,6 +60,7 @@ impl Sharded { } } + /// The shard is selected by hashing `val` with `FxHasher`. #[inline] pub fn get_shard_by_value(&self, val: &K) -> &Lock { if SHARDS == 1 { @@ -69,6 +70,11 @@ impl Sharded { } } + /// Get a shard with a pre-computed hash value. If `get_shard_by_value` is + /// ever used in combination with `get_shard_by_hash` on a single `Sharded` + /// instance, then `hash` must be computed with `FxHasher`. Otherwise, + /// `hash` can be computed with any hasher, so long as that hasher is used + /// consistently for each `Sharded` instance. #[inline] pub fn get_shard_by_hash(&self, hash: u64) -> &Lock { let hash_len = mem::size_of::();