diff options
author | Iulian Dragos <jaguarul@gmail.com> | 2006-09-25 15:37:45 +0000 |
---|---|---|
committer | Iulian Dragos <jaguarul@gmail.com> | 2006-09-25 15:37:45 +0000 |
commit | ce2affc166c29d34616bcfef53c8aaa9a95749a9 (patch) | |
tree | 2b678738782fa64ca7b00a519bd3586b3ddf6327 | |
parent | d12123f57d8dc08c6d55c7c11735b27b56b1182a (diff) | |
download | scala-ce2affc166c29d34616bcfef53c8aaa9a95749a9.tar.gz scala-ce2affc166c29d34616bcfef53c8aaa9a95749a9.tar.bz2 scala-ce2affc166c29d34616bcfef53c8aaa9a95749a9.zip |
Fixed bug regarding 'return's inside try-finall...
Fixed bug regarding 'return's inside try-finally blocks
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 60 | ||||
-rw-r--r-- | test/files/run/exceptions-2.check | 8 | ||||
-rw-r--r-- | test/files/run/exceptions-2.scala | 32 |
3 files changed, 85 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 61f6de9260..9a6d31895b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -454,11 +454,15 @@ abstract class GenICode extends SubComponent { case Return(expr) => val returnedKind = toTypeKind(expr.tpe) - val ctx1 = genLoad(expr, ctx, returnedKind) - for (val m <- ctx1.monitors) { - ctx1.bb.emit(LOAD_LOCAL(m)) - ctx1.bb.emit(MONITOR_EXIT()) + var ctx1 = genLoad(expr, ctx, returnedKind) + for (val op <- ctx1.cleanups) op match { + case MonitorRelease(m) => + ctx1.bb.emit(LOAD_LOCAL(m)) + ctx1.bb.emit(MONITOR_EXIT()) + case Finalizer(f) => + ctx1 = genLoad(f, ctx1, UNIT) } + ctx1.bb.emit(RETURN(returnedKind), tree.pos) ctx1.bb.enterIgnoreMode generatedType = expectedType @@ -525,7 +529,8 @@ abstract class GenICode extends SubComponent { } else genLoad(finalizer, ctx1, UNIT) }, - handlers) + handlers, + finalizer) case Throw(expr) => val ctx1 = genLoad(expr, ctx, THROWABLE) @@ -717,7 +722,7 @@ abstract class GenICode extends SubComponent { exhCtx.bb.emit(THROW()) exhCtx.bb.enterIgnoreMode exhCtx - }))); + })), EmptyTree); if (settings.debug.value) log("synchronized block end with block " + ctx1.bb + " closed=" + ctx1.bb.isClosed); @@ -1497,6 +1502,14 @@ abstract class GenICode extends SubComponent { /////////////////////// Context //////////////////////////////// + abstract class Cleanup; + case class MonitorRelease(m: Local) extends Cleanup { + override def equals(other: Any) = m == other; + } + case class Finalizer(f: Tree) extends Cleanup { + override def equals(other: Any) = f == other; + } + /** * The Context class keeps information relative to the current state @@ -1525,8 +1538,8 @@ abstract class GenICode extends SubComponent { /** current exception handlers */ var handlers: List[ExceptionHandler] = Nil - /** The current monitors, if inside synchronized blocks. */ - var monitors: List[Local] = Nil + /** The current monitors or finalizers, to be cleaned up upon `return'. */ + var cleanups: List[Cleanup] = Nil /** The current exception handler, when we generate code for one. */ var currentExceptionHandler: Option[ExceptionHandler] = None @@ -1541,7 +1554,7 @@ abstract class GenICode extends SubComponent { buf.append("\tbb: ").append(bb).append('\n') buf.append("\tlabels: ").append(labels).append('\n') buf.append("\texception handlers: ").append(handlers).append('\n') - buf.append("\tmonitors: ").append(monitors).append('\n') + buf.append("\tcleanups: ").append(cleanups).append('\n') buf.toString() } @@ -1555,7 +1568,7 @@ abstract class GenICode extends SubComponent { this.defdef = other.defdef this.handlers = other.handlers this.handlerCount = other.handlerCount - this.monitors = other.monitors + this.cleanups = other.cleanups this.currentExceptionHandler = other.currentExceptionHandler } @@ -1580,14 +1593,26 @@ abstract class GenICode extends SubComponent { } def enterSynchronized(monitor: Local): this.type = { - monitors = monitor :: monitors + cleanups = MonitorRelease(monitor) :: cleanups this } def exitSynchronized(monitor: Local): this.type = { - assert(monitors.head == monitor, - "Bad nesting of monitors: " + monitors + " trying to exit from: " + monitor) - monitors = monitors.tail + assert(cleanups.head == monitor, + "Bad nesting of cleanup operations: " + cleanups + " trying to exit from monitor: " + monitor) + cleanups = cleanups.tail + this + } + + def addFinalizer(f: Tree): this.type = { + cleanups = Finalizer(f) :: cleanups; + this + } + + def removeFinalizer(f: Tree): this.type = { + assert(cleanups.head == f, + "Illegal nesting of cleanup operations: " + cleanups + " while exiting finalizer" + f); + cleanups = cleanups.tail this } @@ -1670,7 +1695,8 @@ abstract class GenICode extends SubComponent { * } ))</code> */ def Try(body: Context => Context, - handlers: List[Pair[Symbol, (Context => Context)]]) = { + handlers: List[Pair[Symbol, (Context => Context)]], + finalizer: Tree) = { val outerCtx = this.dup val afterCtx = outerCtx.newBlock @@ -1682,6 +1708,8 @@ abstract class GenICode extends SubComponent { exh } val bodyCtx = this.newBlock + if (finalizer != EmptyTree) + bodyCtx.addFinalizer(finalizer) val finalCtx = body(bodyCtx) @@ -1689,6 +1717,8 @@ abstract class GenICode extends SubComponent { outerCtx.bb.close exhs.reverse foreach finalCtx.removeHandler + if (finalizer != EmptyTree) + finalCtx.removeFinalizer(finalizer) finalCtx.bb.emit(JUMP(afterCtx.bb)) finalCtx.bb.close diff --git a/test/files/run/exceptions-2.check b/test/files/run/exceptions-2.check index bb9c3dcd92..0cfb9a6a8c 100644 --- a/test/files/run/exceptions-2.check +++ b/test/files/run/exceptions-2.check @@ -28,3 +28,11 @@ NoExcep.method3: method3 NoExcep.method4: .. +Return inside body: +Normal execution... +inner finally +Outer finally +Return inside synchronized body: +Synchronized normal execution... +inner finally +Outer finally diff --git a/test/files/run/exceptions-2.scala b/test/files/run/exceptions-2.scala index bc374a1c49..7391789937 100644 --- a/test/files/run/exceptions-2.scala +++ b/test/files/run/exceptions-2.scala @@ -151,6 +151,32 @@ object Test { } catch { case _ => () } }; + def returnInBody: Unit = try { + try { + Console.println("Normal execution..."); + return + Console.println("non reachable code"); + } finally { + Console.println("inner finally"); + } + } finally { + Console.println("Outer finally"); + } + + def returnInBodySynch: Unit = try { + synchronized { + try { + Console.println("Synchronized normal execution..."); + return + Console.println("non reachable code"); + } finally { + Console.println("inner finally"); + } + } + } finally { + Console.println("Outer finally"); + } + def execute(f: => Unit) = try { f; @@ -196,5 +222,11 @@ object Test { Console.println("NoExcep.method4:"); execute(NoExcep.method4); + + Console.println("Return inside body:"); + execute(returnInBody); + + Console.println("Return inside synchronized body:"); + execute(returnInBodySynch); } } |