summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sources/scala/tools/nsc/backend/WorklistAlgorithm.scala14
-rw-r--r--sources/scala/tools/nsc/backend/icode/BasicBlocks.scala6
-rw-r--r--sources/scala/tools/nsc/backend/icode/Checkers.scala3
-rw-r--r--sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala6
-rw-r--r--sources/scala/tools/nsc/backend/icode/GenICode.scala175
-rw-r--r--sources/scala/tools/nsc/backend/icode/Linearizers.scala63
-rw-r--r--sources/scala/tools/nsc/backend/icode/Members.scala66
-rw-r--r--sources/scala/tools/nsc/backend/icode/Opcodes.scala21
-rw-r--r--sources/scala/tools/nsc/backend/icode/Printers.scala14
-rw-r--r--sources/scala/tools/nsc/backend/jvm/GenJVM.scala131
10 files changed, 370 insertions, 129 deletions
diff --git a/sources/scala/tools/nsc/backend/WorklistAlgorithm.scala b/sources/scala/tools/nsc/backend/WorklistAlgorithm.scala
index d69f4929ed..6676c820bc 100644
--- a/sources/scala/tools/nsc/backend/WorklistAlgorithm.scala
+++ b/sources/scala/tools/nsc/backend/WorklistAlgorithm.scala
@@ -8,12 +8,12 @@
package scala.tools.nsc.backend;
import scala.tools.nsc.ast._;
-import scala.collection.mutable.Queue;
+import scala.collection.mutable.MutableList;
/**
* Simple implementation of a worklist algorithm. A processing
* function is applied repeatedly to the first element in the
- * worklist queue, as long as the queue is not empty.
+ * worklist, as long as the stack is not empty.
*
* The client class should mix-in this trait and initialize the
* worklist field and define the processElement method. Then call
@@ -24,8 +24,9 @@ import scala.collection.mutable.Queue;
*/
trait WorklistAlgorithm {
type Elem;
+ type WList <: MutableList[Elem];
- val worklist: Queue[Elem];
+ val worklist: WList;
/**
* Run the iterative algorithm until the worklist
@@ -35,12 +36,15 @@ trait WorklistAlgorithm {
def run(initWorklist: => Unit) = {
initWorklist;
- while (!worklist.isEmpty)
- processElement(worklist.dequeue);
+ while (!(worklist.length == 0))
+ processElement(dequeue);
}
/**
* Process the current element from the worklist.
*/
def processElement(e: Elem): Unit;
+
+ /** Remove and return the first element to be processed from the worklist. */
+ def dequeue: Elem;
}
diff --git a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
index b0a4cb6eae..a77d195ca0 100644
--- a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -136,9 +136,10 @@ trait BasicBlocks: ICodes {
}
def emit(instr: Instruction, pos: Int) = {
- assert (!closed || ignore, "BasicBlock closed");
+ assert (!closed || ignore, "BasicBlock " + label + " closed");
if (!ignore) {
+// Console.println("block " + label + ": " + instr);
instr.pos = pos;
instructionList = instr :: instructionList;
_lastInstruction = instr;
@@ -150,6 +151,9 @@ trait BasicBlocks: ICodes {
assert(instructionList.length > 0,
"Empty block.");
closed = true;
+
+// Console.println("block " + label + " <closed>");
+
instrs = toInstructionArray(instructionList.reverse);
}
diff --git a/sources/scala/tools/nsc/backend/icode/Checkers.scala b/sources/scala/tools/nsc/backend/icode/Checkers.scala
index bda1e4d7fa..fdd8912d84 100644
--- a/sources/scala/tools/nsc/backend/icode/Checkers.scala
+++ b/sources/scala/tools/nsc/backend/icode/Checkers.scala
@@ -55,6 +55,7 @@ abstract class Checkers {
val STRING = REFERENCE(definitions.StringClass);
val SCALA_ALL = REFERENCE(definitions.AllClass);
+ val SCALA_ALL_REF = REFERENCE(definitions.AllRefClass);
def checkICodes: Unit = {
Console.println("[[consistency check at beginning of phase " + globalPhase.name + "]]");
@@ -299,7 +300,7 @@ abstract class Checkers {
case Pair(value, obj) =>
checkField(obj, field);
val fieldType = toTypeKind(field.tpe);
- if (!(value <:< fieldType))
+ if (fieldType != SCALA_ALL_REF && !(value <:< fieldType))
typeError(fieldType, value);
}
}
diff --git a/sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala b/sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
index 86cba32ccb..126e20ebef 100644
--- a/sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
+++ b/sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
@@ -23,6 +23,7 @@ trait ExceptionHandlers: ICodes {
class ExceptionHandler(val method: IMethod, label: String, val cls: Symbol) {
private var coveredBlocks: List[BasicBlock] = Nil;
private var _startBlock: BasicBlock = _;
+ var finalizer: Finalizer = _;
def setStartBlock(b: BasicBlock) = _startBlock = b;
def startBlock = _startBlock;
@@ -40,4 +41,9 @@ trait ExceptionHandlers: ICodes {
class Finalizer(method: IMethod, label: String) extends ExceptionHandler(method, label, NoSymbol) {
override def toString() = "finalizer_" + label;
}
+
+ object NoFinalizer extends Finalizer(null, "<no finalizer>") {
+ override def startBlock: BasicBlock = error("NoFinalizer cannot have a start block.");
+ override def setStartBlock(b: BasicBlock): Unit = error("NoFinalizer cannot have a start block.");
+ }
}
diff --git a/sources/scala/tools/nsc/backend/icode/GenICode.scala b/sources/scala/tools/nsc/backend/icode/GenICode.scala
index 9b58cf4e27..009b6fb8b2 100644
--- a/sources/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/sources/scala/tools/nsc/backend/icode/GenICode.scala
@@ -23,12 +23,12 @@ abstract class GenICode extends SubComponent {
import icodes._;
import icodes.opcodes._;
- val phaseName = "genicode";
+ val phaseName = "icode";
override def newPhase(prev: Phase) = new ICodePhase(prev);
class ICodePhase(prev: Phase) extends StdPhase(prev) {
- override def name = "genicode";
+ override def name = "icode";
override def description = "Generate ICode from the AST";
@@ -250,19 +250,26 @@ abstract class GenICode extends SubComponent {
def genArrayOp(tree: Tree, ctx: Context, code: Int): Context = {
import scalaPrimitives._;
val Apply(Select(arrayObj, _), args) = tree;
- var ctx1 = genLoad(arrayObj, ctx, toTypeKind(arrayObj.tpe));
+ val k = toTypeKind(arrayObj.tpe);
+ val ARRAY(elem) = k;
+ var ctx1 = genLoad(arrayObj, ctx, k);
if (scalaPrimitives.isArrayGet(code)) {
- // load argument on stack
- assert(args.length == 1,
- "Too many arguments for array get operation: " + tree);
- ctx1 = genLoad(args.head, ctx1, INT);
+ // load argument on stack
+ assert(args.length == 1,
+ "Too many arguments for array get operation: " + tree);
+ ctx1 = genLoad(args.head, ctx1, INT);
+ generatedType = elem;
} else if (scalaPrimitives.isArraySet(code)) {
assert(args.length == 2,
"Too many arguments for array set operation: " + tree);
ctx1 = genLoad(args.head, ctx1, INT);
ctx1 = genLoad(args.tail.head, ctx1, toTypeKind(args.tail.head.tpe));
- }
+ // the following line should really be here, but because of bugs in erasure
+ // we pretend we generate whatever type is expected from us.
+ //generatedType = UNIT;
+ } else
+ generatedType = INT;
code match {
case ZARRAY_LENGTH =>
@@ -407,24 +414,23 @@ abstract class GenICode extends SubComponent {
val outerCtx = ctx.dup;
var bodyCtx: Context = null;
+ var afterCtx: Context = outerCtx.newBlock;
+ var finalHandler: Finalizer = null;
+ if (finalizer != EmptyTree)
+ finalHandler = ctx.newFinalizer;
+ else
+ finalHandler = NoFinalizer;
+
+
+ def genHandler = genExceptionHandler(ctx, outerCtx, afterCtx, finalHandler);
val handlers = for (val CaseDef(pat, _, body) <- catches)
yield pat match {
case Typed(Ident(nme.WILDCARD), tpt) =>
- val exh = ctx.newHandler(tpt.tpe.symbol);
-
- val ctx1 = genLoad(body, outerCtx.enterHandler(exh), UNIT);
- ctx1.bb.emit(RETURN(UNIT));
- ctx1.bb.close;
- exh
+ genHandler(body, tpt.tpe.symbol);
case Ident(nme.WILDCARD) =>
- val exh = ctx.newHandler(definitions.ThrowableClass);
-
- val ctx1 = genLoad(body, outerCtx.enterHandler(exh), UNIT);
- ctx1.bb.emit(RETURN(UNIT));
- ctx1.bb.close;
- exh
+ genHandler(body, definitions.ThrowableClass);
case Bind(name, _) =>
val exception = new Local(pat.symbol, toTypeKind(pat.symbol.tpe));
@@ -434,8 +440,10 @@ abstract class GenICode extends SubComponent {
val exhCtx = outerCtx.enterHandler(exh);
exhCtx.bb.emit(STORE_LOCAL(exception, false), pat.pos);
- val ctx1 = genLoad(body, exhCtx, UNIT);
- ctx1.bb.emit(RETURN(UNIT));
+ val ctx1 = genLoad(body, exhCtx, toTypeKind(body.tpe));
+ if (finalHandler != NoFinalizer)
+ ctx1.bb.emit(CALL_FINALIZER(finalHandler));
+ ctx1.bb.emit(JUMP(afterCtx.bb));
ctx1.bb.close;
exh
@@ -443,11 +451,13 @@ abstract class GenICode extends SubComponent {
abort("Unknown exception case: " + pat + " at: " + unit.position(pat.pos));
}
- val finalHandler = ctx.newFinalizer;
-
- val ctx1 = genLoad(finalizer, outerCtx.enterHandler(finalHandler), UNIT);
- ctx1.bb.emit(RETURN(UNIT));
- ctx1.bb.close;
+ if (finalizer != EmptyTree) {
+ val finalizerCtx = outerCtx.enterHandler(finalHandler);
+ finalizerCtx.bb.emit(ENTER_FINALIZER(finalHandler));
+ val ctx1 = genLoad(finalizer, finalizerCtx, UNIT);
+ ctx1.bb.emit(LEAVE_FINALIZER(finalHandler));
+ ctx1.bb.close;
+ }
bodyCtx = ctx.newBlock;
outerCtx.bb.emit(JUMP(bodyCtx.bb), tree.pos);
@@ -455,9 +465,18 @@ abstract class GenICode extends SubComponent {
generatedType = toTypeKind(block.tpe);
val ctxfinal = genLoad(block, bodyCtx, generatedType);
- handlers.reverse foreach ctxfinal.exitHandler;
+
+ handlers.reverse foreach (ex => { ex.finalizer = finalHandler; ctxfinal exitHandler ex });
ctxfinal.exitFinalizer(finalHandler);
- ctxfinal
+// if (generatedType != SCALA_ALL)
+ adapt(generatedType, expectedType, ctxfinal, tree);
+
+ if (finalHandler != NoFinalizer)
+ ctxfinal.bb.emit(CALL_FINALIZER(finalHandler));
+ ctxfinal.bb.emit(JUMP(afterCtx.bb));
+ ctxfinal.bb.close;
+ generatedType = expectedType;
+ afterCtx
case Throw(expr) =>
val ctx1 = genLoad(expr, ctx, THROWABLE);
@@ -610,11 +629,29 @@ abstract class GenICode extends SubComponent {
generatedType = BOOL;
ctx1 = afterCtx;
} else if (code == scalaPrimitives.SYNCHRONIZED) {
+ val monitor = new Local(ctx.method.symbol.newVariable(tree.pos, unit.fresh.newName("monitor")).setInfo(definitions.ObjectClass.tpe),
+ ANY_REF_CLASS);
+ ctx.method.addLocal(monitor);
+
ctx1 = genLoadQualifier(fun, ctx1);
+ ctx1.bb.emit(STORE_LOCAL(monitor, false));
ctx1.bb.emit(MONITOR_ENTER(), tree.pos);
- ctx1 = genLoad(args.head, ctx1, toTypeKind(tree.tpe.resultType));
- ctx1 = genLoadQualifier(fun, ctx1);
- ctx1.bb.emit(MONITOR_EXIT(), tree.pos);
+
+ log("synchronized block start");
+ ctx1 = ctx1.Try(NoSymbol,
+ bodyCtx => {
+ val ctx1 = genLoad(args.head, bodyCtx, toTypeKind(tree.tpe.resultType));
+ ctx1.bb.emit(LOAD_LOCAL(monitor, false));
+ ctx1.bb.emit(MONITOR_EXIT(), tree.pos);
+ ctx1
+ },
+ exhCtx => {
+ exhCtx.bb.emit(LOAD_LOCAL(monitor, false));
+ exhCtx.bb.emit(MONITOR_EXIT(), tree.pos);
+ exhCtx.bb.emit(THROW());
+ exhCtx
+ });
+ log("synchronized block end with block " + ctx1.bb + " closed=" + ctx1.bb.isClosed);
} else if (scalaPrimitives.isCoercion(code)) {
ctx1 = genLoad(receiver, ctx1, toTypeKind(receiver.tpe));
genCoercion(tree, ctx1, code);
@@ -780,30 +817,46 @@ abstract class GenICode extends SubComponent {
}
// emit conversion
- if (!(generatedType <:< expectedType)) {
- expectedType match {
+ if (generatedType != expectedType)
+ adapt(generatedType, expectedType, resCtx, tree);
+
+ resCtx;
+ }
+
+ private def adapt(from: TypeKind, to: TypeKind, ctx: Context, tree: Tree): Unit = {
+ if (!(from <:< to)) {
+ to match {
case UNIT =>
- resCtx.bb.emit(DROP(generatedType), tree.pos);
- log("Dropped an " + generatedType);
+ ctx.bb.emit(DROP(from), tree.pos);
+ log("Dropped an " + from);
case _ =>
- assert(generatedType != UNIT, "Can't convert from UNIT to " + expectedType +
+ assert(from != UNIT, "Can't convert from UNIT to " + to +
tree + " at: " + unit.position(tree.pos));
- resCtx.bb.emit(CALL_PRIMITIVE(Conversion(generatedType, expectedType)), tree.pos);
+ ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to)), tree.pos);
}
-// } else if (generatedType == SCALA_ALL && expectedType == UNIT)
-// resCtx.bb.emit(DROP(generatedType));
- } else if (generatedType == SCALA_ALL) {
- resCtx.bb.emit(DROP(generatedType));
- resCtx.bb.emit(getZeroOf(ctx.method.returnType));
- resCtx.bb.emit(RETURN(ctx.method.returnType));
- resCtx.bb.enterIgnoreMode;
- } else if (generatedType == SCALA_ALLREF) {
- resCtx.bb.emit(DROP(generatedType));
- resCtx.bb.emit(CONSTANT(Constant(null)));
+ } else if (from == SCALA_ALL) {
+ ctx.bb.emit(DROP(from));
+ ctx.bb.emit(getZeroOf(ctx.method.returnType));
+ ctx.bb.emit(RETURN(ctx.method.returnType));
+ ctx.bb.enterIgnoreMode;
+ } else if (from == SCALA_ALLREF) {
+ ctx.bb.emit(DROP(from));
+ ctx.bb.emit(CONSTANT(Constant(null)));
}
+ }
- resCtx;
+ private def genExceptionHandler(ctx: Context, outerCtx: Context, afterCtx: Context, finalHandler: Finalizer)(body: Tree, sym: Symbol): ExceptionHandler = {
+ val exh = ctx.newHandler(sym);
+
+ var ctx1 = outerCtx.enterHandler(exh);
+ ctx1.bb.emit(DROP(REFERENCE(sym)));
+ ctx1 = genLoad(body, ctx1, toTypeKind(body.tpe));
+ if (finalHandler != NoFinalizer)
+ ctx1.bb.emit(CALL_FINALIZER(finalHandler));
+ ctx1.bb.emit(JUMP(afterCtx.bb));
+ ctx1.bb.close;
+ exh
}
/** Load the qualifier of `tree' on top of the stack. */
@@ -1356,7 +1409,7 @@ abstract class GenICode extends SubComponent {
handlers = handlers.tail;
}
- def exitFinalizer(f: Finalizer): Unit = {
+ def exitFinalizer(f: Finalizer): Unit = if (f != NoFinalizer) {
assert(handlerCount > 0 && finalizers.head == f,
"Wrong nesting of exception handlers." + this + " for " + f);
handlerCount = handlerCount - 1;
@@ -1365,6 +1418,28 @@ abstract class GenICode extends SubComponent {
/** Clone the current context */
def dup: Context = new Context(this);
+
+ def Try(catched: Symbol, body: Context => Context, handler: Context => Context) = {
+ val outerCtx = this.dup;
+ val afterCtx = outerCtx.newBlock;
+ val exh = this.newHandler(catched);
+
+ val ctx1 = handler(outerCtx.enterHandler(exh));
+ ctx1.bb.emit(JUMP(afterCtx.bb));
+ ctx1.bb.close;
+
+ val bodyCtx = this.newBlock;
+ val finalCtx = body(bodyCtx);
+
+ outerCtx.bb.emit(JUMP(bodyCtx.bb));
+ outerCtx.bb.close;
+
+ finalCtx.exitHandler(exh);
+ finalCtx.bb.emit(JUMP(afterCtx.bb));
+ finalCtx.bb.close;
+
+ afterCtx
+ }
}
/**
diff --git a/sources/scala/tools/nsc/backend/icode/Linearizers.scala b/sources/scala/tools/nsc/backend/icode/Linearizers.scala
index 7f6e71e8ed..baffccef77 100644
--- a/sources/scala/tools/nsc/backend/icode/Linearizers.scala
+++ b/sources/scala/tools/nsc/backend/icode/Linearizers.scala
@@ -8,13 +8,13 @@
package scala.tools.nsc.backend.icode;
import scala.tools.nsc.ast._;
-import scala.collection.mutable.Queue;
+import scala.collection.mutable.Stack;
trait Linearizers: ICodes {
import opcodes._;
trait Linearizer {
- def linearize(c: Code): List[BasicBlock];
+ def linearize(c: IMethod): List[BasicBlock];
}
/**
@@ -26,43 +26,54 @@ trait Linearizers: ICodes {
*/
class NormalLinearizer extends Linearizer with WorklistAlgorithm {
type Elem = BasicBlock;
- val worklist: Queue[Elem] = new Queue();
+ type WList = Stack[Elem];
+
+ val worklist: WList = new Stack();
var blocks: List[BasicBlock] = Nil;
- def linearize(c: Code): List[BasicBlock] = {
- val b = c.startBlock;
- blocks = b :: Nil;
+ def linearize(m: IMethod): List[BasicBlock] = {
+ val b = m.code.startBlock;
+ blocks = Nil;
+
+ run {
+ worklist ++= (m.exh map (.startBlock));
+ worklist ++= (m.finalizers map (.startBlock));
+ worklist.push(b);
+ }
- run( { worklist.enqueue(b); } );
blocks.reverse;
}
+ /** Linearize another subtree and append it to the existing blocks. */
def linearize(startBlock: BasicBlock): List[BasicBlock] = {
- blocks = startBlock :: Nil;
- run( { worklist.enqueue(startBlock); } );
+ //blocks = startBlock :: Nil;
+ run( { worklist.push(startBlock); } );
blocks.reverse;
}
def processElement(b: BasicBlock) =
- if (b.size > 0)
- b.lastInstruction match {
- case JUMP(where) =>
- add(where);
- case CJUMP(success, failure, _, _) =>
- add(success);
- add(failure);
- case CZJUMP(success, failure, _, _) =>
- add(success);
- add(failure);
- case SWITCH(_, labels) =>
- add(labels);
- case RETURN(_) =>
- ()
- case THROW() =>
- ()
+ if (b.size > 0) {
+ add(b);
+ b.lastInstruction match {
+ case JUMP(where) =>
+ add(where);
+ case CJUMP(success, failure, _, _) =>
+ add(success);
+ add(failure);
+ case CZJUMP(success, failure, _, _) =>
+ add(success);
+ add(failure);
+ case SWITCH(_, labels) =>
+ add(labels);
+ case RETURN(_) => ();
+ case THROW() => ();
+ case LEAVE_FINALIZER(_) => ();
+ }
}
+ def dequeue: Elem = worklist.pop;
+
/**
* Prepend b to the list, if not already scheduled.
* TODO: use better test than linear search
@@ -72,7 +83,7 @@ trait Linearizers: ICodes {
()
else {
blocks = b :: blocks;
- worklist enqueue b;
+ worklist push b;
}
def add(bs: List[BasicBlock]): Unit = bs foreach add;
diff --git a/sources/scala/tools/nsc/backend/icode/Members.scala b/sources/scala/tools/nsc/backend/icode/Members.scala
index 3f86291909..50dd3afb5f 100644
--- a/sources/scala/tools/nsc/backend/icode/Members.scala
+++ b/sources/scala/tools/nsc/backend/icode/Members.scala
@@ -8,7 +8,7 @@
package scala.tools.nsc.backend.icode;
import scala.collection.mutable.HashMap;
-import scala.collection.mutable.HashSet;
+import scala.collection.mutable.{Set, HashSet};
import scala.{Symbol => scala_Symbol};
import scala.tools.nsc.symtab.Flags;
@@ -37,9 +37,29 @@ trait Members: ICodes {
startBlock = newBlock;
startBlock.initStack(new TypeStack);
- /** Apply a function to all basic blocks, for side-effects. */
- def traverse(f: BasicBlock => Unit) =
- traverseFeedBack((bb: BasicBlock, hm: HashMap[BasicBlock, boolean]) => f(bb));
+ /**
+ * 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.
+ * Only blocks that are reachable via a path from startBlock are ever visited.
+ */
+ def traverseFrom(startBlock: BasicBlock, f: BasicBlock => Unit) = {
+ val visited: Set[BasicBlock] = new HashSet();
+
+ def traverse0(toVisit: List[BasicBlock]): Unit = toVisit match {
+ case Nil => ();
+ case b :: bs => if (!visited.contains(b)) {
+ f(b);
+ visited += b;
+ traverse0(bs ::: b.successors);
+ } else
+ traverse0(bs);
+ }
+ assert(startBlock.predecessors == Nil,
+ "Starting traverse from a block with predecessors: " + this);
+ traverse0(startBlock :: Nil)
+ }
+
+ def traverse(f: BasicBlock => Unit) = blocks foreach f;
/* This method applies the given function to each basic block. */
def traverseFeedBack(f: (BasicBlock, HashMap[BasicBlock, Boolean]) => Unit) = {
@@ -65,25 +85,25 @@ trait Members: ICodes {
override def toString() : String = "ICode '" + label + "'";
/** This method print the code */
- def print() : unit = print(System.out);
-
- def print(out: java.io.PrintStream) : unit = {
- traverse((bb: BasicBlock) => {
- out.println("Block #" + bb.label);
- out.println("Substituable variables : ");
- if (bb.substituteVars != null)
- bb.substituteVars.foreach(out.print);
- else
- out.println(" {Empty} ");
- out.println("Instructions:");
- bb.traverse((ici: Instruction) =>
- out.println(" "+ici.toString()));
- out.print ("Successors: ");
- bb.successors.foreach((bb: BasicBlock) => out.print(bb.label+", "));
- out.println (""); // ?? Del
- out.println ();
- });
- }
+// def print() : unit = print(System.out);
+
+// def print(out: java.io.PrintStream) : unit = {
+// traverse((bb: BasicBlock) => {
+// out.println("Block #" + bb.label);
+// out.println("Substituable variables : ");
+// if (bb.substituteVars != null)
+// bb.substituteVars.foreach(out.print);
+// else
+// out.println(" {Empty} ");
+// out.println("Instructions:");
+// bb.traverse((ici: Instruction) =>
+// out.println(" "+ici.toString()));
+// out.print ("Successors: ");
+// bb.successors.foreach((bb: BasicBlock) => out.print(bb.label+", "));
+// out.println (""); // ?? Del
+// out.println ();
+// });
+// }
/* Compute a unique new label */
def nextLabel = {
diff --git a/sources/scala/tools/nsc/backend/icode/Opcodes.scala b/sources/scala/tools/nsc/backend/icode/Opcodes.scala
index ec5fb429d4..3f2fb45b17 100644
--- a/sources/scala/tools/nsc/backend/icode/Opcodes.scala
+++ b/sources/scala/tools/nsc/backend/icode/Opcodes.scala
@@ -26,6 +26,8 @@ import scala.tools.util.Position;
case CALL_PRIMITIVE(primitive) =>
case CALL_METHOD(method, style) =>
case CALL_FINALIZER(finalizer) =>
+ case ENTER_FINALIZER(finalizer) =>
+ case LEAVE_FINALIZER(finalizer) =>
case NEW(kind) =>
case CREATE_ARRAY(elem) =>
case IS_INSTANCE(tpe) =>
@@ -236,13 +238,28 @@ import scala.tools.util.Position;
}
case class CALL_FINALIZER(finalizer: Finalizer) extends Instruction {
-
+ assert(finalizer != NoFinalizer, "CALL_FINALIZER cannot call NoFinalizer");
override def toString(): String =
"CALL_FINALIZER " + finalizer;
override def consumed = 0;
+ override def produced = 0;
+ }
- override def produced = 1;
+ case class ENTER_FINALIZER(finalizer: Finalizer) extends Instruction {
+ override def toString(): String =
+ "ENTER_FINALIZER " + finalizer;
+
+ override def consumed = 1;
+ override def produced = 0;
+ }
+
+ case class LEAVE_FINALIZER(finalizer: Finalizer) extends Instruction {
+ override def toString(): String =
+ "LEAVE_FINALIZER " + finalizer;
+
+ override def consumed = 0;
+ override def produced = 0;
}
/** Create a new instance of a class through the specified constructor
diff --git a/sources/scala/tools/nsc/backend/icode/Printers.scala b/sources/scala/tools/nsc/backend/icode/Printers.scala
index de773b1d94..2ec3e00fd8 100644
--- a/sources/scala/tools/nsc/backend/icode/Printers.scala
+++ b/sources/scala/tools/nsc/backend/icode/Printers.scala
@@ -85,7 +85,7 @@ abstract class Printers {
if (!m.isDeferred) {
println(" {");
- printCode(m.code);
+ linearizer.linearize(m) foreach printBlock;
println("}");
indent;println("Exception handlers: ");
@@ -102,14 +102,12 @@ abstract class Printers {
print(" ("); print(p.kind); print(")");
}
- def printCode(code: Code): Unit = {
-// code traverse printBlock;
- linearizer.linearize(code) foreach printBlock;
- }
-
def printExceptionHandler(e: ExceptionHandler) = {
- println(" catch (" + e.cls.simpleName + ") in " + e.covered);
- linearizer.linearize(e.startBlock) foreach printBlock;
+ indent;
+ println("catch (" + e.cls.simpleName + ") in " + e.covered + " starting at: " + e.startBlock);
+ undent;
+ println("with finalizer: " + e.finalizer);
+// linearizer.linearize(e.startBlock) foreach printBlock;
}
def printBlock(bb: BasicBlock): Unit = {
diff --git a/sources/scala/tools/nsc/backend/jvm/GenJVM.scala b/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
index 7f169c7bdb..df117c7146 100644
--- a/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -132,6 +132,7 @@ abstract class GenJVM extends SubComponent {
log("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) +
" owner: " + m.symbol.owner);
method = m;
+ endPC.clear;
computeLocalVarsIndex(m);
var resTpe = javaType(toTypeKind(m.symbol.tpe.resultType));
@@ -157,7 +158,7 @@ abstract class GenJVM extends SubComponent {
jmethod.addNewLocalVariable(javaType(local.kind), javaName(local.sym));
jcode = jmethod.getCode().asInstanceOf[JExtendedCode];
- genCode(m.code);
+ genCode(m);
}
}
@@ -224,12 +225,98 @@ abstract class GenJVM extends SubComponent {
val linearizer = new NormalLinearizer();
+ var linearization: List[BasicBlock] = Nil;
- def genCode(c: Code): Unit = {
- code = c;
- val blocks = linearizer.linearize(code);
- makeLabels(blocks);
- blocks foreach genBlock;
+ def genCode(m: IMethod): Unit = {
+ labels.clear;
+ retAddress.clear;
+ anyHandler.clear;
+
+ code = m.code;
+ linearization = linearizer.linearize(m);
+ makeLabels(linearization);
+ linearization foreach genBlock;
+ if (this.method.exh != Nil || this.method.finalizers != Nil)
+ genExceptionHandlers;
+ }
+
+ /** Map from finalizer to the code area where its 'any' exception handler was generated. */
+ val anyHandler: HashMap[Finalizer, Pair[Int, Int]] = new HashMap();
+
+ /** Generate exception handlers for the current method. */
+ def genExceptionHandlers: Unit = {
+
+ def ranges(e: ExceptionHandler): List[Pair[Int, Int]] = {
+ var covered = e.covered;
+ var ranges: List[Pair[Int, Int]] = Nil;
+ var start = -1;
+ var end = -1;
+
+ linearization foreach ((b) => {
+ if (! (covered contains b) ) {
+ if (start >= 0) { // we're inside a handler range
+ end = labels(b).getAnchor();
+ ranges = Pair(start, end) :: ranges;
+ log("ending range: " + ranges.head);
+ start = -1;
+ }
+ } else {
+ if (start >= 0) { // we're inside a handler range
+ end = endPC(b);
+ log("appending block " + b + " to current range: " + Pair(start, end));
+ } else {
+ start = labels(b).getAnchor();
+ end = endPC(b);
+ log("starting new range with " + b + ": " + Pair(start, end));
+ }
+ covered = covered remove b.==;
+ }
+ });
+
+ if (start >= 0) {
+ ranges = Pair(start, end) :: ranges;
+ log("adding last range: " + ranges.head);
+ }
+
+ if (covered != Nil)
+ log("Some covered blocks were not found in method: " + method +
+ " covered: " + covered + " not in " + linearization);
+ ranges
+ }
+
+ this.method.exh foreach ((e) => {
+ ranges(e) foreach ((p) => {
+ log("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method +
+ " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls);
+ jcode.addExceptionHandler(p._1, p._2,
+ labels(e.startBlock).getAnchor(),
+ if (e.cls == NoSymbol)
+ null
+ else javaName(e.cls))
+ })
+ });
+ this.method.finalizers foreach ((f) => {
+ val targetPC = jcode.getPC();
+ val exceptionLocal = jmethod.addNewLocalVariable(JObjectType.JAVA_LANG_OBJECT, clasz.cunit.fresh.newName("exception"));
+ jcode.emitSTORE(exceptionLocal);
+ jcode.emitJSR(labels(f.startBlock));
+ jcode.emitLOAD(exceptionLocal);
+ jcode.emitATHROW();
+
+ log("Finalizer: " + f + " coveres: " + f.covered);
+ anyHandler.foreach((of: Finalizer, r: Pair[Int, Int]) =>
+ if (f.covered.contains(of.startBlock))
+ jcode.addFinallyHandler(r._1, r._2, targetPC));
+
+ anyHandler += f -> Pair(targetPC, jcode.getPC());
+
+ ranges(f) foreach ((p) => {
+ log("Adding finalizer handler " + f + "at: " + targetPC + " for " + method +
+ " from: " + p._1 + " to: " + p._2);
+ jcode.addFinallyHandler(p._1, p._2, targetPC);
+ });
+
+ });
}
def genBlock(b: BasicBlock): Unit = {
@@ -241,6 +328,9 @@ abstract class GenJVM extends SubComponent {
var crtPC = 0;
b traverse ( instr => {
+ if (b.lastInstruction == instr)
+ endPC(b) = jcode.getPC();
+
instr match {
case THIS(clasz) =>
jcode.emitALOAD_0();
@@ -273,8 +363,8 @@ abstract class GenJVM extends SubComponent {
case LOAD_FIELD(field, isStatic) =>
var owner = javaName(field.owner);
// if (field.owner.hasFlag(Flags.MODULE)) owner = owner + "$";
-
- log("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags));
+ if (settings.debug.value)
+ log("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags));
if (isStatic)
jcode.emitGETSTATIC(owner,
javaName(field),
@@ -286,8 +376,9 @@ abstract class GenJVM extends SubComponent {
case LOAD_MODULE(module) =>
assert(module.isModule || module.isModuleClass, "Expected module: " + module);
- log("genearting LOAD_MODULE for: " + module + " flags: " +
- Flags.flagsToString(module.flags));
+ if (settings.debug.value)
+ log("genearting LOAD_MODULE for: " + module + " flags: " +
+ Flags.flagsToString(module.flags));
jcode.emitGETSTATIC(javaName(module) /* + "$" */ ,
MODULE_INSTANCE_NAME,
javaType(module));
@@ -357,6 +448,16 @@ abstract class GenJVM extends SubComponent {
javaType(method).asInstanceOf[JMethodType]);
}
+ case CALL_FINALIZER(finalizer) =>
+ jcode.emitJSR(labels(finalizer.startBlock));
+
+ case ENTER_FINALIZER(finalizer) =>
+ retAddress(finalizer) = jmethod.addNewLocalVariable(JType.ADDRESS, clasz.cunit.fresh.newName("ret"));
+ jcode.emitSTORE(retAddress(finalizer));
+
+ case LEAVE_FINALIZER(finalizer) =>
+ jcode.emitRET(retAddress(finalizer));
+
case NEW(REFERENCE(cls)) =>
val className = javaName(cls);
jcode.emitNEW(className);
@@ -393,7 +494,8 @@ abstract class GenJVM extends SubComponent {
caze = caze.tail;
}
val branchArray = new Array[JCode$Label](tagArray.length);
- log("Emitting SWITHCH:\ntags: " + tags + "\nbranches: " + branches);
+ if (settings.debug.value)
+ log("Emitting SWITHCH:\ntags: " + tags + "\nbranches: " + branches);
jcode.emitSWITCH(tagArray,
(branches map labels dropRight 1).copyToArray(branchArray, 0),
labels(branches.last),
@@ -603,7 +705,8 @@ abstract class GenJVM extends SubComponent {
}
case Conversion(src, dst) =>
- log("Converting from: " + src + " to: " + dst);
+ if (settings.debug.value)
+ log("Converting from: " + src + " to: " + dst);
if (dst == BOOL) {
Console.println("Illegal conversion at: " + clasz +
" at: " + method.sourceFile + ":" + Position.line(pos));
@@ -638,8 +741,10 @@ abstract class GenJVM extends SubComponent {
}
}
+ val endPC: HashMap[BasicBlock, Int] = new HashMap();
val labels: HashMap[BasicBlock, JCode$Label] = new HashMap();
val conds: HashMap[TestOp, Int] = new HashMap();
+ val retAddress: HashMap[Finalizer, JLocalVariable] = new HashMap();
conds += EQ -> JExtendedCode.COND_EQ;
conds += NE -> JExtendedCode.COND_NE;
@@ -649,7 +754,7 @@ abstract class GenJVM extends SubComponent {
conds += GE -> JExtendedCode.COND_GE;
def makeLabels(bs: List[BasicBlock]) = {
- labels.clear;
+ //labels.clear;
log("Making labels for: " + method);
bs foreach (bb => labels += bb -> jcode.newLabel() );
}