summaryrefslogtreecommitdiff
path: root/test/junit
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-03-30 14:07:23 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-04-01 08:34:20 +0200
commitfa110edd473ac5bbdb66fbd5a51fa2685c0dcf21 (patch)
tree9e927368e5e5e035819005022c74f012ca15e029 /test/junit
parent6cf17ccd0101514a603a8c191438bdc2764838f9 (diff)
downloadscala-fa110edd473ac5bbdb66fbd5a51fa2685c0dcf21.tar.gz
scala-fa110edd473ac5bbdb66fbd5a51fa2685c0dcf21.tar.bz2
scala-fa110edd473ac5bbdb66fbd5a51fa2685c0dcf21.zip
Eliminate unreachable code before inlining a method
Running an ASM analyzer returns null frames for unreachable instructions in the analyzed method. The inliner (and other components of the optimizer) require unreachable code to be eliminated to avoid null frames. Before this change, unreachable code was eliminated before building the call graph, but not again before inlining: the inliner assumed that methods in the call graph have no unreachable code. This invariant can break when inlining a method. Example: def f = throw e def g = f; println() When building the call graph, both f and g contain no unreachable code. After inlining f, the println() call becomes unreachable. This breaks the inliner's assumption if it tries to inline a call to g. This change intruduces a cache to remember methods that have no unreachable code. This allows invoking DCE every time no dead code is required, and bail out fast. This also simplifies following the control flow in the optimizer (call DCE whenever no dead code is required).
Diffstat (limited to 'test/junit')
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala14
2 files changed, 15 insertions, 1 deletions
diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
index 5d5215d887..3ba3caa5e3 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
@@ -160,7 +160,7 @@ object CodeGenTools {
val localOpt = {
val settings = new MutableSettings(msg => throw new IllegalArgumentException(msg))
settings.processArguments(List("-Yopt:l:method"), processAll = true)
- new LocalOpt(settings)
+ new LocalOpt(settings, collection.mutable.Set())
}
import scala.language.implicitConversions
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 39fb28570e..9d23d92c2a 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -950,4 +950,18 @@ class InlinerTest extends ClearAfterClass {
assertInvoke(getSingleMethod(t, "t3"), "B", "<init>")
assertInvoke(getSingleMethod(t, "t4"), "B", "<init>")
}
+
+ @Test
+ def inlineMayRenderCodeDead(): Unit = {
+ val code =
+ """class C {
+ | @inline final def f: String = throw new Error("")
+ | @inline final def g: String = "a" + f + "b" // after inlining f, need to run DCE, because the rest of g becomes dead.
+ | def t = g // the inliner requires no dead code when inlining g (uses an Analyzer).
+ |}
+ """.stripMargin
+
+ val List(c) = compile(code)
+ assertInvoke(getSingleMethod(c, "t"), "java/lang/Error", "<init>")
+ }
}