summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@epfl.ch>2010-01-22 16:55:23 +0000
committerLukas Rytz <lukas.rytz@epfl.ch>2010-01-22 16:55:23 +0000
commitdaf9227e7323c31257fe34bb4f2d38c7c1abbff1 (patch)
treefa7f4e59e132cc707e3d767353247edf936e7a94 /src/compiler/scala/tools
parentac9fb6ad28b88ee4e7896c93d26c76e80bd3ece3 (diff)
downloadscala-daf9227e7323c31257fe34bb4f2d38c7c1abbff1.tar.gz
scala-daf9227e7323c31257fe34bb4f2d38c7c1abbff1.tar.bz2
scala-daf9227e7323c31257fe34bb4f2d38c7c1abbff1.zip
fix several issues in .net backend / type parsing.
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala112
1 files changed, 74 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
index d9261a3006..794f05ce17 100644
--- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
+++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
@@ -248,7 +248,7 @@ abstract class GenMSIL extends SubComponent {
assemblyName.Name = assemName
massembly = AssemblyBuilderFactory.DefineDynamicAssembly(assemblyName)
- moduleName = assemName + (if (entryPoint == null) ".dll" else ".exe")
+ moduleName = assemName // + (if (entryPoint == null) ".dll" else ".exe")
// filename here: .dll or .exe (in both parameters), second: give absolute-path
mmodule = massembly.DefineDynamicModule(moduleName,
new File(outDir, moduleName).getAbsolutePath())
@@ -613,6 +613,7 @@ abstract class GenMSIL extends SubComponent {
beginExBlock.clear()
beginCatchBlock.clear()
endExBlock.clear()
+ endFinallyLabels.clear()
}
def genBlocks(blocks: List[BasicBlock], previous: BasicBlock = null) {
@@ -630,10 +631,13 @@ abstract class GenMSIL extends SubComponent {
val beginCatchBlock = new HashMap[BasicBlock, ExceptionHandler]()
val endExBlock = new HashMap[BasicBlock, List[ExceptionHandler]]()
- // when emitting the code (genBlock), the number of currently active try / catch
- // blocks. When seeing a `RETURN' inside a try / catch, we need to replace
- // it with Leave
- var currentHandlers = 0
+ /** When emitting the code (genBlock), the number of currently active try / catch
+ * blocks. When seeing a `RETURN' inside a try / catch, we need to
+ * - store the result in a local (if it's not UNIT)
+ * - emit `Leave handlerReturnLabel` instead of the Return
+ * - emit code at the end: load the local and return its value
+ */
+ var currentHandlers = new Stack[ExceptionHandler]
// The IMethod the Local/Label/Kind below belong to
var handlerReturnMethod: IMethod = _
// Stores the result when returning inside an exception block
@@ -655,6 +659,13 @@ abstract class GenMSIL extends SubComponent {
(handlerReturnLocal, handlerReturnLabel)
}
+ /** For try/catch nested inside a finally, we can't use `Leave OutsideFinally`, the
+ * Leave target has to be inside the finally (and it has to be the `endfinally` instruction).
+ * So for every finalizer, we have a label which marks the place of the `endfinally`,
+ * nested try/catch blocks will leave there.
+ */
+ val endFinallyLabels = new HashMap[ExceptionHandler, Label]()
+
/** Computes which blocks are the beginning / end of a try or catch block */
private def computeExceptionMaps(blocks: List[BasicBlock], m: IMethod): List[BasicBlock] = {
val visitedBlocks = new HashSet[BasicBlock]()
@@ -826,11 +837,14 @@ abstract class GenMSIL extends SubComponent {
var lastLineNr: Int = 0
+
// EndExceptionBlock must happen before MarkLabel because it adds the
// Leave instruction. Otherwise, labels(block) points to the Leave
// (inside the catch) instead of the instruction afterwards.
for (handlers <- endExBlock.get(block); exh <- handlers) {
- currentHandlers -= 1
+ currentHandlers.pop()
+ for (l <- endFinallyLabels.get(exh))
+ mcode.MarkLabel(l)
mcode.EndExceptionBlock()
}
@@ -848,7 +862,7 @@ abstract class GenMSIL extends SubComponent {
}
}
for (handlers <- beginExBlock.get(block); exh <- handlers) {
- currentHandlers += 1
+ currentHandlers.push(exh)
mcode.BeginExceptionBlock()
}
@@ -904,9 +918,7 @@ abstract class GenMSIL extends SubComponent {
case FLOAT => mcode.Emit(OpCodes.Ldelem_R4)
case DOUBLE => mcode.Emit(OpCodes.Ldelem_R8)
case REFERENCE(cls) => mcode.Emit(OpCodes.Ldelem_Ref)
-
- // case ARRAY(elem) is not possible, for Array[Array[Int]], the
- // load will be case REFERENCE(java.lang.Object)
+ case ARRAY(elem) => mcode.Emit(OpCodes.Ldelem_Ref)
// case UNIT is not possible: an Array[Unit] will be an
// Array[scala.runtime.BoxedUnit] (-> case REFERENCE)
@@ -951,8 +963,9 @@ abstract class GenMSIL extends SubComponent {
case FLOAT => mcode.Emit(OpCodes.Stelem_R4)
case DOUBLE => mcode.Emit(OpCodes.Stelem_R8)
case REFERENCE(cls) => mcode.Emit(OpCodes.Stelem_Ref)
+ case ARRAY(elem) => mcode.Emit(OpCodes.Stelem_Ref) // @TODO: test this! (occurs when calling a Array[Object]* vararg param method)
- // case UNIT / ARRRAY are not possible (see comment at LOAD_ARRAY_ITEM)
+ // case UNIT not possible (see comment at LOAD_ARRAY_ITEM)
}
case STORE_LOCAL(local) =>
@@ -1183,11 +1196,12 @@ abstract class GenMSIL extends SubComponent {
mcode.Emit(OpCodes.Br, defaultTarget)
case JUMP(whereto) =>
- val (leaveHandler, leaveFinally) = leavesHandler(block, whereto, method.exh)
+ val (leaveHandler, leaveFinally, lfTarget) = leavesHandler(block, whereto)
if (leaveHandler) {
- if (leaveFinally)
- mcode.Emit(OpCodes.Endfinally)
- else
+ if (leaveFinally) {
+ if (lfTarget.isDefined) mcode.Emit(OpCodes.Leave, lfTarget.get)
+ else mcode.Emit(OpCodes.Endfinally)
+ } else
mcode.Emit(OpCodes.Leave, labels(whereto))
} else if (next != whereto)
mcode.Emit(OpCodes.Br, labels(whereto))
@@ -1198,13 +1212,13 @@ abstract class GenMSIL extends SubComponent {
// kind is TypeKind
val isFloat = kind == FLOAT || kind == DOUBLE
val emit = (c: TestOp, l: Label) => emitBr(c, l, isFloat)
- emitCondBr(block, cond, success, failure, next, method.exh, emit)
+ emitCondBr(block, cond, success, failure, next, emit)
case CZJUMP(success, failure, cond, kind) =>
- emitCondBr(block, cond, success, failure, next, method.exh, emitBrBool(_, _))
+ emitCondBr(block, cond, success, failure, next, emitBrBool(_, _))
case RETURN(kind) =>
- if (currentHandlers == 0)
+ if (currentHandlers.isEmpty)
mcode.Emit(OpCodes.Ret)
else {
val (local, label) = returnFromHandler(kind)
@@ -1362,24 +1376,44 @@ abstract class GenMSIL extends SubComponent {
////////////////////// branches ///////////////////////
- def leavesHandler(from: BasicBlock, to: BasicBlock, handlers: List[ExceptionHandler]) =
- if (currentHandlers == 0) (false, false)
+ /** Returns a Triple (Boolean, Boolean, Option[Label])
+ * - wether the jump leaves some exception block (try / catch / finally)
+ * - wether the it leaves a finally handler (finally block, but not it's try / catch)
+ * - a label where to jump for leaving the finally handler
+ * . None to leave directly using `endfinally`
+ * . Some(label) to emit `leave label` (for try / catch inside a finally handler)
+ */
+ def leavesHandler(from: BasicBlock, to: BasicBlock): (Boolean, Boolean, Option[Label]) =
+ if (currentHandlers.isEmpty) (false, false, None)
else {
- val h = handlers.find(e => {
- e.covers(from) != e.covers(to) ||
- e.blocks.contains(from) != e.blocks.contains(to)
- })
- if (h.isDefined) {
- val leavesFinalizerHandler =
- h.get.cls == NoSymbol && h.get.blocks.contains(from) != h.get.blocks.contains(to)
- (true, leavesFinalizerHandler)
- } else (false, false)
+ val h = currentHandlers.head
+ val leaveHead = { h.covers(from) != h.covers(to) ||
+ h.blocks.contains(from) != h.blocks.contains(to) }
+ if (leaveHead) {
+ // we leave the innermost exception block.
+ // find out if we also leave som e `finally` handler
+ currentHandlers.find(e => {
+ e.cls == NoSymbol && e.blocks.contains(from) != e.blocks.contains(to)
+ }) match {
+ case Some(finallyHandler) =>
+ if (h == finallyHandler) {
+ // the finally handler is the innermost, so we can emit `endfinally` directly
+ (true, true, None)
+ } else {
+ // we need to `Leave` to the `endfinally` of the next outer finally handler
+ val l = endFinallyLabels.getOrElseUpdate(finallyHandler, mcode.DefineLabel())
+ (true, true, Some(l))
+ }
+ case None =>
+ (true, false, None)
+ }
+ } else (false, false, None)
}
def emitCondBr(block: BasicBlock, cond: TestOp, success: BasicBlock, failure: BasicBlock,
- next: BasicBlock, handlers: List[ExceptionHandler], emitBrFun: (TestOp, Label) => Unit) {
- val (sLeaveHandler, sLeaveFinally) = leavesHandler(block, success, handlers)
- val (fLeaveHandler, fLeaveFinally) = leavesHandler(block, failure, handlers)
+ next: BasicBlock, emitBrFun: (TestOp, Label) => Unit) {
+ val (sLeaveHandler, sLeaveFinally, slfTarget) = leavesHandler(block, success)
+ val (fLeaveHandler, fLeaveFinally, flfTarget) = leavesHandler(block, failure)
if (sLeaveHandler || fLeaveHandler) {
val sLabelOpt = if (sLeaveHandler) {
@@ -1392,18 +1426,20 @@ abstract class GenMSIL extends SubComponent {
}
if (fLeaveHandler) {
- if (fLeaveFinally)
- mcode.Emit(OpCodes.Endfinally)
- else
+ if (fLeaveFinally) {
+ if (flfTarget.isDefined) mcode.Emit(OpCodes.Leave, flfTarget.get)
+ else mcode.Emit(OpCodes.Endfinally)
+ } else
mcode.Emit(OpCodes.Leave, labels(failure))
} else
mcode.Emit(OpCodes.Br, labels(failure))
sLabelOpt.map(l => {
mcode.MarkLabel(l)
- if (sLeaveFinally)
- mcode.Emit(OpCodes.Endfinally)
- else
+ if (sLeaveFinally) {
+ if (slfTarget.isDefined) mcode.Emit(OpCodes.Leave, slfTarget.get)
+ else mcode.Emit(OpCodes.Endfinally)
+ } else
mcode.Emit(OpCodes.Leave, labels(success))
})
} else {