@@ -7,6 +7,7 @@ use rustc_macros::HashStable_Generic;
7
7
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
8
8
use std::borrow::Borrow;
9
9
use std::fmt;
10
+ use std::hash::{Hash, Hasher};
10
11
11
12
rustc_index::newtype_index! {
12
13
pub struct CrateNum {
@@ -146,9 +147,6 @@ impl StableCrateId {
146
147
/// Computes the stable ID for a crate with the given name and
147
148
/// `-Cmetadata` arguments.
148
149
pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
149
- use std::hash::Hash;
150
- use std::hash::Hasher;
151
-
152
150
let mut hasher = StableHasher::new();
153
151
crate_name.hash(&mut hasher);
154
152
@@ -205,10 +203,38 @@ impl<D: Decoder> Decodable<D> for DefIndex {
205
203
/// index and a def index.
206
204
///
207
205
/// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`.
208
- #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
206
+ #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
207
+ // On below-64 bit systems we can simply use the derived `Hash` impl
208
+ #[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
209
+ // Note that the order is essential here, see below why
209
210
pub struct DefId {
210
- pub krate: CrateNum,
211
211
pub index: DefIndex,
212
+ pub krate: CrateNum,
213
+ }
214
+
215
+ // On 64-bit systems, we can hash the whole `DefId` as one `u64` instead of two `u32`s. This
216
+ // improves performance without impairing `FxHash` quality. So the below code gets compiled to a
217
+ // noop on little endian systems because the memory layout of `DefId` is as follows:
218
+ //
219
+ // ```
220
+ // +-1--------------31-+-32-------------63-+
221
+ // ! index ! krate !
222
+ // +-------------------+-------------------+
223
+ // ```
224
+ //
225
+ // The order here has direct impact on `FxHash` quality because we have far more `DefIndex` per
226
+ // crate than we have `Crate`s within one compilation. Or in other words, this arrangement puts
227
+ // more entropy in the low bits than the high bits. The reason this matters is that `FxHash`, which
228
+ // is used throughout rustc, has problems distributing the entropy from the high bits, so reversing
229
+ // the order would lead to a large number of collisions and thus far worse performance.
230
+ //
231
+ // On 64-bit big-endian systems, this compiles to a 64-bit rotation by 32 bits, which is still
232
+ // faster than another `FxHash` round.
233
+ #[cfg(target_pointer_width = "64")]
234
+ impl Hash for DefId {
235
+ fn hash<H: Hasher>(&self, h: &mut H) {
236
+ (((self.krate.as_u32() as u64) << 32) | (self.index.as_u32() as u64)).hash(h)
237
+ }
212
238
}
213
239
214
240
impl DefId {
0 commit comments