From a61d85b2fe5ebc25bcc54c7a9e6ce3b98ce00b7c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 13 Oct 2016 23:39:50 +0300 Subject: [PATCH] add a per-param-env cache to `impls_bound` There used to be only a global cache, which led to uncached calls to trait selection when there were type parameters. I'm running a check that there are no adverse performance effects. Fixes #37106 (drop elaboration times are now ~half of borrow checking, so might still be worthy of optimization, but not critical). --- src/librustc/traits/select.rs | 2 +- src/librustc/ty/mod.rs | 16 +++++++++++++-- src/librustc/ty/structural_impls.rs | 17 ---------------- src/librustc/ty/util.rs | 31 +++++++++++++++++++++++------ src/librustc_typeck/check/mod.rs | 2 +- 5 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 666311110971d..dbaa8db3e8971 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -336,7 +336,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.tcx } - pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'tcx> { + pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'gcx> { self.infcx.param_env() } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6db82b862074d..82f3c37b7b1a0 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -34,7 +34,7 @@ use util::nodemap::FnvHashMap; use serialize::{self, Encodable, Encoder}; use std::borrow::Cow; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::hash::{Hash, Hasher}; use std::iter; use std::ops::Deref; @@ -1220,6 +1220,12 @@ pub struct ParameterEnvironment<'tcx> { /// regions don't have this implicit scope and instead introduce /// relationships in the environment. pub free_id_outlive: CodeExtent, + + /// A cache for `moves_by_default`. + pub is_copy_cache: RefCell, bool>>, + + /// A cache for `type_is_sized` + pub is_sized_cache: RefCell, bool>>, } impl<'a, 'tcx> ParameterEnvironment<'tcx> { @@ -1232,6 +1238,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { implicit_region_bound: self.implicit_region_bound, caller_bounds: caller_bounds, free_id_outlive: self.free_id_outlive, + is_copy_cache: RefCell::new(FnvHashMap()), + is_sized_cache: RefCell::new(FnvHashMap()), } } @@ -2773,7 +2781,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { free_substs: Substs::empty(self), caller_bounds: Vec::new(), implicit_region_bound: self.mk_region(ty::ReEmpty), - free_id_outlive: free_id_outlive + free_id_outlive: free_id_outlive, + is_copy_cache: RefCell::new(FnvHashMap()), + is_sized_cache: RefCell::new(FnvHashMap()), } } @@ -2844,6 +2854,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)), caller_bounds: predicates, free_id_outlive: free_id_outlive, + is_copy_cache: RefCell::new(FnvHashMap()), + is_sized_cache: RefCell::new(FnvHashMap()), }; let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps)); diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index abd5cb51f39ba..5948e02620eca 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -901,23 +901,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::ParameterEnvironment { - free_substs: self.free_substs.fold_with(folder), - implicit_region_bound: self.implicit_region_bound.fold_with(folder), - caller_bounds: self.caller_bounds.fold_with(folder), - free_id_outlive: self.free_id_outlive, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.free_substs.visit_with(visitor) || - self.implicit_region_bound.visit_with(visitor) || - self.caller_bounds.visit_with(visitor) - } -} - impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::error::ExpectedFound { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c9ab577a9921d..5b0f43e3cf1f2 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -20,9 +20,11 @@ use ty::{Disr, ParameterEnvironment}; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; use ty::TypeVariants::*; +use util::nodemap::FnvHashMap; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; +use std::cell::RefCell; use std::cmp; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; @@ -579,11 +581,24 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc impl<'a, 'tcx> ty::TyS<'tcx> { fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: &ParameterEnvironment<'tcx>, - bound: ty::BuiltinBound, span: Span) -> bool + bound: ty::BuiltinBound, + cache: &RefCell, bool>>, + span: Span) -> bool { - tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch).enter(|infcx| { - traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span) - }) + if self.has_param_types() || self.has_self_ty() { + if let Some(result) = cache.borrow().get(self) { + return *result; + } + } + let result = + tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch) + .enter(|infcx| { + traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span) + }); + if self.has_param_types() || self.has_self_ty() { + cache.borrow_mut().insert(self, result); + } + return result; } // FIXME (@jroesch): I made this public to use it, not sure if should be private @@ -610,7 +625,9 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) | TyClosure(..) | TyAdt(..) | TyAnon(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None - }.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span)); + }.unwrap_or_else(|| { + !self.impls_bound(tcx, param_env, ty::BoundCopy, ¶m_env.is_copy_cache, span) + }); if !self.has_param_types() && !self.has_self_ty() { self.flags.set(self.flags.get() | if result { @@ -650,7 +667,9 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyAdt(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyAnon(..) | TyError => None - }.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span)); + }.unwrap_or_else(|| { + self.impls_bound(tcx, param_env, ty::BoundSized, ¶m_env.is_sized_cache, span) + }); if !self.has_param_types() && !self.has_self_ty() { self.flags.set(self.flags.get() | if result { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 155a858c1bb20..4116a84c74641 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1458,7 +1458,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn param_env(&self) -> &ty::ParameterEnvironment<'tcx> { + pub fn param_env(&self) -> &ty::ParameterEnvironment<'gcx> { &self.parameter_environment }