summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2005-12-02 17:16:52 +0000
committerIulian Dragos <jaguarul@gmail.com>2005-12-02 17:16:52 +0000
commita84e0a9b9e5104f146853b89ce8b7ba56fbb03d8 (patch)
treeff073338f6f1727ef378f9d3337081ea037600a5
parentd4a7e14e41a918cd6de0a5efc1002c9d87fb7708 (diff)
downloadscala-a84e0a9b9e5104f146853b89ce8b7ba56fbb03d8.tar.gz
scala-a84e0a9b9e5104f146853b89ce8b7ba56fbb03d8.tar.bz2
scala-a84e0a9b9e5104f146853b89ce8b7ba56fbb03d8.zip
Improved generated code and line number informa...
Improved generated code and line number information.
-rw-r--r--sources/scala/tools/nsc/backend/icode/BasicBlocks.scala25
-rw-r--r--sources/scala/tools/nsc/backend/icode/GenICode.scala98
-rw-r--r--sources/scala/tools/nsc/backend/icode/Members.scala15
-rw-r--r--sources/scala/tools/nsc/backend/jvm/GenJVM.scala7
4 files changed, 129 insertions, 16 deletions
diff --git a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 50f3c75a3a..77877c1dc0 100644
--- a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -70,7 +70,11 @@ trait BasicBlocks: ICodes {
}
/** The number of instructions in this basic block so far. */
- def size: Int = instrs.length;
+ def size: Int =
+ if (isClosed)
+ instrs.length;
+ else
+ instructionList.length;
/** Initialize the stack of the block, must be done before evaluation
* the type stack */
@@ -139,6 +143,8 @@ trait BasicBlocks: ICodes {
instructionList = subst(instructionList);
}
+ ////////////////////// Emit //////////////////////
+
/** Add a new instruction at the end of the block,
* using the same source position as the last emitted instruction
@@ -166,12 +172,11 @@ trait BasicBlocks: ICodes {
assert(instructionList.length > 0,
"Empty block.");
closed = true;
-
-// Console.println("block " + label + " <closed>");
-
instrs = toInstructionArray(instructionList.reverse);
}
+ def isEmpty: Boolean = instructionList.isEmpty;
+
/** Enter ignore mode: new 'emit'ted instructions will not be
* added to this basic block. It makes the generation of THROW
* and RETURNs easier.
@@ -190,6 +195,12 @@ trait BasicBlocks: ICodes {
else
instructionList.head;
+ def firstInstruction =
+ if (closed)
+ instrs(0)
+ else
+ instructionList.last;
+
/** Convert the list to an array */
def toInstructionArray(l: List[Instruction]): Array[Instruction] = {
var array = new Array[Instruction](l.length);
@@ -202,7 +213,7 @@ trait BasicBlocks: ICodes {
def isClosed = closed;
// TODO: Take care of exception handlers!
- def successors : List[BasicBlock] = // here order will count
+ def successors : List[BasicBlock] = if (isEmpty) Nil else
lastInstruction match {
case JUMP (where) => List(where);
case CJUMP(success, failure, _, _) => failure::success::Nil;
@@ -211,7 +222,9 @@ trait BasicBlocks: ICodes {
case RETURN(_) => Nil;
case THROW() => Nil;
case _ =>
- global.abort("The last instruction is not a control flow instruction: " + lastInstruction);
+ if (isClosed)
+ global.abort("The last instruction is not a control flow instruction: " + lastInstruction);
+ else Nil;
}
/** Returns the precessors of this block, in the current 'code' chunk.
diff --git a/sources/scala/tools/nsc/backend/icode/GenICode.scala b/sources/scala/tools/nsc/backend/icode/GenICode.scala
index e2ac18a65d..330302b184 100644
--- a/sources/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/sources/scala/tools/nsc/backend/icode/GenICode.scala
@@ -113,9 +113,13 @@ abstract class GenICode extends SubComponent {
rhs match {
case Block(_, Return(_)) => ();
case Return(_) => ();
- case _ => ctx1.bb.emit(RETURN(m.returnType), rhs.pos);
+ case _ => if (ctx1.bb.isEmpty)
+ ctx1.bb.emit(RETURN(m.returnType), rhs.pos);
+ else
+ ctx1.bb.emit(RETURN(m.returnType));
}
ctx1.bb.close;
+ prune(ctx1.method);
} else
ctx1.method.setCode(null);
ctx1;
@@ -349,6 +353,14 @@ abstract class GenICode extends SubComponent {
if (settings.debug.value)
log("Adding label " + tree.symbol);
}
+
+// if (!isTailCallLabel(tree.asInstanceOf[LabelDef], ctx)) {
+// log("Non-tail call label found (" + tree.symbol + "), initializing arguments to default values.");
+// genLoadLabelArguments(params map { p => zeroOf(toTypeKind(p.symbol.tpe)) },
+// ctx1.labels(tree.symbol),
+// ctx);
+// }
+
ctx.bb.emit(JUMP(ctx1.bb), tree.pos);
ctx.bb.close;
genLoad(rhs, ctx1, expectedType /*toTypeKind(tree.symbol.info.resultType)*/);
@@ -400,10 +412,11 @@ abstract class GenICode extends SubComponent {
elseCtx = genLoad(elsep, elseCtx, ifKind);
}
- thenCtx.bb.emit(JUMP(contCtx.bb), thenp.pos);
+ thenCtx.bb.emit(JUMP(contCtx.bb));
thenCtx.bb.close;
- elseCtx.bb.emit(JUMP(contCtx.bb), elsep.pos);
+ elseCtx.bb.emit(JUMP(contCtx.bb));
elseCtx.bb.close;
+
contCtx;
case Return(expr) =>
@@ -822,7 +835,7 @@ abstract class GenICode extends SubComponent {
}
private def adapt(from: TypeKind, to: TypeKind, ctx: Context, tree: Tree): Unit = {
- if (!(from <:< to)) {
+ if (!(from <:< to) && !(from == SCALA_ALLREF && to == SCALA_ALL)) {
to match {
case UNIT =>
ctx.bb.emit(DROP(from), tree.pos);
@@ -1272,6 +1285,70 @@ abstract class GenICode extends SubComponent {
abort("Malformed parameter list: " + vparamss);
}
+ /**
+ * If the block consists of a single unconditional jump, prune
+ * it by replacing the instructions in the predecessor to jump
+ * directly to the JUMP target of the block.
+ */
+ def prune(method: IMethod) = {
+ var changed = false;
+ var n = 0;
+
+ def prune0(block: BasicBlock): Unit = {
+ val optCont = block.lastInstruction match {
+ case JUMP(b) if (b != block) => Some(b);
+ case _ => None
+ }
+ if (block.size == 1 && optCont != None) {
+ val Some(cont) = optCont;
+ val pred = block.predecessors;
+ log("Preds: " + pred + " of " + block);
+ pred foreach { p =>
+ p.lastInstruction match {
+ case CJUMP(succ, fail, cond, kind) =>
+ if (settings.debug.value)
+ log("Pruning empty if branch.");
+ changed = true;
+ p.replaceInstruction(p.lastInstruction,
+ if (block == succ)
+ CJUMP(cont, fail, cond, kind)
+ else if (block == fail)
+ CJUMP(succ, cont, cond, kind)
+ else
+ abort("Could not find block in preds"));
+
+ case CZJUMP(succ, fail, cond, kind) =>
+ if (settings.debug.value)
+ log("Pruning empty if branch.");
+ changed = true;
+ p.replaceInstruction(p.lastInstruction,
+ if (block == succ)
+ CZJUMP(cont, fail, cond, kind)
+ else if (block == fail)
+ CZJUMP(succ, cont, cond, kind)
+ else
+ abort("Could not find block in preds"));
+
+ case JUMP(b) =>
+ if (settings.debug.value)
+ log("Pruning empty if branch.");
+ changed = true;
+ p.replaceInstruction(p.lastInstruction, JUMP(cont));
+ }
+ }
+ if (changed)
+ method.code.removeBlock(block);
+ }
+ }
+
+ do {
+ changed = false;
+ n = n + 1;
+ method.code traverse prune0;
+ } while (changed);
+
+ log("Prune fixpoint reached in " + n + " iterations.");
+ }
def getMaxType(ts: List[Type]): TypeKind = {
def maxType(a: TypeKind, b: TypeKind): TypeKind =
@@ -1281,6 +1358,15 @@ abstract class GenICode extends SubComponent {
kinds reduceLeft maxType;
}
+ /** Check weather a given label definition is introduced by the tail call phase
+ * It is considered to be so if all value parameters of the label are the
+ * same as the value parameters of the current method.
+ */
+ def isTailCallLabel(tree: LabelDef, ctx: Context) =
+ tree.params.length == ctx.defdef.vparamss.head &&
+ List.forall2(tree.params, ctx.defdef.vparamss.head)
+ { (x, y) => x.symbol == y.symbol }
+
/////////////////////// Context ////////////////////////////////
@@ -1455,6 +1541,7 @@ abstract class GenICode extends SubComponent {
afterCtx
}
}
+ }
/**
* Represent a label in the current method code. In order
@@ -1544,7 +1631,7 @@ abstract class GenICode extends SubComponent {
* It is used temporarily during code generation. It is replaced
* by a real JUMP instruction when all labels are resolved.
*/
- class PseudoJUMP(label: Label) extends Instruction {
+ abstract class PseudoJUMP(label: Label) extends Instruction {
override def toString(): String ="PJUMP " + label.symbol.simpleName;
override def consumed = 0;
@@ -1571,6 +1658,5 @@ abstract class GenICode extends SubComponent {
failure.addCallingInstruction(this);
}
- }
}
diff --git a/sources/scala/tools/nsc/backend/icode/Members.scala b/sources/scala/tools/nsc/backend/icode/Members.scala
index 1a8c15aa05..35fe48bcbe 100644
--- a/sources/scala/tools/nsc/backend/icode/Members.scala
+++ b/sources/scala/tools/nsc/backend/icode/Members.scala
@@ -37,6 +37,21 @@ trait Members: ICodes {
startBlock = newBlock;
startBlock.initStack(new TypeStack);
+
+ def removeBlock(b: BasicBlock) = {
+ if (settings.debug.value) {
+ assert(blocks.forall(p => !(p.successors.contains(b))),
+ "Removing block that is still referenced in method code " + label);
+ if (b == startBlock)
+ assert(b.successors.length == 1,
+ "Removing start block with more than one successor.");
+ }
+
+ if (b == startBlock)
+ startBlock = b.successors.head;
+ blocks -= b;
+ }
+
/**
* Apply a function to all basic blocks, for side-effects. It starts at
* the given startBlock and checks that are no predecessors of the given node.
diff --git a/sources/scala/tools/nsc/backend/jvm/GenJVM.scala b/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
index fc9bd73608..c1e299b6ea 100644
--- a/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -312,7 +312,7 @@ abstract class GenJVM extends SubComponent {
log("Generating code for block: " + b + " at pc: " + labels(b).getAnchor());
var lastMappedPC = 0;
- var lastLineNr = 0;
+ var lastLineNr =0;
var crtPC = 0;
b traverse ( instr => {
@@ -559,13 +559,12 @@ abstract class GenJVM extends SubComponent {
crtPC = jcode.getPC();
val crtLine = try { clasz.cunit.position(instr.pos).line; } catch {
- case _: Error => Position.NOPOS;
+ case _: Error => lastLineNr;
}
//System.err.println("CRTLINE: " + instr.pos + " " +
// /* (if (instr.pos < clasz.cunit.source.content.length) clasz.cunit.source.content(instr.pos) else '*') + */ " " + crtLine);
- if (crtLine != lastLineNr &&
- crtPC > lastMappedPC) {
+ if (crtPC > lastMappedPC) {
jcode.completeLineNumber(lastMappedPC, crtPC, crtLine);
lastMappedPC = crtPC;
lastLineNr = crtLine;