@@ -7,6 +7,7 @@ use rustc_macros::HashStable_Generic;
77use rustc_serialize:: { Decodable , Decoder , Encodable , Encoder } ;
88use std:: borrow:: Borrow ;
99use std:: fmt;
10+ use std:: hash:: { Hash , Hasher } ;
1011
1112rustc_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
209210pub 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
214240impl DefId {
0 commit comments