From 9bc15f8ed8c01758e7414908566bcaedc5fb100b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 30 Apr 2018 08:59:23 +0200 Subject: [PATCH 1/4] Only lookup types in one interner --- src/librustc/ty/context.rs | 60 +++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ce4439e7c5464..22a98ddb7885b 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2266,15 +2266,59 @@ 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 flags = super::flags::FlagComputation::for_sty(&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 flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) { + let mut interner = self.interners.type_.borrow_mut(); + if let Some(&Interned(ty)) = interner.get(&st) { + return ty; + } + + 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 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> { From 89d711d8c497958872771bb753dd0c589ab23f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 1 May 2018 10:16:57 +0200 Subject: [PATCH 2/4] Add a fast path for computing if a type should be in the local interner --- src/librustc/ty/context.rs | 16 +++- src/librustc/ty/flags.rs | 157 +++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 22a98ddb7885b..327cd24824fa8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2267,17 +2267,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> { - let flags = super::flags::FlagComputation::for_sty(&st); + 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 flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) { + 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, @@ -2302,6 +2308,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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, diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 086fc66c70f9d..08ef497c968b9 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -250,3 +250,160 @@ 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(_) => {} + } + } + region_in_local_arena(r) + } + + 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) => { + region_in_local_arena(r) || + 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 +} + +fn region_in_local_arena(r: ty::Region) -> bool { + match *r { + ty::ReVar(..) | ty::ReSkolemized(..) => true, + ty::ReLateBound(..) | + ty::ReEarlyBound(..) | + ty::ReEmpty | + ty::ReStatic | + ty::ReFree { .. } | + ty::ReScope { .. } | + ty::ReErased | + ty::ReCanonical(..) | + ty::ReClosureBound(..) => 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 region_in_local_arena(r) { + return true; + } + } + false +} From abb5a63aef7d6aea499ca12f7b9e3f5c858f3fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 1 May 2018 15:45:54 +0200 Subject: [PATCH 3/4] wip --- src/librustc/ty/sty.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0d6555622149b..b20703bb050aa 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -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, @@ -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> { From d452c3e7ec634aaa1c35a1f171e4726297cebfa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 2 May 2018 09:59:28 +0200 Subject: [PATCH 4/4] fix --- src/librustc/ty/flags.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 08ef497c968b9..515756b26fa8e 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -317,7 +317,7 @@ pub(crate) fn sty_in_local_arena(st: &ty::TypeVariants) -> bool { ty::ExistentialPredicate::AutoTrait(_) => {} } } - region_in_local_arena(r) + r.keep_in_local_tcx() } ty::TyArray(tt, len) => { @@ -334,7 +334,7 @@ pub(crate) fn sty_in_local_arena(st: &ty::TypeVariants) -> bool { } ty::TyRef(r, ref m) => { - region_in_local_arena(r) || + r.keep_in_local_tcx() || ty_in_local_arena(m.ty) } @@ -367,21 +367,6 @@ fn tys_in_local_arena(tys: &[Ty]) -> bool { false } -fn region_in_local_arena(r: ty::Region) -> bool { - match *r { - ty::ReVar(..) | ty::ReSkolemized(..) => true, - ty::ReLateBound(..) | - ty::ReEarlyBound(..) | - ty::ReEmpty | - ty::ReStatic | - ty::ReFree { .. } | - ty::ReScope { .. } | - ty::ReErased | - ty::ReCanonical(..) | - ty::ReClosureBound(..) => false - } -} - #[inline(always)] fn const_in_local_arena(constant: &ty::Const) -> bool { if ty_in_local_arena(constant.ty) { @@ -401,7 +386,7 @@ fn substs_in_local_arena(substs: &Substs) -> bool { } for r in substs.regions() { - if region_in_local_arena(r) { + if r.keep_in_local_tcx() { return true; } }