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

[WIP] Use a custom hash set for interning #50959

Closed
wants to merge 3 commits into from
Closed
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
190 changes: 73 additions & 117 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use ty::BindingMode;
use ty::CanonicalTy;
use util::nodemap::{DefIdSet, ItemLocalMap};
use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::fx::FxInterner;
use rustc_data_structures::accumulate_vec::AccumulateVec;
use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
StableHasher, StableHasherResult,
Expand Down Expand Up @@ -124,15 +125,15 @@ impl<'tcx> GlobalArenas<'tcx> {
}
}

type InternedSet<'tcx, T> = Lock<FxHashSet<Interned<'tcx, T>>>;
type InternedSet<'tcx, T> = Lock<FxInterner<Interned<'tcx, T>>>;

pub struct CtxtInterners<'tcx> {
/// The arena that types, regions, etc are allocated from
arena: &'tcx SyncDroplessArena,

/// Specifically use a speedy hash algorithm for these hash sets,
/// they're accessed quite often.
type_: InternedSet<'tcx, TyS<'tcx>>,
type_: Lock<FxInterner<Interned<'tcx, TyS<'tcx>>>>,
type_list: InternedSet<'tcx, Slice<Ty<'tcx>>>,
substs: InternedSet<'tcx, Substs<'tcx>>,
canonical_var_infos: InternedSet<'tcx, Slice<CanonicalVarInfo>>,
Expand Down Expand Up @@ -173,51 +174,39 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
// determine that all contents are in the global tcx.
// See comments on Lift for why we can't use that.
if flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
let mut interner = local.type_.borrow_mut();
if let Some(&Interned(ty)) = interner.get(&st) {
return ty;
}

let ty_struct = TyS {
sty: st,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
};
local.type_.borrow_mut().intern(st, |st| {
let ty_struct = TyS {
sty: st,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
};

// Make sure we don't end up with inference
// types/regions in the global interner
if local as *const _ as usize == global as *const _ as usize {
bug!("Attempted to intern `{:?}` which contains \
inference types/regions in the global type context",
&ty_struct);
}
// Make sure we don't end up with inference
// types/regions in the global interner
if local as *const _ as usize == global as *const _ as usize {
bug!("Attempted to intern `{:?}` which contains \
inference types/regions in the global type context",
&ty_struct);
}

// Don't be &mut TyS.
let ty: Ty<'tcx> = local.arena.alloc(ty_struct);
interner.insert(Interned(ty));
ty
Interned(local.arena.alloc(ty_struct))
}).0
} else {
let mut interner = global.type_.borrow_mut();
if let Some(&Interned(ty)) = interner.get(&st) {
return ty;
}

let ty_struct = TyS {
sty: st,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
};
global.type_.borrow_mut().intern(st, |st| {
let ty_struct = TyS {
sty: st,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
};

// This is safe because all the types the ty_struct can point to
// already is in the global arena
let ty_struct: TyS<'gcx> = unsafe {
mem::transmute(ty_struct)
};
// This is safe because all the types the ty_struct can point to
// already is in the global arena
let ty_struct: TyS<'gcx> = unsafe {
mem::transmute(ty_struct)
};

// Don't be &mut TyS.
let ty: Ty<'gcx> = global.arena.alloc(ty_struct);
interner.insert(Interned(ty));
ty
Interned(global.arena.alloc(ty_struct))
}).0
}
}
}
Expand Down Expand Up @@ -800,12 +789,9 @@ impl<'tcx> CommonTypes<'tcx> {

let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
let mk_region = |r| {
if let Some(r) = interners.region.borrow().get(&r) {
return r.0;
}
let r = interners.arena.alloc(r);
interners.region.borrow_mut().insert(Interned(r));
&*r
interners.region.borrow_mut().intern(r, |r| {
Interned(interners.arena.alloc(r))
}).0
};
CommonTypes {
bool: mk(TyBool),
Expand Down Expand Up @@ -916,14 +902,14 @@ pub struct GlobalCtxt<'tcx> {
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,

stability_interner: Lock<FxHashSet<&'tcx attr::Stability>>,
stability_interner: Lock<FxInterner<&'tcx attr::Stability>>,

/// Stores the value of constants (and deduplicates the actual memory)
allocation_interner: Lock<FxHashSet<&'tcx Allocation>>,
allocation_interner: Lock<FxInterner<&'tcx Allocation>>,

pub alloc_map: Lock<interpret::AllocMap<'tcx, &'tcx Allocation>>,

layout_interner: Lock<FxHashSet<&'tcx LayoutDetails>>,
layout_interner: Lock<FxInterner<&'tcx LayoutDetails>>,

/// A general purpose channel to throw data out the back towards LLVM worker
/// threads.
Expand Down Expand Up @@ -1006,16 +992,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self,
alloc: Allocation,
) -> &'gcx Allocation {
let allocs = &mut self.allocation_interner.borrow_mut();
if let Some(alloc) = allocs.get(&alloc) {
return alloc;
}

let interned = self.global_arenas.const_allocs.alloc(alloc);
if let Some(prev) = allocs.replace(interned) {
bug!("Tried to overwrite interned Allocation: {:#?}", prev)
}
interned
self.allocation_interner.borrow_mut().intern(alloc, |alloc| {
self.global_arenas.const_allocs.alloc(alloc)
})
}

/// Allocates a byte or string literal for `mir::interpret`
Expand All @@ -1027,29 +1006,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}

pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {
let mut stability_interner = self.stability_interner.borrow_mut();
if let Some(st) = stability_interner.get(&stab) {
return st;
}

let interned = self.global_interners.arena.alloc(stab);
if let Some(prev) = stability_interner.replace(interned) {
bug!("Tried to overwrite interned Stability: {:?}", prev)
}
interned
self.stability_interner.borrow_mut().intern(stab, |stab| {
self.global_interners.arena.alloc(stab)
})
}

pub fn intern_layout(self, layout: LayoutDetails) -> &'gcx LayoutDetails {
let mut layout_interner = self.layout_interner.borrow_mut();
if let Some(layout) = layout_interner.get(&layout) {
return layout;
}

let interned = self.global_arenas.layout.alloc(layout);
if let Some(prev) = layout_interner.replace(interned) {
bug!("Tried to overwrite interned Layout: {:?}", prev)
}
interned
self.layout_interner.borrow_mut().intern(layout, |layout| {
self.global_arenas.layout.alloc(layout)
})
}

pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
Expand Down Expand Up @@ -1171,9 +1136,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
evaluation_cache: traits::EvaluationCache::new(),
crate_name: Symbol::intern(crate_name),
data_layout,
layout_interner: Lock::new(FxHashSet()),
stability_interner: Lock::new(FxHashSet()),
allocation_interner: Lock::new(FxHashSet()),
layout_interner: Default::default(),
stability_interner: Default::default(),
allocation_interner: Default::default(),
alloc_map: Lock::new(interpret::AllocMap::new()),
tx_to_llvm_workers: Lock::new(tx),
output_filenames: Arc::new(output_filenames.clone()),
Expand Down Expand Up @@ -1909,7 +1874,7 @@ macro_rules! sty_debug_print {
($ctxt: expr, $($variant: ident),*) => {{
// curious inner module to allow variant names to be used as
// variable names.
#[allow(non_snake_case)]
#[allow(non_snake_case, warnings)]
mod inner {
use ty::{self, TyCtxt};
use ty::context::Interned;
Expand All @@ -1929,7 +1894,7 @@ macro_rules! sty_debug_print {
};
$(let mut $variant = total;)*


/*
for &Interned(t) in tcx.interners.type_.borrow().iter() {
let variant = match t.sty {
ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
Expand All @@ -1945,7 +1910,7 @@ macro_rules! sty_debug_print {
if region { total.region_infer += 1; variant.region_infer += 1 }
if ty { total.ty_infer += 1; variant.ty_infer += 1 }
if region && ty { total.both_infer += 1; variant.both_infer += 1 }
}
}*/
println!("Ty interner total ty region both");
$(println!(" {:18}: {uses:6} {usespc:4.1}%, \
{ty:4.1}% {region:5.1}% {both:4.1}%",
Expand Down Expand Up @@ -2096,37 +2061,28 @@ macro_rules! intern_method {
// determine that all contents are in the global tcx.
// See comments on Lift for why we can't use that.
if ($keep_in_local_tcx)(&v) {
let mut interner = self.interners.$name.borrow_mut();
if let Some(&Interned(v)) = interner.get(key) {
return v;
}

// Make sure we don't end up with inference
// types/regions in the global tcx.
if self.is_global() {
bug!("Attempted to intern `{:?}` which contains \
inference types/regions in the global type context",
v);
}

let i = $alloc_method(&self.interners.arena, v);
interner.insert(Interned(i));
i
self.interners.$name.borrow_mut().intern_ref(key, || {
// Make sure we don't end up with inference
// types/regions in the global tcx.
if self.is_global() {
bug!("Attempted to intern `{:?}` which contains \
inference types/regions in the global type context",
v);
}

Interned($alloc_method(&self.interners.arena, v))
}).0
} else {
let mut interner = self.global_interners.$name.borrow_mut();
if let Some(&Interned(v)) = interner.get(key) {
return v;
}

// This transmutes $alloc<'tcx> to $alloc<'gcx>
let v = unsafe {
mem::transmute(v)
};
let i: &$lt_tcx $ty = $alloc_method(&self.global_interners.arena, v);
// Cast to 'gcx
let i = unsafe { mem::transmute(i) };
interner.insert(Interned(i));
i
self.global_interners.$name.borrow_mut().intern_ref(key, || {
// This transmutes $alloc<'tcx> to $alloc<'gcx>
let v = unsafe {
mem::transmute(v)
};
let i: &$lt_tcx $ty = $alloc_method(&self.global_interners.arena, v);
// Cast to 'gcx
let i = unsafe { mem::transmute(i) };
Interned(i)
}).0
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_data_structures/fx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::hash::Hash;
use std::hash::BuildHasherDefault;
use interner;

pub use rustc_hash::FxHashMap;
pub use rustc_hash::FxHashSet;
pub use rustc_hash::FxHasher;
pub type FxInterner<V> = interner::Interner<V, BuildHasherDefault<FxHasher>>;

#[allow(non_snake_case)]
pub fn FxHashMap<K: Hash + Eq, V>() -> FxHashMap<K, V> {
Expand Down
Loading