From b72ca1e0c90e0e9fad487b9ab1e3ee3b521fa7b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 28 Mar 2019 20:26:02 +0100 Subject: [PATCH] Use a more lightweight cache for erase_regions --- src/librustc/dep_graph/graph.rs | 51 ++++++++++++++++++++++++++++++++ src/librustc/query/mod.rs | 17 +---------- src/librustc/ty/context.rs | 13 ++++++-- src/librustc/ty/erase_regions.rs | 23 +++++++------- src/librustc/ty/mod.rs | 1 - 5 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 8a2f79e6793c0..fa517e962a1ca 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -136,6 +136,43 @@ impl DepGraph { DepGraphQuery::new(&nodes[..], &edges[..]) } + pub fn debug_assert_no_deps(op: OP) -> R + where OP: FnOnce() -> R + { + if cfg!(debug_assertions) { + ty::tls::with_context(|icx| { + let task_deps = Lock::new(TaskDeps { + #[cfg(debug_assertions)] + node: None, + #[cfg(debug_assertions)] + no_deps: true, + reads: SmallVec::new(), + read_set: Default::default(), + }); + let icx = ty::tls::ImplicitCtxt { + task_deps: Some(&task_deps), + ..icx.clone() + }; + + let r = ty::tls::enter_context(&icx, |_| { + op() + }); + + for read in &task_deps.lock().reads { + icx.tcx.dep_graph.data.as_ref().map(|graph| { + eprintln!("read: {:?}", graph.current.lock().data[*read].node); + }); + } + // Ensure no dependencies were recorded + assert_eq!(task_deps.into_inner().reads, SmallVec::<[DepNodeIndex; 8]>::new()); + + r + }) + } else { + op() + } + } + pub fn assert_ignored(&self) { if let Some(..) = self.data { @@ -203,6 +240,8 @@ impl DepGraph { |_key| Some(TaskDeps { #[cfg(debug_assertions)] node: Some(_key), + #[cfg(debug_assertions)] + no_deps: false, reads: SmallVec::new(), read_set: Default::default(), }), @@ -345,6 +384,8 @@ impl DepGraph { let task_deps = Lock::new(TaskDeps { #[cfg(debug_assertions)] node: None, + #[cfg(debug_assertions)] + no_deps: false, reads: SmallVec::new(), read_set: Default::default(), }); @@ -1109,6 +1150,14 @@ impl DepGraphData { let icx = if let Some(icx) = icx { icx } else { return }; if let Some(task_deps) = icx.task_deps { let mut task_deps = task_deps.lock(); + + #[cfg(debug_assertions)] + { + if task_deps.no_deps { + panic!("tried to add dependency, but no dependencies are allowed"); + } + } + if cfg!(debug_assertions) { self.current.lock().total_read_count += 1; } @@ -1140,6 +1189,8 @@ impl DepGraphData { pub struct TaskDeps { #[cfg(debug_assertions)] node: Option, + #[cfg(debug_assertions)] + no_deps: bool, reads: SmallVec<[DepNodeIndex; 8]>, read_set: FxHashSet, } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 8d64818f49b18..26c9b7b325870 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -1,6 +1,6 @@ use crate::ty::query::QueryDescription; use crate::ty::query::queries; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, TyCtxt}; use crate::hir::def_id::{DefId, CrateNum}; use crate::dep_graph::SerializedDepNodeIndex; use crate::traits; @@ -113,21 +113,6 @@ rustc_queries! { } TypeChecking { - // Erases regions from `ty` to yield a new type. - // Normally you would just use `tcx.erase_regions(&value)`, - // however, which uses this query as a kind of cache. - query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { - // This query is not expected to have input -- as a result, it - // is not a good candidates for "replay" because it is essentially a - // pure function of its input (and hence the expectation is that - // no caller would be green **apart** from just these - // queries). Making it anonymous avoids hashing the result, which - // may save a bit of time. - anon - no_force - desc { "erasing regions from `{:?}`", ty } - } - query program_clauses_for(_: DefId) -> Clauses<'tcx> { desc { "generating chalk-style clauses" } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6de0a39c91b51..377c13f4f6b83 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -999,6 +999,8 @@ pub struct GlobalCtxt<'tcx> { /// Common types, pre-interned for your convenience. pub types: CommonTypes<'tcx>, + pub(in crate::ty) erased_region_cache: Lock, Ty<'tcx>>>, + /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. trait_map: FxHashMap TyCtxt<'a, 'gcx, 'tcx> { global_interners: interners, dep_graph, types: common_types, + erased_region_cache: Default::default(), trait_map, export_map: resolutions.export_map.into_iter().map(|(k, v)| { (k, Lrc::new(v)) @@ -2727,8 +2730,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>]) -> &'tcx List> { - assert!(!eps.is_empty()); - assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater)); + if cfg!(debug_assertions) { + assert!(!eps.is_empty()); + self.dep_graph.with_ignore(|| { + assert!(eps.windows(2).all(|w| { + w[0].stable_cmp(self, &w[1]) != Ordering::Greater + })); + }); + } self._intern_existential_predicates(eps) } diff --git a/src/librustc/ty/erase_regions.rs b/src/librustc/ty/erase_regions.rs index 0431afcc76c9e..51211fe6f90bf 100644 --- a/src/librustc/ty/erase_regions.rs +++ b/src/librustc/ty/erase_regions.rs @@ -1,17 +1,18 @@ use crate::ty::{self, Ty, TyCtxt, TypeFlags}; use crate::ty::fold::{TypeFolder, TypeFoldable}; - -pub(super) fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { - erase_regions_ty, - ..*providers - }; -} +use crate::dep_graph::DepGraph; fn erase_regions_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - // N.B., use `super_fold_with` here. If we used `fold_with`, it - // could invoke the `erase_regions_ty` query recursively. - ty.super_fold_with(&mut RegionEraserVisitor { tcx }) + if let Some(ty) = tcx.erased_region_cache.lock().get(ty) { + return ty; + } + let result = DepGraph::debug_assert_no_deps(|| { + // N.B., use `super_fold_with` here. If we used `fold_with`, it + // could invoke the `erase_regions_ty` function recursively. + ty.super_fold_with(&mut RegionEraserVisitor { tcx }) + }); + tcx.erased_region_cache.lock().insert(ty, result); + result } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -43,7 +44,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 't fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let Some(ty_lifted) = self.tcx.lift_to_global(&ty) { - self.tcx.erase_regions_ty(ty_lifted) + erase_regions_ty(self.tcx.global_tcx(), ty_lifted) } else { ty.super_fold_with(self) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f0045136f41bf..cdaea2f0bae59 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3345,7 +3345,6 @@ fn issue33140_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn provide(providers: &mut ty::query::Providers<'_>) { context::provide(providers); - erase_regions::provide(providers); layout::provide(providers); util::provide(providers); constness::provide(providers);