Skip to content

Commit 09a2c4d

Browse files
dwijnandWojciechMazur
authored andcommitted
Automate list optimisation threshhold cases
[Cherry-picked 3b9f0c9]
1 parent afd622c commit 09a2c4d

File tree

2 files changed

+96
-23
lines changed

2 files changed

+96
-23
lines changed

compiler/test/dotty/tools/backend/jvm/ArrayApplyOptTest.scala

Lines changed: 96 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -201,34 +201,108 @@ class ArrayApplyOptTest extends DottyBytecodeTest {
201201
""".stripMargin
202202
}
203203

204-
def checkApplyAvoidsIntermediateArray(name: String)(source: String) = {
204+
@Test def testListApplyAvoidsIntermediateArray_max1 = {
205+
checkApplyAvoidsIntermediateArray_examples("max1"):
206+
""" def meth1: List[Object] = List[Object]("1", "2", "3", "4", "5", "6", "7")
207+
| def meth2: List[Object] = new ::("1", new ::("2", new ::("3", new ::("4", new ::("5", new ::("6", new ::("7", Nil)))))))
208+
""".stripMargin
209+
}
210+
211+
@Test def testListApplyAvoidsIntermediateArray_max2 = {
212+
checkApplyAvoidsIntermediateArray_examples("max2"):
213+
""" def meth1: List[Object] = List[Object]("1", "2", "3", "4", "5", "6", List[Object]())
214+
| def meth2: List[Object] = new ::("1", new ::("2", new ::("3", new ::("4", new ::("5", new ::("6", new ::(Nil, Nil)))))))
215+
""".stripMargin
216+
}
217+
218+
@Test def testListApplyAvoidsIntermediateArray_max3 = {
219+
checkApplyAvoidsIntermediateArray_examples("max3"):
220+
""" def meth1: List[Object] = List[Object]("1", "2", "3", "4", "5", List[Object]("6"))
221+
| def meth2: List[Object] = new ::("1", new ::("2", new ::("3", new ::("4", new ::("5", new ::(new ::("6", Nil), Nil))))))
222+
""".stripMargin
223+
}
224+
225+
@Test def testListApplyAvoidsIntermediateArray_max4 = {
226+
checkApplyAvoidsIntermediateArray_examples("max4"):
227+
""" def meth1: List[Object] = List[Object]("1", "2", "3", "4", List[Object]("5", "6"))
228+
| def meth2: List[Object] = new ::("1", new ::("2", new ::("3", new ::("4", new ::(new ::("5", new ::("6", Nil)), Nil)))))
229+
""".stripMargin
230+
}
231+
232+
@Test def testListApplyAvoidsIntermediateArray_over1 = {
233+
checkApplyAvoidsIntermediateArray_examples("over1"):
234+
""" def meth1: List[Object] = List("1", "2", "3", "4", "5", "6", "7", "8")
235+
| def meth2: List[Object] = List(wrapRefArray(Array("1", "2", "3", "4", "5", "6", "7", "8"))*)
236+
""".stripMargin
237+
}
238+
239+
@Test def testListApplyAvoidsIntermediateArray_over2 = {
240+
checkApplyAvoidsIntermediateArray_examples("over2"):
241+
""" def meth1: List[Object] = List[Object]("1", "2", "3", "4", "5", "6", "7", List[Object]())
242+
| def meth2: List[Object] = List(wrapRefArray(Array[Object]("1", "2", "3", "4", "5", "6", "7", Nil))*)
243+
""".stripMargin
244+
}
245+
246+
@Test def testListApplyAvoidsIntermediateArray_over3 = {
247+
checkApplyAvoidsIntermediateArray_examples("over3"):
248+
""" def meth1: List[Object] = List[Object]("1", "2", "3", "4", "5", "6", List[Object]("7"))
249+
| def meth2: List[Object] = new ::("1", new ::("2", new ::("3", new ::("4", new ::("5", new ::("6", new ::(List(wrapRefArray(Array[Object]("7"))*), Nil)))))))
250+
""".stripMargin
251+
}
252+
253+
@Test def testListApplyAvoidsIntermediateArray_over4 = {
254+
checkApplyAvoidsIntermediateArray_examples("over4"):
255+
""" def meth1: List[Object] = List[Object]("1", "2", "3", "4", "5", List[Object]("6", "7"))
256+
| def meth2: List[Object] = new ::("1", new ::("2", new ::("3", new ::("4", new ::("5", new ::(List(wrapRefArray(Array[Object]("6", "7"))*), Nil))))))
257+
""".stripMargin
258+
}
259+
260+
@Test def testListApplyAvoidsIntermediateArray_max5 = {
261+
checkApplyAvoidsIntermediateArray_examples("max5"):
262+
""" def meth1: List[Object] = List[Object](List[Object](List[Object](List[Object](List[Object](List[Object](List[Object](List[Object]())))))))
263+
| def meth2: List[Object] = new ::(new ::(new ::(new ::(new ::(new ::(new ::(Nil, Nil), Nil), Nil), Nil), Nil), Nil), Nil)
264+
""".stripMargin
265+
}
266+
267+
@Test def testListApplyAvoidsIntermediateArray_over5 = {
268+
checkApplyAvoidsIntermediateArray_examples("over5"):
269+
""" def meth1: List[Object] = List[Object](List[Object](List[Object](List[Object](List[Object](List[Object](List[Object](List[Object](List[Object]()))))))))
270+
| def meth2: List[Object] = new ::(new ::(new ::(new ::(new ::(new ::(new ::(List[Object](wrapRefArray(Array[Object](Nil))*), Nil), Nil), Nil), Nil), Nil), Nil), Nil)
271+
""".stripMargin
272+
}
273+
274+
@Test def testListApplyAvoidsIntermediateArray_max6 = {
275+
checkApplyAvoidsIntermediateArray_examples("max6"):
276+
""" def meth1: List[Object] = List[Object]("1", "2", List[Object]("3", "4", List[Object](List[Object]())))
277+
| def meth2: List[Object] = new ::("1", new ::("2", new ::(new ::("3", new ::("4", new ::(new ::(Nil, Nil), Nil))), Nil)))
278+
""".stripMargin
279+
}
280+
281+
@Test def testListApplyAvoidsIntermediateArray_over6 = {
282+
checkApplyAvoidsIntermediateArray_examples("over6"):
283+
""" def meth1: List[Object] = List[Object]("1", "2", List[Object]("3", "4", List[Object]("5")))
284+
| def meth2: List[Object] = new ::("1", new ::("2", new ::(new ::("3", new ::("4", new ::(new ::("5", Nil), Nil))), Nil)))
285+
""".stripMargin
286+
}
287+
288+
def checkApplyAvoidsIntermediateArray_examples(name: String)(body: String): Unit = {
289+
checkApplyAvoidsIntermediateArray(s"List_$name"):
290+
s"""import scala.collection.immutable.{ ::, Nil }, scala.runtime.ScalaRunTime.wrapRefArray
291+
|class Foo {
292+
|$body
293+
|}
294+
""".stripMargin
295+
}
296+
297+
def checkApplyAvoidsIntermediateArray(name: String)(source: String): Unit = {
205298
checkBCode(source) { dir =>
206299
val clsIn = dir.lookupName("Foo.class", directory = false).input
207300
val clsNode = loadClassNode(clsIn)
208301
val meth1 = getMethod(clsNode, "meth1")
209302
val meth2 = getMethod(clsNode, "meth2")
210303

211-
val instructions1 = instructionsFromMethod(meth1) match
212-
case instr :+ TypeOp(CHECKCAST, _) :+ TypeOp(CHECKCAST, _) :+ (ret @ Op(ARETURN)) =>
213-
instr :+ ret
214-
case instr :+ TypeOp(CHECKCAST, _) :+ (ret @ Op(ARETURN)) =>
215-
// List.apply[?A] doesn't, strictly, return List[?A],
216-
// because it cascades to its definition on IterableFactory
217-
// where it returns CC[A]. The erasure of that is Object,
218-
// which is why Erasure's Typer adds a cast to compensate.
219-
// If we drop that cast while optimising (because using
220-
// the constructor for :: doesn't require the cast like
221-
// List.apply did) then then cons construction chain will
222-
// be typed as ::.
223-
// Unfortunately the LUB of :: and Nil.type is Product
224-
// instead of List, so a cast remains necessary,
225-
// across whatever causes the lub, like `if` or `try` branches.
226-
// Therefore if we dropping the cast may cause a needed cast
227-
// to be necessary, we shouldn't drop the cast,
228-
// which was only motivated by the assert here.
229-
instr :+ ret
230-
case instr => instr
231-
val instructions2 = instructionsFromMethod(meth2)
304+
val instructions1 = instructionsFromMethod(meth1).filter { case TypeOp(CHECKCAST, _) => false case _ => true }
305+
val instructions2 = instructionsFromMethod(meth2).filter { case TypeOp(CHECKCAST, _) => false case _ => true }
232306

233307
assert(instructions1 == instructions2,
234308
s"the $name.apply method\n" +

tests/run/list-apply-eval.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ object Test:
3434

3535
// Examples of arity and nesting arity
3636
// to find the thresholds and reproduce the behaviour of nsc
37-
// tested manually, comparing -Xprint across compilers (ran out of time)
3837
def examples(): Unit =
3938
val max1 = List[Object]("1", "2", "3", "4", "5", "6", "7") // 7 cons w/ 7 string heads + nil
4039
val max2 = List[Object]("1", "2", "3", "4", "5", "6", List[Object]()) // 7 cons w/ 6 string heads + 1 nil head + nil

0 commit comments

Comments
 (0)