Skip to content

Cached stable hash cleanups #95524

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

Merged
merged 5 commits into from
Apr 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
73 changes: 73 additions & 0 deletions compiler/rustc_data_structures/src/intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::ptr;

use crate::fingerprint::Fingerprint;

mod private {
#[derive(Clone, Copy, Debug)]
pub struct PrivateZst;
Expand Down Expand Up @@ -108,5 +110,76 @@ where
}
}

/// A helper trait so that `Interned` things can cache stable hashes reproducibly.
pub trait InternedHashingContext {
fn with_def_path_and_no_spans(&mut self, f: impl FnOnce(&mut Self));
}

#[derive(Copy, Clone)]
pub struct InTy<T> {
pub internee: T,
pub stable_hash: Fingerprint,
}

impl<T: PartialEq> PartialEq for InTy<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.internee.eq(&other.internee)
}
}

impl<T: Eq> Eq for InTy<T> {}

impl<T: Ord> PartialOrd for InTy<T> {
fn partial_cmp(&self, other: &InTy<T>) -> Option<Ordering> {
Some(self.internee.cmp(&other.internee))
}
}

impl<T: Ord> Ord for InTy<T> {
fn cmp(&self, other: &InTy<T>) -> Ordering {
self.internee.cmp(&other.internee)
}
}

impl<T> Deref for InTy<T> {
type Target = T;

#[inline]
fn deref(&self) -> &T {
&self.internee
}
}

impl<T: Hash> Hash for InTy<T> {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
self.internee.hash(s)
}
}

impl<T: HashStable<CTX>, CTX: InternedHashingContext> HashStable<CTX> for InTy<T> {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
let stable_hash = self.stable_hash;

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.

// 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();
hcx.with_def_path_and_no_spans(|hcx| self.internee.hash_stable(hcx, &mut hasher));
hasher.finish()
};
stable_hash.hash_stable(hcx, hasher);
} else {
stable_hash.hash_stable(hcx, hasher);
}
}
}

#[cfg(test)]
mod tests;
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ macro_rules! arena_types {
[] hir_id_set: rustc_hir::HirIdSet,

// Interned types
[] tys: rustc_middle::ty::TyS<'tcx>,
[] tys: rustc_data_structures::intern::InTy<rustc_middle::ty::TyS<'tcx>>,
[] predicates: rustc_middle::ty::PredicateS<'tcx>,
[] consts: rustc_middle::ty::ConstS<'tcx>,

Expand Down
17 changes: 8 additions & 9 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::ty::{
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::intern::{InTy, Interned};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
Expand Down Expand Up @@ -105,7 +105,7 @@ pub struct CtxtInterners<'tcx> {

// Specifically use a speedy hash algorithm for these hash sets, since
// they're accessed quite often.
type_: InternedSet<'tcx, TyS<'tcx>>,
type_: InternedSet<'tcx, InTy<TyS<'tcx>>>,
substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
region: InternedSet<'tcx, RegionKind>,
Expand Down Expand Up @@ -178,10 +178,9 @@ impl<'tcx> CtxtInterners<'tcx> {
kind,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
stable_hash,
};

InternedInSet(self.arena.alloc(ty_struct))
InternedInSet(self.arena.alloc(InTy { internee: ty_struct, stable_hash }))
})
.0,
))
Expand Down Expand Up @@ -2048,23 +2047,23 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> {
}

#[allow(rustc::usage_of_ty_tykind)]
impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, TyS<'tcx>> {
impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, InTy<TyS<'tcx>>> {
fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
&self.0.kind
}
}

impl<'tcx> PartialEq for InternedInSet<'tcx, TyS<'tcx>> {
fn eq(&self, other: &InternedInSet<'tcx, TyS<'tcx>>) -> bool {
impl<'tcx> PartialEq for InternedInSet<'tcx, InTy<TyS<'tcx>>> {
fn eq(&self, other: &InternedInSet<'tcx, InTy<TyS<'tcx>>>) -> bool {
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
// `x == y`.
self.0.kind == other.0.kind
}
}

impl<'tcx> Eq for InternedInSet<'tcx, TyS<'tcx>> {}
impl<'tcx> Eq for InternedInSet<'tcx, InTy<TyS<'tcx>>> {}

impl<'tcx> Hash for InternedInSet<'tcx, TyS<'tcx>> {
impl<'tcx> Hash for InternedInSet<'tcx, InTy<TyS<'tcx>>> {
fn hash<H: Hasher>(&self, s: &mut H) {
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
self.0.kind.hash(s)
Expand Down
45 changes: 11 additions & 34 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ use crate::ty::util::Discr;
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, NodeIdHashingMode, StableHasher};
use rustc_data_structures::intern::{InTy, Interned};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
Expand Down Expand Up @@ -433,32 +433,28 @@ 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<'_>, 56);
static_assert_size!(TyS<'_>, 40);

/// Use this rather than `TyS`, whenever possible.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
#[rustc_diagnostic_item = "Ty"]
#[rustc_pass_by_value]
pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>);
pub struct Ty<'tcx>(Interned<'tcx, InTy<TyS<'tcx>>>);

// Statics only used for internal testing.
pub static BOOL_TY: Ty<'static> = Ty(Interned::new_unchecked(&BOOL_TYS));
static BOOL_TYS: TyS<'static> = TyS {
pub static BOOL_TY: Ty<'static> =
Ty(Interned::new_unchecked(&InTy { internee: BOOL_TYS, stable_hash: Fingerprint::ZERO }));
const 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> {
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let TyS {
kind,
Expand All @@ -468,28 +464,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Ty<'tcx> {
flags: _,

outer_exclusive_binder: _,
} = self;

stable_hash,
} = self.0.0;

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);
}
kind.hash_stable(hcx, hasher)
}
}

Expand Down
49 changes: 34 additions & 15 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
use rustc_apfloat::ieee::{Double, Single};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
use rustc_data_structures::intern::{InTy, Interned};
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
Expand Down Expand Up @@ -1266,18 +1266,29 @@ pub trait PrettyPrinter<'tcx>:
ty::Ref(
_,
Ty(Interned(
Copy link
Member

@bjorn3 bjorn3 Apr 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use nested match with the inner match matching on pointee.kind()? This indentation is getting crazy and pretty unreadable. In addition there are other match arms where the outer type is a reference.

ty::TyS {
kind:
ty::Array(
Ty(Interned(ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, _)),
ty::Const(Interned(
ty::ConstS {
val: ty::ConstKind::Value(ConstValue::Scalar(int)),
..
},
_,
)),
),
InTy {
internee:
ty::TyS {
kind:
ty::Array(
Ty(Interned(
InTy {
internee:
ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. },
..
},
_,
)),
ty::Const(Interned(
ty::ConstS {
val: ty::ConstKind::Value(ConstValue::Scalar(int)),
..
},
_,
)),
),
..
},
..
},
_,
Expand Down Expand Up @@ -1439,7 +1450,11 @@ pub trait PrettyPrinter<'tcx>:
// Byte/string slices, printed as (byte) string literals.
(
ConstValue::Slice { data, start, end },
ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Slice(t), .. }, _)), _),
ty::Ref(
_,
Ty(Interned(InTy { internee: ty::TyS { kind: ty::Slice(t), .. }, .. }, _)),
_,
),
) if *t == u8_type => {
// The `inspect` here is okay since we checked the bounds, and there are
// no relocations (we have an active slice reference here). We don't use
Expand All @@ -1450,7 +1465,11 @@ pub trait PrettyPrinter<'tcx>:
}
(
ConstValue::Slice { data, start, end },
ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Str, .. }, _)), _),
ty::Ref(
_,
Ty(Interned(InTy { internee: ty::TyS { kind: ty::Str, .. }, .. }, _)),
_,
),
) => {
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor}
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};

use rustc_data_structures::intern::Interned;
use rustc_data_structures::intern::{InTy, Interned};
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_serialize::{self, Decodable, Encodable};
Expand Down Expand Up @@ -85,7 +85,7 @@ impl<'tcx> GenericArgKind<'tcx> {
GenericArgKind::Type(ty) => {
// Ensure we can use the tag bits.
assert_eq!(mem::align_of_val(ty.0.0) & TAG_MASK, 0);
(TYPE_TAG, ty.0.0 as *const ty::TyS<'tcx> as usize)
(TYPE_TAG, ty.0.0 as *const InTy<ty::TyS<'tcx>> as usize)
}
GenericArgKind::Const(ct) => {
// Ensure we can use the tag bits.
Expand Down Expand Up @@ -154,7 +154,7 @@ impl<'tcx> GenericArg<'tcx> {
&*((ptr & !TAG_MASK) as *const ty::RegionKind),
))),
TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
&*((ptr & !TAG_MASK) as *const ty::TyS<'tcx>),
&*((ptr & !TAG_MASK) as *const InTy<ty::TyS<'tcx>>),
))),
CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
&*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_apfloat::Float as _;
use rustc_ast as ast;
use rustc_attr::{self as attr, SignedInt, UnsignedInt};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::intern::{InTy, Interned};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
Expand Down Expand Up @@ -427,7 +427,7 @@ impl<'tcx> TyCtxt<'tcx> {
!impl_generics.region_param(ebr, self).pure_wrt_drop
}
GenericArgKind::Type(Ty(Interned(
ty::TyS { kind: ty::Param(ref pt), .. },
InTy { internee: ty::TyS { kind: ty::Param(ref pt), .. }, .. },
_,
))) => !impl_generics.type_param(pt, self).pure_wrt_drop,
GenericArgKind::Const(Const(Interned(
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_query_system/src/ich/hcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,12 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
}
}

impl<'a> rustc_data_structures::intern::InternedHashingContext for StableHashingContext<'a> {
fn with_def_path_and_no_spans(&mut self, f: impl FnOnce(&mut Self)) {
self.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| f(hcx))
});
}
}

impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}