Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use rustc-stable-hash in the compiler #127479

Merged
merged 1 commit into from
Jul 12, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -3514,6 +3514,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84"

[[package]]
name = "rustc-stable-hash"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5c9f15eec8235d7cb775ee6f81891db79b98fd54ba1ad8fae565b88ef1ae4e2"

[[package]]
name = "rustc-std-workspace-alloc"
version = "1.99.0"
@@ -3852,6 +3858,7 @@ dependencies = [
"portable-atomic",
"rustc-hash",
"rustc-rayon",
"rustc-stable-hash",
"rustc_arena",
"rustc_graphviz",
"rustc_index",
1 change: 1 addition & 0 deletions compiler/rustc_data_structures/Cargo.toml
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ jobserver_crate = { version = "0.1.28", package = "jobserver" }
measureme = "11"
rustc-hash = "1.1.0"
rustc-rayon = { version = "0.5.0", optional = true }
rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
rustc_arena = { path = "../rustc_arena" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_index = { path = "../rustc_index", package = "rustc_index" }
9 changes: 5 additions & 4 deletions compiler/rustc_data_structures/src/fingerprint.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::stable_hasher::impl_stable_traits_for_trivial_type;
use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult};
use crate::stable_hasher::{FromStableHash, Hash64, StableHasherHash};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::hash::{Hash, Hasher};

@@ -154,10 +154,11 @@ impl FingerprintHasher for crate::unhash::Unhasher {
}
}

impl StableHasherResult for Fingerprint {
impl FromStableHash for Fingerprint {
type Hash = StableHasherHash;

#[inline]
fn finish(hasher: StableHasher) -> Self {
let (_0, _1) = hasher.finalize();
fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self {
Fingerprint(_0, _1)
}
}
17 changes: 10 additions & 7 deletions compiler/rustc_data_structures/src/hashes.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
//! connect the fact that they can only be produced by a `StableHasher` to their
//! `Encode`/`Decode` impls.

use crate::stable_hasher::{StableHasher, StableHasherResult};
use crate::stable_hasher::{FromStableHash, StableHasherHash};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
use std::ops::BitXorAssign;
@@ -56,10 +56,12 @@ impl<D: Decoder> Decodable<D> for Hash64 {
}
}

impl StableHasherResult for Hash64 {
impl FromStableHash for Hash64 {
type Hash = StableHasherHash;

#[inline]
fn finish(hasher: StableHasher) -> Self {
Self { inner: hasher.finalize().0 }
fn from(StableHasherHash([_0, __1]): Self::Hash) -> Self {
Self { inner: _0 }
}
}

@@ -121,10 +123,11 @@ impl<D: Decoder> Decodable<D> for Hash128 {
}
}

impl StableHasherResult for Hash128 {
impl FromStableHash for Hash128 {
type Hash = StableHasherHash;

#[inline]
fn finish(hasher: StableHasher) -> Self {
let (_0, _1) = hasher.finalize();
fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self {
Self { inner: u128::from(_0) | (u128::from(_1) << 64) }
}
}
2 changes: 0 additions & 2 deletions compiler/rustc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
@@ -24,7 +24,6 @@
#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(hash_raw_entry)]
#![feature(hasher_prefixfree_extras)]
#![feature(macro_metavar_expr)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
@@ -67,7 +66,6 @@ pub mod owned_slice;
pub mod packed;
pub mod profiling;
pub mod sharded;
pub mod sip128;
pub mod small_c_str;
pub mod snapshot_map;
pub mod sorted_map;
505 changes: 0 additions & 505 deletions compiler/rustc_data_structures/src/sip128.rs

This file was deleted.

304 changes: 0 additions & 304 deletions compiler/rustc_data_structures/src/sip128/tests.rs

This file was deleted.

162 changes: 3 additions & 159 deletions compiler/rustc_data_structures/src/stable_hasher.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use crate::sip128::SipHasher128;
use rustc_index::bit_set::{self, BitSet};
use rustc_index::{Idx, IndexSlice, IndexVec};
use smallvec::SmallVec;
use std::fmt;
use std::hash::{BuildHasher, Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
@@ -13,163 +11,9 @@ mod tests;

pub use crate::hashes::{Hash128, Hash64};

/// When hashing something that ends up affecting properties like symbol names,
/// we want these symbol names to be calculated independently of other factors
/// like what architecture you're compiling *from*.
///
/// To that end we always convert integers to little-endian format before
/// hashing and the architecture dependent `isize` and `usize` types are
/// extended to 64 bits if needed.
pub struct StableHasher {
state: SipHasher128,
}

impl fmt::Debug for StableHasher {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.state)
}
}

pub trait StableHasherResult: Sized {
fn finish(hasher: StableHasher) -> Self;
}

impl StableHasher {
#[inline]
pub fn new() -> Self {
StableHasher { state: SipHasher128::new_with_keys(0, 0) }
}

#[inline]
pub fn finish<W: StableHasherResult>(self) -> W {
W::finish(self)
}
}

impl StableHasher {
#[inline]
pub fn finalize(self) -> (u64, u64) {
self.state.finish128()
}
}

impl Hasher for StableHasher {
fn finish(&self) -> u64 {
panic!("use StableHasher::finalize instead");
}

#[inline]
fn write(&mut self, bytes: &[u8]) {
self.state.write(bytes);
}

#[inline]
fn write_str(&mut self, s: &str) {
self.state.write_str(s);
}

#[inline]
fn write_length_prefix(&mut self, len: usize) {
// Our impl for `usize` will extend it if needed.
self.write_usize(len);
}

#[inline]
fn write_u8(&mut self, i: u8) {
self.state.write_u8(i);
}

#[inline]
fn write_u16(&mut self, i: u16) {
self.state.short_write(i.to_le_bytes());
}

#[inline]
fn write_u32(&mut self, i: u32) {
self.state.short_write(i.to_le_bytes());
}

#[inline]
fn write_u64(&mut self, i: u64) {
self.state.short_write(i.to_le_bytes());
}

#[inline]
fn write_u128(&mut self, i: u128) {
self.write_u64(i as u64);
self.write_u64((i >> 64) as u64);
}

#[inline]
fn write_usize(&mut self, i: usize) {
// Always treat usize as u64 so we get the same results on 32 and 64 bit
// platforms. This is important for symbol hashes when cross compiling,
// for example.
self.state.short_write((i as u64).to_le_bytes());
}

#[inline]
fn write_i8(&mut self, i: i8) {
self.state.write_i8(i);
}

#[inline]
fn write_i16(&mut self, i: i16) {
self.state.short_write((i as u16).to_le_bytes());
}

#[inline]
fn write_i32(&mut self, i: i32) {
self.state.short_write((i as u32).to_le_bytes());
}

#[inline]
fn write_i64(&mut self, i: i64) {
self.state.short_write((i as u64).to_le_bytes());
}

#[inline]
fn write_i128(&mut self, i: i128) {
self.state.write(&(i as u128).to_le_bytes());
}

#[inline]
fn write_isize(&mut self, i: isize) {
// Always treat isize as a 64-bit number so we get the same results on 32 and 64 bit
// platforms. This is important for symbol hashes when cross compiling,
// for example. Sign extending here is preferable as it means that the
// same negative number hashes the same on both 32 and 64 bit platforms.
let value = i as u64;

// Cold path
#[cold]
#[inline(never)]
fn hash_value(state: &mut SipHasher128, value: u64) {
state.write_u8(0xFF);
state.short_write(value.to_le_bytes());
}

// `isize` values often seem to have a small (positive) numeric value in practice.
// To exploit this, if the value is small, we will hash a smaller amount of bytes.
// However, we cannot just skip the leading zero bytes, as that would produce the same hash
// e.g. if you hash two values that have the same bit pattern when they are swapped.
// See https://github.com/rust-lang/rust/pull/93014 for context.
//
// Therefore, we employ the following strategy:
// 1) When we encounter a value that fits within a single byte (the most common case), we
// hash just that byte. This is the most common case that is being optimized. However, we do
// not do this for the value 0xFF, as that is a reserved prefix (a bit like in UTF-8).
// 2) When we encounter a larger value, we hash a "marker" 0xFF and then the corresponding
// 8 bytes. Since this prefix cannot occur when we hash a single byte, when we hash two
// `isize`s that fit within a different amount of bytes, they should always produce a different
// byte stream for the hasher.
if value < 0xFF {
self.state.write_u8(value as u8);
} else {
hash_value(&mut self.state, value);
}
}
}
pub use rustc_stable_hash::FromStableHash;
pub use rustc_stable_hash::SipHasher128Hash as StableHasherHash;
pub use rustc_stable_hash::StableSipHasher128 as StableHasher;

/// Something that implements `HashStable<CTX>` can be hashed in a way that is
/// stable across multiple compilation sessions.
65 changes: 0 additions & 65 deletions compiler/rustc_data_structures/src/stable_hasher/tests.rs
Original file line number Diff line number Diff line change
@@ -7,71 +7,6 @@ use super::*;
// ways). The expected values depend on the hashing algorithm used, so they
// need to be updated whenever StableHasher changes its hashing algorithm.

#[test]
fn test_hash_integers() {
// Test that integers are handled consistently across platforms.
let test_u8 = 0xAB_u8;
let test_u16 = 0xFFEE_u16;
let test_u32 = 0x445577AA_u32;
let test_u64 = 0x01234567_13243546_u64;
let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128;
let test_usize = 0xD0C0B0A0_usize;

let test_i8 = -100_i8;
let test_i16 = -200_i16;
let test_i32 = -300_i32;
let test_i64 = -400_i64;
let test_i128 = -500_i128;
let test_isize = -600_isize;

let mut h = StableHasher::new();
test_u8.hash(&mut h);
test_u16.hash(&mut h);
test_u32.hash(&mut h);
test_u64.hash(&mut h);
test_u128.hash(&mut h);
test_usize.hash(&mut h);
test_i8.hash(&mut h);
test_i16.hash(&mut h);
test_i32.hash(&mut h);
test_i64.hash(&mut h);
test_i128.hash(&mut h);
test_isize.hash(&mut h);

// This depends on the hashing algorithm. See note at top of file.
let expected = (13997337031081104755, 6178945012502239489);

assert_eq!(h.finalize(), expected);
}

#[test]
fn test_hash_usize() {
// Test that usize specifically is handled consistently across platforms.
let test_usize = 0xABCDEF01_usize;

let mut h = StableHasher::new();
test_usize.hash(&mut h);

// This depends on the hashing algorithm. See note at top of file.
let expected = (12037165114281468837, 3094087741167521712);

assert_eq!(h.finalize(), expected);
}

#[test]
fn test_hash_isize() {
// Test that isize specifically is handled consistently across platforms.
let test_isize = -7_isize;

let mut h = StableHasher::new();
test_isize.hash(&mut h);

// This depends on the hashing algorithm. See note at top of file.
let expected = (3979067582695659080, 2322428596355037273);

assert_eq!(h.finalize(), expected);
}

fn hash<T: HashStable<()>>(t: &T) -> Hash128 {
let mut h = StableHasher::new();
let ctx = &mut ();
6 changes: 3 additions & 3 deletions compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::ptr;

use crate::hashes::Hash128;
use crate::stable_hasher::{HashStable, StableHasher};
use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag, Tag2};

@@ -31,14 +32,13 @@ fn stable_hash_hashes_as_tuple() {
let hash_packed = {
let mut hasher = StableHasher::new();
tag_ptr(&12, Tag2::B11).hash_stable(&mut (), &mut hasher);

hasher.finalize()
hasher.finish::<Hash128>()
};

let hash_tupled = {
let mut hasher = StableHasher::new();
(&12, Tag2::B11).hash_stable(&mut (), &mut hasher);
hasher.finalize()
hasher.finish::<Hash128>()
};

assert_eq!(hash_packed, hash_tupled);
1 change: 1 addition & 0 deletions src/tools/tidy/src/deps.rs
Original file line number Diff line number Diff line change
@@ -353,6 +353,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"rustc-hash",
"rustc-rayon",
"rustc-rayon-core",
"rustc-stable-hash",
"rustc_apfloat",
"rustc_version",
"rustix",