From 3d827b4671d62a80a615fb7af11569a2e61ad2e4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 24 Jul 2019 18:57:01 +0200 Subject: [PATCH 1/3] Define TupleXXL and FunctionXXL using IArray This way we can avoid some unnecessary array copies. --- .../dotty/tools/dotc/core/Definitions.scala | 2 -- library/src/scala/FunctionXXL.scala | 2 +- library/src/scala/Tuple.scala | 15 +++++++++++++ library/src/scala/TupleXXL.scala | 22 +++++++++---------- library/src/scala/TupledFunction.scala | 2 +- library/src/scala/runtime/DynamicTuple.scala | 14 ++++++++++-- .../staged-tuples/StagedTuple.scala | 2 +- 7 files changed, 41 insertions(+), 18 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 33af87223344..60df6c4e5fe1 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -710,8 +710,6 @@ class Definitions { @threadUnsafe lazy val TupleXXLClass: ClassSymbolPerRun = perRunClass(ctx.requiredClassRef("scala.TupleXXL")) def TupleXXLModule(implicit ctx: Context): Symbol = TupleXXLClass.companionModule - def TupleXXL_apply(implicit ctx: Context): Symbol = - TupleXXLModule.info.member(nme.apply).requiredSymbol("method", nme.apply, TupleXXLModule)(_.info.isVarArgsMethod) def TupleXXL_fromIterator(implicit ctx: Context): Symbol = TupleXXLModule.requiredMethod("fromIterator") lazy val DynamicTupleModule: Symbol = ctx.requiredModule("scala.runtime.DynamicTuple") diff --git a/library/src/scala/FunctionXXL.scala b/library/src/scala/FunctionXXL.scala index 25e7af609b3b..7b14f871d796 100644 --- a/library/src/scala/FunctionXXL.scala +++ b/library/src/scala/FunctionXXL.scala @@ -3,7 +3,7 @@ package scala /** A function with all parameters grouped in an array. */ trait FunctionXXL { - def apply(xs: Array[Object]): Object + def apply(xs: IArray[Object]): Object override def toString() = "" } diff --git a/library/src/scala/Tuple.scala b/library/src/scala/Tuple.scala index 24389c0747b7..87fb5c2073ec 100644 --- a/library/src/scala/Tuple.scala +++ b/library/src/scala/Tuple.scala @@ -13,6 +13,10 @@ sealed trait Tuple extends Any { inline def toArray: Array[Object] = DynamicTuple.dynamicToArray(this) + /** Create a copy this tuple as an IArray */ + inline def toIArray: IArray[Object] = + DynamicTuple.dynamicToIArray(this) + /** Return a new tuple by prepending the element to `this` tuple. * This opteration is O(this.size) */ @@ -79,6 +83,17 @@ object Tuple { DynamicTuple.dynamicFromArray[Tuple](xs2) } + /** Convert an immutable array into a tuple of unknown arity and types */ + def fromIArray[T](xs: IArray[T]): Tuple = { + val xs2: IArray[Object] = xs match { + case xs: IArray[Object] => xs + case xs => + // TODO suport IArray.map + xs.asInstanceOf[Array[T]].map(_.asInstanceOf[Object]).asInstanceOf[IArray[Object]] + } + DynamicTuple.dynamicFromIArray[Tuple](xs2) + } + /** Convert a Product into a tuple of unknown arity and types */ def fromProduct(product: Product): Tuple = runtime.DynamicTuple.dynamicFromProduct[Tuple](product) diff --git a/library/src/scala/TupleXXL.scala b/library/src/scala/TupleXXL.scala index 4f609683933d..8404c9787f5c 100644 --- a/library/src/scala/TupleXXL.scala +++ b/library/src/scala/TupleXXL.scala @@ -1,35 +1,35 @@ package scala import java.util.Arrays.{deepEquals, deepHashCode} -final class TupleXXL private (es: Array[Object]) extends Product { +final class TupleXXL private (es: IArray[Object]) extends Product { assert(es.length > 22) def productElement(n: Int): Any = es(n) def productArity: Int = es.length - override def toString = elems.mkString("(", ",", ")") - override def hashCode = getClass.hashCode * 41 + deepHashCode(elems) + override def toString = elems.asInstanceOf[Array[Object]].mkString("(", ",", ")") + override def hashCode = getClass.hashCode * 41 + deepHashCode(elems.asInstanceOf[Array[Object]]) override def canEqual(that: Any): Boolean = that match { case that: TupleXXL => that.productArity == this.productArity case _ => false } override def equals(that: Any) = that match { - case that: TupleXXL => deepEquals(this.elems, that.elems) + case that: TupleXXL => deepEquals(this.elems.asInstanceOf[Array[Object]], that.elems.asInstanceOf[Array[Object]]) case _ => false } - def elems: Array[Object] = es + def elems: IArray[Object] = es def tailXXL: TupleXXL = { assert(es.length > 23) - new TupleXXL(es.tail) + new TupleXXL(es.asInstanceOf[Array[Object]].tail.asInstanceOf[IArray[Object]]) } - def toArray: Array[Object] = es.clone + def toArray: Array[Object] = es.asInstanceOf[Array[Object]].clone } object TupleXXL { - def fromIterator(elems: Iterator[Any]) = new TupleXXL(elems.map(_.asInstanceOf[Object]).toArray) - def apply(elems: Array[Object]) = new TupleXXL(elems.clone) - def apply(elems: Any*) = new TupleXXL(elems.asInstanceOf[Seq[Object]].toArray) - def unapplySeq(x: TupleXXL): Option[Seq[Any]] = Some(x.elems.toSeq) + def fromIterator(elems: Iterator[Any]) = new TupleXXL(elems.map(_.asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) + def fromIArray(elems: IArray[Object]) = new TupleXXL(elems) + def apply(elems: Any*) = new TupleXXL(elems.asInstanceOf[Seq[Object]].toArray.asInstanceOf[IArray[Object]]) + def unapplySeq(x: TupleXXL): Option[Seq[Any]] = Some(x.elems.asInstanceOf[Array[Object]].toSeq) } diff --git a/library/src/scala/TupledFunction.scala b/library/src/scala/TupledFunction.scala index ceba68089b8c..213f02182382 100644 --- a/library/src/scala/TupledFunction.scala +++ b/library/src/scala/TupledFunction.scala @@ -169,7 +169,7 @@ package internal { def tupledFunctionXXL[F, G]: TupledFunction[F, G] = new TupledFunction { def tupled(f: F): G = ((args: TupleXXL) => f.asInstanceOf[FunctionXXL].apply(args.elems)).asInstanceOf[G] def untupled(g: G): F = new FunctionXXL { - override def apply(xs: Array[Object]): AnyRef = g.asInstanceOf[TupleXXL => AnyRef].apply(TupleXXL(xs)) + override def apply(xs: IArray[Object]): AnyRef = g.asInstanceOf[TupleXXL => AnyRef].apply(TupleXXL.fromIArray(xs)) }.asInstanceOf[F] } diff --git a/library/src/scala/runtime/DynamicTuple.scala b/library/src/scala/runtime/DynamicTuple.scala index b27b38d59f5d..fdaf21a0df12 100644 --- a/library/src/scala/runtime/DynamicTuple.scala +++ b/library/src/scala/runtime/DynamicTuple.scala @@ -52,9 +52,13 @@ object DynamicTuple { 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 _ => TupleXXL.fromIArray(xs.clone().asInstanceOf[IArray[Object]]).asInstanceOf[T] } + def dynamicFromIArray[T <: Tuple](xs: IArray[Object]): T = + if (xs.length <= 22) dynamicFromArray(xs.asInstanceOf[Array[Object]]) + else TupleXXL.fromIArray(xs).asInstanceOf[T] + def dynamicFromProduct[T <: Tuple](xs: Product): T = (xs.productArity match { case 1 => xs match { @@ -169,7 +173,7 @@ object DynamicTuple { case _ => xs match { case xs: TupleXXL => xs - case xs => TupleXXL(xs.productIterator.map(_.asInstanceOf[Object]).toArray) + case xs => TupleXXL.fromIArray(xs.productIterator.map(_.asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) } }).asInstanceOf[T] @@ -180,6 +184,12 @@ object DynamicTuple { case self: Product => productToArray(self) } + def dynamicToIArray(self: Tuple): IArray[Object] = (self: Any) match { + case self: Unit => Array.emptyObjectArray.asInstanceOf[IArray[Object]] + case self: TupleXXL => self.elems + case self: Product => productToArray(self).asInstanceOf[IArray[Object]] + } + def productToArray(self: Product): Array[Object] = { val arr = new Array[Object](self.productArity) for (i <- 0 until arr.length) arr(i) = self.productElement(i).asInstanceOf[Object] diff --git a/tests/run-with-compiler/staged-tuples/StagedTuple.scala b/tests/run-with-compiler/staged-tuples/StagedTuple.scala index 1e0431d8b3b5..f91b911ffd87 100644 --- a/tests/run-with-compiler/staged-tuples/StagedTuple.scala +++ b/tests/run-with-compiler/staged-tuples/StagedTuple.scala @@ -28,7 +28,7 @@ object StagedTuple { case Some(n) if n <= MaxSpecialized => '{to$Array($tup, ${ n.toExpr })} case Some(n) => - '{${ tup.as[TupleXXL] }.elems} + '{ ${tup.as[TupleXXL]}.toArray } case None => '{dynamicToArray($tup)} } From 14bbae865e84dd7fc3d0ca8b8d1b0da35a0cfca4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 26 Jul 2019 09:39:53 +0200 Subject: [PATCH 2/3] Use IArray.apply and state where operations are missing on IArray --- library/src/scala/TupleXXL.scala | 10 +++++----- library/src/scala/runtime/DynamicTuple.scala | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/src/scala/TupleXXL.scala b/library/src/scala/TupleXXL.scala index 8404c9787f5c..1122c8e8277c 100644 --- a/library/src/scala/TupleXXL.scala +++ b/library/src/scala/TupleXXL.scala @@ -22,14 +22,14 @@ final class TupleXXL private (es: IArray[Object]) extends Product { def tailXXL: TupleXXL = { assert(es.length > 23) - new TupleXXL(es.asInstanceOf[Array[Object]].tail.asInstanceOf[IArray[Object]]) + new TupleXXL(es.asInstanceOf[Array[Object]].tail.asInstanceOf[IArray[Object]]) // TODO use IArray.tail } - def toArray: Array[Object] = es.asInstanceOf[Array[Object]].clone + def toArray: Array[Object] = es.asInstanceOf[Array[Object]].clone // TODO use IArray.toArray } object TupleXXL { - def fromIterator(elems: Iterator[Any]) = new TupleXXL(elems.map(_.asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) + def fromIterator(elems: Iterator[Any]) = new TupleXXL(elems.map(_.asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) // TODO use Iterator.toIArray def fromIArray(elems: IArray[Object]) = new TupleXXL(elems) - def apply(elems: Any*) = new TupleXXL(elems.asInstanceOf[Seq[Object]].toArray.asInstanceOf[IArray[Object]]) - def unapplySeq(x: TupleXXL): Option[Seq[Any]] = Some(x.elems.asInstanceOf[Array[Object]].toSeq) + def apply(elems: Any*) = new TupleXXL(IArray(elems.asInstanceOf[Seq[AnyRef]]: _*)) + def unapplySeq(x: TupleXXL): Option[Seq[Any]] = Some(x.elems.asInstanceOf[Array[Object]].toSeq) // TODO use IArray.toSeq } diff --git a/library/src/scala/runtime/DynamicTuple.scala b/library/src/scala/runtime/DynamicTuple.scala index fdaf21a0df12..50b5f9f33999 100644 --- a/library/src/scala/runtime/DynamicTuple.scala +++ b/library/src/scala/runtime/DynamicTuple.scala @@ -173,7 +173,7 @@ object DynamicTuple { case _ => xs match { case xs: TupleXXL => xs - case xs => TupleXXL.fromIArray(xs.productIterator.map(_.asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) + case xs => TupleXXL.fromIArray(xs.productIterator.map(_.asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) // TODO use Iterator.toIArray } }).asInstanceOf[T] From 0c320fa893cd91e7ba8ee3ce67d7fe6c24326f54 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 26 Jul 2019 09:44:47 +0200 Subject: [PATCH 3/3] Add empty IArrays --- library/src-bootstrapped/scala/IArray.scala | 10 ++++++++++ library/src/scala/runtime/DynamicTuple.scala | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index d6f0156136f3..24b8a7ecedbe 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -48,6 +48,16 @@ object IArray { */ def empty[T: ClassTag]: IArray[T] = new Array[T](0).asInstanceOf + def emptyBooleanIArray = Array.emptyBooleanArray.asInstanceOf[IArray[Boolean]] + def emptyByteIArray = Array.emptyByteArray.asInstanceOf[IArray[Byte]] + def emptyCharIArray = Array.emptyCharArray.asInstanceOf[IArray[Char]] + def emptyDoubleIArray = Array.emptyDoubleArray.asInstanceOf[IArray[Double]] + def emptyFloatIArray = Array.emptyFloatArray.asInstanceOf[IArray[Float]] + def emptyIntIArray = Array.emptyIntArray.asInstanceOf[IArray[Int]] + def emptyLongIArray = Array.emptyLongArray.asInstanceOf[IArray[Long]] + def emptyShortIArray = Array.emptyShortArray.asInstanceOf[IArray[Short]] + def emptyObjectIArray = Array.emptyObjectArray.asInstanceOf[IArray[Object]] + /** An immutable array with given elements. */ def apply[T: ClassTag](xs: T*): IArray[T] = Array(xs: _*).asInstanceOf diff --git a/library/src/scala/runtime/DynamicTuple.scala b/library/src/scala/runtime/DynamicTuple.scala index 50b5f9f33999..fa9c90cffd04 100644 --- a/library/src/scala/runtime/DynamicTuple.scala +++ b/library/src/scala/runtime/DynamicTuple.scala @@ -185,7 +185,7 @@ object DynamicTuple { } def dynamicToIArray(self: Tuple): IArray[Object] = (self: Any) match { - case self: Unit => Array.emptyObjectArray.asInstanceOf[IArray[Object]] + case self: Unit => Array.emptyObjectArray.asInstanceOf[IArray[Object]] // TODO use IArray.emptyObjectIArray case self: TupleXXL => self.elems case self: Product => productToArray(self).asInstanceOf[IArray[Object]] }