Auto merge of #94299 - oli-obk:stable_hash_ty, r=michaelwoerister

Caching the stable hash of Ty within itself

Instead of computing stable hashes on types as needed, we compute it during interning.

This way we can, when a hash is requested, just hash that hash, which is significantly faster than traversing the type itself.

We only do this for incremental for now, as incremental is the only frequent user of stable hashing.

As a next step we can try out

* moving the hash and TypeFlags to Interner, so projections and regions get the same benefit (tho regions are not nested, so maybe that's not a good idea? Would be nice for dedup tho)
* start comparing types via their stable hash instead of their address?
This commit is contained in:
bors 2022-02-28 23:38:05 +00:00
commit 8d6f527530
4 changed files with 67 additions and 13 deletions

View file

@ -24,6 +24,7 @@ use crate::ty::{
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
};
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::memmap::Mmap;
@ -58,6 +59,7 @@ use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
use rustc_target::spec::abi;
use rustc_type_ir::TypeFlags;
use smallvec::SmallVec;
use std::any::Any;
use std::borrow::Borrow;
@ -140,16 +142,39 @@ impl<'tcx> CtxtInterners<'tcx> {
/// Interns a type.
#[allow(rustc::usage_of_ty_tykind)]
#[inline(never)]
fn intern_ty(&self, kind: TyKind<'tcx>) -> Ty<'tcx> {
fn intern_ty(
&self,
kind: TyKind<'tcx>,
sess: &Session,
resolutions: &ty::ResolverOutputs,
) -> Ty<'tcx> {
Ty(Interned::new_unchecked(
self.type_
.intern(kind, |kind| {
let flags = super::flags::FlagComputation::for_kind(&kind);
// It's impossible to hash inference regions (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.
let stable_hash = if flags.flags.intersects(TypeFlags::HAS_RE_INFER)
|| sess.opts.incremental.is_none()
{
Fingerprint::ZERO
} else {
let mut hasher = StableHasher::new();
let mut hcx = StableHashingContext::ignore_spans(
sess,
&resolutions.definitions,
&*resolutions.cstore,
);
kind.hash_stable(&mut hcx, &mut hasher);
hasher.finish()
};
let ty_struct = TyS {
kind,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
stable_hash,
};
InternedInSet(self.arena.alloc(ty_struct))
@ -887,8 +912,12 @@ pub enum UserType<'tcx> {
}
impl<'tcx> CommonTypes<'tcx> {
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
let mk = |ty| interners.intern_ty(ty);
fn new(
interners: &CtxtInterners<'tcx>,
sess: &Session,
resolutions: &ty::ResolverOutputs,
) -> CommonTypes<'tcx> {
let mk = |ty| interners.intern_ty(ty, sess, resolutions);
CommonTypes {
unit: mk(Tuple(List::empty())),
@ -1162,7 +1191,7 @@ impl<'tcx> TyCtxt<'tcx> {
s.fatal(&err);
});
let interners = CtxtInterners::new(arena);
let common_types = CommonTypes::new(&interners);
let common_types = CommonTypes::new(&interners, s, &resolutions);
let common_lifetimes = CommonLifetimes::new(&interners);
let common_consts = CommonConsts::new(&interners, &common_types);
@ -2276,7 +2305,7 @@ impl<'tcx> TyCtxt<'tcx> {
#[allow(rustc::usage_of_ty_tykind)]
#[inline]
pub fn mk_ty(self, st: TyKind<'tcx>) -> Ty<'tcx> {
self.interners.intern_ty(st)
self.interners.intern_ty(st, self.sess, &self.gcx.untracked_resolutions)
}
#[inline]

View file

@ -17,6 +17,7 @@ pub use self::Variance::*;
pub use adt::*;
pub use assoc::*;
pub use generics::*;
use rustc_data_structures::fingerprint::Fingerprint;
pub use vtable::*;
use crate::metadata::ModChild;
@ -30,7 +31,7 @@ use rustc_ast as ast;
use rustc_attr as attr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stable_hasher::{HashStable, NodeIdHashingMode, StableHasher};
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@ -424,11 +425,15 @@ crate struct TyS<'tcx> {
/// De Bruijn indices within the type are contained within `0..D`
/// (exclusive).
outer_exclusive_binder: ty::DebruijnIndex,
/// The stable hash of the type. This way hashing of types will not have to work
/// on the address of the type anymore, but can instead just read this field
stable_hash: Fingerprint,
}
// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(TyS<'_>, 40);
static_assert_size!(TyS<'_>, 56);
/// Use this rather than `TyS`, whenever possible.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -442,21 +447,41 @@ static BOOL_TYS: TyS<'static> = TyS {
kind: ty::Bool,
flags: TypeFlags::empty(),
outer_exclusive_binder: DebruijnIndex::from_usize(0),
stable_hash: Fingerprint::ZERO,
};
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Ty<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let TyS {
ref kind,
kind,
// The other fields just provide fast access to information that is
// also contained in `kind`, so no need to hash them.
flags: _,
outer_exclusive_binder: _,
stable_hash,
} = self.0.0;
kind.hash_stable(hcx, hasher);
if *stable_hash == Fingerprint::ZERO {
// 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.
let stable_hash: Fingerprint = {
let mut hasher = StableHasher::new();
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
kind.hash_stable(hcx, &mut hasher)
})
});
hasher.finish()
};
stable_hash.hash_stable(hcx, hasher);
} else {
stable_hash.hash_stable(hcx, hasher);
}
}
}

View file

@ -1,10 +1,10 @@
error: symbol-name(_ZN5basic4main17h611df9c6948c15f7E)
error: symbol-name(_ZN5basic4main17h87acd86b3a6f1754E)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(basic::main::h611df9c6948c15f7)
error: demangling(basic::main::h87acd86b3a6f1754)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]

View file

@ -1,10 +1,10 @@
error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h5425dadb5b1e5fb6E)
error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h8d22952c45e20d65E)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h5425dadb5b1e5fb6)
error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h8d22952c45e20d65)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]