Skip to content

Commit a5657db

Browse files
committed
perf: Avoid creating a SmallVec if nothing changes during a fold
Not sure if this helps but in theory it should be less work than what the current micro optimization does for `ty::Predicate` lists. (It would explain the overhead I am seeing from `perf`.)
1 parent f48e576 commit a5657db

File tree

1 file changed

+30
-17
lines changed

1 file changed

+30
-17
lines changed

src/librustc/ty/structural_impls.rs

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -803,8 +803,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
803803

804804
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
805805
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
806-
let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
807-
folder.tcx().intern_existential_predicates(&v)
806+
fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v))
808807
}
809808

810809
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -814,8 +813,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>>
814813

815814
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
816815
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
817-
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
818-
folder.tcx().intern_type_list(&v)
816+
fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v))
819817
}
820818

821819
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -825,8 +823,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
825823

826824
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
827825
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
828-
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
829-
folder.tcx().intern_projs(&v)
826+
fold_list(*self, folder, |tcx, v| tcx.intern_projs(v))
830827
}
831828

832829
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -990,17 +987,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
990987

991988
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
992989
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
993-
// This code is hot enough that it's worth specializing for a list of
994-
// length 0. (No other length is common enough to be worth singling
995-
// out).
996-
if self.len() == 0 {
997-
self
998-
} else {
999-
// Don't bother interning if nothing changed, which is the common
1000-
// case.
1001-
let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
1002-
if v[..] == self[..] { self } else { folder.tcx().intern_predicates(&v) }
1003-
}
990+
fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v))
1004991
}
1005992

1006993
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -1073,3 +1060,29 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
10731060
false
10741061
}
10751062
}
1063+
1064+
fn fold_list<'tcx, F, T>(
1065+
list: &'tcx ty::List<T>,
1066+
folder: &mut F,
1067+
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
1068+
) -> &'tcx ty::List<T>
1069+
where
1070+
F: TypeFolder<'tcx>,
1071+
T: TypeFoldable<'tcx> + PartialEq + Copy,
1072+
{
1073+
let mut iter = list.iter();
1074+
// Look for the first element that changed
1075+
if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
1076+
let new_t = t.fold_with(folder);
1077+
if new_t == *t { None } else { Some((i, new_t)) }
1078+
}) {
1079+
// An element changed, prepare to intern the resulting list
1080+
let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
1081+
new_list.copy_from_slice(&list[..i]);
1082+
new_list.push(new_t);
1083+
new_list.extend(iter.map(|t| t.fold_with(folder)));
1084+
intern(folder.tcx(), &new_list)
1085+
} else {
1086+
list
1087+
}
1088+
}

0 commit comments

Comments
 (0)