From 401baad565218da34558318ebd1f65edb31b39c8 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 27 Jul 2011 00:52:47 +0000 Subject: Fix/workaround for inliner bug uncovered by fin... Fix/workaround for inliner bug uncovered by finalizing Option methods. Something in the backend is leaving open but empty blocks in the worklist. Rather than freaking out at the merest mention of an empty block, I quietly remove the empty ones. A proper fix will involve not leaving empty blocks lying around but we're on a schedule here people. Review by dragos. --- .../scala/tools/nsc/backend/icode/ICodes.scala | 19 +++++++++++--- .../tools/nsc/backend/icode/Linearizers.scala | 7 ++++- test/files/pos/bug4840.flags | 1 + test/files/pos/bug4840.scala | 13 ++++++++++ test/files/run/run-bug4840.check | 2 ++ test/files/run/run-bug4840.flags | 1 + test/files/run/run-bug4840.scala | 30 ++++++++++++++++++++++ 7 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 test/files/pos/bug4840.flags create mode 100644 test/files/pos/bug4840.scala create mode 100644 test/files/run/run-bug4840.check create mode 100644 test/files/run/run-bug4840.flags create mode 100644 test/files/run/run-bug4840.scala diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala index 9553d5cf9b..06c3ee2a9e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala @@ -35,7 +35,7 @@ abstract class ICodes extends AnyRef with Repository { val global: Global - import global.{ definitions, settings, perRunCaches } + import global.{ log, definitions, settings, perRunCaches } /** The ICode representation of classes */ val classes = perRunCaches.newMap[global.Symbol, IClass]() @@ -72,11 +72,22 @@ abstract class ICodes extends AnyRef } def checkValid(m: IMethod) { - for (b <- m.code.blocks) - if (!b.closed) { + // always dicey to iterate over mutable structures + val bs = m.code.blocks.toList + + for (b <- bs ; if !b.closed) { + // Something is leaving open/empty blocks around (see SI-4840) so + // let's not kill the deal unless it's nonempty. + if (b.isEmpty) { + log("!!! Found open but empty block while inlining " + m + ": removing from block list.") + m.code removeBlock b + } + else { + Console.println("Fatal bug in inliner: found open block when inlining " + m) m.dump - global.abort("Open block: " + b + " " + b.flagsString) + global.abort("Open block was: " + b + " " + b.flagsString) } + } } object liveness extends Liveness { diff --git a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala index 9f22a6de90..8130c99978 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala @@ -14,6 +14,8 @@ import mutable.ListBuffer trait Linearizers { self: ICodes => + + import global.debuglog import opcodes._ abstract class Linearizer { @@ -178,11 +180,14 @@ trait Linearizers { * Prepend b to the list, if not already scheduled. * @return Returns true if the block was added. */ - def add(b: BasicBlock) = + def add(b: BasicBlock) = { + debuglog("Linearizer adding block " + b.label) + if (!added(b.label)) { added += b.label blocks = b :: blocks; } + } } /** A 'dump' of the blocks in this method, which does not diff --git a/test/files/pos/bug4840.flags b/test/files/pos/bug4840.flags new file mode 100644 index 0000000000..eb4d19bcb9 --- /dev/null +++ b/test/files/pos/bug4840.flags @@ -0,0 +1 @@ +-optimise \ No newline at end of file diff --git a/test/files/pos/bug4840.scala b/test/files/pos/bug4840.scala new file mode 100644 index 0000000000..bf44f71d7a --- /dev/null +++ b/test/files/pos/bug4840.scala @@ -0,0 +1,13 @@ +class Crashy { + def g(): Option[Any] = None + + def crashy() = { + for (_ <- g()) { + (null: Any) match { + case Some(_) => 5 + case None => sys.error("") + } + } + } +} + diff --git a/test/files/run/run-bug4840.check b/test/files/run/run-bug4840.check new file mode 100644 index 0000000000..cdfc1f911f --- /dev/null +++ b/test/files/run/run-bug4840.check @@ -0,0 +1,2 @@ +Some(5) +Some(Some(Some(5))) diff --git a/test/files/run/run-bug4840.flags b/test/files/run/run-bug4840.flags new file mode 100644 index 0000000000..eb4d19bcb9 --- /dev/null +++ b/test/files/run/run-bug4840.flags @@ -0,0 +1 @@ +-optimise \ No newline at end of file diff --git a/test/files/run/run-bug4840.scala b/test/files/run/run-bug4840.scala new file mode 100644 index 0000000000..dda280fd17 --- /dev/null +++ b/test/files/run/run-bug4840.scala @@ -0,0 +1,30 @@ +object Test { + def g(x: Boolean): Option[String] = if (x) Some("booya") else None + + def f1() = { + for (x <- g(true)) yield { + g(false) match { + case Some(_) => sys.error("") + case None => 5 + } + } + } + + def f2() = { + for (x <- g(true) ; y <- g(true) ; z <- g(true)) yield { + for (x <- g(true) ; y <- g(true) ; z <- g(true)) yield { + g(true) map { _ => + (null: Any) match { + case Some(x: Int) => x + case _ => 5 + } + } + } + } + } + + def main(args: Array[String]): Unit = { + println(f1()) + println(f2()) + } +} -- cgit v1.2.3