Auto merge of #155329 - nnethercote:rm-WithCachedTypeInfo-stable_hash, r=oli-obk

Remove `WithCachedTypeInfo::stable_hash`.



We store a stable hash value in the most common interned values (e.g. types, predicates, regions). This is 16 bytes of data.
- In non-incremental builds it's a straightforward performance loss: the stable hash isn't computed or used, and the 16 bytes of space goes to waste (but it still gets hashed when interning).
- In incremental builds it avoids some hashing but doesn't seem to actually be a genuine performance win, and the complexity doesn't seem worth it.

r? @oli-obk
This commit is contained in:
bors
2026-04-28 07:33:06 +00:00
8 changed files with 25 additions and 131 deletions
+14 -85
View File
@@ -18,13 +18,12 @@ use std::{fmt, iter, mem};
use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx};
use rustc_ast as ast;
use rustc_data_structures::defer;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
use rustc_data_structures::jobserver::Proxy;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stable_hasher::HashStable;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{
self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal,
@@ -47,9 +46,7 @@ use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
use rustc_type_ir::TyKind::*;
pub use rustc_type_ir::lift::Lift;
use rustc_type_ir::{
CollectAndApply, FnSigKind, TypeFlags, WithCachedTypeInfo, elaborate, search_graph,
};
use rustc_type_ir::{CollectAndApply, FnSigKind, WithCachedTypeInfo, elaborate, search_graph};
use tracing::{debug, instrument};
use crate::arena::Arena;
@@ -247,16 +244,13 @@ impl<'tcx> CtxtInterners<'tcx> {
/// Interns a type. (Use `mk_*` functions instead, where possible.)
#[allow(rustc::usage_of_ty_tykind)]
#[inline(never)]
fn intern_ty(&self, kind: TyKind<'tcx>, sess: &Session, untracked: &Untracked) -> Ty<'tcx> {
fn intern_ty(&self, kind: TyKind<'tcx>) -> Ty<'tcx> {
Ty(Interned::new_unchecked(
self.type_
.intern(kind, |kind| {
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_kind(&kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
internee: kind,
stable_hash,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
}))
@@ -268,21 +262,13 @@ impl<'tcx> CtxtInterners<'tcx> {
/// Interns a const. (Use `mk_*` functions instead, where possible.)
#[allow(rustc::usage_of_ty_tykind)]
#[inline(never)]
fn intern_const(
&self,
kind: ty::ConstKind<'tcx>,
sess: &Session,
untracked: &Untracked,
) -> Const<'tcx> {
fn intern_const(&self, kind: ty::ConstKind<'tcx>) -> Const<'tcx> {
Const(Interned::new_unchecked(
self.const_
.intern(kind, |kind: ty::ConstKind<'_>| {
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_const_kind(&kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
internee: kind,
stable_hash,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
}))
@@ -291,43 +277,15 @@ impl<'tcx> CtxtInterners<'tcx> {
))
}
fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
&self,
flags: &ty::FlagComputation<TyCtxt<'tcx>>,
sess: &'a Session,
untracked: &'a Untracked,
val: &T,
) -> Fingerprint {
// It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them.
// Without incremental, we rarely stable-hash types, so let's not do it proactively.
if flags.flags.intersects(TypeFlags::HAS_INFER) || sess.opts.incremental.is_none() {
Fingerprint::ZERO
} else {
let mut hasher = StableHasher::new();
let mut hcx = StableHashingContext::new(sess, untracked);
val.hash_stable(&mut hcx, &mut hasher);
hasher.finish()
}
}
/// Interns a predicate. (Use `mk_predicate` instead, where possible.)
#[inline(never)]
fn intern_predicate(
&self,
kind: Binder<'tcx, PredicateKind<'tcx>>,
sess: &Session,
untracked: &Untracked,
) -> Predicate<'tcx> {
fn intern_predicate(&self, kind: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
Predicate(Interned::new_unchecked(
self.predicate
.intern(kind, |kind| {
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_predicate(kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
internee: kind,
stable_hash,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
}))
@@ -463,12 +421,8 @@ pub struct CommonConsts<'tcx> {
}
impl<'tcx> CommonTypes<'tcx> {
fn new(
interners: &CtxtInterners<'tcx>,
sess: &Session,
untracked: &Untracked,
) -> CommonTypes<'tcx> {
let mk = |ty| interners.intern_ty(ty, sess, untracked);
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
let mk = |ty| interners.intern_ty(ty);
let ty_vars =
(0..NUM_PREINTERNED_TY_VARS).map(|n| mk(Infer(ty::TyVar(TyVid::from(n))))).collect();
@@ -584,18 +538,8 @@ impl<'tcx> CommonLifetimes<'tcx> {
}
impl<'tcx> CommonConsts<'tcx> {
fn new(
interners: &CtxtInterners<'tcx>,
types: &CommonTypes<'tcx>,
sess: &Session,
untracked: &Untracked,
) -> CommonConsts<'tcx> {
let mk_const = |c| {
interners.intern_const(
c, sess, // This is only used to create a stable hashing context.
untracked,
)
};
fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> {
let mk_const = |c| interners.intern_const(c);
let mk_valtree = |v| {
ty::ValTree(Interned::new_unchecked(
@@ -1088,9 +1032,9 @@ impl<'tcx> TyCtxt<'tcx> {
s.dcx().emit_fatal(err);
});
let interners = CtxtInterners::new(arena);
let common_types = CommonTypes::new(&interners, s, &untracked);
let common_types = CommonTypes::new(&interners);
let common_lifetimes = CommonLifetimes::new(&interners);
let common_consts = CommonConsts::new(&interners, &common_types, s, &untracked);
let common_consts = CommonConsts::new(&interners, &common_types);
let gcx = gcx_cell.get_or_init(|| GlobalCtxt {
sess: s,
@@ -2221,12 +2165,7 @@ impl<'tcx> TyCtxt<'tcx> {
#[inline]
pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
self.interners.intern_predicate(
binder,
self.sess,
// This is only used to create a stable hashing context.
&self.untracked,
)
self.interners.intern_predicate(binder)
}
#[inline]
@@ -2347,24 +2286,14 @@ impl<'tcx> TyCtxt<'tcx> {
#[inline]
pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>) -> Const<'tcx> {
self.interners.intern_const(
kind,
self.sess,
// This is only used to create a stable hashing context.
&self.untracked,
)
self.interners.intern_const(kind)
}
// Avoid this in favour of more specific `Ty::new_*` methods, where possible.
#[allow(rustc::usage_of_ty_tykind)]
#[inline]
pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> {
self.interners.intern_ty(
st,
self.sess,
// This is only used to create a stable hashing context.
&self.untracked,
)
self.interners.intern_ty(st)
}
pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
+1 -1
View File
@@ -644,6 +644,6 @@ mod size_asserts {
use super::*;
// tidy-alphabetical-start
static_assert_size!(PredicateKind<'_>, 40);
static_assert_size!(WithCachedTypeInfo<PredicateKind<'_>>, 64);
static_assert_size!(WithCachedTypeInfo<PredicateKind<'_>>, 48);
// tidy-alphabetical-end
}
+1 -1
View File
@@ -460,6 +460,6 @@ mod size_asserts {
use super::*;
// tidy-alphabetical-start
static_assert_size!(RegionKind<'_>, 20);
static_assert_size!(ty::WithCachedTypeInfo<RegionKind<'_>>, 48);
static_assert_size!(ty::WithCachedTypeInfo<RegionKind<'_>>, 28);
// tidy-alphabetical-end
}
+1 -1
View File
@@ -2167,6 +2167,6 @@ mod size_asserts {
use super::*;
// tidy-alphabetical-start
static_assert_size!(TyKind<'_>, 32);
static_assert_size!(ty::WithCachedTypeInfo<TyKind<'_>>, 56);
static_assert_size!(ty::WithCachedTypeInfo<TyKind<'_>>, 40);
// tidy-alphabetical-end
}
+3 -38
View File
@@ -2,8 +2,6 @@ use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
#[cfg(feature = "nightly")]
use rustc_data_structures::fingerprint::Fingerprint;
#[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_type_ir_macros::GenericTypeVisitable;
@@ -11,19 +9,12 @@ use rustc_type_ir_macros::GenericTypeVisitable;
use crate::{DebruijnIndex, TypeFlags};
/// A helper type that you can wrap round your own type in order to automatically
/// cache the stable hash, type flags and debruijn index on creation and
/// not recompute it whenever the information is needed.
/// This is only done in incremental mode. You can also opt out of caching by using
/// StableHash::ZERO for the hash, in which case the hash gets computed each time.
/// This is useful if you have values that you intern but never (can?) use for stable
/// hashing.
/// cache the type flags and debruijn index on creation and not recompute it
/// whenever the information is needed.
#[derive(Copy, Clone, GenericTypeVisitable)]
pub struct WithCachedTypeInfo<T> {
pub internee: T,
#[cfg(feature = "nightly")]
pub stable_hash: Fingerprint,
/// This field provides fast access to information that is also contained
/// in `kind`.
///
@@ -87,11 +78,6 @@ impl<T> Deref for WithCachedTypeInfo<T> {
impl<T: Hash> Hash for WithCachedTypeInfo<T> {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
#[cfg(feature = "nightly")]
if self.stable_hash != Fingerprint::ZERO {
return self.stable_hash.hash(s);
}
self.internee.hash(s)
}
}
@@ -99,27 +85,6 @@ impl<T: Hash> Hash for WithCachedTypeInfo<T> {
#[cfg(feature = "nightly")]
impl<T: HashStable<Hcx>, Hcx> HashStable<Hcx> for WithCachedTypeInfo<T> {
fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) {
// No cached hash available. This can only mean that incremental is disabled.
// We don't cache stable hashes in non-incremental mode, because they are used
// so rarely that the performance actually suffers.
// We need to build the hash as if we cached it and then hash that hash, as
// otherwise the hashes will differ between cached and non-cached mode.
let stable_hash: Fingerprint = {
let mut hasher = StableHasher::new();
self.internee.hash_stable(hcx, &mut hasher);
hasher.finish()
};
if cfg!(debug_assertions) && self.stable_hash != Fingerprint::ZERO {
assert_eq!(
stable_hash, self.stable_hash,
"cached stable hash does not match freshly computed stable hash"
);
}
stable_hash.hash_stable(hcx, hasher);
} else {
self.stable_hash.hash_stable(hcx, hasher);
}
self.internee.hash_stable(hcx, hasher);
}
}
+1 -1
View File
@@ -39,7 +39,7 @@
// Const generic parameter
//@ gdb-command:info functions -q function_names::const_generic_fn.*
//@ gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
//@ gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#6dd80cc0c950c171}>();
//@ gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#68cf9e429c783d36}>();
//@ gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
//@ gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
+2 -2
View File
@@ -1,10 +1,10 @@
error: symbol-name(_ZN5basic4main17h947b7a9ed2b2bf56E)
error: symbol-name(_ZN5basic4main17h27f62b2d0b2beac6E)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_dump_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: demangling(basic::main::h947b7a9ed2b2bf56)
error: demangling(basic::main::h27f62b2d0b2beac6)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_dump_symbol_name]
@@ -1,10 +1,10 @@
error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hba5ac046b858f549E)
error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h1eb769490ff06e77E)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_dump_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hba5ac046b858f549)
error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h1eb769490ff06e77)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_dump_symbol_name]