]> git.lizzy.rs Git - rust.git/commitdiff
introduce a specializes cache
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 17 May 2016 16:05:02 +0000 (12:05 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 17 May 2016 19:52:03 +0000 (15:52 -0400)
This query is frequently used during trait selection and caching the
result can be a reasonable performance win.

src/librustc/traits/mod.rs
src/librustc/traits/specialize/mod.rs
src/librustc/ty/context.rs

index 65df056fd424b2ae71d1b213230758ca0068eb1f..c5db2a8a7807b99c6729d9ae51a67ee9a423e10a 100644 (file)
@@ -38,6 +38,7 @@
 pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
 pub use self::select::{MethodMatchedData}; // intentionally don't export variants
 pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
+pub use self::specialize::{SpecializesCache};
 pub use self::util::elaborate_predicates;
 pub use self::util::supertraits;
 pub use self::util::Supertraits;
index d43d2de1f1fbcdb6f73b6ea80c1e2da0a1864ce8..b2d14dab9a0b0463ce6f623e8bec3cb150e389f4 100644 (file)
@@ -20,6 +20,7 @@
 use super::{SelectionContext, FulfillmentContext};
 use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig};
 
+use rustc_data_structures::fnv::FnvHashMap;
 use hir::def_id::DefId;
 use infer::{InferCtxt, TypeOrigin};
 use middle::region;
@@ -111,6 +112,10 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              impl1_def_id: DefId,
                              impl2_def_id: DefId) -> bool {
+    if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) {
+        return r;
+    }
+
     // The feature gate should prevent introducing new specializations, but not
     // taking advantage of upstream ones.
     if !tcx.sess.features.borrow().specialization &&
@@ -146,7 +151,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              .unwrap()
                              .subst(tcx, &penv.free_substs);
 
-    tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).enter(|mut infcx| {
+    let result = tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).enter(|mut infcx| {
         // Normalize the trait reference, adding any obligations
         // that arise into the impl1 assumptions.
         let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
@@ -167,7 +172,10 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         // Attempt to prove that impl2 applies, given all of the above.
         fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
-    })
+    });
+
+    tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result);
+    result
 }
 
 /// Attempt to fulfill all obligations of `target_impl` after unification with
@@ -225,3 +233,23 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
         }
     })
 }
+
+pub struct SpecializesCache {
+    map: FnvHashMap<(DefId, DefId), bool>
+}
+
+impl SpecializesCache {
+    pub fn new() -> Self {
+        SpecializesCache {
+            map: FnvHashMap()
+        }
+    }
+
+    pub fn check(&self, a: DefId, b: DefId) -> Option<bool> {
+        self.map.get(&(a, b)).cloned()
+    }
+
+    pub fn insert(&mut self, a: DefId, b: DefId, result: bool) {
+        self.map.insert((a, b), result);
+    }
+}
index 39fe744c67d01528f865e96728918c589d6e2b45..aa50266977795ad642460b3db58293337b4c29c6 100644 (file)
@@ -291,6 +291,8 @@ fn deref(&self) -> &Self::Target {
 pub struct GlobalCtxt<'tcx> {
     global_interners: CtxtInterners<'tcx>,
 
+    pub specializes_cache: RefCell<traits::SpecializesCache>,
+
     pub dep_graph: DepGraph,
 
     /// Common types, pre-interned for your convenience.
@@ -637,6 +639,7 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
         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_interners: interners,
             dep_graph: dep_graph.clone(),
             types: common_types,