diff options
34 files changed, 374 insertions, 655 deletions
diff --git a/test/junit/scala/collection/immutable/SetTests.scala b/test/junit/scala/collection/immutable/SetTest.scala index 28c7864359..4029c98009 100644 --- a/test/junit/scala/collection/immutable/SetTests.scala +++ b/test/junit/scala/collection/immutable/SetTest.scala @@ -6,7 +6,7 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) -class SetTests { +class SetTest { @Test def test_SI8346_toSet_soundness(): Unit = { val any2stringadd = "Disabled string conversions so as not to get confused!" diff --git a/test/junit/scala/issues/BytecodeTests.scala b/test/junit/scala/issues/BytecodeTest.scala index 7c446894df..7260f43c87 100644 --- a/test/junit/scala/issues/BytecodeTests.scala +++ b/test/junit/scala/issues/BytecodeTest.scala @@ -11,15 +11,15 @@ import scala.collection.JavaConverters._ import scala.tools.partest.ASMConverters._ import scala.tools.testing.ClearAfterClass -object BytecodeTests extends ClearAfterClass.Clearable { +object BytecodeTest extends ClearAfterClass.Clearable { var compiler = newCompiler() def clear(): Unit = { compiler = null } } @RunWith(classOf[JUnit4]) -class BytecodeTests extends ClearAfterClass { - ClearAfterClass.stateToClear = BytecodeTests - val compiler = BytecodeTests.compiler +class BytecodeTest extends ClearAfterClass { + ClearAfterClass.stateToClear = BytecodeTest + val compiler = BytecodeTest.compiler @Test def t8731(): Unit = { @@ -107,7 +107,6 @@ class BytecodeTests extends ClearAfterClass { import Opcodes._ val expected = List( - LineNumber(3, Label(0)), LineNumber(4, Label(0)), LineNumber(5, Label(5)), Jump(IFNE, Label(11)), diff --git a/test/junit/scala/reflect/ClassTag.scala b/test/junit/scala/reflect/ClassTagTest.scala index 90cc981fc1..90cc981fc1 100644 --- a/test/junit/scala/reflect/ClassTag.scala +++ b/test/junit/scala/reflect/ClassTagTest.scala diff --git a/test/junit/scala/sys/process/t7350.scala b/test/junit/scala/sys/process/t7350.scala index 3c0e5145e6..9fdcac8ccc 100644 --- a/test/junit/scala/sys/process/t7350.scala +++ b/test/junit/scala/sys/process/t7350.scala @@ -1,4 +1,3 @@ - package scala.sys.process import org.junit.runner.RunWith diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala index 69c3f69380..342f403426 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala @@ -48,7 +48,7 @@ object CodeGenTools { resetOutput(compiler) compiler } - + def newCompilerWithoutVirtualOutdir(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Global = { val settings = new Settings() val args = (CommandLineParser tokenize defaultArgs) ++ (CommandLineParser tokenize extraArgs) 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 192a036d5b..942b62b32c 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -1468,4 +1468,52 @@ class InlinerTest extends ClearAfterClass { assertEquals(casts("t5"), Nil) assertEquals(casts("t6"), Nil) } + + @Test + def inlineFromSealed(): Unit = { + val code = + """sealed abstract class Foo { + | @inline def bar(x: Int) = x + 1 + |} + |object Foo { + | def mkFoo(): Foo = new Baz2 + |} + | + |object Baz1 extends Foo + |final class Baz2 extends Foo + | + |object Test { + | def f = Foo.mkFoo() bar 10 + |} + """.stripMargin + + val cls = compile(code) + val test = cls.find(_.name == "Test$").get + assertEquals( + getSingleMethod(test, "f").instructions.summary, + List(GETSTATIC, "mkFoo", + BIPUSH, ISTORE, + IFNONNULL, ACONST_NULL, ATHROW, -1 /*label*/, + ILOAD, ICONST_1, IADD, IRETURN)) + } + + @Test // a test taken from the test suite for the 2.11 inliner + def oldInlineHigherOrderTest(): Unit = { + val code = + """class C { + | private var debug = false + | @inline private def ifelse[T](cond: => Boolean, ifPart: => T, elsePart: => T): T = if (cond) ifPart else elsePart + | final def t = ifelse(debug, 1, 2) + |} + """.stripMargin + val List(c) = compile(code) + val t = getSingleMethod(c, "t") + + // box-unbox will clean it up + assertEquals(getSingleMethod(c, "t").instructions.summary, + List( + ALOAD, "C$$$anonfun$1", IFEQ /*A*/, + "C$$$anonfun$2", IRETURN, + -1 /*A*/, "C$$$anonfun$3", IRETURN)) + } } 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..423ff85f04 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOptsTest.scala @@ -8,6 +8,7 @@ import org.junit.Test import scala.tools.asm.Opcodes._ import org.junit.Assert._ +import scala.tools.asm.tree.ClassNode import scala.tools.nsc.backend.jvm.AsmUtils._ import scala.tools.testing.AssertUtil._ @@ -15,9 +16,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 } } @@ -29,6 +31,8 @@ class MethodLevelOptsTest extends ClearAfterClass { def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1)) + def locals(c: ClassNode, m: String) = findAsmMethod(c, m).localVariables.asScala.toList.map(l => (l.name, l.index)).sortBy(_._2) + @Test def eliminateEmptyTry(): Unit = { val code = "def f = { try {} catch { case _: Throwable => 0; () }; 1 }" @@ -559,4 +563,182 @@ 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 stores(m: String) = getSingleMethod(c, m).instructions.filter(_.opcode == ASTORE) + + assertEquals(locals(c, "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(c, "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(c, "t3"), List(("this",0), ("kept4",1))) + assert(stores("t3") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)), + textify(findAsmMethod(c, "t3"))) + + assertEquals(locals(c, "t4"), List(("this",0), ("kept5",1))) + assert(stores("t4") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)), + textify(findAsmMethod(c, "t4"))) + + assertEquals(locals(c, "t5"), List(("this",0), ("kept6",1))) + assert(stores("t5") == List(VarOp(ASTORE, 1), VarOp(ASTORE, 1)), + textify(findAsmMethod(c, "t5"))) + } + + @Test + def testCpp(): Unit = { + // copied from an old test (run/test-cpp.scala) + val code = + """class C { + | import scala.util.Random._ + | + | def t1(x: Int) = { + | val y = x + | println(y) + | } + | + | def t2 = { + | val x = 2 + | val y = x + | println(y) + | } + | + | def t3 = { + | val x = this + | val y = x + | println(y) + | } + | + | def f = nextInt + | + | def t4 = { + | val x = f + | val y = x + | println(y) + | } + | + | def t5 = { + | var x = nextInt + | var y = x + | println(y) + | + | y = nextInt + | x = y + | println(x) + | } + |} + """.stripMargin + + val List(c) = compileClasses(methodOptCompiler)(code) + assertEquals(locals(c, "t1"), List(("this", 0), ("x", 1))) + + assertEquals(locals(c, "t2"), List(("this", 0), ("x", 1))) + // we don't have constant propagation (yet). + // the local var can't be optimized as a store;laod sequence, there's a GETSTATIC between the two + assertEquals( + textify(findAsmMethod(c, "t2")), + getSingleMethod(c, "t2").instructions.dropNonOp.map(_.opcode), + List( + ICONST_2, ISTORE, + GETSTATIC, // Predef.MODULE$ + ILOAD, INVOKESTATIC, // boxToInteger + INVOKEVIRTUAL, // println + RETURN)) + + assertEquals(locals(c, "t3"), List(("this", 0))) + assertEquals(locals(c, "t4"), List(("this", 0), ("x", 1))) + assertEquals(locals(c, "t5"), List(("this", 0), ("x", 1))) + } + + @Test + def t7006(): Unit = { + val code = + """class C { + | def t: Unit = { + | try { + | val x = 3 + | } finally { + | print("hello") + | } + | while(true) { } + | } + |} + """.stripMargin + val List(c) = compileClasses(methodOptCompiler)(code) + val t = getSingleMethod(c, "t") + assertEquals(t.handlers, Nil) + assertEquals(locals(c, "t"), List(("this", 0))) + assertEquals(t.instructions.summary, + List( + GETSTATIC, LDC, "print", + -1, GOTO)) + } } diff --git a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala new file mode 100644 index 0000000000..cef27b4d87 --- /dev/null +++ b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala @@ -0,0 +1,137 @@ +package scala.tools.nsc +package transform.patmat + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import scala.tools.asm.Opcodes._ +import org.junit.Assert._ + +import scala.tools.nsc.backend.jvm.AsmUtils._ +import scala.tools.nsc.backend.jvm.CodeGenTools +import scala.tools.testing.AssertUtil._ + +import CodeGenTools._ +import scala.tools.partest.ASMConverters +import ASMConverters._ +import scala.tools.testing.ClearAfterClass + +object PatmatBytecodeTest extends ClearAfterClass.Clearable { + var compiler = newCompiler() + var optCompiler = newCompiler(extraArgs = "-Yopt:l:method") + def clear(): Unit = { compiler = null; optCompiler = null } +} + +@RunWith(classOf[JUnit4]) +class PatmatBytecodeTest extends ClearAfterClass { + ClearAfterClass.stateToClear = PatmatBytecodeTest + + val compiler = PatmatBytecodeTest.compiler + val optCompiler = PatmatBytecodeTest.optCompiler + + @Test + def t6956(): Unit = { + val code = + """class C { + | private[this] final val ONE = 1 + | + | def s1(i: Byte): Int = i match { + | case ONE => 1 + | case 2 => 2 + | case 3 => 3 + | case _ => 0 + | } + | + | def s2(i: Byte): Int = i match { + | case 1 => 1 + | case 2 => 2 + | case 3 => 3 + | case _ => 0 + | } + |} + """.stripMargin + + val List(c) = compileClasses(compiler)(code) + assert(getSingleMethod(c, "s1").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c)) + assert(getSingleMethod(c, "s2").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c)) + } + + @Test + def t6955(): Unit = { + val code = + """class C { + | type Tag = Byte + | + | def s1(i: Tag): Int = i match { // notice type of i is Tag = Byte + | case 1 => 1 + | case 2 => 2 + | case 3 => 3 + | case _ => 0 + | } + | + | // this worked before, should keep working + | def s2(i: Byte): Int = i match { + | case 1 => 1 + | case 2 => 2 + | case 3 => 3 + | case _ => 0 + | } + |} + """.stripMargin + + val List(c) = compileClasses(compiler)(code) + assert(getSingleMethod(c, "s1").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c)) + assert(getSingleMethod(c, "s2").instructions.count(_.opcode == TABLESWITCH) == 1, textify(c)) + } + + @Test + def optNoPrimitiveTypetest(): Unit = { + val code = + """case class Foo(x: Int, y: String) + |class C { + | def a = Foo(1, "a") match { + | case Foo(_: Int, y) => y + | } + |} + """.stripMargin + val c = compileClasses(optCompiler)(code).head + + assertEquals(textify(findAsmMethod(c, "a")), getSingleMethod(c, "a").instructions.summary, + List( + NEW, DUP, ICONST_1, LDC, "<init>", + "y", ARETURN)) + } + + @Test + def optNoNullCheck(): Unit = { + val code = + """case class Foo(x: Any) + |class C { + | def a = (Foo(1): Any) match { + | case Foo(_: String) => + | } + |} + """.stripMargin + val c = compileClasses(optCompiler)(code).head + assert(!getSingleMethod(c, "a").instructions.exists(i => i.opcode == IFNULL || i.opcode == IFNONNULL), textify(findAsmMethod(c, "a"))) + } + + @Test + def optNoLoacalForUnderscore(): Unit = { + val code = + """case class Foo(x: Any, y: String) + |class C { + | def a = Foo(1, "a") match { + | case Foo(_: String, y) => y + | } + |} + """.stripMargin + val c = compileClasses(optCompiler)(code).head + assertEquals(textify(findAsmMethod(c, "a")), getSingleMethod(c, "a").instructions.summary, + List(NEW, DUP, ICONST_1, "boxToInteger", LDC, "<init>", ASTORE /*1*/, + ALOAD /*1*/, "y", ASTORE /*2*/, + ALOAD /*1*/, "x", INSTANCEOF, IFNE /*R*/, + NEW, DUP, ALOAD /*1*/, "<init>", ATHROW, + /*R*/ -1, ALOAD /*2*/, ARETURN)) + } +} diff --git a/test/pending/jvm/patmat_opt_ignore_underscore.check b/test/pending/jvm/patmat_opt_ignore_underscore.check deleted file mode 100644 index 43f53aba12..0000000000 --- a/test/pending/jvm/patmat_opt_ignore_underscore.check +++ /dev/null @@ -1 +0,0 @@ -bytecode identical diff --git a/test/pending/jvm/patmat_opt_ignore_underscore.flags b/test/pending/jvm/patmat_opt_ignore_underscore.flags deleted file mode 100644 index 453b6b7895..0000000000 --- a/test/pending/jvm/patmat_opt_ignore_underscore.flags +++ /dev/null @@ -1 +0,0 @@ --Yopt:l:project
\ No newline at end of file diff --git a/test/pending/jvm/patmat_opt_ignore_underscore/Analyzed_1.scala b/test/pending/jvm/patmat_opt_ignore_underscore/Analyzed_1.scala deleted file mode 100644 index b0506018f6..0000000000 --- a/test/pending/jvm/patmat_opt_ignore_underscore/Analyzed_1.scala +++ /dev/null @@ -1,29 +0,0 @@ -// this class's bytecode, compiled under -optimize is analyzed by the test -// method a's bytecode should be identical to method b's bytecode -// this is not the best test for shielding against regressing on this particular issue, -// but it sets the stage for checking the bytecode emitted by the pattern matcher and -// comparing it to manually tuned code using if/then/else etc. -class SameBytecode { - case class Foo(x: Any, y: String) - - def a = - Foo(1, "a") match { - case Foo(_: String, y) => y - } - - // this method's body holds the tree that should be generated by the pattern matcher for method a (-Xprint:patmat) - // the test checks that bytecode for a and b is identical (modulo line numbers) - // we can't diff trees as they are quite different (patmat uses jumps to labels that cannot be expressed in source, for example) - // note that the actual tree is quite bad: we do an unnecessary null check, isInstanceOf and local val (x3) - // some of these will be fixed soon (the initial null check is for the scrutinee, which is harder to fix in patmat) - def b: String = { - val x1 = Foo(1, "a") - if (x1.ne(null)) { - if (x1.x.isInstanceOf[String]) { - return x1.y - } - } - - throw new MatchError(x1) - } -}
\ No newline at end of file diff --git a/test/pending/jvm/patmat_opt_ignore_underscore/test.scala b/test/pending/jvm/patmat_opt_ignore_underscore/test.scala deleted file mode 100644 index d6630e80a0..0000000000 --- a/test/pending/jvm/patmat_opt_ignore_underscore/test.scala +++ /dev/null @@ -1,18 +0,0 @@ -/* - * filter: inliner warning; re-run with - */ -import scala.tools.partest.BytecodeTest - -import scala.tools.nsc.util.JavaClassPath -import java.io.InputStream -import scala.tools.asm -import asm.ClassReader -import asm.tree.{ClassNode, InsnList} -import scala.collection.JavaConverters._ - -object Test extends BytecodeTest { - def show: Unit = { - val classNode = loadClassNode("SameBytecode") - sameBytecode(getMethod(classNode, "a"), getMethod(classNode, "b")) - } -} diff --git a/test/pending/jvm/patmat_opt_no_nullcheck.check b/test/pending/jvm/patmat_opt_no_nullcheck.check deleted file mode 100644 index 43f53aba12..0000000000 --- a/test/pending/jvm/patmat_opt_no_nullcheck.check +++ /dev/null @@ -1 +0,0 @@ -bytecode identical diff --git a/test/pending/jvm/patmat_opt_no_nullcheck.flags b/test/pending/jvm/patmat_opt_no_nullcheck.flags deleted file mode 100644 index 453b6b7895..0000000000 --- a/test/pending/jvm/patmat_opt_no_nullcheck.flags +++ /dev/null @@ -1 +0,0 @@ --Yopt:l:project
\ No newline at end of file diff --git a/test/pending/jvm/patmat_opt_no_nullcheck/Analyzed_1.scala b/test/pending/jvm/patmat_opt_no_nullcheck/Analyzed_1.scala deleted file mode 100644 index 1e4d564cdf..0000000000 --- a/test/pending/jvm/patmat_opt_no_nullcheck/Analyzed_1.scala +++ /dev/null @@ -1,24 +0,0 @@ -// this class's bytecode, compiled under -optimize is analyzed by the test -// method a's bytecode should be identical to method b's bytecode -case class Foo(x: Any) - -class SameBytecode { - def a = - (Foo(1): Any) match { - case Foo(_: String) => - } - - // there's no null check - def b: Unit = { - val x1: Any = Foo(1) - if (x1.isInstanceOf[Foo]) { - val x3 = x1.asInstanceOf[Foo] - if (x3.x.isInstanceOf[String]) { - val x = () - return - } - } - - throw new MatchError(x1) - } -}
\ No newline at end of file diff --git a/test/pending/jvm/patmat_opt_no_nullcheck/test.scala b/test/pending/jvm/patmat_opt_no_nullcheck/test.scala deleted file mode 100644 index 5a4a398b67..0000000000 --- a/test/pending/jvm/patmat_opt_no_nullcheck/test.scala +++ /dev/null @@ -1,14 +0,0 @@ -/* - * filter: inliner warning; re-run with - */ -import scala.tools.partest.{ BytecodeTest, ASMConverters } - -object Test extends BytecodeTest { - def show: Unit = { - val classNode = loadClassNode("SameBytecode") - // ASM and GenBCode assign variable slots slightly differently - val instrsA = ASMConverters.instructionsFromMethod(getMethod(classNode, "a")) - val instrsB = ASMConverters.instructionsFromMethod(getMethod(classNode, "b")) - assert(ASMConverters.equivalentBytecode(instrsA, instrsB), diffInstructions(instrsA, instrsB)) // doesn't work - } -} diff --git a/test/pending/jvm/patmat_opt_primitive_typetest.check b/test/pending/jvm/patmat_opt_primitive_typetest.check deleted file mode 100644 index 43f53aba12..0000000000 --- a/test/pending/jvm/patmat_opt_primitive_typetest.check +++ /dev/null @@ -1 +0,0 @@ -bytecode identical diff --git a/test/pending/jvm/patmat_opt_primitive_typetest.flags b/test/pending/jvm/patmat_opt_primitive_typetest.flags deleted file mode 100644 index 19c578e4ad..0000000000 --- a/test/pending/jvm/patmat_opt_primitive_typetest.flags +++ /dev/null @@ -1 +0,0 @@ --Yopt:l:project diff --git a/test/pending/jvm/patmat_opt_primitive_typetest/Analyzed_1.scala b/test/pending/jvm/patmat_opt_primitive_typetest/Analyzed_1.scala deleted file mode 100644 index c961082fa7..0000000000 --- a/test/pending/jvm/patmat_opt_primitive_typetest/Analyzed_1.scala +++ /dev/null @@ -1,24 +0,0 @@ -// this class's bytecode, compiled under -optimize is analyzed by the test -// method a's bytecode should be identical to method b's bytecode -class SameBytecode { - case class Foo(x: Int, y: String) - - def a = - Foo(1, "a") match { - case Foo(_: Int, y) => y - } - - // this method's body holds the tree that should be generated by the pattern matcher for method a (-Xprint:patmat) - // the test checks that bytecode for a and b is identical (modulo line numbers) - // we can't diff trees as they are quite different (patmat uses jumps to labels that cannot be expressed in source, for example) - // note that the actual tree is quite bad: we do an unnecessary null check, and local val (x3) - // some of these will be fixed soon (the initial null check is for the scrutinee, which is harder to fix in patmat) - def b: String = { - val x1 = Foo(1, "a") - if (x1.ne(null)) { - return x1.y - } - - throw new MatchError(x1) - } -}
\ No newline at end of file diff --git a/test/pending/jvm/patmat_opt_primitive_typetest/test.scala b/test/pending/jvm/patmat_opt_primitive_typetest/test.scala deleted file mode 100644 index 2927e763d5..0000000000 --- a/test/pending/jvm/patmat_opt_primitive_typetest/test.scala +++ /dev/null @@ -1,8 +0,0 @@ -import scala.tools.partest.BytecodeTest - -object Test extends BytecodeTest { - def show: Unit = { - val classNode = loadClassNode("SameBytecode") - sameBytecode(getMethod(classNode, "a"), getMethod(classNode, "b")) - } -} diff --git a/test/pending/jvm/t7006.check b/test/pending/jvm/t7006.check deleted file mode 100644 index 6294b14d62..0000000000 --- a/test/pending/jvm/t7006.check +++ /dev/null @@ -1,29 +0,0 @@ -[running phase parser on Foo_1.scala] -[running phase namer on Foo_1.scala] -[running phase packageobjects on Foo_1.scala] -[running phase typer on Foo_1.scala] -[running phase patmat on Foo_1.scala] -[running phase superaccessors on Foo_1.scala] -[running phase extmethods on Foo_1.scala] -[running phase pickler on Foo_1.scala] -[running phase refchecks on Foo_1.scala] -[running phase uncurry on Foo_1.scala] -[running phase tailcalls on Foo_1.scala] -[running phase specialize on Foo_1.scala] -[running phase explicitouter on Foo_1.scala] -[running phase erasure on Foo_1.scala] -[running phase posterasure on Foo_1.scala] -[running phase lazyvals on Foo_1.scala] -[running phase lambdalift on Foo_1.scala] -[running phase constructors on Foo_1.scala] -[running phase flatten on Foo_1.scala] -[running phase mixin on Foo_1.scala] -[running phase cleanup on Foo_1.scala] -[running phase delambdafy on Foo_1.scala] -[running phase icode on Foo_1.scala] -[running phase inliner on Foo_1.scala] -[running phase inlinehandlers on Foo_1.scala] -[running phase closelim on Foo_1.scala] -[running phase constopt on Foo_1.scala] -[running phase dce on Foo_1.scala] -[running phase jvm on icode] diff --git a/test/pending/jvm/t7006/Foo_1.flags b/test/pending/jvm/t7006/Foo_1.flags deleted file mode 100644 index 5d1b6b2644..0000000000 --- a/test/pending/jvm/t7006/Foo_1.flags +++ /dev/null @@ -1 +0,0 @@ --Yopt:l:project -Ydebug -Xfatal-warnings diff --git a/test/pending/jvm/t7006/Foo_1.scala b/test/pending/jvm/t7006/Foo_1.scala deleted file mode 100644 index 3985557d9f..0000000000 --- a/test/pending/jvm/t7006/Foo_1.scala +++ /dev/null @@ -1,10 +0,0 @@ -class Foo_1 { - def foo { - try { - val x = 3 // this will be optimized away, leaving a useless jump only block - } finally { - print("hello") - } - while(true){} // ensure infinite loop doesn't break the algorithm - } -} diff --git a/test/pending/jvm/t7006/Test.scala b/test/pending/jvm/t7006/Test.scala deleted file mode 100644 index 7b4a8c45fb..0000000000 --- a/test/pending/jvm/t7006/Test.scala +++ /dev/null @@ -1,21 +0,0 @@ -import scala.tools.partest.BytecodeTest -import scala.tools.asm -import asm.tree.InsnList -import scala.collection.JavaConverters._ - -object Test extends BytecodeTest { - def show: Unit = { - val classNode = loadClassNode("Foo_1") - val methodNode = getMethod(classNode, "foo") - val nopCount = count(methodNode.instructions, asm.Opcodes.NOP) - val gotoCount = count(methodNode.instructions, asm.Opcodes.GOTO) - assert(nopCount == 0, s"NOPs expected: 0, actual: $nopCount") - assert(gotoCount == 1, s"GOTOs expected: 1, actual: $gotoCount") - } - - def count(insnList: InsnList, opcode: Int): Int = { - def isNop(node: asm.tree.AbstractInsnNode): Boolean = - (node.getOpcode == opcode) - insnList.iterator.asScala.count(isNop) - } -} diff --git a/test/pending/pos/inliner2.flags b/test/pending/pos/inliner2.flags deleted file mode 100644 index 4bf93a9c2a..0000000000 --- a/test/pending/pos/inliner2.flags +++ /dev/null @@ -1,35 +0,0 @@ --optimise -Ybackend:GenASM -Xfatal-warnings -/* -This is what we get with 2.11.2-M3 and -Yopt:l:project: - - public final int bob1(); - Code: - 0: aload_0 - 1: aload_0 - 2: astore 6 - 4: aload 6 - 6: invokedynamic #62, 0 // InvokeDynamic #0:apply$mcZ$sp:(LA;)Lscala/runtime/java8/JFunction0$mcZ$sp; - 11: checkcast #29 // class scala/Function0 - 14: invokedynamic #71, 0 // InvokeDynamic #1:apply$mcI$sp:()Lscala/runtime/java8/JFunction0$mcI$sp; - 19: checkcast #29 // class scala/Function0 - 22: invokedynamic #76, 0 // InvokeDynamic #2:apply$mcI$sp:()Lscala/runtime/java8/JFunction0$mcI$sp; - 27: checkcast #29 // class scala/Function0 - 30: astore 4 - 32: astore_3 - 33: astore_2 - 34: astore_1 - 35: aload_2 - 36: pop - 37: aload 6 - 39: invokevirtual #53 // Method A$$$anonfun$1:()Z - 42: ifeq 54 - 45: aload_3 - 46: invokeinterface #36, 1 // InterfaceMethod scala/Function0.apply:()Ljava/lang/Object; - 51: goto 61 - 54: aload 4 - 56: invokeinterface #36, 1 // InterfaceMethod scala/Function0.apply:()Ljava/lang/Object; - 61: astore 5 - 63: aload 5 - 65: invokestatic #82 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I - 68: ireturn -*/
\ No newline at end of file diff --git a/test/pending/pos/inliner2.scala b/test/pending/pos/inliner2.scala deleted file mode 100644 index bc83e04312..0000000000 --- a/test/pending/pos/inliner2.scala +++ /dev/null @@ -1,57 +0,0 @@ -// This isn't actually testing much, because no warning is emitted in versions -// before the fix which comes with this because the method isn't even considered -// for inlining due to the bug. -class A { - private var debug = false - @inline private def ifelse[T](cond: => Boolean, ifPart: => T, elsePart: => T): T = - if (cond) ifPart else elsePart - - final def bob1() = ifelse(debug, 1, 2) - final def bob2() = if (debug) 1 else 2 -} -// Cool: -// -// % ls -1 /tmp/2901/ -// A$$anonfun$bob1$1.class -// A$$anonfun$bob1$2.class -// A$$anonfun$bob1$3.class -// A.class -// % ls -1 /tmp/trunk -// A.class -// -// Observations: -// -// (1) The inlined version accesses the field: the explicit one calls the accessor. -// (2) The inlined version fails to eliminate boxing. With reference types it emits -// an unneeded checkcast. -// (3) The private var debug is mangled to A$$debug, but after inlining it is never accessed -// from outside of the class and doesn't need mangling. -// (4) We could forego emitting bytecode for ifelse entirely if it has been -// inlined at all sites. -// -// Generated bytecode for the above: -// -// public final int bob1(); -// Code: -// Stack=1, Locals=1, Args_size=1 -// 0: aload_0 -// 1: getfield #11; //Field A$$debug:Z -// 4: ifeq 14 -// 7: iconst_1 -// 8: invokestatic #41; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; -// 11: goto 18 -// 14: iconst_2 -// 15: invokestatic #41; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; -// 18: invokestatic #45; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I -// 21: ireturn -// -// public final int bob2(); -// Code: -// Stack=1, Locals=1, Args_size=1 -// 0: aload_0 -// 1: invokevirtual #48; //Method A$$debug:()Z -// 4: ifeq 11 -// 7: iconst_1 -// 8: goto 12 -// 11: iconst_2 -// 12: ireturn diff --git a/test/pending/pos/sealed-final.flags b/test/pending/pos/sealed-final.flags deleted file mode 100644 index 63d024a0ba..0000000000 --- a/test/pending/pos/sealed-final.flags +++ /dev/null @@ -1,41 +0,0 @@ --Xfatal-warnings -Yinline-warnings -Ybackend:GenASM -optimise -/* -The new flag settings could be - -Yopt-warnings -Yopt:l:project - -The issue here is that things are being inlined, but a lot of -redundant load/store instructions are left behind: - -2.11.7: - - public int f(); - Code: - 0: getstatic #19 // Field Foo$.MODULE$:LFoo$; - 3: invokevirtual #23 // Method Foo$.mkFoo:()LFoo; - 6: pop - 7: bipush 10 - 9: iconst_1 - 10: iadd - 11: ireturn - - -2.12.0-M3: - - public int f(); - Code: - 0: getstatic #19 // Field Foo$.MODULE$:LFoo$; - 3: invokevirtual #23 // Method Foo$.mkFoo:()LFoo; - 6: bipush 10 - 8: istore_2 - 9: dup - 10: ifnonnull 15 - 13: aconst_null - 14: athrow - 15: astore_1 - 16: iload_2 - 17: iconst_1 - 18: iadd - 19: istore_3 - 20: iload_3 - 21: ireturn -*/
\ No newline at end of file diff --git a/test/pending/pos/sealed-final.scala b/test/pending/pos/sealed-final.scala deleted file mode 100644 index bdedb5c1f6..0000000000 --- a/test/pending/pos/sealed-final.scala +++ /dev/null @@ -1,14 +0,0 @@ -sealed abstract class Foo { - @inline def bar(x: Int) = x + 1 -} -object Foo { - def mkFoo(): Foo = new Baz2 -} - -object Baz1 extends Foo -final class Baz2 extends Foo - -object Test { - // bar should be inlined now - def f = Foo.mkFoo() bar 10 -} 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") - } -} diff --git a/test/pending/run/t6955.scala b/test/pending/run/t6955.scala deleted file mode 100644 index 787617eff1..0000000000 --- a/test/pending/run/t6955.scala +++ /dev/null @@ -1,33 +0,0 @@ -import scala.tools.partest.IcodeComparison - -// this class should compile to code that uses switches (twice) -class Switches { - type Tag = Byte - - def switchBad(i: Tag): Int = i match { // notice type of i is Tag = Byte - case 1 => 1 - case 2 => 2 - case 3 => 3 - case _ => 0 - } - - // this worked before, should keep working - def switchOkay(i: Byte): Int = i match { - case 1 => 1 - case 2 => 2 - case 3 => 3 - case _ => 0 - } -} - -object Test extends IcodeComparison { - // ensure we get two switches out of this -- ignore the rest of the output for robustness - // exclude the constant we emit for the "SWITCH ..." string below (we get the icode for all the code you see in this file) - override def show() = { - val expected = 2 - val actual = (collectIcode() filter { - x => x.indexOf("SWITCH ...") >= 0 && x.indexOf("CONSTANT(") == -1 - }).size - assert(actual == expected, s"switches expected: $expected, actual: $actual") - } -} diff --git a/test/pending/run/t6956.scala b/test/pending/run/t6956.scala deleted file mode 100644 index 57d721807d..0000000000 --- a/test/pending/run/t6956.scala +++ /dev/null @@ -1,31 +0,0 @@ -import scala.tools.partest.IcodeComparison - -class Switches { - private[this] final val ONE = 1 - - def switchBad(i: Byte): Int = i match { - case ONE => 1 - case 2 => 2 - case 3 => 3 - case _ => 0 - } - - def switchOkay(i: Byte): Int = i match { - case 1 => 1 - case 2 => 2 - case 3 => 3 - case _ => 0 - } -} - -object Test extends IcodeComparison { - // ensure we get two switches out of this -- ignore the rest of the output for robustness - // exclude the constant we emit for the "SWITCH ..." string below (we get the icode for all the code you see in this file) - override def show() = { - val expected = 2 - val actual = (collectIcode() filter { - x => x.indexOf("SWITCH ...") >= 0 && x.indexOf("CONSTANT(") == -1 - }).size - assert(actual == expected, s"switches expected: $expected, actual: $actual") - } -} diff --git a/test/pending/run/test-cpp.check b/test/pending/run/test-cpp.check deleted file mode 100644 index ff4c9bf2bf..0000000000 --- a/test/pending/run/test-cpp.check +++ /dev/null @@ -1,81 +0,0 @@ ---- a -+++ b -@@ -54,3 +54,3 @@ - def main(args: Array[String] (ARRAY[REF(class String)])): Unit { -- locals: value args, value x, value y -+ locals: value args - startBlock: 1 -@@ -59,10 +59,6 @@ - 1: -- 52 CONSTANT(2) -- 52 STORE_LOCAL(value x) - 52 SCOPE_ENTER value x -- 53 LOAD_LOCAL(value x) -- 53 STORE_LOCAL(value y) - 53 SCOPE_ENTER value y - 54 LOAD_MODULE object Predef -- 54 LOAD_LOCAL(value y) -+ 54 CONSTANT(2) - 54 BOX INT -@@ -109,3 +105,3 @@ - def main(args: Array[String] (ARRAY[REF(class String)])): Unit { -- locals: value args, value x, value y -+ locals: value args, value x - startBlock: 1 -@@ -118,7 +114,5 @@ - 81 SCOPE_ENTER value x -- 82 LOAD_LOCAL(value x) -- 82 STORE_LOCAL(value y) - 82 SCOPE_ENTER value y - 83 LOAD_MODULE object Predef -- 83 LOAD_LOCAL(value y) -+ 83 LOAD_LOCAL(value x) - 83 BOX INT -@@ -152,3 +146,3 @@ - def main(args: Array[String] (ARRAY[REF(class String)])): Unit { -- locals: value args, value x, value y -+ locals: value args - startBlock: 1 -@@ -157,10 +151,6 @@ - 1: -- 66 THIS(TestAliasChainDerefThis) -- 66 STORE_LOCAL(value x) - 66 SCOPE_ENTER value x -- 67 LOAD_LOCAL(value x) -- 67 STORE_LOCAL(value y) - 67 SCOPE_ENTER value y - 68 LOAD_MODULE object Predef -- 68 LOAD_LOCAL(value y) -+ 68 THIS(Object) - 68 CALL_METHOD scala.Predef.println (dynamic) -@@ -193,3 +183,3 @@ - def test(x: Int (INT)): Unit { -- locals: value x, value y -+ locals: value x - startBlock: 1 -@@ -198,7 +188,5 @@ - 1: -- 29 LOAD_LOCAL(value x) -- 29 STORE_LOCAL(value y) - 29 SCOPE_ENTER value y - 30 LOAD_MODULE object Predef -- 30 LOAD_LOCAL(value y) -+ 30 LOAD_LOCAL(value x) - 30 BOX INT -@@ -240,7 +228,5 @@ - 96 SCOPE_ENTER variable x -- 97 LOAD_LOCAL(variable x) -- 97 STORE_LOCAL(variable y) - 97 SCOPE_ENTER variable y - 98 LOAD_MODULE object Predef -- 98 LOAD_LOCAL(variable y) -+ 98 LOAD_LOCAL(variable x) - 98 BOX INT -@@ -250,6 +236,4 @@ - 100 STORE_LOCAL(variable y) -- 101 LOAD_LOCAL(variable y) -- 101 STORE_LOCAL(variable x) - 102 LOAD_MODULE object Predef -- 102 LOAD_LOCAL(variable x) -+ 102 LOAD_LOCAL(variable y) - 102 BOX INT diff --git a/test/pending/run/test-cpp.scala b/test/pending/run/test-cpp.scala deleted file mode 100644 index 4fca67d51e..0000000000 --- a/test/pending/run/test-cpp.scala +++ /dev/null @@ -1,104 +0,0 @@ -/** - * The only change is in the decision to replace a LOAD_LOCAL(l) - * in the copy-propagation performed before ClosureElimination. - * - * In the general case, the local variable 'l' is connected through - * an alias chain with other local variables and at the end of the - * alias chain there may be a Value, call it 'v'. - * - * If 'v' is cheaper to access (it is a Deref(This) or Const(_)), then - * replace the instruction to load it from the cheaper place. - * Otherwise, we use the local variable at the end of the alias chain - * instead of 'l'. - */ - -import scala.tools.partest.IcodeComparison - -object Test extends IcodeComparison { - override def printIcodeAfterPhase = "dce" -} - -import scala.util.Random._ - -/** - * The example in the bug report (Issue-5321): an alias chain which store - * an Unknown. Should remove local variable 'y'. - */ -object TestBugReport { - def test(x: Int) = { - val y = x - println(y) - } -} - -/** - * The code taken from scala.tools.nsc.settings.Settings: - * After inlining of the setter is performed, there is an opportunity for - * copy-propagation to eliminate some local variables. - */ -object TestSetterInline { - private var _postSetHook: this.type => Unit = (x: this.type) => () - def withPostSetHook(f: this.type => Unit): this.type = { _postSetHook = f ; this } -} - - -/** - * The access of the local variable 'y' should be replaced by the - * constant. - */ -object TestAliasChainConstant { - - def main(args: Array[String]): Unit = { - val x = 2 - val y = x - println(y) - } -} - -/** - * At the end of the alias chain we have a reference to 'this'. - * The local variables should be all discarded and replace by a - * direct reference to this - */ -class TestAliasChainDerefThis { - - def main(args: Array[String]): Unit = { - val x = this - val y = x - println(y) - } -} - -/** - * At the end of the alias chain, there is the value of a field. - * The use of variable 'y' should be replaced by 'x', not by an access - * to the field 'f' since it is more costly. - */ -object TestAliasChainDerefField { - def f = nextInt - - def main(args: Array[String]): Unit = { - val x = f - val y = x - println(y) - } -} - - -/** - * The first time 'println' is called, 'x' is replaced by 'y' - * and the second time, 'y' is replaced by 'x'. But none of them - * can be removed. - */ -object TestDifferentBindings { - - def main(args: Array[String]): Unit = { - var x = nextInt - var y = x - println(y) - - y = nextInt - x = y - println(x) - } -} |