8000 Experiment: Avoid `JSArrayConstr` for Varargs to optimize the Wasm backend by tanishiking · Pull Request #5148 · scala-js/scala-js · GitHub
[go: up one dir, main page]

Skip to content

Experiment: Avoid JSArrayConstr for Varargs to optimize the Wasm backend #5148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5775,8 +5775,22 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
if (wasRepeated) {
tryGenRepeatedParamAsJSArray(arg, handleNil = false).fold {
genExpr(arg)
} { genArgs =>
genJSArrayToVarArgs(js.JSArrayConstr(genArgs))
} { case (elemType, genArgs) =>
val arrayTypeRef = jstpe.ArrayTypeRef.of(toTypeRef(elemType))
val arrayRef = js.ArrayValue(arrayTypeRef, genArgs.map(genExpr(_)))
val methodSym = toIRType(elemType) match {
case jstpe.IntType => Runtime_toScalaVarArgsFromScalaArrayInt
case jstpe.DoubleType => Runtime_toScalaVarArgsFromScalaArrayDouble
case jstpe.LongType => Runtime_toScalaVarArgsFromScalaArrayLong
case jstpe.FloatType => Runtime_toScalaVarArgsFromScalaArrayFloat
case jstpe.CharType => Runtime_toScalaVarArgsFromScalaArrayChar
case jstpe.ByteType => Runtime_toScalaVarArgsFromScalaArrayByte
case jstpe.ShortType => Runtime_toScalaVarArgsFromScalaArrayShort
case jstpe.BooleanType => Runtime_toScalaVarArgsFromScalaArrayBoolean
case jstpe.VoidType => Runtime_toScalaVarArgsFromScalaArrayUnit
case _ => Runtime_toScalaVarArgsFromScalaArrayAnyRef
}
genApplyMethod(genLoadModule(RuntimePackageModule), methodSym, List(arrayRef))
}
} else {
genExpr(arg)
Expand Down Expand Up @@ -5928,7 +5942,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
* Otherwise, it returns a JSSpread with the Seq converted to a js.Array.
*/
private def genPrimitiveJSRepeatedParam(arg: Tree): List[js.TreeOrJSSpread] = {
tryGenRepeatedParamAsJSArray(arg, handleNil = true) getOrElse {
tryGenRepeatedParamAsJSArray(arg, handleNil = true).fold {
/* Fall back to calling runtime.toJSVarArgs to perform the conversion
* to js.Array, then wrap in a Spread operator.
*/
Expand All @@ -5937,7 +5951,9 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
genLoadModule(RuntimePackageModule),
Runtime_toJSVarArgs,
List(genExpr(arg)))
List(js.JSSpread(jsArrayArg))
List(js.JSSpread(jsArrayArg).asInstanceOf[js.TreeOrJSSpread])
} { case (elemTpe, genArgs) =>
genArgs.map(e => ensureBoxed(genExpr(e), elemTpe)(arg.pos).asInstanceOf[js.TreeOrJSSpread])
}
}

Expand All @@ -5948,7 +5964,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
* method returns `None`.
*/
private def tryGenRepeatedParamAsJSArray(arg: Tree,
handleNil: Boolean): Option[List[js.Tree]] = {
handleNil: Boolean): Option[(Type, List[Tree])] = {
implicit val pos = arg.pos

// Given a method `def foo(args: T*)`
Expand All @@ -5960,11 +5976,11 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
* the type before erasure.
*/
val elemTpe = tpt.tpe
Some(elems.map(e => ensureBoxed(genExpr(e), elemTpe)))
Some((tpt.tpe, elems))

// foo()
case Select(_, _) if handleNil && arg.symbol == NilModule =>
Some(Nil)
Some((NoType, Nil))

// foo(argSeq:_*) - cannot be optimized
case _ =>
Expand Down
14 changes: 14 additions & 0 deletions compiler/src/main/scala/org/scalajs/nscplugin/JSDefinitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,17 @@ trait JSDefinitions {
lazy val Runtime_identityHashCode = getMemberMethod(RuntimePackageModule, newTermName("identityHashCode"))
lazy val Runtime_dynamicImport = getMemberMethod(RuntimePackageModule, newTermName("dynamicImport"))

lazy val Runtime_toScalaVarArgsFromScalaArrayAnyRef = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayAnyRef"))
lazy val Runtime_toScalaVarArgsFromScalaArrayInt = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayInt"))
lazy val Runtime_toScalaVarArgsFromScalaArrayDouble = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayDouble"))
lazy val Runtime_toScalaVarArgsFromScalaArrayLong = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayLong"))
lazy val Runtime_toScalaVarArgsFromScalaArrayFloat = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayFloat"))
lazy val Runtime_toScalaVarArgsFromScalaArrayChar = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayChar"))
lazy val Runtime_toScalaVarArgsFromScalaArrayByte = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayByte"))
lazy val Runtime_toScalaVarArgsFromScalaArrayShort = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayShort"))
lazy val Runtime_toScalaVarArgsFromScalaArrayBoolean = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayBoolean"))
lazy val Runtime_toScalaVarArgsFromScalaArrayUnit = getMemberMethod(RuntimePackageModule, newTermName("toScalaVarArgsFromScalaArrayUnit"))

lazy val LinkingInfoModule = getRequiredModule("scala.scalajs.LinkingInfo")
lazy val LinkingInfo_linkTimePropertyBoolean = getMemberMethod(LinkingInfoModule, newTermName("linkTimePropertyBoolean"))
lazy val LinkingInfo_linkTimePropertyInt = getMemberMethod(LinkingInfoModule, newTermName("linkTimePropertyInt"))
Expand All @@ -152,6 +163,9 @@ trait JSDefinitions {

lazy val ExecutionContextImplicitsModule = getRequiredModule("scala.concurrent.ExecutionContext.Implicits")
lazy val ExecutionContextImplicits_global = getMemberMethod(ExecutionContextImplicitsModule, newTermName("global"))

lazy val WrappedArrayOfIntClass = getRequiredClass("scala.collection.mutable.WrappedArray$ofInt")
lazy val WrappedArrayOfDoubleClass = getRequiredClass("scala.collection.mutable.WrappedArray$ofDouble")
}

// scalastyle:on line.size.limit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

package scala.scalajs.runtime

import scala.collection.immutable.ArraySeq
import scala.collection.IterableOnce

import scala.scalajs.js
Expand All @@ -21,6 +22,36 @@ private[runtime] object Compat {
@inline def toScalaVarArgsImpl[A](array: js.Array[A]): Seq[A] =
WrappedVarArgs.wrap(array)

@inline def toScalaVarArgsFromScalaArrayAnyRefImpl(array: Array[AnyRef]): Seq[AnyRef] =
new ArraySeq.ofRef(array)

@inline def toScalaVarArgsFromScalaArrayIntImpl(array: Array[Int]): Seq[Int] =
new ArraySeq.ofInt(array)

@inline def toScalaVarArgsFromScalaArrayDoubleImpl(array: Array[Double]): Seq[Double] =
new ArraySeq.ofDouble(array)

@inline def toScalaVarArgsFromScalaArrayLongImpl(array: Array[Long]): Seq[Long] =
new ArraySeq.ofLong(array)

@inline def toScalaVarArgsFromScalaArrayFloatImpl(array: Array[Float]): Seq[Float] =
new ArraySeq.ofFloat(array)

@inline def toScalaVarArgsFromScalaArrayCharImpl(array: Array[Char]): Seq[Char] =
new ArraySeq.ofChar(array)

@inline def toScalaVarArgsFromScalaArrayByteImpl(array: Array[Byte]): Seq[Byte] =
new ArraySeq.ofByte(array)

@inline def toScalaVarArgsFromScalaArrayShortImpl(array: Array[Short]): Seq[Short] =
new ArraySeq.ofShort(array)

@inline def toScalaVarArgsFromScalaArrayBooleanImpl(array: Array[Boolean]): Seq[Boolean] =
new ArraySeq.ofBoolean(array)

@inline def toScalaVarArgsFromScalaArrayUnitImpl(array: Array[Unit]): Seq[Unit] =
new ArraySeq.ofUnit(array)

def toJSVarArgsImpl[A](seq: Seq[A]): js.Array[A] = {
seq match {
case seq: WrappedVarArgs[A] =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,45 @@
package scala.scalajs.runtime

import scala.collection.GenTraversableOnce
import scala.collection.mutable.WrappedArray
import scala.scalajs.js

private[runtime] object Compat {

@inline def toScalaVarArgsImpl[A](array: js.Array[A]): Seq[A] =
new js.WrappedArray(array)

@inline def toScalaVarArgsFromScalaArrayAnyRefImpl(array: Array[AnyRef]): Seq[AnyRef] =
new WrappedArray.ofRef(array)

@inline def toScalaVarArgsFromScalaArrayIntImpl(array: Array[Int]): Seq[Int] =
new WrappedArray.ofInt(array)

@inline def toScalaVarArgsFromScalaArrayDoubleImpl(array: Array[Double]): Seq[Double] =
new WrappedArray.ofDouble(array)

@inline def toScalaVarArgsFromScalaArrayLongImpl(array: Array[Long]): Seq[Long] =
new WrappedArray.ofLong(array)

@inline def toScalaVarArgsFromScalaArrayFloatImpl(array: Array[Float]): Seq[Float] =
new WrappedArray.ofFloat(array)

@inline def toScalaVarArgsFromScalaArrayCharImpl(array: Array[Char]): Seq[Char] =
new WrappedArray.ofChar(array)

@inline def toScalaVarArgsFromScalaArrayByteImpl(array: Array[Byte]): Seq[Byte] =
new WrappedArray.ofByte(array)

@inline def toScalaVarArgsFromScalaArrayShortImpl(array: Array[Short]): Seq[Short] =
new WrappedArray.ofShort(array)

@inline def toScalaVarArgsFromScalaArrayBooleanImpl(array: Array[Boolean]): Seq[Boolean] =
new WrappedArray.ofBoolean(array)

@inline def toScalaVarArgsFromScalaArrayUnitImpl(array: Array[Unit]): Seq[Unit] =
new WrappedArray.ofUnit(array)


def toJSVarArgsImpl[A](seq: Seq[A]): js.Array[A] = {
seq match {
case seq: js.WrappedArray[A] =>
Expand Down
30 changes: 30 additions & 0 deletions library/src/main/scala/scala/scalajs/runtime/package.scala
727E
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,36 @@ package object runtime {
@inline def toScalaVarArgs[A](array: js.Array[A]): Seq[A] =
toScalaVarArgsImpl(array)

@inline def toScalaVarArgsFromScalaArrayAnyRef(array: Array[AnyRef]): Seq[AnyRef] =
toScalaVarArgsFromScalaArrayAnyRefImpl(array)

@inline def toScalaVarArgsFromScalaArrayInt(array: Array[Int]): Seq[Int] =
toScalaVarArgsFromScalaArrayIntImpl(array)

@inline def toScalaVarArgsFromScalaArrayDouble(array: Array[Double]): Seq[Double] =
toScalaVarArgsFromScalaArrayDoubleImpl(array)

@inline def toScalaVarArgsFromScalaArrayLong(array: Array[Long]): Seq[Long] =
toScalaVarArgsFromScalaArrayLongImpl(array)

@inline def toScalaVarArgsFromScalaArrayFloat(array: Array[Float]): Seq[Float] =
toScalaVarArgsFromScalaArrayFloatImpl(array)

@inline def toScalaVarArgsFromScalaArrayChar(array: Array[Char]): Seq[Char] =
toScalaVarArgsFromScalaArrayCharImpl(array)

@inline def toScalaVarArgsFromScalaArrayByte(array: Array[Byte]): Seq[Byte] =
toScalaVarArgsFromScalaArrayByteImpl(array)

@inline def toScalaVarArgsFromScalaArrayShort(array: Array[Short]): Seq[Short] =
toScalaVarArgsFromScalaArrayShortImpl(array)

@inline def toScalaVarArgsFromScalaArrayBoolean(array: Array[Boolean]): Seq[Boolean] =
toScalaVarArgsFromScalaArrayBooleanImpl(array)

@inline def toScalaVarArgsFromScalaArrayUnit(array: Array[Unit]): Seq[Unit] =
toScalaVarArgsFromScalaArrayUnitImpl(array)

@inline def toJSVarArgs[A](seq: Seq[A]): js.Array[A] =
toJSVarArgsImpl(seq)

Expand Down
0