@@ -383,14 +383,41 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
383
383
384
384
impl < ' tcx > TypeFoldable < ' tcx > for SubstsRef < ' tcx > {
385
385
fn super_fold_with < F : TypeFolder < ' tcx > > ( & self , folder : & mut F ) -> Self {
386
- let params: SmallVec < [ _ ; 8 ] > = self . iter ( ) . map ( |k| k. fold_with ( folder) ) . collect ( ) ;
387
-
388
- // If folding doesn't change the substs, it's faster to avoid
389
- // calling `mk_substs` and instead reuse the existing substs.
390
- if params[ ..] == self [ ..] {
391
- self
392
- } else {
393
- folder. tcx ( ) . intern_substs ( & params)
386
+ // This code is hot enough that it's worth specializing for the most
387
+ // common length lists, to avoid the overhead of `SmallVec` creation.
388
+ // The match arms are in order of frequency. The 1, 2, and 0 cases are
389
+ // typically hit in 90--99.99% of cases. When folding doesn't change
390
+ // the substs, it's faster to reuse the existing substs rather than
391
+ // calling `intern_substs`.
392
+ match self . len ( ) {
393
+ 1 => {
394
+ let param0 = self [ 0 ] . fold_with ( folder) ;
395
+ if param0 == self [ 0 ] {
396
+ self
397
+ } else {
398
+ folder. tcx ( ) . intern_substs ( & [ param0] )
399
+ }
400
+ }
401
+ 2 => {
402
+ let param0 = self [ 0 ] . fold_with ( folder) ;
403
+ let param1 = self [ 1 ] . fold_with ( folder) ;
404
+ if param0 == self [ 0 ] && param1 == self [ 1 ] {
405
+ self
406
+ } else {
407
+ folder. tcx ( ) . intern_substs ( & [ param0, param1] )
408
+ }
409
+ }
410
+ 0 => {
411
+ self
412
+ }
413
+ _ => {
414
+ let params: SmallVec < [ _ ; 8 ] > = self . iter ( ) . map ( |k| k. fold_with ( folder) ) . collect ( ) ;
415
+ if params[ ..] == self [ ..] {
416
+ self
417
+ } else {
418
+ folder. tcx ( ) . intern_substs ( & params)
419
+ }
420
+ }
394
421
}
395
422
}
396
423
0 commit comments