summaryrefslogtreecommitdiff
path: root/test
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
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')
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala40
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala9
3 files changed, 41 insertions, 10 deletions
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
index 99041b5497..0f87280000 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala
@@ -85,6 +85,6 @@ class ClosureOptimizerTest extends ClearAfterClass {
assertSameCode(getSingleMethod(c, "t").instructions.dropNonOp,
List(VarOp(ALOAD, 1), Invoke(INVOKEVIRTUAL, "scala/collection/immutable/List", "head", "()Ljava/lang/Object;", false),
TypeOp(CHECKCAST, "java/lang/String"), Invoke(INVOKESTATIC, "C", "C$$$anonfun$1", "(Ljava/lang/String;)Ljava/lang/String;", false),
- TypeOp(CHECKCAST, "java/lang/String"), Op(ARETURN)))
+ Op(ARETURN)))
}
}
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)
+ }
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
index 94c9f55728..fda38fa2e8 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
@@ -472,8 +472,7 @@ class MethodLevelOptsTest extends ClearAfterClass {
val List(c) = compileClasses(methodOptCompiler)(code)
assertNoInvoke(getSingleMethod(c, "t1"))
assertEquals(getSingleMethod(c, "t2").instructions.summary, List(ICONST_1, ICONST_3, IADD, IRETURN))
- // cannot eliminate boxes because of casts
- assertEquals(getSingleMethod(c, "t3").instructions collect { case TypeOp(CHECKCAST, tp) => tp }, List("java/lang/Integer", "java/lang/Integer"))
+ assertEquals(getSingleMethod(c, "t3").instructions.summary, List(ICONST_3, ICONST_4, IADD, IRETURN))
assertEquals(getSingleMethod(c, "t4").instructions.summary, List(ICONST_3, "boxToInteger", ARETURN))
assertEquals(getSingleMethod(c, "t5").instructions collect { case Invoke(_, owner, name, _, _) => (owner, name) }, List(
("scala/runtime/BoxesRunTime", "boxToInteger"),
@@ -482,11 +481,11 @@ class MethodLevelOptsTest extends ClearAfterClass {
("scala/Tuple2", "_1$mcI$sp")))
// cannot eliminate boxes because of null checks
assert(getSingleMethod(c, "t6").instructions.exists(_.opcode == IFNONNULL))
- // cannot eliminate boxed because of casts and null checks
+ // cannot eliminate boxed because of null checks
def castsNullChecks(m: String) = getSingleMethod(c, m).instructions collect { case op if op.opcode == IFNULL || op.opcode == CHECKCAST => op }
assertEquals(castsNullChecks("t7"),
- List(Jump(IFNULL, Label(29)), TypeOp(CHECKCAST, "scala/Tuple2"), Jump(IFNULL, Label(29))))
- assertEquals(castsNullChecks("t8").size, 7)
+ List(Jump(IFNULL, Label(28)), Jump(IFNULL, Label(28))))
+ assertEquals(castsNullChecks("t8").size, 3)
assertEquals(castsNullChecks("t9").size, 2)
}
}