diff options
8 files changed, 118 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index c6569088d0..3002f34b58 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -571,7 +571,8 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable private def writeICode(): Unit = { val printer = new icodePrinter.TextPrinter(null, icodes.linearizer); icodes.classes.values.foreach((cls) => { - var file = getFile(cls.symbol, ".icode"); + val suffix = if (cls.symbol.hasFlag(Flags.MODULE)) "$.icode" else ".icode"; + var file = getFile(cls.symbol, suffix); // if (file.exists()) // file = new File(file.getParentFile(), file.getName() + "1"); try { diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 8f694ea764..5209fde3cb 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -53,6 +53,11 @@ trait BasicBlocks requires ICodes { instructionList } + def fromList(is: List[Instruction]): Unit = { + instrs = toInstructionArray(is); + closed = true; + } + // public: /** Compute an hashCode for the block */ @@ -133,7 +138,7 @@ trait BasicBlocks requires ICodes { newInstrs(j) = x; j = j + 1; } - if (i + 1 < instrs.length - 1) + if (i + 1 < instrs.length) System.arraycopy(instrs, i + 1, newInstrs, j, instrs.length - i - 1) instrs = newInstrs; } diff --git a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala index c22cfa26eb..172c90cf7a 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ExceptionHandlers.scala @@ -34,6 +34,8 @@ trait ExceptionHandlers requires ICodes { var covered: List[BasicBlock] = Nil; + def covers(b: BasicBlock): Boolean = covered.contains(b); + override def toString() = "exh_" + label + "(" + cls.simpleName + ")"; def this(other: ExceptionHandler) = { diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 4f79ae3f30..b130ddb9a7 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -364,8 +364,8 @@ abstract class GenICode extends SubComponent { case ValDef(_, _, _, rhs) => val sym = tree.symbol; - val local = new Local(sym, toTypeKind(sym.info), false); - ctx.method.addLocal(local); + var local = new Local(sym, toTypeKind(sym.info), false); + local = ctx.method.addLocal(local); if (rhs == EmptyTree) { if (settings.debug.value) @@ -461,7 +461,13 @@ abstract class GenICode extends SubComponent { if (finalizer != EmptyTree) handlers = Pair(NoSymbol, { ctx: Context => + val exception = new Local(ctx.method.symbol.newVariable(finalizer.pos, unit.fresh.newName("exc")) + .setInfo(definitions.ThrowableClass.tpe), + REFERENCE(definitions.ThrowableClass), false); + ctx.method.addLocal(exception); + ctx.bb.emit(STORE_LOCAL(exception)); val ctx1 = genLoad(finalizer, ctx, UNIT); + ctx1.bb.emit(LOAD_LOCAL(exception)); ctx1.bb.emit(THROW()); ctx1.bb.enterIgnoreMode; ctx1 @@ -471,7 +477,16 @@ abstract class GenICode extends SubComponent { bodyCtx => { generatedType = kind; //toTypeKind(block.tpe); val ctx1 = genLoad(block, bodyCtx, generatedType); - genLoad(finalizer, ctx1, UNIT) + if (kind != UNIT && mayCleanStack(finalizer)) { + val tmp = new Local(ctx.method.symbol.newVariable(tree.pos, unit.fresh.newName("tmp")).setInfo(tree.tpe), + kind, false); + ctx1.method.addLocal(tmp); + ctx1.bb.emit(STORE_LOCAL(tmp)); + val ctx2 = genLoad(finalizer, ctx1, UNIT) + ctx2.bb.emit(LOAD_LOCAL(tmp)); + ctx2 + } else + genLoad(finalizer, ctx1, UNIT) }, handlers) @@ -1286,6 +1301,18 @@ abstract class GenICode extends SubComponent { abort("Malformed parameter list: " + vparamss); } + /** Does this tree have a try-catch block? */ + def mayCleanStack(tree: Tree): Boolean = { + var hasTry = false; + new Traverser() { + override def traverse(t: Tree) = t match { + case Try(_, _, _) => hasTry = true; + case _ => super.traverse(t); + } + }.traverse(tree); + hasTry + } + /** * If the block consists of a single unconditional jump, prune * it by replacing the instructions in the predecessor to jump diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala index a49eb80eef..9863b54417 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala @@ -55,6 +55,28 @@ abstract class ICodes extends AnyRef printer.printMethod(m); } + /** Merge together blocks that have a single successor which has a + * single predecessor. Exception handlers are taken into account (they + * might force to break a block of straight line code like that). + * + * This method should be most effective after heavy inlining. + */ + def normalize(m: IMethod): Unit = if (m.code ne null) { + Console.println("Method " + m); + val mergeablePairs = + for (val b <- m.code.blocks.toList; + b.successors.length == 1; + val succ = b.successors.head; + succ.predecessors.length == 1; + succ.predecessors.head == b +/* !(m.exh.contains { (e: ExceptionHandler) => e.covers(b) && !e.covers(succ) }) */) { + Console.println("Block " + b + ".lastInstruction" + b.lastInstruction); + Console.println(" has successors: " + b.successors + " and succ has pred: " + succ.predecessors); + //yield Pair(b, succ) + } +// Console.println("Mergeable: " + mergeablePairs.mkString("", "\n", "")); + () + } def init = { } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 62ce35732e..20d948b6ab 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -173,12 +173,16 @@ trait Members requires ICodes { this } - def addLocal(l: Local): Unit = - if (!(locals contains l)) - locals = l :: locals; + def addLocal(l: Local): Local = + locals find (l.==) match { + case Some(loc) => loc + case None => + locals = l :: locals; + l + } def addLocals(ls: List[Local]): Unit = - ls foreach addLocal; + ls foreach { l => addLocal(l); }; def addParam(p: Local): Unit = if (!(params contains p)) { diff --git a/test/files/run/exceptions-2.check b/test/files/run/exceptions-2.check index 3ec0dfcc1c..e67f147506 100644 --- a/test/files/run/exceptions-2.check +++ b/test/files/run/exceptions-2.check @@ -17,11 +17,17 @@ method3: Exception occurred with stack trace: java.lang.NullPointerException at Test$.method3(exceptions-2.scala:108) - at Test$$anonfun$5.apply(exceptions-2.scala:151) - at Test$$anonfun$5.apply(exceptions-2.scala:151) - at Test$.execute(exceptions-2.scala:128) - at Test$.main(exceptions-2.scala:151) + at Test$$anonfun$5.apply(exceptions-2.scala:180) + at Test$$anonfun$5.apply(exceptions-2.scala:180) + at Test$.execute(exceptions-2.scala:157) + at Test$.main(exceptions-2.scala:180) at Test.main(exceptions-2.scala) +tryFinallyTry: +Silently ignore exception in finally +valInFinally: +Abc +tryAndValInFinally +Abc ================= NoExcep.method2: Hello, world diff --git a/test/files/run/exceptions-2.scala b/test/files/run/exceptions-2.scala index 2583542747..e006bc053d 100644 --- a/test/files/run/exceptions-2.scala +++ b/test/files/run/exceptions-2.scala @@ -1,7 +1,7 @@ /* * Try exception handling and finally blocks. * - * $Id: $ + * $Id$ */ @@ -124,6 +124,35 @@ object Test { Console.println(x); } + def tryFinallyTry: Unit = { + try { + () + } finally { + try { + error("a"); + } catch { + case _ => Console.println("Silently ignore exception in finally"); + } + } + } + + def valInFinally: Unit = + try { + } finally { + val fin = "Abc"; + Console.println(fin); + }; + + def tryAndValInFinally: Unit = + try { + } finally { + val fin = "Abc"; + try { + Console.println(fin); + } catch { case _ => () } + }; + + def execute(f: => Unit) = try { f; } catch { @@ -150,6 +179,14 @@ object Test { Console.println("method3:"); execute(method3); + Console.println("tryFinallyTry:"); + execute(tryFinallyTry); + + Console.println("valInFinally:"); + execute(valInFinally); + Console.println("tryAndValInFinally"); + execute(tryAndValInFinally); + Console.println("================="); Console.println("NoExcep.method2:"); |