Skip to content

Commit a3379a0

Browse files
sjrdtgodzik
authored andcommitted
Scala.js: Emit js.NewArray IR nodes when possible.
Although there is a *correct* implementation of `sr.Arrays.newArray`, it is not efficient when creating 1-dimensional arrays. The JVM backend special-cases it to emit `newarray` bytecode instructions. We now also special-case it in the JS backend. In the Scala.js IR however, `js.NewArray` only accepts a single dimension. For multiple dimensions, the right thing to do is to emit a direct call to `jlr.Array.newInstance`. [Cherry-picked 2852168]
1 parent 2b87171 commit a3379a0

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

+24-1
Original file line numberDiff line numberDiff line change
@@ -2553,6 +2553,8 @@ class JSCodeGen()(using genCtx: Context) {
25532553
genCoercion(tree, receiver, code)
25542554
else if (code == JSPrimitives.THROW)
25552555
genThrow(tree, args)
2556+
else if (code == JSPrimitives.NEW_ARRAY)
2557+
genNewArray(tree, args)
25562558
else if (JSPrimitives.isJSPrimitive(code))
25572559
genJSPrimitive(tree, args, code, isStat)
25582560
else
@@ -3022,6 +3024,24 @@ class JSCodeGen()(using genCtx: Context) {
30223024
}
30233025
}
30243026

3027+
/** Gen a call to the special `newArray` method. */
3028+
private def genNewArray(tree: Apply, args: List[Tree]): js.Tree = {
3029+
implicit val pos: SourcePosition = tree.sourcePos
3030+
3031+
val List(elemClazz, Literal(arrayClassConstant), dimsArray: JavaSeqLiteral) = args: @unchecked
3032+
3033+
dimsArray.elems match {
3034+
case singleDim :: Nil =>
3035+
// Use a js.NewArray
3036+
val arrayTypeRef = toTypeRef(arrayClassConstant.typeValue).asInstanceOf[jstpe.ArrayTypeRef]
3037+
js.NewArray(arrayTypeRef, genExpr(singleDim))
3038+
case _ =>
3039+
// Delegate to jlr.Array.newInstance
3040+
js.ApplyStatic(js.ApplyFlags.empty, JLRArrayClassName, js.MethodIdent(JLRArrayNewInstanceMethodName),
3041+
List(genExpr(elemClazz), genJavaSeqLiteral(dimsArray)))(jstpe.AnyType)
3042+
}
3043+
}
3044+
30253045
/** Gen a "normal" apply (to a true method).
30263046
*
30273047
* But even these are further refined into:
@@ -4834,7 +4854,7 @@ class JSCodeGen()(using genCtx: Context) {
48344854

48354855
object JSCodeGen {
48364856

4837-
private val NullPointerExceptionClass = ClassName("java.lang.NullPointerException")
4857+
private val JLRArrayClassName = ClassName("java.lang.reflect.Array")
48384858
private val JSObjectClassName = ClassName("scala.scalajs.js.Object")
48394859
private val JavaScriptExceptionClassName = ClassName("scala.scalajs.js.JavaScriptException")
48404860

@@ -4844,6 +4864,9 @@ object JSCodeGen {
48444864

48454865
private val selectedValueMethodName = MethodName("selectedValue", Nil, ObjectClassRef)
48464866

4867+
private val JLRArrayNewInstanceMethodName =
4868+
MethodName("newInstance", List(jstpe.ClassRef(jsNames.ClassClass), jstpe.ArrayTypeRef(jstpe.IntRef, 1)), ObjectClassRef)
4869+
48474870
private val ObjectArgConstructorName = MethodName.constructor(List(ObjectClassRef))
48484871

48494872
private val thisOriginalName = OriginalName("this")

compiler/src/dotty/tools/backend/sjs/JSPrimitives.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ object JSPrimitives {
4848
inline val UNWRAP_FROM_THROWABLE = WRAP_AS_THROWABLE + 1 // js.special.unwrapFromThrowable
4949
inline val DEBUGGER = UNWRAP_FROM_THROWABLE + 1 // js.special.debugger
5050

51-
inline val THROW = DEBUGGER + 1
51+
inline val THROW = DEBUGGER + 1 // <special-ops>.throw
52+
inline val NEW_ARRAY = THROW + 1 // scala.runtime.Arrays.newArray
5253

53-
inline val UNION_FROM = THROW + 1 // js.|.from
54+
inline val UNION_FROM = NEW_ARRAY + 1 // js.|.from
5455
inline val UNION_FROM_TYPE_CONSTRUCTOR = UNION_FROM + 1 // js.|.fromTypeConstructor
5556

5657
inline val REFLECT_SELECTABLE_SELECTDYN = UNION_FROM_TYPE_CONSTRUCTOR + 1 // scala.reflect.Selectable.selectDynamic
@@ -137,6 +138,7 @@ class JSPrimitives(ictx: Context) extends DottyPrimitives(ictx) {
137138
addPrimitive(jsdefn.Special_debugger, DEBUGGER)
138139

139140
addPrimitive(defn.throwMethod, THROW)
141+
addPrimitive(defn.newArrayMethod, NEW_ARRAY)
140142

141143
addPrimitive(jsdefn.PseudoUnion_from, UNION_FROM)
142144
addPrimitive(jsdefn.PseudoUnion_fromTypeConstructor, UNION_FROM_TYPE_CONSTRUCTOR)

0 commit comments

Comments
 (0)