From d944ea10e60b3a4e3016ac3d99f4719c306be7d4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Apr 2026 12:07:55 +1000 Subject: [PATCH] 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. --- compiler/rustc_middle/src/ty/context.rs | 99 +++---------------- compiler/rustc_middle/src/ty/predicate.rs | 2 +- compiler/rustc_middle/src/ty/region.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_type_ir/src/ty_info.rs | 41 +------- tests/debuginfo/function-names.rs | 2 +- tests/ui/symbol-names/basic.legacy.stderr | 4 +- .../ui/symbol-names/issue-60925.legacy.stderr | 4 +- 8 files changed, 25 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d1f82af3416b6..dd86ba7a8f0c5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -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::>::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::>::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>>( - &self, - flags: &ty::FlagComputation>, - 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::>::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> { diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index d6aaf62c1d1a2..3a16ec4af7418 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -644,6 +644,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(PredicateKind<'_>, 40); - static_assert_size!(WithCachedTypeInfo>, 64); + static_assert_size!(WithCachedTypeInfo>, 48); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 798b98c5def5c..6974fedd51830 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -460,6 +460,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(RegionKind<'_>, 20); - static_assert_size!(ty::WithCachedTypeInfo>, 48); + static_assert_size!(ty::WithCachedTypeInfo>, 28); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f8e1dc334f1f6..61ff6cde91d74 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2167,6 +2167,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(TyKind<'_>, 32); - static_assert_size!(ty::WithCachedTypeInfo>, 56); + static_assert_size!(ty::WithCachedTypeInfo>, 40); // tidy-alphabetical-end } diff --git a/compiler/rustc_type_ir/src/ty_info.rs b/compiler/rustc_type_ir/src/ty_info.rs index 5e297a51f0ce7..1ea42fb5f4c04 100644 --- a/compiler/rustc_type_ir/src/ty_info.rs +++ b/compiler/rustc_type_ir/src/ty_info.rs @@ -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 { 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 Deref for WithCachedTypeInfo { impl Hash for WithCachedTypeInfo { #[inline] fn hash(&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 Hash for WithCachedTypeInfo { #[cfg(feature = "nightly")] impl, Hcx> HashStable for WithCachedTypeInfo { 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); } } diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs index 5973f63bbae9e..38921743130f0 100644 --- a/tests/debuginfo/function-names.rs +++ b/tests/debuginfo/function-names.rs @@ -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(); -//@ 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>(); diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index 8309b8f957a7a..f88fdf7509c76 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -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] diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr index 359bafdff4692..c1fc9f4b1cea1 100644 --- a/tests/ui/symbol-names/issue-60925.legacy.stderr +++ b/tests/ui/symbol-names/issue-60925.legacy.stderr @@ -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::foo::hba5ac046b858f549) +error: demangling(issue_60925::foo::Foo::foo::h1eb769490ff06e77) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_dump_symbol_name]