summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshack <shack@epfl.ch>2008-01-22 11:26:46 +0000
committershack <shack@epfl.ch>2008-01-22 11:26:46 +0000
commit3e1f51aad2c854eae6fd4b6aa60d0382a20d3d20 (patch)
treea541ab986869c5e3d56b132a7f7359fa11b89a7f
parente8558ed48a00979a261e0fec21731e555e835f43 (diff)
downloadscala-3e1f51aad2c854eae6fd4b6aa60d0382a20d3d20.tar.gz
scala-3e1f51aad2c854eae6fd4b6aa60d0382a20d3d20.tar.bz2
scala-3e1f51aad2c854eae6fd4b6aa60d0382a20d3d20.zip
Fixed #311 and #312
Disable tail call recursion for certain cases when compiling for MSIL to adhere to CIL conventions
-rw-r--r--src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala32
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala11
3 files changed, 43 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
index 362a4f0347..7fed4c77c6 100644
--- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
+++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
@@ -910,7 +910,13 @@ abstract class GenMSIL extends SubComponent {
**/
def adaptBlocks(blocks: List[BasicBlock], exh: ExceptionHandler): (List[BasicBlock], Option[BasicBlock]) = {
def outsideTargets(block: BasicBlock, blocks: List[BasicBlock]) = {
- block.successors.filter(scc => !blocks.contains(scc))
+ /* The catch block of the ExceptionHandler is always a successor of any block inside the try
+ * (see successors method in BasicBlocks.scala)
+ * Thus, this successor does not correspond to a jump outside the exception handler
+ * and has to be ignored when computing the list of blocks leaving the exception handler. */
+ val res = block.successors.filter(scc => !blocks.contains(scc) && scc != exh.startBlock)
+ if (settings.debug.value) log("outside of " + block + " = " + res + " succ " + block.successors)
+ res
}
// get leaving blocks and their outside targets
def leavingBlocks(blocks: List[BasicBlock]): List[(BasicBlock, List[BasicBlock])] = {
@@ -952,11 +958,13 @@ abstract class GenMSIL extends SubComponent {
val lBlock = p._1
val target = p._2(0) // the elemets of p._2 are all the same, checked before
replaceJump(lBlock, target, jumpOutBlock)
+ if (settings.debug.value) log("replacing " + lBlock + " target " + target + " jump out " + jumpOutBlock)
})
(blocks ::: List(jumpOutBlock), Some(jumpOutBlock))
}
val leaving = leavingBlocks(blocks)
+ if (settings.debug.value) log("leaving " + leaving)
if (leaving.length == 0)
(blocks, None)
else if (leaving.length == 1) {
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index b0140dae73..ea6e66344b 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -504,12 +504,15 @@ abstract class CleanUp extends Transform {
/* end of dynamic call transformer. */
- case Template(parents, self, body) if !forMSIL =>
+ case Template(parents, self, body) =>
localTyper = typer.atOwner(tree, currentOwner)
- classConstantMeth.clear
- newDefs.clear
- val body1 = transformTrees(body)
- copy.Template(tree, parents, self, newDefs.toList ::: body1)
+ if (!forMSIL) {
+ classConstantMeth.clear
+ newDefs.clear
+ val body1 = transformTrees(body)
+ copy.Template(tree, parents, self, newDefs.toList ::: body1)
+ }
+ else super.transform(tree)
case Literal(c) if (c.tag == ClassTag) && !forMSIL=>
val tpe = c.typeValue
@@ -524,6 +527,25 @@ abstract class CleanUp extends Transform {
else tree
}
}
+
+ /* MSIL requires that the stack is empty at the end of a try-block.
+ * Hence, we here rewrite all try blocks with a result != {Unit, All} such that they
+ * store their result in a local variable. The catch blocks are adjusted as well.
+ * The try tree is subsituted by a block whose result expression is read of that variable. */
+ case theTry @ Try(block, catches, finalizer)
+ if theTry.tpe.typeSymbol != definitions.UnitClass && theTry.tpe.typeSymbol != definitions.AllClass =>
+ val tpe = theTry.tpe.widen
+ val tempVar = currentOwner.newValue(theTry.pos, unit.fresh.newName("exceptionResult"))
+ .setInfo(tpe).setFlag(Flags.MUTABLE)
+
+ val newBlock = Block(Nil, Assign(Ident(tempVar), transform(block)))
+ val newCatches = for (CaseDef(pattern, guard, body) <- catches) yield {
+ CaseDef(pattern, transform(guard), Block(Nil, Assign(Ident(tempVar), transform(body))))
+ }
+ val newTry = Try(newBlock, newCatches, finalizer)
+ val res = Block(List(ValDef(tempVar, EmptyTree), newTry), Ident(tempVar))
+ localTyper.typed(res)
+
case _ =>
super.transform(tree)
}
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index b2e7fb079e..20d7b97320 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -248,16 +248,17 @@ abstract class TailCalls extends Transform
case Typed(expr, tpt) => super.transform(tree)
case Apply(tapply @ TypeApply(fun, targs), vargs) =>
+ lazy val defaultTree = copy.Apply(tree, tapply, transformTrees(vargs, mkContext(ctx, false)))
if ( ctx.currentMethod.isFinal &&
ctx.tailPos &&
isSameTypes(ctx.tparams, targs map (_.tpe.typeSymbol)) &&
isRecursiveCall(fun)) {
fun match {
- case Select(receiver, _) => rewriteTailCall(fun, receiver :: transformTrees(vargs, mkContext(ctx, false)))
+ case Select(receiver, _) => if (!forMSIL) rewriteTailCall(fun, receiver :: transformTrees(vargs, mkContext(ctx, false))) else defaultTree
case _ => rewriteTailCall(fun, This(currentClass) :: transformTrees(vargs, mkContext(ctx, false)))
}
} else
- copy.Apply(tree, tapply, transformTrees(vargs, mkContext(ctx, false)))
+ defaultTree
case TypeApply(fun, args) =>
super.transform(tree)
@@ -267,15 +268,17 @@ abstract class TailCalls extends Transform
copy.Apply(tree, fun, transformTrees(args))
case Apply(fun, args) =>
+ lazy val defaultTree = copy.Apply(tree, fun, transformTrees(args, mkContext(ctx, false)))
if (ctx.currentMethod.isFinal &&
ctx.tailPos &&
isRecursiveCall(fun)) {
fun match {
- case Select(receiver, _) => rewriteTailCall(fun, receiver :: transformTrees(args, mkContext(ctx, false)))
+ case Select(receiver, _) => if (!forMSIL) rewriteTailCall(fun, receiver :: transformTrees(args, mkContext(ctx, false))) else defaultTree
case _ => rewriteTailCall(fun, This(currentClass) :: transformTrees(args, mkContext(ctx, false)))
}
} else
- copy.Apply(tree, fun, transformTrees(args, mkContext(ctx, false)))
+ defaultTree
+
case Super(qual, mix) =>
tree