Skip to content

Commit

Permalink
Auto merge of #50959 - Zoxc:int-map, r=<try>
Browse files Browse the repository at this point in the history
[WIP] Use a custom hash set for interning

r? @michaelwoerister
  • Loading branch information
bors committed Jun 4, 2018
2 parents cdc193d + c124143 commit 8a5761a
Show file tree
Hide file tree
Showing 4 changed files with 370 additions and 117 deletions.
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

0 comments on commit 8a5761a

Please sign in to comment.