diff options
| -rw-r--r-- | src/librustc/ty/context.rs | 185 | ||||
| -rw-r--r-- | src/librustc_data_structures/interner.rs | 68 | ||||
| -rw-r--r-- | src/librustc_data_structures/lib.rs | 2 |
3 files changed, 144 insertions, 111 deletions
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5780fbe55ad..4034abb468f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -53,6 +53,7 @@ use ty::CanonicalTy; use ty::CanonicalPolyFnSig; use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; +use rustc_data_structures::interner::HashInterner; use smallvec::SmallVec; use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableHasher, StableHasherResult, @@ -113,7 +114,7 @@ pub struct GlobalArenas<'tcx> { const_allocs: TypedArena<interpret::Allocation>, } -type InternedSet<'tcx, T> = Lock<FxHashSet<Interned<'tcx, T>>>; +type InternedSet<'tcx, T> = Lock<FxHashMap<Interned<'tcx, T>, ()>>; pub struct CtxtInterners<'tcx> { /// The arena that types, regions, etc are allocated from @@ -166,51 +167,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 } } } @@ -825,12 +814,9 @@ impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'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(Bool), @@ -950,14 +936,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<FxHashMap<&'tcx attr::Stability, ()>>, /// Stores the value of constants (and deduplicates the actual memory) - allocation_interner: Lock<FxHashSet<&'tcx Allocation>>, + allocation_interner: Lock<FxHashMap<&'tcx Allocation, ()>>, pub alloc_map: Lock<interpret::AllocMap<'tcx, &'tcx Allocation>>, - layout_interner: Lock<FxHashSet<&'tcx LayoutDetails>>, + layout_interner: Lock<FxHashMap<&'tcx LayoutDetails, ()>>, /// A general purpose channel to throw data out the back towards LLVM worker /// threads. @@ -1040,16 +1026,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) { // insert into interner - 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`, read-only @@ -1061,29 +1040,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) + }) } /// Returns a range of the start/end indices specified with the @@ -2193,7 +2158,7 @@ macro_rules! sty_debug_print { }; $(let mut $variant = total;)* - for &Interned(t) in tcx.interners.type_.borrow().iter() { + for &Interned(t) in tcx.interners.type_.borrow().keys() { let variant = match t.sty { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, @@ -2252,6 +2217,13 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// An entry in an interner. struct Interned<'tcx, T: 'tcx+?Sized>(&'tcx T); +impl<'tcx, T: 'tcx+?Sized> Clone for Interned<'tcx, T> { + fn clone(&self) -> Self { + Interned(self.0) + } +} +impl<'tcx, T: 'tcx+?Sized> Copy for Interned<'tcx, T> {} + // NB: An Interned<Ty> compares and hashes as a sty. impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool { @@ -2372,37 +2344,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 } } } diff --git a/src/librustc_data_structures/interner.rs b/src/librustc_data_structures/interner.rs new file mode 100644 index 00000000000..29e5aefee7f --- /dev/null +++ b/src/librustc_data_structures/interner.rs @@ -0,0 +1,68 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::hash::Hash; +use std::hash::BuildHasher; +use std::hash::Hasher; +use std::collections::HashMap; +use std::collections::hash_map::RawEntryMut; +use std::borrow::Borrow; + +pub trait HashInterner<K: Eq + Hash> { + fn intern_ref<Q: ?Sized, F: FnOnce() -> K>(&mut self, value: &Q, make: F) -> K + where K: Borrow<Q>, + Q: Hash + Eq; + + fn intern<Q, F: FnOnce(Q) -> K>(&mut self, value: Q, make: F) -> K + where K: Borrow<Q>, + Q: Hash + Eq; +} + +impl<K: Eq + Hash + Copy, S: BuildHasher> HashInterner<K> for HashMap<K, (), S> { + #[inline] + fn intern_ref<Q: ?Sized, F: FnOnce() -> K>(&mut self, value: &Q, make: F) -> K + where K: Borrow<Q>, + Q: Hash + Eq + { + let mut hasher = self.hasher().build_hasher(); + value.hash(&mut hasher); + let hash = hasher.finish(); + let entry = self.raw_entry_mut().from_key_hashed_nocheck(hash, value); + + match entry { + RawEntryMut::Occupied(e) => *e.key(), + RawEntryMut::Vacant(e) => { + let v = make(); + e.insert_hashed_nocheck(hash, v, ()); + v + } + } + } + + #[inline] + fn intern<Q, F: FnOnce(Q) -> K>(&mut self, value: Q, make: F) -> K + where K: Borrow<Q>, + Q: Hash + Eq + { + let mut hasher = self.hasher().build_hasher(); + value.hash(&mut hasher); + let hash = hasher.finish(); + let entry = self.raw_entry_mut().from_key_hashed_nocheck(hash, &value); + + match entry { + RawEntryMut::Occupied(e) => *e.key(), + RawEntryMut::Vacant(e) => { + let v = make(value); + e.insert_hashed_nocheck(hash, v, ()); + v + } + } + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 135abebdacb..96cb235a933 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -29,6 +29,7 @@ #![feature(nll)] #![feature(allow_internal_unstable)] #![feature(vec_resize_with)] +#![feature(hash_raw_entry)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] @@ -66,6 +67,7 @@ pub mod flock; pub mod fx; pub mod graph; pub mod indexed_vec; +pub mod interner; pub mod obligation_forest; pub mod owning_ref; pub mod ptr_key; |
