summaryrefslogtreecommitdiff
path: root/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-12-15 15:03:08 +0100
committerLukas Rytz <lukas.rytz@gmail.com>2015-12-15 15:12:47 +0100
commite4319789ea6d1a4e958d383619cf7e51338bfde2 (patch)
treeafc73a35b4564da3ff55afecc7e10669c07a075c /test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
parent1265e19de8073da2691fac4d52bc763091ad7b9c (diff)
downloadscala-e4319789ea6d1a4e958d383619cf7e51338bfde2.tar.gz
scala-e4319789ea6d1a4e958d383619cf7e51338bfde2.tar.bz2
scala-e4319789ea6d1a4e958d383619cf7e51338bfde2.zip
Eliminate unnecessary casts
Eliminate casts that are statically known to succeed. This enables boxes to be eliminated and simplifies the implementation of closure allocation elimination.
Diffstat (limited to 'test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala')
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala40
1 files changed, 36 insertions, 4 deletions
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index 7b3936f867..4c6b3ed286 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -1326,9 +1326,9 @@ class InlinerTest extends ClearAfterClass {
// value class instantiation-extraction should be optimized by boxing elim
assertEquals(getSingleMethod(c, "t3").instructions.summary, List(
NEW, DUP, ICONST_1, "<init>", ASTORE,
- NEW, DUP, ALOAD, CHECKCAST, "x",
+ NEW, DUP, ALOAD, "x",
"C$$$anonfun$4",
- "<init>", CHECKCAST,
+ "<init>",
"x", IRETURN))
assertEquals(getSingleMethod(c, "t4").instructions.summary, List(
@@ -1432,9 +1432,41 @@ class InlinerTest extends ClearAfterClass {
val List(c) = compile(code)
assertSameCode(getSingleMethod(c, "t1").instructions.dropNonOp, List(Op(ICONST_3), Op(ICONST_4), Op(IADD), Op(IRETURN)))
assertSameCode(getSingleMethod(c, "t2").instructions.dropNonOp, List(Op(ICONST_1), Op(ICONST_2), Op(IADD), Op(IRETURN)))
- // tuple not yet eliminated due to null checks, casts
+ // tuple not yet eliminated due to null checks
assert(getSingleMethod(c, "t3").instructions.exists(_.opcode == IFNONNULL))
- assert(getSingleMethod(c, "t4").instructions.exists(_.opcode == CHECKCAST))
+ assert(getSingleMethod(c, "t4").instructions.exists(_.opcode == IFNULL))
assert(getSingleMethod(c, "t5").instructions.exists(_.opcode == IFNULL))
}
+
+ @Test
+ def redundantCasts(): Unit = {
+
+ // we go through the hoop of inlining the casts because erasure eliminates `asInstanceOf` calls
+ // that are statically known to succeed. For example the following cast is removed by erasure:
+ // `(if (b) c else d).asInstanceOf[C]`
+
+ val code =
+ """class C {
+ | @inline final def asO(a: Any) = a.asInstanceOf[Object]
+ | @inline final def asC(a: Any) = a.asInstanceOf[C]
+ | @inline final def asD(a: Any) = a.asInstanceOf[D]
+ |
+ | def t1(c: C) = asC(c) // eliminated
+ | def t2(c: C) = asO(c) // eliminated
+ | def t3(c: Object) = asC(c) // not elimianted
+ | def t4(c: C, d: D, b: Boolean) = asC(if (b) c else d) // not eliminated: lub of two non-equal reference types approximated with Object
+ | def t5(c: C, d: D, b: Boolean) = asO(if (b) c else d)
+ | def t6(c: C, cs: Array[C], b: Boolean) = asO(if (b) c else cs)
+ |}
+ |class D extends C
+ """.stripMargin
+ val List(c, _) = compile(code)
+ def casts(m: String) = getSingleMethod(c, m).instructions collect { case TypeOp(CHECKCAST, tp) => tp }
+ assertSameCode(getSingleMethod(c, "t1").instructions.dropNonOp, List(VarOp(ALOAD, 1), Op(ARETURN)))
+ assertSameCode(getSingleMethod(c, "t2").instructions.dropNonOp, List(VarOp(ALOAD, 1), Op(ARETURN)))
+ assertSameCode(getSingleMethod(c, "t3").instructions.dropNonOp, List(VarOp(ALOAD, 1), TypeOp(CHECKCAST, "C"), Op(ARETURN)))
+ assertEquals(casts("t4"), List("C"))
+ assertEquals(casts("t5"), Nil)
+ assertEquals(casts("t6"), Nil)
+ }
}