Skip to content

Commit 9e5bf00

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 bcc96b3 commit 9e5bf00

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
@@ -2550,6 +2550,8 @@ class JSCodeGen()(using genCtx: Context) {
25502550
genCoercion(tree, receiver, code)
25512551
else if (code == JSPrimitives.THROW)
25522552
genThrow(tree, args)
2553+
else if (code == JSPrimitives.NEW_ARRAY)
2554+
genNewArray(tree, args)
25532555
else if (JSPrimitives.isJSPrimitive(code))
25542556
genJSPrimitive(tree, args, code, isStat)
25552557
else
@@ -3019,6 +3021,24 @@ class JSCodeGen()(using genCtx: Context) {
30193021
}
30203022
}
30213023

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

48324852
object JSCodeGen {
48334853

4834-
private val NullPointerExceptionClass = ClassName("java.lang.NullPointerException")
4854+
private val JLRArrayClassName = ClassName("java.lang.reflect.Array")
48354855
private val JSObjectClassName = ClassName("scala.scalajs.js.Object")
48364856
private val JavaScriptExceptionClassName = ClassName("scala.scalajs.js.JavaScriptException")
48374857

@@ -4841,6 +4861,9 @@ object JSCodeGen {
48414861

48424862
private val selectedValueMethodName = MethodName("selectedValue", Nil, ObjectClassRef)
48434863

4864+
private val JLRArrayNewInstanceMethodName =
4865+
MethodName("newInstance", List(jstpe.ClassRef(jsNames.ClassClass), jstpe.ArrayTypeRef(jstpe.IntRef, 1)), ObjectClassRef)
4866+
48444867
private val ObjectArgConstructorName = MethodName.constructor(List(ObjectClassRef))
48454868

48464869
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)