Skip to content

Commit a2d25b4

Browse files
committed
Auto merge of #91660 - llogiq:make-a-hash-of-def-ids, r=nnethercote
manually implement `Hash` for `DefId` This might speed up hashing for hashers that can work on individual u64s. Just as an experiment, suggested in a reddit thread on `FxHasher`. cc `@nnethercote` Note that this should not be merged as is without cfg-ing the code path for 64 bits.
2 parents 8f117a7 + 635533b commit a2d25b4

File tree

3 files changed

+48
-22
lines changed

3 files changed

+48
-22
lines changed

Diff for: compiler/rustc_span/src/def_id.rs

+31-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_macros::HashStable_Generic;
77
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
88
use std::borrow::Borrow;
99
use std::fmt;
10+
use std::hash::{Hash, Hasher};
1011

1112
rustc_index::newtype_index! {
1213
pub struct CrateNum {
@@ -146,9 +147,6 @@ impl StableCrateId {
146147
/// Computes the stable ID for a crate with the given name and
147148
/// `-Cmetadata` arguments.
148149
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-
152150
let mut hasher = StableHasher::new();
153151
crate_name.hash(&mut hasher);
154152

@@ -205,10 +203,38 @@ impl<D: Decoder> Decodable<D> for DefIndex {
205203
/// index and a def index.
206204
///
207205
/// 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
209210
pub struct DefId {
210-
pub krate: CrateNum,
211211
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+
}
212238
}
213239

214240
impl DefId {

Diff for: src/test/ui/coherence/coherence-orphan.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
1-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
2-
--> $DIR/coherence-orphan.rs:17:1
3-
|
4-
LL | impl !Send for Vec<isize> { }
5-
| ^^^^^^^^^^^^^^^----------
6-
| | |
7-
| | `Vec` is not defined in the current crate
8-
| impl doesn't use only types from inside the current crate
9-
|
10-
= note: define and implement a trait or new type instead
11-
121
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
132
--> $DIR/coherence-orphan.rs:10:1
143
|
@@ -21,6 +10,17 @@ LL | impl TheTrait<usize> for isize { }
2110
|
2211
= note: define and implement a trait or new type instead
2312

13+
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
14+
--> $DIR/coherence-orphan.rs:17:1
15+
|
16+
LL | impl !Send for Vec<isize> { }
17+
| ^^^^^^^^^^^^^^^----------
18+
| | |
19+
| | `Vec` is not defined in the current crate
20+
| impl doesn't use only types from inside the current crate
21+
|
22+
= note: define and implement a trait or new type instead
23+
2424
error: aborting due to 2 previous errors
2525

2626
For more information about this error, try `rustc --explain E0117`.

Diff for: src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ error[E0034]: multiple applicable items in scope
44
LL | fn main() { 1_usize.me(); }
55
| ^^ multiple `me` found
66
|
7-
note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize`
7+
= note: candidate #1 is defined in an impl of the trait `Me` for the type `usize`
8+
note: candidate #2 is defined in an impl of the trait `Me2` for the type `usize`
89
--> $DIR/method-ambig-two-traits-cross-crate.rs:10:22
910
|
1011
LL | impl Me2 for usize { fn me(&self) -> usize { *self } }
1112
| ^^^^^^^^^^^^^^^^^^^^^
12-
= note: candidate #2 is defined in an impl of the trait `Me` for the type `usize`
1313
help: disambiguate the associated function for candidate #1
1414
|
15-
LL | fn main() { Me2::me(&1_usize); }
16-
| ~~~~~~~~~~~~~~~~~
17-
help: disambiguate the associated function for candidate #2
18-
|
1915
LL | fn main() { Me::me(&1_usize); }
2016
| ~~~~~~~~~~~~~~~~
17+
help: disambiguate the associated function for candidate #2
18+
|
19+
LL | fn main() { Me2::me(&1_usize); }
20+
| ~~~~~~~~~~~~~~~~~
2121

2222
error: aborting due to previous error
2323

0 commit comments

Comments
 (0)