Skip to content

Commit 89c20f8

Browse files
authored
Scala.js: Emit js.NewArray IR nodes when possible. (#22446)
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`.
2 parents 555aedd + 2852168 commit 89c20f8

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
@@ -2569,6 +2569,8 @@ class JSCodeGen()(using genCtx: Context) {
25692569
genCoercion(tree, receiver, code)
25702570
else if (code == JSPrimitives.THROW)
25712571
genThrow(tree, args)
2572+
else if (code == JSPrimitives.NEW_ARRAY)
2573+
genNewArray(tree, args)
25722574
else if (JSPrimitives.isJSPrimitive(code))
25732575
genJSPrimitive(tree, args, code, isStat)
25742576
else
@@ -3038,6 +3040,24 @@ class JSCodeGen()(using genCtx: Context) {
30383040
}
30393041
}
30403042

3043+
/** Gen a call to the special `newArray` method. */
3044+
private def genNewArray(tree: Apply, args: List[Tree]): js.Tree = {
3045+
implicit val pos: SourcePosition = tree.sourcePos
3046+
3047+
val List(elemClazz, Literal(arrayClassConstant), dimsArray: JavaSeqLiteral) = args: @unchecked
3048+
3049+
dimsArray.elems match {
3050+
case singleDim :: Nil =>
3051+
// Use a js.NewArray
3052+
val arrayTypeRef = toTypeRef(arrayClassConstant.typeValue).asInstanceOf[jstpe.ArrayTypeRef]
3053+
js.NewArray(arrayTypeRef, genExpr(singleDim))
3054+
case _ =>
3055+
// Delegate to jlr.Array.newInstance
3056+
js.ApplyStatic(js.ApplyFlags.empty, JLRArrayClassName, js.MethodIdent(JLRArrayNewInstanceMethodName),
3057+
List(genExpr(elemClazz), genJavaSeqLiteral(dimsArray)))(jstpe.AnyType)
3058+
}
3059+
}
3060+
30413061
/** Gen a "normal" apply (to a true method).
30423062
*
30433063
* But even these are further refined into:
@@ -4846,7 +4866,7 @@ class JSCodeGen()(using genCtx: Context) {
48464866

48474867
object JSCodeGen {
48484868

4849-
private val NullPointerExceptionClass = ClassName("java.lang.NullPointerException")
4869+
private val JLRArrayClassName = ClassName("java.lang.reflect.Array")
48504870
private val JSObjectClassName = ClassName("scala.scalajs.js.Object")
48514871
private val JavaScriptExceptionClassName = ClassName("scala.scalajs.js.JavaScriptException")
48524872

@@ -4856,6 +4876,9 @@ object JSCodeGen {
48564876

48574877
private val selectedValueMethodName = MethodName("selectedValue", Nil, ObjectClassRef)
48584878

4879+
private val JLRArrayNewInstanceMethodName =
4880+
MethodName("newInstance", List(jstpe.ClassRef(jsNames.ClassClass), jstpe.ArrayTypeRef(jstpe.IntRef, 1)), ObjectClassRef)
4881+
48594882
private val ObjectArgConstructorName = MethodName.constructor(List(ObjectClassRef))
48604883

48614884
private val thisOriginalName = OriginalName("this")

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

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

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

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

5556
inline val REFLECT_SELECTABLE_SELECTDYN = UNION_FROM_TYPE_CONSTRUCTOR + 1 // scala.reflect.Selectable.selectDynamic
@@ -135,6 +136,7 @@ class JSPrimitives(ictx: Context) extends DottyPrimitives(ictx) {
135136
addPrimitive(jsdefn.Special_debugger, DEBUGGER)
136137

137138
addPrimitive(defn.throwMethod, THROW)
139+
addPrimitive(defn.newArrayMethod, NEW_ARRAY)
138140

139141
addPrimitive(jsdefn.PseudoUnion_from, UNION_FROM)
140142
addPrimitive(jsdefn.PseudoUnion_fromTypeConstructor, UNION_FROM_TYPE_CONSTRUCTOR)

0 commit comments

Comments
 (0)