Auto merge of #38653 - Mark-Simulacrum:dropless-arena, r=eddyb

Add a DroplessArena and utilize it as a more efficient arena when possible

I will collect performance (probably just `-Ztime-passes`, and more if that shows significant differences, perhaps).

6feba98 also fixes a potential infinite loop if inplace reallocation failed for `TypedArena` (and `DroplessArena` via copied code).

r? @eddyb
This commit is contained in:
bors 2017-01-01 02:39:40 +00:00
commit 08babdb412
9 changed files with 228 additions and 100 deletions

View file

@ -41,6 +41,7 @@ use syntax::ast;
use errors::DiagnosticBuilder;
use syntax_pos::{self, Span, DUMMY_SP};
use util::nodemap::{FxHashMap, FxHashSet, NodeMap};
use arena::DroplessArena;
use self::combine::CombineFields;
use self::higher_ranked::HrMatchResult;
@ -374,7 +375,7 @@ impl fmt::Display for FixupError {
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>).
pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
arenas: ty::CtxtArenas<'tcx>,
arena: DroplessArena,
tables: Option<RefCell<ty::Tables<'tcx>>>,
param_env: Option<ty::ParameterEnvironment<'gcx>>,
projection_mode: Reveal,
@ -388,7 +389,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
InferCtxtBuilder {
global_tcx: self,
arenas: ty::CtxtArenas::new(),
arena: DroplessArena::new(),
tables: tables.map(RefCell::new),
param_env: param_env,
projection_mode: projection_mode,
@ -426,7 +427,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
{
let InferCtxtBuilder {
global_tcx,
ref arenas,
ref arena,
ref tables,
ref mut param_env,
projection_mode,
@ -439,7 +440,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
let param_env = param_env.take().unwrap_or_else(|| {
global_tcx.empty_parameter_environment()
});
global_tcx.enter_local(arenas, |tcx| f(InferCtxt {
global_tcx.enter_local(arena, |tcx| f(InferCtxt {
tcx: tcx,
tables: tables,
projection_cache: RefCell::new(traits::ProjectionCache::new()),

View file

@ -39,7 +39,7 @@ use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::accumulate_vec::AccumulateVec;
use arena::TypedArena;
use arena::{TypedArena, DroplessArena};
use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::hash::{Hash, Hasher};
@ -55,16 +55,9 @@ use syntax::symbol::{Symbol, keywords};
use hir;
/// Internal storage
pub struct CtxtArenas<'tcx> {
pub struct GlobalArenas<'tcx> {
// internings
type_: TypedArena<TyS<'tcx>>,
type_list: TypedArena<Ty<'tcx>>,
substs: TypedArena<Kind<'tcx>>,
bare_fn: TypedArena<BareFnTy<'tcx>>,
region: TypedArena<Region>,
stability: TypedArena<attr::Stability>,
layout: TypedArena<Layout>,
existential_predicates: TypedArena<ExistentialPredicate<'tcx>>,
// references
generics: TypedArena<ty::Generics<'tcx>>,
@ -73,29 +66,21 @@ pub struct CtxtArenas<'tcx> {
mir: TypedArena<RefCell<Mir<'tcx>>>,
}
impl<'tcx> CtxtArenas<'tcx> {
pub fn new() -> CtxtArenas<'tcx> {
CtxtArenas {
type_: TypedArena::new(),
type_list: TypedArena::new(),
substs: TypedArena::new(),
bare_fn: TypedArena::new(),
region: TypedArena::new(),
stability: TypedArena::new(),
impl<'tcx> GlobalArenas<'tcx> {
pub fn new() -> GlobalArenas<'tcx> {
GlobalArenas {
layout: TypedArena::new(),
existential_predicates: TypedArena::new(),
generics: TypedArena::new(),
trait_def: TypedArena::new(),
adt_def: TypedArena::new(),
mir: TypedArena::new()
mir: TypedArena::new(),
}
}
}
pub struct CtxtInterners<'tcx> {
/// The arenas that types etc are allocated from.
arenas: &'tcx CtxtArenas<'tcx>,
/// The arena that types, regions, etc are allocated from
arena: &'tcx DroplessArena,
/// Specifically use a speedy hash algorithm for these hash sets,
/// they're accessed quite often.
@ -104,22 +89,18 @@ pub struct CtxtInterners<'tcx> {
substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
bare_fn: RefCell<FxHashSet<Interned<'tcx, BareFnTy<'tcx>>>>,
region: RefCell<FxHashSet<Interned<'tcx, Region>>>,
stability: RefCell<FxHashSet<&'tcx attr::Stability>>,
layout: RefCell<FxHashSet<&'tcx Layout>>,
existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
}
impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
fn new(arenas: &'tcx CtxtArenas<'tcx>) -> CtxtInterners<'tcx> {
fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> {
CtxtInterners {
arenas: arenas,
arena: arena,
type_: RefCell::new(FxHashSet()),
type_list: RefCell::new(FxHashSet()),
substs: RefCell::new(FxHashSet()),
bare_fn: RefCell::new(FxHashSet()),
region: RefCell::new(FxHashSet()),
stability: RefCell::new(FxHashSet()),
layout: RefCell::new(FxHashSet()),
existential_predicates: RefCell::new(FxHashSet()),
}
}
@ -158,7 +139,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
let ty_struct: TyS<'gcx> = unsafe {
mem::transmute(ty_struct)
};
let ty: Ty<'gcx> = interner.arenas.type_.alloc(ty_struct);
let ty: Ty<'gcx> = interner.arena.alloc(ty_struct);
global_interner.unwrap().insert(Interned(ty));
return ty;
}
@ -174,7 +155,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
}
// Don't be &mut TyS.
let ty: Ty<'tcx> = self.arenas.type_.alloc(ty_struct);
let ty: Ty<'tcx> = self.arena.alloc(ty_struct);
interner.insert(Interned(ty));
ty
};
@ -391,6 +372,7 @@ impl<'a, 'gcx, 'tcx> Deref for TyCtxt<'a, 'gcx, 'tcx> {
}
pub struct GlobalCtxt<'tcx> {
global_arenas: &'tcx GlobalArenas<'tcx>,
global_interners: CtxtInterners<'tcx>,
pub specializes_cache: RefCell<traits::SpecializesCache>,
@ -586,6 +568,10 @@ pub struct GlobalCtxt<'tcx> {
/// Map from function to the `#[derive]` mode that it's defining. Only used
/// by `proc-macro` crates.
pub derive_macros: RefCell<NodeMap<Symbol>>,
stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,
layout_interner: RefCell<FxHashSet<&'tcx Layout>>,
}
impl<'tcx> GlobalCtxt<'tcx> {
@ -649,15 +635,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn alloc_generics(self, generics: ty::Generics<'gcx>)
-> &'gcx ty::Generics<'gcx> {
self.global_interners.arenas.generics.alloc(generics)
self.global_arenas.generics.alloc(generics)
}
pub fn alloc_mir(self, mir: Mir<'gcx>) -> &'gcx RefCell<Mir<'gcx>> {
self.global_interners.arenas.mir.alloc(RefCell::new(mir))
self.global_arenas.mir.alloc(RefCell::new(mir))
}
pub fn alloc_trait_def(self, def: ty::TraitDef) -> &'gcx ty::TraitDef {
self.global_interners.arenas.trait_def.alloc(def)
self.global_arenas.trait_def.alloc(def)
}
pub fn alloc_adt_def(self,
@ -666,32 +652,28 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
variants: Vec<ty::VariantDef>)
-> &'gcx ty::AdtDef {
let def = ty::AdtDef::new(self, did, kind, variants);
self.global_interners.arenas.adt_def.alloc(def)
self.global_arenas.adt_def.alloc(def)
}
pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {
if let Some(st) = self.global_interners.stability.borrow().get(&stab) {
if let Some(st) = self.stability_interner.borrow().get(&stab) {
return st;
}
let interned = self.global_interners.arenas.stability.alloc(stab);
if let Some(prev) = self.global_interners.stability
.borrow_mut()
.replace(interned) {
let interned = self.global_interners.arena.alloc(stab);
if let Some(prev) = self.stability_interner.borrow_mut().replace(interned) {
bug!("Tried to overwrite interned Stability: {:?}", prev)
}
interned
}
pub fn intern_layout(self, layout: Layout) -> &'gcx Layout {
if let Some(layout) = self.global_interners.layout.borrow().get(&layout) {
if let Some(layout) = self.layout_interner.borrow().get(&layout) {
return layout;
}
let interned = self.global_interners.arenas.layout.alloc(layout);
if let Some(prev) = self.global_interners.layout
.borrow_mut()
.replace(interned) {
let interned = self.global_arenas.layout.alloc(layout);
if let Some(prev) = self.layout_interner.borrow_mut().replace(interned) {
bug!("Tried to overwrite interned Layout: {:?}", prev)
}
interned
@ -728,24 +710,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
/// reference to the context, to allow formatting values that need it.
pub fn create_and_enter<F, R>(s: &'tcx Session,
arenas: &'tcx CtxtArenas<'tcx>,
arenas: &'tcx GlobalArenas<'tcx>,
arena: &'tcx DroplessArena,
resolutions: ty::Resolutions,
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
region_maps: RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index<'tcx>,
crate_name: &str,
crate_name: &str,
f: F) -> R
where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R
{
let data_layout = TargetDataLayout::parse(s);
let interners = CtxtInterners::new(arenas);
let interners = CtxtInterners::new(arena);
let common_types = CommonTypes::new(&interners);
let dep_graph = map.dep_graph.clone();
let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
tls::enter_global(GlobalCtxt {
specializes_cache: RefCell::new(traits::SpecializesCache::new()),
global_arenas: arenas,
global_interners: interners,
dep_graph: dep_graph.clone(),
types: common_types,
@ -794,18 +778,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
crate_name: Symbol::intern(crate_name),
data_layout: data_layout,
layout_cache: RefCell::new(FxHashMap()),
layout_interner: RefCell::new(FxHashSet()),
layout_depth: Cell::new(0),
derive_macros: RefCell::new(NodeMap()),
stability_interner: RefCell::new(FxHashSet()),
}, f)
}
}
impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
/// Call the closure with a local `TyCtxt` using the given arenas.
pub fn enter_local<F, R>(&self, arenas: &'tcx CtxtArenas<'tcx>, f: F) -> R
/// Call the closure with a local `TyCtxt` using the given arena.
pub fn enter_local<F, R>(&self, arena: &'tcx DroplessArena, f: F) -> R
where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
{
let interners = CtxtInterners::new(arenas);
let interners = CtxtInterners::new(arena);
tls::enter(self, &interners, f)
}
}
@ -835,10 +821,8 @@ pub trait Lift<'tcx> {
impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
type Lifted = Ty<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
if let Some(&Interned(ty)) = tcx.interners.type_.borrow().get(&self.sty) {
if *self as *const _ == ty as *const _ {
return Some(ty);
}
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
@ -855,10 +839,8 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
if self.len() == 0 {
return Some(Slice::empty());
}
if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(&self[..]) {
if *self as *const _ == substs as *const _ {
return Some(substs);
}
if tcx.interners.arena.in_arena(&self[..] as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
@ -872,10 +854,8 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
impl<'a, 'tcx> Lift<'tcx> for &'a Region {
type Lifted = &'tcx Region;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Region> {
if let Some(&Interned(region)) = tcx.interners.region.borrow().get(*self) {
if *self as *const _ == region as *const _ {
return Some(region);
}
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
@ -893,10 +873,8 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Ty<'a>> {
if self.len() == 0 {
return Some(Slice::empty());
}
if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(&self[..]) {
if *self as *const _ == list as *const _ {
return Some(list);
}
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
@ -914,10 +892,8 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<ExistentialPredicate<'a>> {
if self.is_empty() {
return Some(Slice::empty());
}
if let Some(&Interned(eps)) = tcx.interners.existential_predicates.borrow().get(&self[..]) {
if *self as *const _ == eps as *const _ {
return Some(eps);
}
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
@ -932,10 +908,8 @@ impl<'a, 'tcx> Lift<'tcx> for &'a BareFnTy<'a> {
type Lifted = &'tcx BareFnTy<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
-> Option<&'tcx BareFnTy<'tcx>> {
if let Some(&Interned(fty)) = tcx.interners.bare_fn.borrow().get(*self) {
if *self as *const _ == fty as *const _ {
return Some(fty);
}
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
@ -1101,8 +1075,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
println!("Substs interner: #{}", self.interners.substs.borrow().len());
println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
println!("Region interner: #{}", self.interners.region.borrow().len());
println!("Stability interner: #{}", self.interners.stability.borrow().len());
println!("Layout interner: #{}", self.interners.layout.borrow().len());
println!("Stability interner: #{}", self.stability_interner.borrow().len());
println!("Layout interner: #{}", self.layout_interner.borrow().len());
}
}
@ -1205,8 +1179,7 @@ macro_rules! intern_method {
let v = unsafe {
mem::transmute(v)
};
let i = ($alloc_to_ret)(self.global_interners.arenas.$name
.$alloc_method(v));
let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
self.global_interners.$name.borrow_mut().insert(Interned(i));
return i;
}
@ -1220,7 +1193,7 @@ macro_rules! intern_method {
}
}
let i = ($alloc_to_ret)(self.interners.arenas.$name.$alloc_method(v));
let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
self.interners.$name.borrow_mut().insert(Interned(i));
i
}

View file

@ -68,8 +68,8 @@ pub use self::sty::Region::*;
pub use self::sty::TypeVariants::*;
pub use self::contents::TypeContents;
pub use self::context::{TyCtxt, tls};
pub use self::context::{CtxtArenas, Lift, Tables};
pub use self::context::{TyCtxt, GlobalArenas, tls};
pub use self::context::{Lift, Tables};
pub use self::trait_def::{TraitDef, TraitFlags};