diff options
Diffstat (limited to 'test')
59 files changed, 365 insertions, 93 deletions
diff --git a/test/files/neg/incompatibleSettings.check b/test/files/neg/incompatibleSettings.check new file mode 100644 index 0000000000..0f28d41825 --- /dev/null +++ b/test/files/neg/incompatibleSettings.check @@ -0,0 +1,6 @@ +warning: Conflicting compiler settings were detected. Some settings will be ignored. +Compiler settings for the 2.11 optimizer (-optimise) are incompatible with -Ybackend:GenBCode (which is the default in 2.12). +The optimizer settings are ignored. See -Yopt:help for enabling the new optimizer in 2.12. +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/incompatibleSettings.flags b/test/files/neg/incompatibleSettings.flags new file mode 100644 index 0000000000..00dd9c1c24 --- /dev/null +++ b/test/files/neg/incompatibleSettings.flags @@ -0,0 +1 @@ +-optimise -Ybackend:GenBCode -Xfatal-warnings diff --git a/test/files/neg/incompatibleSettings.scala b/test/files/neg/incompatibleSettings.scala new file mode 100644 index 0000000000..826a1a5bc2 --- /dev/null +++ b/test/files/neg/incompatibleSettings.scala @@ -0,0 +1 @@ +class C diff --git a/test/files/neg/inlineIndyLambdaPrivate.check b/test/files/neg/inlineIndyLambdaPrivate.check new file mode 100644 index 0000000000..dbd142f59e --- /dev/null +++ b/test/files/neg/inlineIndyLambdaPrivate.check @@ -0,0 +1,16 @@ +Test_2.scala:2: warning: A_1::test()Ljava/lang/String; could not be inlined: +The callee A_1::test()Ljava/lang/String; contains the instruction INVOKEDYNAMIC m()LA_1$Fun; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; + // arguments: + (Ljava/lang/String;)Ljava/lang/String;, + // handle kind 0x6 : INVOKESTATIC + A_1.lambda$test$0(Ljava/lang/String;)Ljava/lang/String;, + (Ljava/lang/String;)Ljava/lang/String; + ] +that would cause an IllegalAccessError when inlined into class Test. + def foo = A_1.test + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/inlineIndyLambdaPrivate.flags b/test/files/neg/inlineIndyLambdaPrivate.flags new file mode 100644 index 0000000000..01b466bd8c --- /dev/null +++ b/test/files/neg/inlineIndyLambdaPrivate.flags @@ -0,0 +1 @@ +-Yopt:l:classpath -Yopt-inline-heuristics:everything -Yopt-warnings:_ -Xfatal-warnings
\ No newline at end of file diff --git a/test/files/neg/inlineIndyLambdaPrivate/A_1.java b/test/files/neg/inlineIndyLambdaPrivate/A_1.java new file mode 100644 index 0000000000..a9144a9fa6 --- /dev/null +++ b/test/files/neg/inlineIndyLambdaPrivate/A_1.java @@ -0,0 +1,9 @@ +public class A_1 { + interface Fun { + String m(String s); + } + public static final String test() { + Fun f = s -> s.trim(); + return f.m(" eh "); + } +} diff --git a/test/files/neg/inlineIndyLambdaPrivate/Test_2.scala b/test/files/neg/inlineIndyLambdaPrivate/Test_2.scala new file mode 100644 index 0000000000..dd59c05176 --- /dev/null +++ b/test/files/neg/inlineIndyLambdaPrivate/Test_2.scala @@ -0,0 +1,3 @@ +class Test { + def foo = A_1.test +} diff --git a/test/files/neg/sealed-final-neg.flags b/test/files/neg/sealed-final-neg.flags index cfabf7a5b4..3f0fcd2201 100644 --- a/test/files/neg/sealed-final-neg.flags +++ b/test/files/neg/sealed-final-neg.flags @@ -1 +1 @@ --Xfatal-warnings -Yinline-warnings -optimise
\ No newline at end of file +-Xfatal-warnings -Ybackend:GenASM -Yinline-warnings -optimise
\ No newline at end of file diff --git a/test/files/neg/t4425.flags b/test/files/neg/t4425.flags deleted file mode 100644 index 1182725e86..0000000000 --- a/test/files/neg/t4425.flags +++ /dev/null @@ -1 +0,0 @@ --optimize
\ No newline at end of file diff --git a/test/files/neg/t5639b.flags b/test/files/neg/t5639b.flags new file mode 100644 index 0000000000..90b87663af --- /dev/null +++ b/test/files/neg/t5639b.flags @@ -0,0 +1 @@ +-Xsource:2.11
\ No newline at end of file diff --git a/test/files/pos/inline-access-levels.flags b/test/files/pos/inline-access-levels.flags index 882f40f050..9bda07eb6c 100644 --- a/test/files/pos/inline-access-levels.flags +++ b/test/files/pos/inline-access-levels.flags @@ -1 +1 @@ --optimise -Xfatal-warnings -Yinline-warnings +-optimise -Ybackend:GenASM -Xfatal-warnings -Yinline-warnings diff --git a/test/files/pos/inliner2.flags b/test/files/pos/inliner2.flags index ea03113c66..bff4bb8afa 100644 --- a/test/files/pos/inliner2.flags +++ b/test/files/pos/inliner2.flags @@ -1 +1 @@ --optimise -Xfatal-warnings
\ No newline at end of file +-optimise -Ybackend:GenASM -Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/sealed-final.flags b/test/files/pos/sealed-final.flags index cfabf7a5b4..63f5e65527 100644 --- a/test/files/pos/sealed-final.flags +++ b/test/files/pos/sealed-final.flags @@ -1 +1 @@ --Xfatal-warnings -Yinline-warnings -optimise
\ No newline at end of file +-Xfatal-warnings -Yinline-warnings -Ybackend:GenASM -optimise
\ No newline at end of file diff --git a/test/files/pos/t3420.flags b/test/files/pos/t3420.flags index ea03113c66..bff4bb8afa 100644 --- a/test/files/pos/t3420.flags +++ b/test/files/pos/t3420.flags @@ -1 +1 @@ --optimise -Xfatal-warnings
\ No newline at end of file +-optimise -Ybackend:GenASM -Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/t8410.flags b/test/files/pos/t8410.flags index dcd5943c2f..2f32e3b26a 100644 --- a/test/files/pos/t8410.flags +++ b/test/files/pos/t8410.flags @@ -1 +1 @@ --optimise -Xfatal-warnings -deprecation:false -Yinline-warnings:false +-optimise -Ybackend:GenASM -Xfatal-warnings -deprecation:false -Yinline-warnings:false diff --git a/test/files/run/blame_eye_triple_eee-double.flags b/test/files/run/blame_eye_triple_eee-double.flags deleted file mode 100644 index c9b68d70dc..0000000000 --- a/test/files/run/blame_eye_triple_eee-double.flags +++ /dev/null @@ -1 +0,0 @@ --optimise diff --git a/test/files/run/blame_eye_triple_eee-float.flags b/test/files/run/blame_eye_triple_eee-float.flags deleted file mode 100644 index c9b68d70dc..0000000000 --- a/test/files/run/blame_eye_triple_eee-float.flags +++ /dev/null @@ -1 +0,0 @@ --optimise diff --git a/test/files/run/classfile-format-51.scala b/test/files/run/classfile-format-51.scala index da322bb5d9..0e90b881e5 100644 --- a/test/files/run/classfile-format-51.scala +++ b/test/files/run/classfile-format-51.scala @@ -16,7 +16,7 @@ import Opcodes._ // verify. So the test includes a version check that short-circuites the whole test // on JDK 6 object Test extends DirectTest { - override def extraSettings: String = "-optimise -usejavacp -d " + testOutput.path + " -cp " + testOutput.path + override def extraSettings: String = "-Yopt:l:classpath -usejavacp -d " + testOutput.path + " -cp " + testOutput.path def generateClass() { val invokerClassName = "DynamicInvoker" diff --git a/test/files/run/classfile-format-52.scala b/test/files/run/classfile-format-52.scala index e278d40b8b..ebd0826303 100644 --- a/test/files/run/classfile-format-52.scala +++ b/test/files/run/classfile-format-52.scala @@ -13,7 +13,7 @@ import Opcodes._ // By its nature the test can only work on JDK 8+ because under JDK 7- the // interface won't verify. object Test extends DirectTest { - override def extraSettings: String = "-optimise -usejavacp -d " + testOutput.path + " -cp " + testOutput.path + override def extraSettings: String = "-Yopt:l:classpath -usejavacp -d " + testOutput.path + " -cp " + testOutput.path def generateInterface() { val interfaceName = "HasDefaultMethod" diff --git a/test/files/run/constant-optimization.flags b/test/files/run/constant-optimization.flags index c9b68d70dc..6c9965e749 100644 --- a/test/files/run/constant-optimization.flags +++ b/test/files/run/constant-optimization.flags @@ -1 +1 @@ --optimise +-optimise -Ybackend:GenASM diff --git a/test/files/run/dead-code-elimination.flags b/test/files/run/dead-code-elimination.flags index 49d036a887..b9bb09167e 100644 --- a/test/files/run/dead-code-elimination.flags +++ b/test/files/run/dead-code-elimination.flags @@ -1 +1 @@ --optimize +-optimize -Ybackend:GenASM diff --git a/test/files/run/elidable-opt.flags b/test/files/run/elidable-opt.flags index 62897ff218..6537d2f57a 100644 --- a/test/files/run/elidable-opt.flags +++ b/test/files/run/elidable-opt.flags @@ -1 +1 @@ --optimise -Xelide-below 900 +-optimise -Ybackend:GenASM -Xelide-below 900 diff --git a/test/files/run/elidable-opt.scala b/test/files/run/elidable-opt.scala index a2f29d2caf..ebada46de8 100644 --- a/test/files/run/elidable-opt.scala +++ b/test/files/run/elidable-opt.scala @@ -1,3 +1,6 @@ +/* + * filter: inliner warnings; re-run with + */ import annotation._ import elidable._ diff --git a/test/files/run/finalvar.flags b/test/files/run/finalvar.flags index aee3039bec..8d9be3d62e 100644 --- a/test/files/run/finalvar.flags +++ b/test/files/run/finalvar.flags @@ -1 +1 @@ --Yoverride-vars -Yinline
\ No newline at end of file +-Yoverride-vars -Yinline -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/icode-reader-dead-code.scala b/test/files/run/icode-reader-dead-code.scala index 00ba58829f..535ef2a2e2 100644 --- a/test/files/run/icode-reader-dead-code.scala +++ b/test/files/run/icode-reader-dead-code.scala @@ -36,7 +36,7 @@ object Test extends DirectTest { // If inlining fails, the compiler will issue an inliner warning that is not present in the // check file - compileString(newCompiler("-usejavacp", "-optimise"))(bCode) + compileString(newCompiler("-usejavacp", "-optimise", "-Ybackend:GenASM"))(bCode) } def readClass(file: String) = { diff --git a/test/files/run/indylambda-specialization.scala b/test/files/run/indylambda-specialization.scala new file mode 100644 index 0000000000..2c66073e90 --- /dev/null +++ b/test/files/run/indylambda-specialization.scala @@ -0,0 +1,15 @@ +object Test { + def assertApply(expected: Boolean) = { + val frames = Thread.currentThread.getStackTrace.takeWhile(_.getMethodName != "main") + val usesObjectApply = frames.exists(_.getMethodName == "apply") + assert(expected == usesObjectApply, frames.mkString("\n")) + } + def assertSpecialized() = assertApply(false) + def assertUnspecialized() = assertApply(true) + def main(args: Array[String]): Unit = { + ((i: String) => {assertUnspecialized(); i}).apply("") + (() => {assertSpecialized(); 0}).apply() + ((i: Int) => {assertSpecialized(); i}).apply(0) + ((i: Int, j: Int) => {assertSpecialized(); i + j}).apply(0, 0) + } +} diff --git a/test/files/run/macroPlugins-namerHooks.check b/test/files/run/macroPlugins-namerHooks.check index c2db5935d4..56b170cbd9 100644 --- a/test/files/run/macroPlugins-namerHooks.check +++ b/test/files/run/macroPlugins-namerHooks.check @@ -28,7 +28,7 @@ enterStat(<synthetic> val C$1: C = x$1.asInstanceOf[C]) enterSym(def <init>() = { super.<init>(); () }) enterSym(final override <synthetic> def toString() = "C") enterSym(case <synthetic> def apply(x: Int, y: Int): C = new C(x, y)) -enterSym(case <synthetic> def unapply(x$0: C) = if (x$0.==(null)) scala.this.None else Some(scala.Tuple2(x$0.x, x$0.y))) +enterSym(case <synthetic> def unapply(x$0: C): _root_.scala.Option[scala.Tuple2[Int, Int]] = if (x$0.==(null)) scala.this.None else Some(scala.Tuple2(x$0.x, x$0.y))) enterStat(def <init>() = { super.<init>(); () }) enterStat(final override <synthetic> def toString() = "C") enterSym(def <init>() = { super.<init>(); () }) diff --git a/test/files/run/noInlineUnknownIndy.check b/test/files/run/noInlineUnknownIndy.check new file mode 100644 index 0000000000..7cc6d1b675 --- /dev/null +++ b/test/files/run/noInlineUnknownIndy.check @@ -0,0 +1,13 @@ +newSource1.scala:1: warning: A_1::test()Ljava/lang/String; could not be inlined: +Failed to check if A_1::test()Ljava/lang/String; can be safely inlined to T without causing an IllegalAccessError. Checking instruction INVOKEDYNAMIC m()LA_1$Fun; [ + // handle kind 0x6 : INVOKESTATIC + not/java/lang/SomeLambdaMetafactory.notAMetaFactoryMethod(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; + // arguments: + (Ljava/lang/String;)Ljava/lang/String;, + // handle kind 0x6 : INVOKESTATIC + A_1.lambda$test$0(Ljava/lang/String;)Ljava/lang/String;, + (Ljava/lang/String;)Ljava/lang/String; + ] failed: +The callee contains an InvokeDynamic instruction with an unknown bootstrap method (not a LambdaMetaFactory). +class T { def foo = A_1.test } + ^ diff --git a/test/files/run/noInlineUnknownIndy/A_1.java b/test/files/run/noInlineUnknownIndy/A_1.java new file mode 100644 index 0000000000..a9144a9fa6 --- /dev/null +++ b/test/files/run/noInlineUnknownIndy/A_1.java @@ -0,0 +1,9 @@ +public class A_1 { + interface Fun { + String m(String s); + } + public static final String test() { + Fun f = s -> s.trim(); + return f.m(" eh "); + } +} diff --git a/test/files/run/noInlineUnknownIndy/Test.scala b/test/files/run/noInlineUnknownIndy/Test.scala new file mode 100644 index 0000000000..16d8126543 --- /dev/null +++ b/test/files/run/noInlineUnknownIndy/Test.scala @@ -0,0 +1,28 @@ +import java.io.File + +import scala.collection.convert.decorateAsScala._ +import scala.tools.asm.tree.{ClassNode, InvokeDynamicInsnNode} +import scala.tools.asm.{Handle, Opcodes} +import scala.tools.partest.BytecodeTest.modifyClassFile +import scala.tools.partest._ + +object Test extends DirectTest { + def code = ??? + + def compileCode(code: String) = { + val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator") + compileString(newCompiler("-cp", classpath, "-d", testOutput.path, "-Yopt:l:classpath", "-Yopt-inline-heuristics:everything", "-Yopt-warnings:_"))(code) + } + + def show(): Unit = { + val unknownBootstrapMethod = new Handle(Opcodes.H_INVOKESTATIC, "not/java/lang/SomeLambdaMetafactory", "notAMetaFactoryMethod", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;") + modifyClassFile(new File(testOutput.toFile, "A_1.class"))((cn: ClassNode) => { + val testMethod = cn.methods.iterator.asScala.find(_.name == "test").head + val indy = testMethod.instructions.iterator.asScala.collect({ case i: InvokeDynamicInsnNode => i }).next() + indy.bsm = unknownBootstrapMethod + cn + }) + + compileCode("class T { def foo = A_1.test }") + } +} diff --git a/test/files/run/optimizer-array-load.flags b/test/files/run/optimizer-array-load.flags index eb4d19bcb9..99bd6c895d 100644 --- a/test/files/run/optimizer-array-load.flags +++ b/test/files/run/optimizer-array-load.flags @@ -1 +1 @@ --optimise
\ No newline at end of file +-optimise -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/run-bug4840.flags b/test/files/run/run-bug4840.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/run/run-bug4840.flags +++ /dev/null @@ -1 +0,0 @@ --optimise
\ No newline at end of file diff --git a/test/files/run/synchronized.flags b/test/files/run/synchronized.flags index 49d036a887..b9bb09167e 100644 --- a/test/files/run/synchronized.flags +++ b/test/files/run/synchronized.flags @@ -1 +1 @@ --optimize +-optimize -Ybackend:GenASM diff --git a/test/files/run/t2106.check b/test/files/run/t2106.check index c6457216b5..b19165824b 100644 --- a/test/files/run/t2106.check +++ b/test/files/run/t2106.check @@ -1,13 +1,5 @@ -#partest !-Ybackend:GenASM t2106.scala:7: warning: A::foo()Ljava/lang/Object; is annotated @inline but could not be inlined: The callee A::foo()Ljava/lang/Object; contains the instruction INVOKEVIRTUAL java/lang/Object.clone ()Ljava/lang/Object; that would cause an IllegalAccessError when inlined into class Test$. def main(args: Array[String]): Unit = x.foo ^ -#partest -Ybackend:GenASM -t2106.scala:7: warning: Could not inline required method foo because access level required by callee not matched by caller. - def main(args: Array[String]): Unit = x.foo - ^ -t2106.scala:7: warning: At the end of the day, could not inline @inline-marked method foo - def main(args: Array[String]): Unit = x.foo - ^ diff --git a/test/files/run/t2106.flags b/test/files/run/t2106.flags index a2e413bb22..5d6ee831df 100644 --- a/test/files/run/t2106.flags +++ b/test/files/run/t2106.flags @@ -1 +1 @@ --optimise -Yinline-warnings -Yopt:l:classpath +-Yinline-warnings -Yopt:l:classpath diff --git a/test/files/run/t3368-c.check b/test/files/run/t3368-c.check index e0c10cc0dd..4cbe98c577 100644 --- a/test/files/run/t3368-c.check +++ b/test/files/run/t3368-c.check @@ -6,8 +6,8 @@ package <empty> { }; def x = { val $buf = new _root_.scala.xml.NodeBuffer(); - $buf.$amp$plus(new _root_.scala.xml.Text("hi & bye")); - $buf.$amp$plus(new _root_.scala.xml.Text("red & black")); + $buf.$amp$plus(new _root_.scala.xml.PCData("hi & bye")); + $buf.$amp$plus(new _root_.scala.xml.PCData("red & black")); $buf } }; @@ -24,7 +24,8 @@ package <empty> { new _root_.scala.xml.Elem(null, "b", _root_.scala.xml.Null, $scope, true) } }); - $buf.$amp$plus(new _root_.scala.xml.Text("starthi & bye")); + $buf.$amp$plus(new _root_.scala.xml.Text("start")); + $buf.$amp$plus(new _root_.scala.xml.PCData("hi & bye")); $buf.$amp$plus({ { new _root_.scala.xml.Elem(null, "c", _root_.scala.xml.Null, $scope, true) @@ -36,7 +37,8 @@ package <empty> { new _root_.scala.xml.Elem(null, "d", _root_.scala.xml.Null, $scope, true) } }); - $buf.$amp$plus(new _root_.scala.xml.Text("stuffred & black")); + $buf.$amp$plus(new _root_.scala.xml.Text("stuff")); + $buf.$amp$plus(new _root_.scala.xml.PCData("red & black")); $buf }: _*)) } @@ -46,18 +48,19 @@ package <empty> { def $init$() = { () }; - def d = new _root_.scala.xml.Text("hello, world"); + def d = new _root_.scala.xml.PCData("hello, world"); def e = { val $buf = new _root_.scala.xml.NodeBuffer(); - $buf.$amp$plus(new _root_.scala.xml.Text("hello, world")); - $buf.$amp$plus(new _root_.scala.xml.Text("hello, world")); + $buf.$amp$plus(new _root_.scala.xml.PCData("hello, world")); + $buf.$amp$plus(new _root_.scala.xml.PCData("hello, world")); $buf }; def f = { { new _root_.scala.xml.Elem(null, "foo", _root_.scala.xml.Null, $scope, false, ({ val $buf = new _root_.scala.xml.NodeBuffer(); - $buf.$amp$plus(new _root_.scala.xml.Text("xhello, world")); + $buf.$amp$plus(new _root_.scala.xml.Text("x")); + $buf.$amp$plus(new _root_.scala.xml.PCData("hello, world")); $buf }: _*)) } @@ -66,7 +69,7 @@ package <empty> { { new _root_.scala.xml.Elem(null, "foo", _root_.scala.xml.Null, $scope, false, ({ val $buf = new _root_.scala.xml.NodeBuffer(); - $buf.$amp$plus(new _root_.scala.xml.Text("hello, world")); + $buf.$amp$plus(new _root_.scala.xml.PCData("hello, world")); $buf }: _*)) } @@ -75,7 +78,8 @@ package <empty> { { new _root_.scala.xml.Elem(null, "foo", _root_.scala.xml.Null, $scope, false, ({ val $buf = new _root_.scala.xml.NodeBuffer(); - $buf.$amp$plus(new _root_.scala.xml.Text("hello, worldhello, world")); + $buf.$amp$plus(new _root_.scala.xml.PCData("hello, world")); + $buf.$amp$plus(new _root_.scala.xml.PCData("hello, world")); $buf }: _*)) } diff --git a/test/files/run/t3509.flags b/test/files/run/t3509.flags index 6933d924d3..9c59981aa9 100644 --- a/test/files/run/t3509.flags +++ b/test/files/run/t3509.flags @@ -1 +1 @@ --Yinline
\ No newline at end of file +-Yinline -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t3569.flags b/test/files/run/t3569.flags index 6933d924d3..9c59981aa9 100644 --- a/test/files/run/t3569.flags +++ b/test/files/run/t3569.flags @@ -1 +1 @@ --Yinline
\ No newline at end of file +-Yinline -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t4285.flags b/test/files/run/t4285.flags index eb4d19bcb9..99bd6c895d 100644 --- a/test/files/run/t4285.flags +++ b/test/files/run/t4285.flags @@ -1 +1 @@ --optimise
\ No newline at end of file +-optimise -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t4935.flags b/test/files/run/t4935.flags index 49d036a887..b9bb09167e 100644 --- a/test/files/run/t4935.flags +++ b/test/files/run/t4935.flags @@ -1 +1 @@ --optimize +-optimize -Ybackend:GenASM diff --git a/test/files/run/t5789.scala b/test/files/run/t5789.scala index 2903dada48..c8d95f2153 100644 --- a/test/files/run/t5789.scala +++ b/test/files/run/t5789.scala @@ -5,7 +5,7 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { - override def extraSettings = "-Yinline" + override def extraSettings = "-Yinline -Ybackend:GenASM" def code = """ val n = 2 () => n diff --git a/test/files/run/t6102.check b/test/files/run/t6102.check index 395864f57c..ce01362503 100644 --- a/test/files/run/t6102.check +++ b/test/files/run/t6102.check @@ -1,37 +1 @@ -[running phase parser on t6102.scala] -[running phase namer on t6102.scala] -[running phase packageobjects on t6102.scala] -[running phase typer on t6102.scala] -[running phase patmat on t6102.scala] -[running phase superaccessors on t6102.scala] -[running phase extmethods on t6102.scala] -[running phase pickler on t6102.scala] -[running phase refchecks on t6102.scala] -[running phase uncurry on t6102.scala] -[running phase tailcalls on t6102.scala] -[running phase specialize on t6102.scala] -[running phase explicitouter on t6102.scala] -[running phase erasure on t6102.scala] -[running phase posterasure on t6102.scala] -[running phase lazyvals on t6102.scala] -[running phase lambdalift on t6102.scala] -[running phase constructors on t6102.scala] -[running phase flatten on t6102.scala] -[running phase mixin on t6102.scala] -[running phase cleanup on t6102.scala] -[running phase delambdafy on t6102.scala] -[running phase icode on t6102.scala] -#partest -optimise -[running phase inliner on t6102.scala] -[running phase inlinehandlers on t6102.scala] -[running phase closelim on t6102.scala] -[running phase constopt on t6102.scala] -#partest -[running phase dce on t6102.scala] -#partest -Ybackend:GenASM -[running phase jvm on icode] -#partest !-Ybackend:GenASM -[running phase jvm on t6102.scala] -[running phase jvm on t6102.scala] -#partest hello diff --git a/test/files/run/t6102.flags b/test/files/run/t6102.flags index 726e2a997f..db58cf3b4c 100644 --- a/test/files/run/t6102.flags +++ b/test/files/run/t6102.flags @@ -1 +1 @@ --Ydead-code -Ydebug -Xfatal-warnings +-Yopt:l:classpath -Xfatal-warnings diff --git a/test/files/run/t6188.flags b/test/files/run/t6188.flags index 0ebca3e7af..b9bb09167e 100644 --- a/test/files/run/t6188.flags +++ b/test/files/run/t6188.flags @@ -1 +1 @@ - -optimize +-optimize -Ybackend:GenASM diff --git a/test/files/run/t7459b-optimize.flags b/test/files/run/t7459b-optimize.flags index 49d036a887..b9bb09167e 100644 --- a/test/files/run/t7459b-optimize.flags +++ b/test/files/run/t7459b-optimize.flags @@ -1 +1 @@ --optimize +-optimize -Ybackend:GenASM diff --git a/test/files/run/t7582.flags b/test/files/run/t7582.flags index 1182725e86..2cd4b38726 100644 --- a/test/files/run/t7582.flags +++ b/test/files/run/t7582.flags @@ -1 +1 @@ --optimize
\ No newline at end of file +-optimize -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t7582b.flags b/test/files/run/t7582b.flags index 1182725e86..2cd4b38726 100644 --- a/test/files/run/t7582b.flags +++ b/test/files/run/t7582b.flags @@ -1 +1 @@ --optimize
\ No newline at end of file +-optimize -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t8601.flags b/test/files/run/t8601.flags index 1182725e86..2cd4b38726 100644 --- a/test/files/run/t8601.flags +++ b/test/files/run/t8601.flags @@ -1 +1 @@ --optimize
\ No newline at end of file +-optimize -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t8601b.flags b/test/files/run/t8601b.flags index 1182725e86..2cd4b38726 100644 --- a/test/files/run/t8601b.flags +++ b/test/files/run/t8601b.flags @@ -1 +1 @@ --optimize
\ No newline at end of file +-optimize -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t8601c.flags b/test/files/run/t8601c.flags index 1182725e86..2cd4b38726 100644 --- a/test/files/run/t8601c.flags +++ b/test/files/run/t8601c.flags @@ -1 +1 @@ --optimize
\ No newline at end of file +-optimize -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t8601d.flags b/test/files/run/t8601d.flags index 1182725e86..2cd4b38726 100644 --- a/test/files/run/t8601d.flags +++ b/test/files/run/t8601d.flags @@ -1 +1 @@ --optimize
\ No newline at end of file +-optimize -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/run/t8601e.flags b/test/files/run/t8601e.flags index 49d036a887..b9bb09167e 100644 --- a/test/files/run/t8601e.flags +++ b/test/files/run/t8601e.flags @@ -1 +1 @@ --optimize +-optimize -Ybackend:GenASM diff --git a/test/files/run/t9003.flags b/test/files/run/t9003.flags index 49d036a887..b9bb09167e 100644 --- a/test/files/run/t9003.flags +++ b/test/files/run/t9003.flags @@ -1 +1 @@ --optimize +-optimize -Ybackend:GenASM diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala new file mode 100644 index 0000000000..f5f93fef5c --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala @@ -0,0 +1,55 @@ +package scala.tools.nsc.backend.jvm + +import org.junit.Assert._ +import org.junit.{Assert, Test} + +import scala.tools.asm.{Handle, Opcodes} +import scala.tools.asm.tree.InvokeDynamicInsnNode +import scala.tools.nsc.backend.jvm.AsmUtils._ +import scala.tools.nsc.backend.jvm.CodeGenTools._ +import scala.tools.testing.ClearAfterClass +import scala.collection.JavaConverters._ + +object IndyLambdaTest extends ClearAfterClass.Clearable { + var compiler = newCompiler(extraArgs = "-Ybackend:GenBCode") + + def clear(): Unit = { + compiler = null + } +} + +class IndyLambdaTest extends ClearAfterClass { + ClearAfterClass.stateToClear = IndyLambdaTest + val compiler = IndyLambdaTest.compiler + + @Test def boxingBridgeMethodUsedSelectively(): Unit = { + def implMethodDescriptorFor(code: String): String = { + val method = compileMethods(compiler)(s"""def f = $code """).find(_.name == "f").get + val x = method.instructions.iterator.asScala.toList + x.flatMap { + case insn : InvokeDynamicInsnNode => insn.bsmArgs.collect { case h : Handle => h.getDesc } + case _ => Nil + }.head + } + // unspecialized functions that have a primitive in parameter or return position + // give rise to a "boxing bridge" method (which has the suffix `$adapted`). + // This is because Scala's unboxing of null values gives zero, whereas Java's throw a NPE. + + // 1. Here we show that we are calling the boxing bridge (the lambda bodies here are compiled into + // methods of `(I)Ljava/lang/Object;` / `(I)Ljava/lang/Object;` respectively.) + assertEquals("(Ljava/lang/Object;)Ljava/lang/Object;", implMethodDescriptorFor("(x: Int) => new Object")) + assertEquals("(Ljava/lang/Object;)Ljava/lang/Object;", implMethodDescriptorFor("(x: Object) => 0")) + + // 2a. We don't need such adaptations for parameters or return values with types that differ + // from Object due to other generic substitution, LambdaMetafactory will downcast the arguments. + assertEquals("(Ljava/lang/String;)Ljava/lang/String;", implMethodDescriptorFor("(x: String) => x")) + + // 2b. Testing 2a. in combination with 1. + assertEquals("(Ljava/lang/Object;)Ljava/lang/String;", implMethodDescriptorFor("(x: Int) => \"\"")) + assertEquals("(Ljava/lang/String;)Ljava/lang/Object;", implMethodDescriptorFor("(x: String) => 0")) + + // 3. Specialized functions, don't need any of this as they implement a method like `apply$mcII$sp`, + // and the (un)boxing is handled in the base class in code emitted by scalac. + assertEquals("(I)I", implMethodDescriptorFor("(x: Int) => x")) + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala index 9af9ef54fc..a5b3faced8 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerTest.scala @@ -246,4 +246,46 @@ class ProdConsAnalyzerTest extends ClearAfterClass { testSingleInsn(a.consumersOfOutputsFrom(l2i), "IRETURN") testSingleInsn(a.producersForInputsOf(ret), "L2I") } + + @Test + def cyclicProdCons(): Unit = { + import Opcodes._ + val m = genMethod(descriptor = "(I)I")( + Label(1), + VarOp(ILOAD, 1), + IntOp(BIPUSH, 10), + Op(IADD), // consumer of the above ILOAD + + Op(ICONST_0), + Jump(IF_ICMPNE, Label(2)), + + VarOp(ILOAD, 1), + VarOp(ISTORE, 1), + Jump(GOTO, Label(1)), + + Label(2), + IntOp(BIPUSH, 9), + Op(IRETURN) + ) + m.maxLocals = 2 + m.maxStack = 2 + val a = new ProdConsAnalyzer(m, "C") + + val List(iadd) = findInstr(m, "IADD") + val firstLoad = iadd.getPrevious.getPrevious + assert(firstLoad.getOpcode == ILOAD) + val secondLoad = findInstr(m, "ISTORE").head.getPrevious + assert(secondLoad.getOpcode == ILOAD) + + testSingleInsn(a.producersForValueAt(iadd, 2), "ILOAD") + testSingleInsn(a.initialProducersForValueAt(iadd, 2), "ParameterProducer(1)") + testMultiInsns(a.producersForInputsOf(firstLoad), List("ParameterProducer", "ISTORE")) + testMultiInsns(a.producersForInputsOf(secondLoad), List("ParameterProducer", "ISTORE")) + + testSingleInsn(a.ultimateConsumersOfOutputsFrom(firstLoad), "IADD") + testSingleInsn(a.ultimateConsumersOfOutputsFrom(secondLoad), "IADD") + + testSingleInsn(a.consumersOfOutputsFrom(firstLoad), "IADD") + testSingleInsn(a.consumersOfOutputsFrom(secondLoad), "ISTORE") + } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala new file mode 100644 index 0000000000..69eed1f75d --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ClosureOptimizerTest.scala @@ -0,0 +1,74 @@ +package scala.tools.nsc +package backend.jvm +package opt + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import scala.collection.generic.Clearable +import scala.collection.mutable.ListBuffer +import scala.reflect.internal.util.BatchSourceFile +import scala.tools.asm.Opcodes._ +import org.junit.Assert._ + +import scala.tools.asm.tree._ +import scala.tools.asm.tree.analysis._ +import scala.tools.nsc.backend.jvm.opt.BytecodeUtils.AsmAnalyzer +import scala.tools.nsc.io._ +import scala.tools.nsc.reporters.StoreReporter +import scala.tools.testing.AssertUtil._ + +import CodeGenTools._ +import scala.tools.partest.ASMConverters +import ASMConverters._ +import AsmUtils._ + +import BackendReporting._ + +import scala.collection.convert.decorateAsScala._ +import scala.tools.testing.ClearAfterClass + +object ClosureOptimizerTest extends ClearAfterClass.Clearable { + var compiler = newCompiler(extraArgs = "-Yopt:l:classpath -Yopt-warnings") + def clear(): Unit = { compiler = null } +} + +@RunWith(classOf[JUnit4]) +class ClosureOptimizerTest extends ClearAfterClass { + ClearAfterClass.stateToClear = ClosureOptimizerTest + + val compiler = ClosureOptimizerTest.compiler + + @Test + def nothingTypedClosureBody(): Unit = { + val code = + """abstract class C { + | def isEmpty: Boolean + | @inline final def getOrElse[T >: C](f: => T) = if (isEmpty) f else this + | def t = getOrElse(throw new Error("")) + |} + """.stripMargin + + val List(c) = compileClasses(compiler)(code) + val t = c.methods.asScala.toList.find(_.name == "t").get + val List(bodyCall) = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Nothing$") + assert(bodyCall.getNext.getOpcode == ATHROW) + } + + @Test + def nullTypedClosureBody(): Unit = { + val code = + """abstract class C { + | def isEmpty: Boolean + | @inline final def getOrElse[T >: C](f: => T) = if (isEmpty) f else this + | def t = getOrElse(null) + |} + """.stripMargin + + val List(c) = compileClasses(compiler)(code) + val t = c.methods.asScala.toList.find(_.name == "t").get + val List(bodyCall) = findInstr(t, "INVOKESTATIC C.C$$$anonfun$1 ()Lscala/runtime/Null$") + assert(bodyCall.getNext.getOpcode == POP) + assert(bodyCall.getNext.getNext.getOpcode == ACONST_NULL) + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala index 57088bdd2f..5ccb940415 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineInfoTest.scala @@ -27,7 +27,9 @@ object InlineInfoTest extends ClearAfterClass.Clearable { } @RunWith(classOf[JUnit4]) -class InlineInfoTest { +class InlineInfoTest extends ClearAfterClass { + ClearAfterClass.stateToClear = InlineInfoTest + val compiler = InlineInfoTest.compiler def compile(code: String) = { 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 0309bb97cc..617eced560 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -991,4 +991,41 @@ class InlinerTest extends ClearAfterClass { assert(2 == t.collect({case Ldc(_, "hai!") => }).size) // twice the body of f assert(1 == t.collect({case Jump(IFNONNULL, _) => }).size) // one single null check } + + @Test + def inlineIndyLambda(): Unit = { + val code = + """object M { + | @inline def m(s: String) = { + | val f = (x: String) => x.trim + | f(s) + | } + |} + |class C { + | @inline final def m(s: String) = { + | val f = (x: String) => x.trim + | f(s) + | } + | def t1 = m("foo") + | def t2 = M.m("bar") + |} + """.stripMargin + + val List(c, _, _) = compile(code) + + val t1 = getSingleMethod(c, "t1") + assert(t1.instructions exists { + case _: InvokeDynamic => true + case _ => false + }) + // the indy call is inlined into t, and the closure elimination rewrites the closure invocation to the body method + assertInvoke(t1, "C", "C$$$anonfun$2") + + val t2 = getSingleMethod(c, "t2") + assert(t2.instructions exists { + case _: InvokeDynamic => true + case _ => false + }) + assertInvoke(t2, "M$", "M$$$anonfun$1") + } } diff --git a/test/junit/scala/tools/nsc/settings/SettingsTest.scala b/test/junit/scala/tools/nsc/settings/SettingsTest.scala index 1a2d695d68..a0015f4465 100644 --- a/test/junit/scala/tools/nsc/settings/SettingsTest.scala +++ b/test/junit/scala/tools/nsc/settings/SettingsTest.scala @@ -172,7 +172,7 @@ class SettingsTest { assert(residual.isEmpty) assertTrue(s.source.value == ScalaVersion(expected)) } - check(expected = "2.11.0") // default + check(expected = "2.12.0") // default check(expected = "2.11.0", "-Xsource:2.11") check(expected = "2.10", "-Xsource:2.10.0") check(expected = "2.12", "-Xsource:2.12") |