summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-01-25 10:51:08 +0100
committerLukas Rytz <lukas.rytz@gmail.com>2016-01-25 11:25:20 +0100
commit7b953e5a6c0239c7368b1b65364ab9cb96e012b3 (patch)
treeb708b90fd6e8db5b6a293a44c8033222ee5f47a8
parente49fda4fab463da13e084d1deeb6f1a58e0041d1 (diff)
downloadscala-7b953e5a6c0239c7368b1b65364ab9cb96e012b3.tar.gz
scala-7b953e5a6c0239c7368b1b65364ab9cb96e012b3.tar.bz2
scala-7b953e5a6c0239c7368b1b65364ab9cb96e012b3.zip
Rewrite test for SI-5313
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala93
-rw-r--r--test/pending/run/t5313.check12
-rw-r--r--test/pending/run/t5313.scala54
3 files changed, 92 insertions, 67 deletions
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 46e1cebfc4..49b9924e97 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala
@@ -15,9 +15,10 @@ import CodeGenTools._
import scala.tools.partest.ASMConverters
import ASMConverters._
import scala.tools.testing.ClearAfterClass
+import scala.collection.convert.decorateAsScala._
object MethodLevelOptsTest extends ClearAfterClass.Clearable {
- var methodOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:method")
+ var methodOptCompiler = newCompiler(extraArgs = "-Yopt:l:method")
def clear(): Unit = { methodOptCompiler = null }
}
@@ -559,4 +560,94 @@ class MethodLevelOptsTest extends ClearAfterClass {
getSingleMethod(c, "t").instructions.dropNonOp,
List(VarOp(ALOAD, 1), Jump(IFNULL, Label(6)), Op(ICONST_1), Op(IRETURN), Label(6), Op(ICONST_0), Op(IRETURN)))
}
+
+ @Test
+ def t5313(): Unit = {
+ val code =
+ """class C {
+ | def randomBoolean = scala.util.Random.nextInt % 2 == 0
+ |
+ | // 3 stores to kept1 (slot 1), 1 store to result (slot 2)
+ | def t1 = {
+ | var kept1 = new Object
+ | val result = new java.lang.ref.WeakReference(kept1)
+ | kept1 = null // we can't eliminate this assignment because result can observe
+ | // when the object has no more references. See SI-5313
+ | kept1 = new Object // could eliminate this one with a more elaborate analysis (we know it contains null)
+ | // however, such is not implemented: if a var is live, then stores are kept.
+ | result
+ | }
+ |
+ | // only two variables are live: kept2 and kept3. they end up on slots 1 and 2.
+ | // kept2 has 2 stores, kept3 has 1 store.
+ | def t2 = {
+ | var erased2 = null // we can eliminate this store because it's never used
+ | val erased3 = erased2 // and this
+ | var erased4 = erased2 // and this
+ | val erased5 = erased4 // and this
+ | var kept2: Object = new Object // ultimately can't be eliminated
+ | while(randomBoolean) {
+ | val kept3 = kept2
+ | kept2 = null // this can't, because it clobbers kept2, which is used
+ | erased4 = null // safe to eliminate
+ | println(kept3)
+ | }
+ | 0
+ | }
+ |
+ | def t3 = {
+ | var kept4 = new Object // have to keep, it's used
+ | try
+ | println(kept4)
+ | catch {
+ | case _ : Throwable => kept4 = null // have to keep, it clobbers kept4 which is used
+ | }
+ | 0
+ | }
+ |
+ | def t4 = {
+ | var kept5 = new Object
+ | print(kept5)
+ | kept5 = null // can't eliminate it's a clobber and it's used
+ | print(kept5)
+ | kept5 = null // eliminated by nullness analysis (store null to a local that is known to be null)
+ | 0
+ | }
+ |
+ | def t5 = {
+ | while(randomBoolean) {
+ | var kept6: AnyRef = null // not used, but have to keep because it clobbers the next used store
+ | // on the back edge of the loop
+ | kept6 = new Object // used
+ | println(kept6)
+ | }
+ | 0
+ | }
+ |}
+ """.stripMargin
+
+ val List(c) = compileClasses(methodOptCompiler)(code)
+ def locals(m: String) = findAsmMethod(c, m).localVariables.asScala.toList.map(l => (l.name, l.index)).sortBy(_._2)
+ def stores(m: String) = getSingleMethod(c, m).instructions.filter(_.opcode == ASTORE)
+
+ assertEquals(locals("t1"), List(("this",0), ("kept1",1), ("result",2)))
+ assert(stores("t1") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 2), VarOp(ASTORE, 1), VarOp(ASTORE, 1)),
+ textify(findAsmMethod(c, "t1")))
+
+ assertEquals(locals("t2"), List(("this",0), ("kept2",1), ("kept3",2)))
+ assert(stores("t2") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 2), VarOp(ASTORE, 1)),
+ textify(findAsmMethod(c, "t2")))
+
+ assertEquals(locals("t3"), List(("this",0), ("kept4",1)))
+ assert(stores("t3") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)),
+ textify(findAsmMethod(c, "t3")))
+
+ assertEquals(locals("t4"), List(("this",0), ("kept5",1)))
+ assert(stores("t4") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)),
+ textify(findAsmMethod(c, "t4")))
+
+ assertEquals(locals("t5"), List(("this",0), ("kept6",1)))
+ assert(stores("t5") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)),
+ textify(findAsmMethod(c, "t5")))
+ }
}
diff --git a/test/pending/run/t5313.check b/test/pending/run/t5313.check
deleted file mode 100644
index 7a48b2b711..0000000000
--- a/test/pending/run/t5313.check
+++ /dev/null
@@ -1,12 +0,0 @@
-STORE_LOCAL(variable kept1)
-STORE_LOCAL(value result)
-STORE_LOCAL(variable kept1)
-STORE_LOCAL(variable kept2)
-STORE_LOCAL(value kept3)
-STORE_LOCAL(variable kept2)
-STORE_LOCAL(variable kept4)
-STORE_LOCAL(variable kept4)
-STORE_LOCAL(variable kept5)
-STORE_LOCAL(variable kept5)
-STORE_LOCAL(variable kept6)
-STORE_LOCAL(variable kept6)
diff --git a/test/pending/run/t5313.scala b/test/pending/run/t5313.scala
deleted file mode 100644
index 4a5b076e6e..0000000000
--- a/test/pending/run/t5313.scala
+++ /dev/null
@@ -1,54 +0,0 @@
-import scala.tools.partest.IcodeComparison
-
-object Test extends IcodeComparison {
- override def printIcodeAfterPhase = "dce"
-
- override def extraSettings: String = super.extraSettings + " -Yopt:l:classpath"
-
- override def code =
- """class Foo {
- def randomBoolean = scala.util.Random.nextInt % 2 == 0
- def bar = {
- var kept1 = new Object
- val result = new java.lang.ref.WeakReference(kept1)
- kept1 = null // we can't eliminate this assignment because result can observe
- // when the object has no more references. See SI-5313
- kept1 = new Object // but we can eliminate this one because kept1 has already been clobbered
- var erased2 = null // we can eliminate this store because it's never used
- val erased3 = erased2 // and this
- var erased4 = erased2 // and this
- val erased5 = erased4 // and this
- var kept2: Object = new Object // ultimately can't be eliminated
- while(randomBoolean) {
- val kept3 = kept2
- kept2 = null // this can't, because it clobbers kept2, which is used
- erased4 = null // safe to eliminate
- println(kept3)
- }
- var kept4 = new Object // have to keep, it's used
- try
- println(kept4)
- catch {
- case _ : Throwable => kept4 = null // have to keep, it clobbers kept4 which is used
- }
- var kept5 = new Object
- print(kept5)
- kept5 = null // can't eliminate it's a clobber and it's used
- print(kept5)
- kept5 = null // can eliminate because we don't care about clobbers of nulls
- while(randomBoolean) {
- var kept6: AnyRef = null // not used, but have to keep because it clobbers the next used store
- // on the back edge of the loop
- kept6 = new Object // used
- println(kept6)
- }
- result
- }
- }""".stripMargin
-
- override def show() {
- val storeLocal = "STORE_LOCAL"
- val lines1 = collectIcode() filter (_ contains storeLocal) map (x => x.drop(x.indexOf(storeLocal)))
- println(lines1 mkString "\n")
- }
-}