Skip to content

Commit

Permalink
Auto merge of #50332 - Zoxc:interner-split, r=<try>
Browse files Browse the repository at this point in the history
[WIP] Only lookup types in one interner
  • Loading branch information
bors committed May 2, 2018
2 parents 6a87289 + d452c3e commit 116cf1c
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 13 deletions.
72 changes: 64 additions & 8 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2266,15 +2266,71 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.mk_fn_ptr(converted_sig)
}

// Interns a type/name combination, stores the resulting box in cx.interners,
// and returns the box as cast to an unsafe ptr (see comments for Ty above).
pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
let global_interners = if !self.is_global() {
Some(&self.global_interners)
pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
let keep_in_local_tcx = super::flags::sty_in_local_arena(&st);

// HACK(eddyb) Depend on flags being accurate to
// 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 {
let mut interner = self.interners.type_.borrow_mut();
if let Some(&Interned(ty)) = interner.get(&st) {
return ty;
}

let flags = super::flags::FlagComputation::for_sty(&st);

assert_eq!(
flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX),
true);

let ty_struct = TyS {
sty: st,
flags: flags.flags,
region_depth: flags.depth,
};

// 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",
&ty_struct);
}

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

let flags = super::flags::FlagComputation::for_sty(&st);

assert_eq!(
flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX),
false);

let ty_struct = TyS {
sty: st,
flags: flags.flags,
region_depth: flags.depth,
};

// 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> = self.global_interners.arena.alloc(ty_struct);
interner.insert(Interned(ty));
ty
}
}

pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
Expand Down
142 changes: 142 additions & 0 deletions src/librustc/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,145 @@ impl FlagComputation {
}
}
}

pub(crate) fn sty_in_local_arena(st: &ty::TypeVariants) -> bool {
match *st {
ty::TyBool |
ty::TyChar |
ty::TyInt(_) |
ty::TyFloat(_) |
ty::TyUint(_) |
ty::TyNever |
ty::TyStr |
ty::TyForeign(..) |
ty::TyError |
ty::TyParam(..) => false,

ty::TyGenerator(_, ref substs, ref interior) => {
substs_in_local_arena(&substs.substs) ||
ty_in_local_arena(interior.witness)
}

ty::TyGeneratorWitness(ref ts) => {
tys_in_local_arena(&ts.skip_binder()[..])
}

ty::TyClosure(_, ref substs) => {
substs_in_local_arena(&substs.substs)
}

ty::TyInfer(infer) => {
match infer {
ty::FreshTy(_) |
ty::FreshIntTy(_) |
ty::FreshFloatTy(_) |
ty::CanonicalTy(_) => false,
ty::TyVar(_) |
ty::IntVar(_) |
ty::FloatVar(_) => true
}
}

ty::TyAdt(_, substs) => {
substs_in_local_arena(substs)
}

ty::TyProjection(ref data) => {
substs_in_local_arena(data.substs)
}

ty::TyAnon(_, substs) => {
substs_in_local_arena(substs)
}

ty::TyDynamic(ref obj, r) => {
for predicate in obj.skip_binder().iter() {
match *predicate {
ty::ExistentialPredicate::Trait(tr) => {
if substs_in_local_arena(tr.substs) {
return true;
}
}
ty::ExistentialPredicate::Projection(p) => {
if substs_in_local_arena(p.substs) || ty_in_local_arena(p.ty) {
return true;
}
}
ty::ExistentialPredicate::AutoTrait(_) => {}
}
}
r.keep_in_local_tcx()
}

ty::TyArray(tt, len) => {
ty_in_local_arena(tt) ||
const_in_local_arena(len)
}

ty::TySlice(tt) => {
ty_in_local_arena(tt)
}

ty::TyRawPtr(ref m) => {
ty_in_local_arena(m.ty)
}

ty::TyRef(r, ref m) => {
r.keep_in_local_tcx() ||
ty_in_local_arena(m.ty)
}

ty::TyTuple(ref ts) => {
tys_in_local_arena(&ts[..])
}

ty::TyFnDef(_, substs) => {
substs_in_local_arena(substs)
}

ty::TyFnPtr(f) => {
tys_in_local_arena(f.skip_binder().inputs()) ||
ty_in_local_arena(f.skip_binder().output())
}
}
}

#[inline(always)]
fn ty_in_local_arena(ty: Ty) -> bool {
ty.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX)
}

fn tys_in_local_arena(tys: &[Ty]) -> bool {
for &ty in tys {
if ty_in_local_arena(ty) {
return true;
}
}
false
}

#[inline(always)]
fn const_in_local_arena(constant: &ty::Const) -> bool {
if ty_in_local_arena(constant.ty) {
return true;
}
match constant.val {
ConstVal::Value(_) => false,
ConstVal::Unevaluated(_, substs) => substs_in_local_arena(substs),
}
}

fn substs_in_local_arena(substs: &Substs) -> bool {
for ty in substs.types() {
if ty_in_local_arena(ty) {
return true;
}
}

for r in substs.regions() {
if r.keep_in_local_tcx() {
return true;
}
}
false
}
24 changes: 19 additions & 5 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,9 @@ impl BoundRegion {
}
}

/// NB: If you change this, you'll probably want to change the corresponding
/// AST structure in libsyntax/ast.rs as well.
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum TypeVariants<'tcx> {
macro_rules! type_variants {
([$($t:tt)*][$($p:tt)*]) => {
$($t)*(
/// The primitive boolean type. Written as `bool`.
TyBool,

Expand Down Expand Up @@ -169,9 +168,24 @@ pub enum TypeVariants<'tcx> {

/// A placeholder for a type which could not be computed; this is
/// propagated to avoid useless error messages.
TyError,
TyError,)$($p)*
}
}

macro_rules! declare_type_variants {
($($t:tt)*) => {
/// NB: If you change this, you'll probably want to change the corresponding
/// AST structure in libsyntax/ast.rs as well.
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum TypeVariants<'tcx> {
$($t)*
}
}
}

type_variants!([declare_type_variants!][;]);


/// A closure can be modeled as a struct that looks like:
///
/// struct Closure<'l0...'li, T0...Tj, CK, CS, U0...Uk> {
Expand Down

0 comments on commit 116cf1c

Please sign in to comment.