short-cut SharedCrateContext::layout_of

That method is *incredibly* hot, so this ends up saving 10% of trans
time.

BTW, we really should be doing dependency tracking there - and possibly be
taking the respective perf hit (got to find a way to make DTMs fast), but
`layout_cache` is a non-dep-tracking map.
This commit is contained in:
Ariel Ben-Yehuda 2017-04-20 03:14:39 +03:00 committed by Ariel Ben-Yehuda
parent e1377a4f47
commit acd0e40b86
2 changed files with 38 additions and 28 deletions

View File

@ -822,7 +822,7 @@ impl<'a, 'gcx, 'tcx> Struct {
}
(_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
let normalized = normalize_associated_type(infcx, ty);
let normalized = infcx.normalize_projections(ty);
if ty == normalized {
return Ok(None);
}
@ -1067,28 +1067,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
}
}
/// Helper function for normalizing associated types in an inference context.
fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'gcx>)
-> Ty<'gcx> {
if !ty.has_projection_types() {
return ty;
}
let mut selcx = traits::SelectionContext::new(infcx);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &ty);
let mut fulfill_cx = traits::FulfillmentContext::new();
for obligation in obligations {
fulfill_cx.register_predicate_obligation(infcx, obligation);
}
infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
}
impl<'a, 'gcx, 'tcx> Layout {
pub fn compute_uncached(ty: Ty<'gcx>,
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
@ -1100,7 +1078,7 @@ impl<'a, 'gcx, 'tcx> Layout {
let ptr_layout = |pointee: Ty<'gcx>| {
let non_zero = !ty.is_unsafe_ptr();
let pointee = normalize_associated_type(infcx, pointee);
let pointee = infcx.normalize_projections(pointee);
if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) {
Ok(Scalar { value: Pointer, non_zero: non_zero })
} else {
@ -1494,7 +1472,7 @@ impl<'a, 'gcx, 'tcx> Layout {
// Types with no meaningful known layout.
ty::TyProjection(_) | ty::TyAnon(..) => {
let normalized = normalize_associated_type(infcx, ty);
let normalized = infcx.normalize_projections(ty);
if ty == normalized {
return Err(LayoutError::Unknown(ty));
}
@ -1812,7 +1790,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
}
ty::TyProjection(_) | ty::TyAnon(..) => {
let normalized = normalize_associated_type(infcx, ty);
let normalized = infcx.normalize_projections(ty);
if ty == normalized {
Err(err)
} else {
@ -1882,13 +1860,14 @@ pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
type TyLayout;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
}
impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
let ty = normalize_associated_type(self, ty);
let ty = self.normalize_projections(ty);
Ok(TyLayout {
ty: ty,
@ -1896,6 +1875,25 @@ impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
variant_index: None
})
}
fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> {
if !ty.has_projection_types() {
return ty;
}
let mut selcx = traits::SelectionContext::new(self);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &ty);
let mut fulfill_cx = traits::FulfillmentContext::new();
for obligation in obligations {
fulfill_cx.register_predicate_obligation(self, obligation);
}
self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
}
}
impl<'a, 'tcx> TyLayout<'tcx> {
@ -2019,6 +2017,6 @@ impl<'a, 'tcx> TyLayout<'tcx> {
}
pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
cx.layout_of(self.field_type(cx, i))
cx.layout_of(cx.normalize_projections(self.field_type(cx, i)))
}
}

View File

@ -771,6 +771,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
type TyLayout = TyLayout<'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) {
return TyLayout { ty: ty, layout: layout, variant_index: None };
}
self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
infcx.layout_of(ty).unwrap_or_else(|e| {
match e {
@ -781,6 +785,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
})
})
}
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.tcx().normalize_associated_type(&ty)
}
}
impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
@ -789,6 +797,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
self.shared.layout_of(ty)
}
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.shared.normalize_projections(ty)
}
}
pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'a, 'tcx>);