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

Put all cached values into a central struct instead of just the stable hash #104898

Merged
merged 6 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
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
83 changes: 0 additions & 83 deletions compiler/rustc_data_structures/src/intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ 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 @@ -110,86 +108,5 @@ where
}
}

/// A helper type that you can wrap round your own type in order to automatically
/// cache the stable hash on creation and not recompute it whenever the stable hash
/// of the type is computed.
/// 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.
#[derive(Copy, Clone)]
pub struct WithStableHash<T> {
pub internee: T,
pub stable_hash: Fingerprint,
}

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

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

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

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

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

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

impl<T: Hash> Hash for WithStableHash<T> {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
if self.stable_hash != Fingerprint::ZERO {
self.stable_hash.hash(s)
} else {
self.internee.hash(s)
}
}
}

impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithStableHash<T> {
fn hash_stable(&self, hcx: &mut CTX, 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);
}
}
}

#[cfg(test)]
mod tests;
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/pass_by_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ declare_tool_lint! {
/// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to
/// always be passed by value. This is usually used for types that are thin wrappers around
/// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which
/// is a reference to an `Interned<TyS>`)
/// is a reference to an `Interned<TyKind>`)
pub rustc::PASS_BY_VALUE,
Warn,
"pass by reference of a type flagged as `#[rustc_pass_by_value]`",
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(rustc::usage_of_ty_tykind)]

/// This higher-order macro declares a list of types which can be allocated by `Arena`.
///
/// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type
Expand Down Expand Up @@ -88,8 +90,8 @@ macro_rules! arena_types {
[] hir_id_set: rustc_hir::HirIdSet,

// Interned types
[] tys: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::TyS<'tcx>>,
[] predicates: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::PredicateS<'tcx>>,
[] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>,
[] predicates: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::PredicateKind<'tcx>>,
[] consts: rustc_middle::ty::ConstS<'tcx>,

// Note that this deliberately duplicates items in the `rustc_hir::arena`,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl hash::Hash for Allocation {
/// Interned types generally have an `Outer` type and an `Inner` type, where
/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
/// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
/// outer type and `TyS` is its inner type.
/// outer type and `TyKind` is its inner type.
///
/// Here things are different because only const allocations are interned. This
/// means that both the inner type (`Allocation`) and the outer type
Expand Down
83 changes: 27 additions & 56 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Type context book-keeping.

#![allow(rustc::usage_of_ty_tykind)]

use crate::arena::Arena;
use crate::dep_graph::{DepGraph, DepKindStruct};
use crate::hir::place::Place as HirPlace;
Expand All @@ -19,15 +21,15 @@ use crate::ty::{
self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy,
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut,
UintTy, Visibility,
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, ProjectionTy, Region,
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy,
Visibility,
};
use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::intern::{Interned, WithStableHash};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
Expand Down Expand Up @@ -67,6 +69,7 @@ use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
use rustc_target::spec::abi;
use rustc_type_ir::sty::TyKind::*;
use rustc_type_ir::WithCachedTypeInfo;
use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags};

use std::any::Any;
Expand Down Expand Up @@ -136,13 +139,13 @@ pub struct CtxtInterners<'tcx> {

// Specifically use a speedy hash algorithm for these hash sets, since
// they're accessed quite often.
type_: InternedSet<'tcx, WithStableHash<TyS<'tcx>>>,
type_: InternedSet<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>,
const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>,
substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
region: InternedSet<'tcx, RegionKind<'tcx>>,
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
predicate: InternedSet<'tcx, WithStableHash<PredicateS<'tcx>>>,
predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
Expand Down Expand Up @@ -193,15 +196,12 @@ impl<'tcx> CtxtInterners<'tcx> {
let stable_hash =
self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);

let ty_struct = TyS {
kind,
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
internee: kind,
stable_hash,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
};

InternedInSet(
self.arena.alloc(WithStableHash { internee: ty_struct, stable_hash }),
)
}))
})
.0,
))
Expand Down Expand Up @@ -245,16 +245,12 @@ impl<'tcx> CtxtInterners<'tcx> {
let stable_hash =
self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);

let predicate_struct = PredicateS {
kind,
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
internee: kind,
stable_hash,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
};

InternedInSet(
self.arena
.alloc(WithStableHash { internee: predicate_struct, stable_hash }),
)
}))
})
.0,
))
Expand Down Expand Up @@ -2057,7 +2053,7 @@ macro_rules! sty_debug_print {
let shards = tcx.interners.type_.lock_shards();
let types = shards.iter().flat_map(|shard| shard.keys());
for &InternedInSet(t) in types {
let variant = match t.kind {
let variant = match t.internee {
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
ty::Float(..) | ty::Str | ty::Never => continue,
ty::Error(_) => /* unimportant */ continue,
Expand Down Expand Up @@ -2167,51 +2163,26 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> {
}

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

impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<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, WithStableHash<TyS<'tcx>>> {}

impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<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)
}
}

impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>>
for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>>
{
fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
&self.0.kind
impl<'tcx, T> Borrow<T> for InternedInSet<'tcx, WithCachedTypeInfo<T>> {
fn borrow<'a>(&'a self) -> &'a T {
&self.0.internee
}
}

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

impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {}
impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, WithCachedTypeInfo<T>> {}

impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {
impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, WithCachedTypeInfo<T>> {
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)
self.0.internee.hash(s)
}
}

Expand Down
Loading