diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2015-03-30 14:07:23 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2015-04-01 08:34:20 +0200 |
commit | fa110edd473ac5bbdb66fbd5a51fa2685c0dcf21 (patch) | |
tree | 9e927368e5e5e035819005022c74f012ca15e029 /test | |
parent | 6cf17ccd0101514a603a8c191438bdc2764838f9 (diff) | |
download | scala-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')
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala | 2 | ||||
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala | 14 |
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>") + } } |