summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2005-10-24 15:31:32 +0000
committerIulian Dragos <jaguarul@gmail.com>2005-10-24 15:31:32 +0000
commitf6f24bd8f5b5429629923a1a0cb055c9c88aba52 (patch)
tree464bbc3057b7ea39991de3ef25ec10ce12ff947c
parent083c4b354e8e9caaea4528959d4a0c8259bb1ab5 (diff)
downloadscala-f6f24bd8f5b5429629923a1a0cb055c9c88aba52.tar.gz
scala-f6f24bd8f5b5429629923a1a0cb055c9c88aba52.tar.bz2
scala-f6f24bd8f5b5429629923a1a0cb055c9c88aba52.zip
Added preliminary exception handling code gener...
Added preliminary exception handling code generation.
-rw-r--r--sources/scala/tools/nsc/backend/icode/BasicBlocks.scala8
-rw-r--r--sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala18
-rw-r--r--sources/scala/tools/nsc/backend/icode/GenICode.scala152
-rw-r--r--sources/scala/tools/nsc/backend/icode/Linearizers.scala7
-rw-r--r--sources/scala/tools/nsc/backend/icode/Members.scala19
-rw-r--r--sources/scala/tools/nsc/backend/icode/Opcodes.scala11
-rw-r--r--sources/scala/tools/nsc/backend/icode/Printers.scala11
7 files changed, 156 insertions, 70 deletions
diff --git a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 3bee7805cc..b0a4cb6eae 100644
--- a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -147,8 +147,8 @@ trait BasicBlocks: ICodes {
/** Close the block */
def close = {
- assert(instructionList.length > 0,
- "Empty block.");
+ assert(instructionList.length > 0,
+ "Empty block.");
closed = true;
instrs = toInstructionArray(instructionList.reverse);
}
@@ -195,6 +195,10 @@ trait BasicBlocks: ICodes {
global.abort("The last instruction is not a control flow instruction");
}
+ /** Returns the precessors of this block, in the current 'code' chunk.
+ * This is signifficant only if there are exception handlers, which live
+ * in different code 'chunks' than the rest of the method.
+ */
def predecessors: List[BasicBlock] = {
if (preds == null)
preds = code.blocks.elements.filter (p => (p.successors contains this)).toList;
diff --git a/sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala b/sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
index 9ca5609ac8..86cba32ccb 100644
--- a/sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
+++ b/sources/scala/tools/nsc/backend/icode/ExceptionHandlers.scala
@@ -18,16 +18,14 @@ import scala.collection.mutable.HashSet;
* in the generated code to preserve nesting.
*/
trait ExceptionHandlers: ICodes {
+ import global.{Symbol, NoSymbol};
- class ExceptionHandler(label: String) {
- val code: Code = new Code("exh" + label);
- var outer: ExceptionHandler = _;
+ class ExceptionHandler(val method: IMethod, label: String, val cls: Symbol) {
private var coveredBlocks: List[BasicBlock] = Nil;
+ private var _startBlock: BasicBlock = _;
- def setOuter(o: ExceptionHandler): ExceptionHandler = {
- outer = o;
- this
- }
+ def setStartBlock(b: BasicBlock) = _startBlock = b;
+ def startBlock = _startBlock;
def addBlock(b: BasicBlock): ExceptionHandler = {
coveredBlocks = b :: coveredBlocks;
@@ -35,7 +33,11 @@ trait ExceptionHandlers: ICodes {
}
def covered: List[BasicBlock] = coveredBlocks;
+
+ override def toString() = "exh_" + label + "(" + cls.simpleName + ")";
}
- object NoHandler extends ExceptionHandler("<nohandler>");
+ class Finalizer(method: IMethod, label: String) extends ExceptionHandler(method, label, NoSymbol) {
+ override def toString() = "finalizer_" + label;
+ }
}
diff --git a/sources/scala/tools/nsc/backend/icode/GenICode.scala b/sources/scala/tools/nsc/backend/icode/GenICode.scala
index e4d83dc70c..9b58cf4e27 100644
--- a/sources/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/sources/scala/tools/nsc/backend/icode/GenICode.scala
@@ -84,6 +84,8 @@ abstract class GenICode extends SubComponent {
// !! modules should be eliminated by refcheck... or not?
case ModuleDef(mods, name, impl) =>
+ abort("Modules should not reach backend!");
+
log("Generating module: " + tree.symbol.fullNameString);
ctx setClass (new IClass(tree.symbol) setCompilationUnit unit);
addClassFields(ctx, tree.symbol);
@@ -125,27 +127,6 @@ abstract class GenICode extends SubComponent {
case _ =>
abort("Illegal tree in gen: " + tree);
-
-
-/* case AbsTypeDef(mods, name, lo, hi) => (eliminated by erasure)
- case AliasTypeDef(mods, name, tparams, rhs) => (eliminated by erasure)
- case Import(expr, selectors) => (eliminated by typecheck)
- case Attributed(attribute, definition) => (eliminated by typecheck)
- case DocDef(comment, definition) => (eliminated by typecheck)
- case CaseDef(pat, guard, body) => (eliminated by transmatch)
- case Sequence(trees) => (eliminated by transmatch)
- case Alternative(trees) => (eliminated by transmatch)
- case Star(elem) => (eliminated by transmatch)
- case Bind(name, body) => (eliminated by transmatch)
- case ArrayValue(elemtpt, trees) => (introduced by uncurry)
- case Function(vparams, body) => (eliminated by typecheck)
- case Typed(expr, tpt) => (eliminated by erasure)
- case TypeApply(fun, args) =>
- case SingletonTypeTree(ref) => (eliminated by typecheck)
- case SelectFromTypeTree(qualifier, selector) => (eliminated by typecheck)
- case CompoundTypeTree(templ: Template) => (eliminated by typecheck)
- case AppliedTypeTree(tpt, args) => (eliminated by typecheck)
-*/
}
private def genStat(trees: List[Tree], ctx: Context): Context = {
@@ -364,19 +345,20 @@ abstract class GenICode extends SubComponent {
genLoad(rhs, ctx1, toTypeKind(tree.symbol.info.resultType));
case ValDef(_, _, _, rhs) =>
- var initialValue = rhs;
val sym = tree.symbol;
val local = new Local(sym, toTypeKind(sym.info));
ctx.method.addLocal(local);
if (rhs == EmptyTree) {
log("Uninitialized variable " + tree + " at: " + unit.position(tree.pos));
- initialValue = zeroOf(local.kind);
+ ctx.bb.emit(getZeroOf(local.kind));
}
- val ctx1 = genLoad(initialValue, ctx, local.kind);
-// if (rhs != EmptyTree)
- ctx1.bb.emit(STORE_LOCAL(local, false), tree.pos);
+ var ctx1 = ctx;
+ if (rhs != EmptyTree)
+ ctx1 = genLoad(rhs, ctx, local.kind);
+
+ ctx1.bb.emit(STORE_LOCAL(local, false), tree.pos);
generatedType = UNIT;
ctx1
@@ -418,22 +400,64 @@ abstract class GenICode extends SubComponent {
val ctx1 = genLoad(expr, ctx, returnedKind);
ctx1.bb.emit(RETURN(returnedKind), tree.pos);
ctx1.bb.enterIgnoreMode;
- // although strange, 'return' does not necessarily close a block
- //ctx1.bb.close;
generatedType = expectedType;
ctx1
case Try(block, catches, finalizer) =>
- var ctx1 = ctx.newHandler.newBlock;
- ctx.bb.emit(JUMP(ctx1.bb), tree.pos);
- ctx.bb.close;
- val currentHandler = ctx.handlers.head;
- ctx1 = genLoad(block, ctx1, toTypeKind(block.tpe));
- assert(ctx1.handlers.head == currentHandler,
- "Handler nesting violated. Expected: " +
- currentHandler + " found: " + ctx1.handlers.head);
- // TODO: generate code for handlers and finalizer
- ctx1
+ val outerCtx = ctx.dup;
+
+ var bodyCtx: Context = null;
+
+ 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
+
+ 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
+
+ case Bind(name, _) =>
+ val exception = new Local(pat.symbol, toTypeKind(pat.symbol.tpe));
+ ctx.method.addLocal(exception);
+
+ val exh = ctx.newHandler(pat.symbol.tpe.symbol);
+
+ 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));
+ ctx1.bb.close;
+ exh
+
+ case _ =>
+ 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;
+
+ bodyCtx = ctx.newBlock;
+ outerCtx.bb.emit(JUMP(bodyCtx.bb), tree.pos);
+ outerCtx.bb.close;
+
+ generatedType = toTypeKind(block.tpe);
+ val ctxfinal = genLoad(block, bodyCtx, generatedType);
+ handlers.reverse foreach ctxfinal.exitHandler;
+ ctxfinal.exitFinalizer(finalHandler);
+ ctxfinal
case Throw(expr) =>
val ctx1 = genLoad(expr, ctx, THROWABLE);
@@ -1227,7 +1251,9 @@ abstract class GenICode extends SubComponent {
var defdef: DefDef = _;
/** current exception handlers */
- var handlers: List[ExceptionHandler] = NoHandler :: Nil;
+ var handlers: List[ExceptionHandler] = Nil;
+
+ var finalizers: List[Finalizer] = Nil;
var handlerCount = 0;
@@ -1238,6 +1264,8 @@ abstract class GenICode extends SubComponent {
buf.append("\tmethod: ").append(method).append('\n');
buf.append("\tbb: ").append(bb).append('\n');
buf.append("\tlabels: ").append(labels).append('\n');
+ buf.append("\texception handlers: ").append(handlers).append('\n');
+ buf.append("\tfinalizers: ").append(finalizers).append('\n');
buf.toString()
}
@@ -1251,6 +1279,7 @@ abstract class GenICode extends SubComponent {
this.labels = other.labels;
this.defdef = other.defdef;
this.handlers = other.handlers;
+ this.finalizers = other.finalizers;
this.handlerCount = other.handlerCount;
}
@@ -1288,23 +1317,54 @@ abstract class GenICode extends SubComponent {
def newBlock: Context = {
val block = method.code.newBlock;
handlers foreach (h => h addBlock block);
+ finalizers foreach (.addBlock(block));
new Context(this) setBasicBlock block;
}
- def newHandler: Context = {
+ /** Create a new exception handler and adds it in the list
+ * of current exception handlers.
+ */
+ def newHandler(cls: Symbol): ExceptionHandler = {
handlerCount = handlerCount + 1;
- val exh = new ExceptionHandler("" + handlerCount) setOuter handlers.head;
+ val exh = new ExceptionHandler(method, "" + handlerCount, cls);
+ method.addHandler(exh);
handlers = exh :: handlers;
- this
+ exh
+ }
+
+ def newFinalizer: Finalizer = {
+ handlerCount = handlerCount + 1;
+ val exh = new Finalizer(method, "" + handlerCount);
+ method.addFinalizer(exh);
+ finalizers = exh :: finalizers;
+ exh
}
- def exitHandler: Context = {
- assert(handlerCount > 0,
- "Wrong nesting of exception handlers.");
+ /** Return a new context for generating code for the given
+ * exception handler.
+ */
+ def enterHandler(exh: ExceptionHandler): Context = {
+ val ctx = newBlock;
+ exh.setStartBlock(ctx.bb);
+ ctx
+ }
+
+ def exitHandler(exh: ExceptionHandler): Unit = {
+ assert(handlerCount > 0 && handlers.head == exh,
+ "Wrong nesting of exception handlers." + this + " for " + exh);
handlerCount = handlerCount - 1;
handlers = handlers.tail;
- this
}
+
+ def exitFinalizer(f: Finalizer): Unit = {
+ assert(handlerCount > 0 && finalizers.head == f,
+ "Wrong nesting of exception handlers." + this + " for " + f);
+ handlerCount = handlerCount - 1;
+ finalizers = finalizers.tail;
+ }
+
+ /** Clone the current context */
+ def dup: Context = new Context(this);
}
/**
diff --git a/sources/scala/tools/nsc/backend/icode/Linearizers.scala b/sources/scala/tools/nsc/backend/icode/Linearizers.scala
index 44fbcceeb3..7f6e71e8ed 100644
--- a/sources/scala/tools/nsc/backend/icode/Linearizers.scala
+++ b/sources/scala/tools/nsc/backend/icode/Linearizers.scala
@@ -38,7 +38,14 @@ trait Linearizers: ICodes {
blocks.reverse;
}
+ def linearize(startBlock: BasicBlock): List[BasicBlock] = {
+ blocks = startBlock :: Nil;
+ run( { worklist.enqueue(startBlock); } );
+ blocks.reverse;
+ }
+
def processElement(b: BasicBlock) =
+ if (b.size > 0)
b.lastInstruction match {
case JUMP(where) =>
add(where);
diff --git a/sources/scala/tools/nsc/backend/icode/Members.scala b/sources/scala/tools/nsc/backend/icode/Members.scala
index c8f73ab368..3f86291909 100644
--- a/sources/scala/tools/nsc/backend/icode/Members.scala
+++ b/sources/scala/tools/nsc/backend/icode/Members.scala
@@ -85,19 +85,6 @@ trait Members: ICodes {
});
}
-// def logType = {
-// log ("// Typing " + toString());
-// traverse( (bb: BasicBlock) => {
-// log ("Typing block #" + bb.label);
-// var typer = new TypeStack;
-// bb.traverse((ic: Instruction) => {
-// typer = typer.eval(ic);
-// log(ic.toString()+" -> "+typer.toString());
-// });
-
-// });
-// }
-
/* Compute a unique new label */
def nextLabel = {
currentLabel = currentLabel + 1;
@@ -155,7 +142,8 @@ trait Members: ICodes {
*/
class IMethod(val symbol: Symbol) {
var code: Code = null;
- var exh: List[ExceptionHandler] = _;
+ var exh: List[ExceptionHandler] = Nil;
+ var finalizers: List[Finalizer] = Nil;
var sourceFile: String = _;
var returnType: TypeKind = _;
@@ -195,6 +183,9 @@ trait Members: ICodes {
def addHandler(e: ExceptionHandler): Unit =
exh = e :: exh;
+ def addFinalizer(e: Finalizer): Unit =
+ finalizers = e :: finalizers;
+
/** Is this method deferred ('abstract' in Java sense) */
def isDeferred =
symbol.hasFlag(Flags.DEFERRED) ||
diff --git a/sources/scala/tools/nsc/backend/icode/Opcodes.scala b/sources/scala/tools/nsc/backend/icode/Opcodes.scala
index 6df4813a8e..ec5fb429d4 100644
--- a/sources/scala/tools/nsc/backend/icode/Opcodes.scala
+++ b/sources/scala/tools/nsc/backend/icode/Opcodes.scala
@@ -25,6 +25,7 @@ import scala.tools.util.Position;
case STORE_FIELD(field, isStatic) =>
case CALL_PRIMITIVE(primitive) =>
case CALL_METHOD(method, style) =>
+ case CALL_FINALIZER(finalizer) =>
case NEW(kind) =>
case CREATE_ARRAY(elem) =>
case IS_INSTANCE(tpe) =>
@@ -234,6 +235,16 @@ import scala.tools.util.Position;
override def produced = 1;
}
+ case class CALL_FINALIZER(finalizer: Finalizer) extends Instruction {
+
+ override def toString(): String =
+ "CALL_FINALIZER " + finalizer;
+
+ override def consumed = 0;
+
+ override def produced = 1;
+ }
+
/** Create a new instance of a class through the specified constructor
* Stack: ...:arg1:arg2:...:argn
* ->: ...:ref
diff --git a/sources/scala/tools/nsc/backend/icode/Printers.scala b/sources/scala/tools/nsc/backend/icode/Printers.scala
index a5337c9f2c..de773b1d94 100644
--- a/sources/scala/tools/nsc/backend/icode/Printers.scala
+++ b/sources/scala/tools/nsc/backend/icode/Printers.scala
@@ -87,6 +87,12 @@ abstract class Printers {
println(" {");
printCode(m.code);
println("}");
+
+ indent;println("Exception handlers: ");
+ m.exh foreach printExceptionHandler;
+
+ m.finalizers foreach printExceptionHandler;
+ undent;println;
} else
println;
}
@@ -101,6 +107,11 @@ abstract class Printers {
linearizer.linearize(code) foreach printBlock;
}
+ def printExceptionHandler(e: ExceptionHandler) = {
+ println(" catch (" + e.cls.simpleName + ") in " + e.covered);
+ linearizer.linearize(e.startBlock) foreach printBlock;
+ }
+
def printBlock(bb: BasicBlock): Unit = {
print(bb.label); print(": "); indent; println;
bb traverse printInstruction;