From c81c258b39e3e189779361804f774385cdf0be09 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Sat, 18 May 2019 09:37:51 +0200 Subject: [PATCH 1/2] Improve performance of generic tuples code generation Improves the state of #6524. Instead of convering all tuples to arrays and performing the operations on them, we take advantage of the fact that those Tuples are products and have productIterators. Implementations of tail, *: and ++ on iterators do not require extra collentions to be created, hence it is also probably more performant at runtime. --- library/src-3.x/scala/Tuple.scala | 64 +++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/library/src-3.x/scala/Tuple.scala b/library/src-3.x/scala/Tuple.scala index 2f0b1a9626de..e2848c0b7445 100644 --- a/library/src-3.x/scala/Tuple.scala +++ b/library/src-3.x/scala/Tuple.scala @@ -49,7 +49,7 @@ sealed trait Tuple extends Any { val t = asInstanceOf[Tuple4[_, _, _, _]] Tuple5(x, t._1, t._2, t._3, t._4).asInstanceOf[Result] case Some(n) => - knownTupleFromArray[H *: this.type](DynamicTuple.cons$Array(x, toArray)) + knownTupleFromItrator[H *: this.type](Iterator.single(x) ++ this.asInstanceOf[Product].productIterator) case _ => DynamicTuple.dynamic_*:[This, H](this, x) } @@ -74,7 +74,7 @@ sealed trait Tuple extends Any { val u = that.asInstanceOf[Tuple2[_, _]] Tuple4(t._1, t._2, u._1, u._2).asInstanceOf[Result] case _ => - knownTupleFromArray[Result](this.toArray ++ that.toArray) + knownTupleFromItrator[Result](this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) } case Some(3) => val t = asInstanceOf[Tuple3[_, _, _]] @@ -84,11 +84,11 @@ sealed trait Tuple extends Any { val u = that.asInstanceOf[Tuple1[_]] Tuple4(t._1, t._2, t._3, u._1).asInstanceOf[Result] case _ => - knownTupleFromArray[Result](this.toArray ++ that.toArray) - } + knownTupleFromItrator[Result](this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) + } case Some(_) => if (constValue[BoundedSize[that.type]] == 0) this.asInstanceOf[Result] - else knownTupleFromArray[Result](this.toArray ++ that.toArray) + else knownTupleFromItrator[Result](this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) case None => DynamicTuple.dynamic_++[This, that.type](this, that) } @@ -143,34 +143,32 @@ object Tuple { private[scala] type BoundedSize[X] = BoundedSizeRecur[X, 23] - private[scala] val $emptyArray = Array[Object]() - - private[scala] inline def knownTupleFromArray[T <: Tuple](xs: Array[Object]): T = + private[scala] inline def knownTupleFromItrator[T <: Tuple](it: Iterator[Any]): T = inline constValue[BoundedSize[T]] match { case 0 => ().asInstanceOf[T] - case 1 => Tuple1(xs(0)).asInstanceOf[T] - case 2 => Tuple2(xs(0), xs(1)).asInstanceOf[T] - case 3 => Tuple3(xs(0), xs(1), xs(2)).asInstanceOf[T] - case 4 => Tuple4(xs(0), xs(1), xs(2), xs(3)).asInstanceOf[T] - case 5 => Tuple5(xs(0), xs(1), xs(2), xs(3), xs(4)).asInstanceOf[T] - case 6 => Tuple6(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5)).asInstanceOf[T] - case 7 => Tuple7(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6)).asInstanceOf[T] - case 8 => Tuple8(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7)).asInstanceOf[T] - case 9 => Tuple9(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8)).asInstanceOf[T] - case 10 => Tuple10(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9)).asInstanceOf[T] - case 11 => Tuple11(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10)).asInstanceOf[T] - case 12 => Tuple12(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11)).asInstanceOf[T] - case 13 => Tuple13(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12)).asInstanceOf[T] - case 14 => Tuple14(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13)).asInstanceOf[T] - case 15 => Tuple15(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14)).asInstanceOf[T] - case 16 => Tuple16(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15)).asInstanceOf[T] - case 17 => Tuple17(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16)).asInstanceOf[T] - case 18 => Tuple18(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17)).asInstanceOf[T] - case 19 => Tuple19(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18)).asInstanceOf[T] - case 20 => Tuple20(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19)).asInstanceOf[T] - case 21 => Tuple21(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19), xs(20)).asInstanceOf[T] - case 22 => Tuple22(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19), xs(20), xs(21)).asInstanceOf[T] - case _ => TupleXXL(xs).asInstanceOf[T] + case 1 => Tuple1(it.next()).asInstanceOf[T] + case 2 => Tuple2(it.next(), it.next()).asInstanceOf[T] + case 3 => Tuple3(it.next(), it.next(), it.next()).asInstanceOf[T] + case 4 => Tuple4(it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 5 => Tuple5(it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 6 => Tuple6(it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 7 => Tuple7(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 8 => Tuple8(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 9 => Tuple9(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 10 => Tuple10(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 11 => Tuple11(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 12 => Tuple12(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 13 => Tuple13(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 14 => Tuple14(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 15 => Tuple15(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 16 => Tuple16(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 17 => Tuple17(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 18 => Tuple18(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 19 => Tuple19(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 20 => Tuple20(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 21 => Tuple21(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case 22 => Tuple22(it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next(), it.next()).asInstanceOf[T] + case _ => TupleXXL(it.asInstanceOf[Iterator[Object]].toArray).asInstanceOf[T] } def fromArray[T](xs: Array[T]): Tuple = { @@ -233,7 +231,9 @@ sealed trait NonEmptyTuple extends Tuple { val t = asInstanceOf[Tuple5[_, _, _, _, _]] Tuple4(t._2, t._3, t._4, t._5).asInstanceOf[Result] case Some(n) if n > 5 => - knownTupleFromArray[Result](toArray.tail) + val it = this.asInstanceOf[Product].productIterator + it.next() + knownTupleFromItrator[Result](it) case None => DynamicTuple.dynamicTail[This](this) } From 77bce3191f707187ff5bc1a6e7e0eb57b5e8754f Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Sat, 18 May 2019 12:05:01 +0200 Subject: [PATCH 2/2] Avoid recomputing tuple size from type --- library/src-3.x/scala/Tuple.scala | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/library/src-3.x/scala/Tuple.scala b/library/src-3.x/scala/Tuple.scala index e2848c0b7445..a330a1bd78aa 100644 --- a/library/src-3.x/scala/Tuple.scala +++ b/library/src-3.x/scala/Tuple.scala @@ -49,7 +49,7 @@ sealed trait Tuple extends Any { val t = asInstanceOf[Tuple4[_, _, _, _]] Tuple5(x, t._1, t._2, t._3, t._4).asInstanceOf[Result] case Some(n) => - knownTupleFromItrator[H *: this.type](Iterator.single(x) ++ this.asInstanceOf[Product].productIterator) + knownTupleFromItrator[H *: this.type](n + 1, Iterator.single(x) ++ this.asInstanceOf[Product].productIterator) case _ => DynamicTuple.dynamic_*:[This, H](this, x) } @@ -73,8 +73,8 @@ sealed trait Tuple extends Any { case 2 => val u = that.asInstanceOf[Tuple2[_, _]] Tuple4(t._1, t._2, u._1, u._2).asInstanceOf[Result] - case _ => - knownTupleFromItrator[Result](this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) + case m => + knownTupleFromItrator[Result](2 + m, this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) } case Some(3) => val t = asInstanceOf[Tuple3[_, _, _]] @@ -83,12 +83,14 @@ sealed trait Tuple extends Any { case 1 => val u = that.asInstanceOf[Tuple1[_]] Tuple4(t._1, t._2, t._3, u._1).asInstanceOf[Result] - case _ => - knownTupleFromItrator[Result](this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) + case m => + knownTupleFromItrator[Result](3 + m, this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) } - case Some(_) => - if (constValue[BoundedSize[that.type]] == 0) this.asInstanceOf[Result] - else knownTupleFromItrator[Result](this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) + case Some(n) => + inline constValue[BoundedSize[that.type]] match { + case 0 => this.asInstanceOf[Result] + case m => knownTupleFromItrator[Result](n + m, this.asInstanceOf[Product].productIterator ++ that.asInstanceOf[Product].productIterator) + } case None => DynamicTuple.dynamic_++[This, that.type](this, that) } @@ -141,10 +143,10 @@ object Tuple { } } - private[scala] type BoundedSize[X] = BoundedSizeRecur[X, 23] + private[scala] type BoundedSize[X] = BoundedSizeRecur[X, 24] - private[scala] inline def knownTupleFromItrator[T <: Tuple](it: Iterator[Any]): T = - inline constValue[BoundedSize[T]] match { + private[scala] inline def knownTupleFromItrator[T <: Tuple](n: Int, it: Iterator[Any]): T = + inline n match { case 0 => ().asInstanceOf[T] case 1 => Tuple1(it.next()).asInstanceOf[T] case 2 => Tuple2(it.next(), it.next()).asInstanceOf[T] @@ -233,7 +235,7 @@ sealed trait NonEmptyTuple extends Tuple { case Some(n) if n > 5 => val it = this.asInstanceOf[Product].productIterator it.next() - knownTupleFromItrator[Result](it) + knownTupleFromItrator[Result](n - 1, it) case None => DynamicTuple.dynamicTail[This](this) }