diff options
13 files changed, 175 insertions, 51 deletions
@@ -1448,6 +1448,15 @@ TODO: <target name="test.junit.comp" depends="pack.done"> <stopwatch name="test.junit.compiler.timer"/> <mkdir dir="${test.junit.classes}"/> + <javac + debug="true" + srcdir="${test.junit.src}" + destdir="${test.junit.classes}" + classpathref="test.junit.compiler.build.path" + target="1.6" + source="1.5" + compiler="javac1.6" + includes="**/*.java"/> <scalacfork destdir="${test.junit.classes}" compilerpathref="quick.compiler.path" diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index 01e4cdf367..ef63078f90 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -355,6 +355,14 @@ abstract class SymbolTable extends macros.Universe cache } + /** + * Removes a cache from the per-run caches. This is useful for testing: it allows running the + * compiler and then inspect the state of a cache. + */ + def unrecordCache[T <: Clearable](cache: T): Unit = { + caches = caches.filterNot(_.get eq cache) + } + def clearAll() = { debuglog("Clearing " + caches.size + " caches.") caches foreach (ref => Option(ref.get).foreach(_.clear)) diff --git a/test/junit/scala/collection/IterableViewLikeTest.scala b/test/junit/scala/collection/IterableViewLikeTest.scala index ab09c4930b..435a43c215 100644 --- a/test/junit/scala/collection/IterableViewLikeTest.scala +++ b/test/junit/scala/collection/IterableViewLikeTest.scala @@ -13,6 +13,7 @@ class IterableViewLikeTest { def hasCorrectDropAndTakeMethods() { val iter = Iterable(1, 2, 3) + import scala.language.postfixOps assertEquals(Iterable.empty[Int], iter.view take Int.MinValue force) assertEquals(Iterable.empty[Int], iter.view takeRight Int.MinValue force) assertEquals(iter, iter.view drop Int.MinValue force) diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala index 2347e8288e..6ada0e20fb 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala @@ -7,35 +7,41 @@ import org.junit.Test import scala.tools.asm.Opcodes import org.junit.Assert._ -@RunWith(classOf[JUnit4]) -class BTypesTest { - val settings = new Settings() - settings.processArgumentString("-usejavacp") - val g: Global = new Global(settings) - val run = new g.Run() // initializes some compiler internals - import g.{definitions => d, Symbol} +import scala.tools.nsc.backend.jvm.CodeGenTools._ +import scala.tools.testing.ClearAfterClass - def duringBackend[T](f: => T) = g.exitingDelambdafy(f) +object BTypesTest extends ClearAfterClass.Clearable { + var compiler = { + val comp = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") + new comp.Run() // initializes some of the compiler + comp.exitingDelambdafy(comp.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler + comp.exitingDelambdafy(comp.genBCode.bTypes.initializeCoreBTypes()) + comp + } + def clear(): Unit = { compiler = null } +} - val btypes = new BTypesFromSymbols[g.type](g) - import btypes._ - duringBackend(btypes.initializeCoreBTypes()) +@RunWith(classOf[JUnit4]) +class BTypesTest extends ClearAfterClass { + ClearAfterClass.stateToClear = BTypesTest - def classBTypeFromSymbol(sym: Symbol) = duringBackend(btypes.classBTypeFromSymbol(sym)) + val compiler = BTypesTest.compiler + import compiler.genBCode.bTypes._ - val jlo = d.ObjectClass - val jls = d.StringClass + def classBTFS(sym: compiler.Symbol) = compiler.exitingDelambdafy(classBTypeFromSymbol(sym)) - val o = classBTypeFromSymbol(jlo) - val s = classBTypeFromSymbol(jls) - val oArr = ArrayBType(o) - val method = MethodBType(List(oArr, INT, DOUBLE, s), UNIT) + def jlo = compiler.definitions.ObjectClass + def jls = compiler.definitions.StringClass + def o = classBTFS(jlo) + def s = classBTFS(jls) + def oArr = ArrayBType(o) + def method = MethodBType(List(oArr, INT, DOUBLE, s), UNIT) @Test def classBTypesEquality() { - val s1 = classBTypeFromSymbol(jls) - val s2 = classBTypeFromSymbol(jls) - val o = classBTypeFromSymbol(jlo) + val s1 = classBTFS(jls) + val s2 = classBTFS(jls) + val o = classBTFS(jlo) assertEquals(s1, s2) assertEquals(s1.hashCode, s2.hashCode) assert(s1 != o) @@ -53,7 +59,7 @@ class BTypesTest { assert(FLOAT.typedOpcode(Opcodes.IALOAD) == Opcodes.FALOAD) assert(LONG.typedOpcode(Opcodes.IALOAD) == Opcodes.LALOAD) assert(DOUBLE.typedOpcode(Opcodes.IALOAD) == Opcodes.DALOAD) - assert(classBTypeFromSymbol(jls).typedOpcode(Opcodes.IALOAD) == Opcodes.AALOAD) + assert(classBTFS(jls).typedOpcode(Opcodes.IALOAD) == Opcodes.AALOAD) assert(UNIT.typedOpcode(Opcodes.IRETURN) == Opcodes.RETURN) assert(BOOL.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN) @@ -64,7 +70,7 @@ class BTypesTest { assert(FLOAT.typedOpcode(Opcodes.IRETURN) == Opcodes.FRETURN) assert(LONG.typedOpcode(Opcodes.IRETURN) == Opcodes.LRETURN) assert(DOUBLE.typedOpcode(Opcodes.IRETURN) == Opcodes.DRETURN) - assert(classBTypeFromSymbol(jls).typedOpcode(Opcodes.IRETURN) == Opcodes.ARETURN) + assert(classBTFS(jls).typedOpcode(Opcodes.IRETURN) == Opcodes.ARETURN) } @Test diff --git a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala index 89900291ca..3b1b009037 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala @@ -7,10 +7,18 @@ import org.junit.Assert._ import CodeGenTools._ import scala.tools.asm.Opcodes._ import scala.tools.partest.ASMConverters._ +import scala.tools.testing.ClearAfterClass + +object DirectCompileTest extends ClearAfterClass.Clearable { + var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:method") + def clear(): Unit = { compiler = null } +} @RunWith(classOf[JUnit4]) -class DirectCompileTest { - val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:method") +class DirectCompileTest extends ClearAfterClass { + ClearAfterClass.stateToClear = DirectCompileTest + + val compiler = DirectCompileTest.compiler @Test def testCompile(): Unit = { diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala index 2975bd060d..4481fcd6be 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala @@ -19,7 +19,8 @@ import scala.collection.convert.decorateAsScala._ @RunWith(classOf[JUnit4]) class BTypesFromClassfileTest { - val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode") + // inliner enabled -> inlineInfos are collected (and compared) in ClassBTypes + val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:inline-global") import compiler._ import definitions._ @@ -29,6 +30,7 @@ class BTypesFromClassfileTest { def duringBackend[T](f: => T) = compiler.exitingDelambdafy(f) val run = new compiler.Run() // initializes some of the compiler + duringBackend(compiler.scalaPrimitives.init()) // needed: it's only done when running the backend, and we don't actually run the compiler duringBackend(bTypes.initializeCoreBTypes()) def clearCache() = bTypes.classBTypeFromInternalName.clear() diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala index 7d83c54b5b..7b0504fec0 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala @@ -11,9 +11,23 @@ import org.junit.Assert._ import CodeGenTools._ import scala.tools.partest.ASMConverters import ASMConverters._ +import scala.tools.testing.ClearAfterClass + +object EmptyExceptionHandlersTest extends ClearAfterClass.Clearable { + var noOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") + var dceCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:unreachable-code") + def clear(): Unit = { + noOptCompiler = null + dceCompiler = null + } +} @RunWith(classOf[JUnit4]) -class EmptyExceptionHandlersTest { +class EmptyExceptionHandlersTest extends ClearAfterClass { + ClearAfterClass.stateToClear = EmptyExceptionHandlersTest + + val noOptCompiler = EmptyExceptionHandlersTest.noOptCompiler + val dceCompiler = EmptyExceptionHandlersTest.dceCompiler val exceptionDescriptor = "java/lang/Exception" @@ -51,9 +65,6 @@ class EmptyExceptionHandlersTest { assertTrue(convertMethod(asmMethod).handlers.isEmpty) } - val noOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") - val dceCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:unreachable-code") - @Test def eliminateUnreachableHandler(): Unit = { val code = "def f: Unit = try { } catch { case _: Exception => println(0) }; println(1)" diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala index 406b8da570..36f297767e 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerIllegalAccessTest.scala @@ -17,10 +17,18 @@ import ASMConverters._ import AsmUtils._ import scala.collection.convert.decorateAsScala._ +import scala.tools.testing.ClearAfterClass + +object InlinerIllegalAccessTest extends ClearAfterClass.Clearable { + var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") + def clear(): Unit = { compiler = null } +} @RunWith(classOf[JUnit4]) -class InlinerIllegalAccessTest { - val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") +class InlinerIllegalAccessTest extends ClearAfterClass { + ClearAfterClass.stateToClear = InlinerIllegalAccessTest + + val compiler = InlinerIllegalAccessTest.compiler import compiler.genBCode.bTypes._ def addToRepo(cls: List[ClassNode]): Unit = for (c <- cls) byteCodeRepository.classes(c.name) = (c, ByteCodeRepository.Classfile) 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 1aa7bd1391..2ec6853f13 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -5,6 +5,7 @@ package opt import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.junit.Test +import scala.collection.generic.Clearable import scala.tools.asm.Opcodes._ import org.junit.Assert._ @@ -19,19 +20,37 @@ import ASMConverters._ import AsmUtils._ import scala.collection.convert.decorateAsScala._ +import scala.tools.testing.ClearAfterClass + +object InlinerTest extends ClearAfterClass.Clearable { + var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:project") + + // allows inspecting the caches after a compilation run + def notPerRun: List[Clearable] = List(compiler.genBCode.bTypes.classBTypeFromInternalName, compiler.genBCode.bTypes.byteCodeRepository.classes) + notPerRun foreach compiler.perRunCaches.unrecordCache + + def clear(): Unit = { compiler = null } +} @RunWith(classOf[JUnit4]) -class InlinerTest { - val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") +class InlinerTest extends ClearAfterClass { + ClearAfterClass.stateToClear = InlinerTest + + val compiler = InlinerTest.compiler import compiler.genBCode.bTypes._ - def addToRepo(cls: List[ClassNode]): List[ClassNode] = { + + def compile(code: String): List[ClassNode] = { + InlinerTest.notPerRun.foreach(_.clear()) + val cls = compileClasses(compiler)(code) + // the compiler doesn't add classes being compiled to the code repo yet, so we do it manually. + // this line is removed in the next commit. for (c <- cls) byteCodeRepository.classes(c.name) = (c, ByteCodeRepository.Classfile) cls } // inline first invocation of f into g in class C def inlineTest(code: String, mod: ClassNode => Unit = _ => ()): (MethodNode, Option[String]) = { - val List(cls) = addToRepo(compileClasses(compiler)(code)) + val List(cls) = compile(code) mod(cls) val clsBType = classBTypeFromParsedClassfile(cls.name) @@ -165,7 +184,7 @@ class InlinerTest { |} """.stripMargin - val List(c, d) = addToRepo(compileClasses(compiler)(code)) + val List(c, d) = compile(code) val cTp = classBTypeFromParsedClassfile(c.name) val dTp = classBTypeFromParsedClassfile(d.name) diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala index 5430e33d6c..2c71e9d533 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala @@ -13,10 +13,18 @@ import scala.tools.testing.AssertUtil._ import CodeGenTools._ import scala.tools.partest.ASMConverters import ASMConverters._ +import scala.tools.testing.ClearAfterClass + +object MethodLevelOpts extends ClearAfterClass.Clearable { + var methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:method") + def clear(): Unit = { methodOptCompiler = null } +} @RunWith(classOf[JUnit4]) -class MethodLevelOpts { - val methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:method") +class MethodLevelOpts extends ClearAfterClass { + ClearAfterClass.stateToClear = MethodLevelOpts + + val methodOptCompiler = MethodLevelOpts.methodOptCompiler def wrapInDefault(code: Instruction*) = List(Label(0), LineNumber(1, Label(0))) ::: code.toList ::: List(Label(1)) diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala index 4a45dd9138..7c9636b8b7 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala @@ -13,9 +13,34 @@ import scala.tools.testing.AssertUtil._ import CodeGenTools._ import scala.tools.partest.ASMConverters import ASMConverters._ +import scala.tools.testing.ClearAfterClass + +object UnreachableCodeTest extends ClearAfterClass.Clearable { + // jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks, + // see comment in BCodeBodyBuilder + var methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:method") + var dceCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code") + var noOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:none") + + // jvm-1.5 disables computing stack map frames, and it emits dead code as-is. + var noOptNoFramesCompiler = newCompiler(extraArgs = "-target:jvm-1.5 -Ybackend:GenBCode -Yopt:l:none") + + def clear(): Unit = { + methodOptCompiler = null + dceCompiler = null + noOptCompiler = null + noOptNoFramesCompiler = null + } +} @RunWith(classOf[JUnit4]) -class UnreachableCodeTest { +class UnreachableCodeTest extends ClearAfterClass { + ClearAfterClass.stateToClear = UnreachableCodeTest + + val methodOptCompiler = UnreachableCodeTest.methodOptCompiler + val dceCompiler = UnreachableCodeTest.dceCompiler + val noOptCompiler = UnreachableCodeTest.noOptCompiler + val noOptNoFramesCompiler = UnreachableCodeTest.noOptNoFramesCompiler def assertEliminateDead(code: (Instruction, Boolean)*): Unit = { val method = genMethod()(code.map(_._1): _*) @@ -25,15 +50,6 @@ class UnreachableCodeTest { assertSameCode(nonEliminated, expectedLive) } - // jvm-1.6 enables emitting stack map frames, which impacts the code generation wrt dead basic blocks, - // see comment in BCodeBodyBuilder - val methodOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:method") - val dceCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:unreachable-code") - val noOptCompiler = newCompiler(extraArgs = "-target:jvm-1.6 -Ybackend:GenBCode -Yopt:l:none") - - // jvm-1.5 disables computing stack map frames, and it emits dead code as-is. - val noOptNoFramesCompiler = newCompiler(extraArgs = "-target:jvm-1.5 -Ybackend:GenBCode -Yopt:l:none") - @Test def basicElimination(): Unit = { assertEliminateDead( diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala index 24a1f9d1c1..769736669b 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnusedLocalVariablesTest.scala @@ -12,10 +12,18 @@ import scala.collection.JavaConverters._ import CodeGenTools._ import scala.tools.partest.ASMConverters import ASMConverters._ +import scala.tools.testing.ClearAfterClass + +object UnusedLocalVariablesTest extends ClearAfterClass.Clearable { + var dceCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:unreachable-code") + def clear(): Unit = { dceCompiler = null } +} @RunWith(classOf[JUnit4]) -class UnusedLocalVariablesTest { - val dceCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:unreachable-code") +class UnusedLocalVariablesTest extends ClearAfterClass { + ClearAfterClass.stateToClear = UnusedLocalVariablesTest + + val dceCompiler = UnusedLocalVariablesTest.dceCompiler @Test def removeUnusedVar(): Unit = { diff --git a/test/junit/scala/tools/testing/ClearAfterClass.java b/test/junit/scala/tools/testing/ClearAfterClass.java new file mode 100644 index 0000000000..232d459c4e --- /dev/null +++ b/test/junit/scala/tools/testing/ClearAfterClass.java @@ -0,0 +1,20 @@ +package scala.tools.testing; + +import org.junit.AfterClass; + +/** + * Extend this class to use JUnit's @AfterClass. This annotation only works on static methods, + * which cannot be written in Scala. + * + * Example: {@link scala.tools.nsc.backend.jvm.opt.InlinerTest} + */ +public class ClearAfterClass { + public static interface Clearable { + void clear(); + } + + public static Clearable stateToClear; + + @AfterClass + public static void clearState() { stateToClear.clear(); } +} |