diff options
author | James Iry <jamesiry@gmail.com> | 2013-02-25 16:30:46 -0800 |
---|---|---|
committer | James Iry <jamesiry@gmail.com> | 2013-02-26 08:26:43 -0800 |
commit | 5f3cd8683d8b2e7429e73c2fa7199232ea7c46ca (patch) | |
tree | 276fcd18c0eb45639ff4c29cf3bffa23df0dada7 /test/files/jvm/t7181 | |
parent | 28a716190c5faf549ed302a1c19d9611c32d2010 (diff) | |
download | scala-5f3cd8683d8b2e7429e73c2fa7199232ea7c46ca.tar.gz scala-5f3cd8683d8b2e7429e73c2fa7199232ea7c46ca.tar.bz2 scala-5f3cd8683d8b2e7429e73c2fa7199232ea7c46ca.zip |
SI-7181 Eliminate unnecessary duplication of finally blocks
The main body of a try and each exception handler were getting a copy of
the finally block for the "normal" flow case (i.e. where they don't
throw an uncaught exception or use "return" to exit early). But that's
not necessary.
With this commit the try body and each exception handler can all jump
to the same copy of the finally block on a normal exit.
A byte code test is included to ensure we're getting fewer copies of
the finally block.
inline-ex-handlers.check is updated because the icode is a bit different
without the extra finally block copies.
Diffstat (limited to 'test/files/jvm/t7181')
-rw-r--r-- | test/files/jvm/t7181/Foo_1.scala | 26 | ||||
-rw-r--r-- | test/files/jvm/t7181/Test.scala | 24 |
2 files changed, 50 insertions, 0 deletions
diff --git a/test/files/jvm/t7181/Foo_1.scala b/test/files/jvm/t7181/Foo_1.scala new file mode 100644 index 0000000000..f9dfdd4442 --- /dev/null +++ b/test/files/jvm/t7181/Foo_1.scala @@ -0,0 +1,26 @@ +class Exception1 extends RuntimeException +class Exception2 extends RuntimeException + +class Foo_1 { + def foo(baz: Baz) { + try { + baz.bar + } catch { + case _: Exception1 => println("exception 1") + case _: Exception2 => println("exception 2") + } finally { + // this should be the only copy of the magic constant 3 + // making it easy to detect copies of this finally block + println(s"finally ${3}") + } + println(s"normal flow") + } +} + +trait Baz { + // does it throw? who knows? This way + // I can ensure that no optimization that honors + // separate compilation could ever + // change the exception handling structure + def bar: Unit +} diff --git a/test/files/jvm/t7181/Test.scala b/test/files/jvm/t7181/Test.scala new file mode 100644 index 0000000000..35dba436c1 --- /dev/null +++ b/test/files/jvm/t7181/Test.scala @@ -0,0 +1,24 @@ +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") + // there should be 2 copies of the finally block, each with the magic constant 3 + // one for the "normal" exit + // one for the uncaught exception exit + // prior to this PR there would have been 4 since each exception handler would also get a copy + val expected = 2 + val got = countMagicThrees(methodNode.instructions) + assert(got == expected, s"expected $expected but got $got magic threes") + } + + def countMagicThrees(insnList: InsnList): Int = { + def isMagicThree(node: asm.tree.AbstractInsnNode): Boolean = + (node.getOpcode == asm.Opcodes.ICONST_3) + insnList.iterator.asScala.count(isMagicThree) + } +} |