summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2005-10-12 15:25:50 +0000
committerIulian Dragos <jaguarul@gmail.com>2005-10-12 15:25:50 +0000
commitf8beba52702f552d9defcc46e4f7c8f7b1ee45d7 (patch)
treef643a254dc7cc06650411397b7a2be4b43222bb9
parent6e1ef09bdc8fe635e60f4456b09415a1c1178926 (diff)
downloadscala-f8beba52702f552d9defcc46e4f7c8f7b1ee45d7.tar.gz
scala-f8beba52702f552d9defcc46e4f7c8f7b1ee45d7.tar.bz2
scala-f8beba52702f552d9defcc46e4f7c8f7b1ee45d7.zip
New version of the backend, that can compile th...
New version of the backend, that can compile the library.
-rw-r--r--sources/scala/tools/nsc/backend/ScalaPrimitives.scala3
-rw-r--r--sources/scala/tools/nsc/backend/icode/BasicBlocks.scala41
-rw-r--r--sources/scala/tools/nsc/backend/icode/Checkers.scala100
-rw-r--r--sources/scala/tools/nsc/backend/icode/GenICode.scala418
-rw-r--r--sources/scala/tools/nsc/backend/icode/Linearizers.scala2
-rw-r--r--sources/scala/tools/nsc/backend/icode/Members.scala1
-rw-r--r--sources/scala/tools/nsc/backend/icode/Opcodes.scala26
-rw-r--r--sources/scala/tools/nsc/backend/icode/Primitives.scala18
-rw-r--r--sources/scala/tools/nsc/backend/icode/TypeKinds.scala17
-rw-r--r--sources/scala/tools/nsc/backend/icode/TypeStacks.scala1
-rw-r--r--sources/scala/tools/nsc/backend/jvm/GenJVM.scala156
11 files changed, 571 insertions, 212 deletions
diff --git a/sources/scala/tools/nsc/backend/ScalaPrimitives.scala b/sources/scala/tools/nsc/backend/ScalaPrimitives.scala
index 14754a8a46..e53014c514 100644
--- a/sources/scala/tools/nsc/backend/ScalaPrimitives.scala
+++ b/sources/scala/tools/nsc/backend/ScalaPrimitives.scala
@@ -205,6 +205,7 @@ abstract class ScalaPrimitives {
// scala.Any
addPrimitive(Any_==, EQ);
+ addPrimitive(Any_!=, NE);
addPrimitive(Any_equals, EQUALS);
addPrimitive(Any_hashCode, HASHCODE);
addPrimitive(Any_toString, TOSTRING);
@@ -216,6 +217,8 @@ abstract class ScalaPrimitives {
// java.lang.Object
addPrimitive(Object_eq, ID);
addPrimitive(Object_ne, NI);
+ addPrimitive(Object_==, EQ);
+ addPrimitive(Object_!=, NE);
addPrimitive(Object_synchronized, SYNCHRONIZED);
addPrimitive(Object_isInstanceOf, IS);
addPrimitive(Object_asInstanceOf, AS);
diff --git a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
index edf2d5021b..3bee7805cc 100644
--- a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -9,6 +9,7 @@ package scala.tools.nsc.backend.icode;
import scala.tools.nsc.ast._;
import scala.collection.mutable.Map;
+import scala.tools.util.Position;
trait BasicBlocks: ICodes {
import opcodes._;
@@ -33,6 +34,9 @@ trait BasicBlocks: ICodes {
/** The stack at the end of the block */
var endStack : TypeStack = null;
+ /** When set, the 'emit' methods will be ignored. */
+ var ignore: Boolean = false;
+
var preds: List[BasicBlock] = null;
/** ICode instructions, used as temporary storage while emitting code.
@@ -121,11 +125,24 @@ trait BasicBlocks: ICodes {
}
}
- /** Add a new instruction at the end of the block */
- def emit(instr: Instruction) = {
- assert (!closed, "BasicBlock closed");
- instructionList = instr :: instructionList;
- _lastInstruction = instr;
+ /** Add a new instruction at the end of the block,
+ * using the same source position as the last emitted instruction
+ */
+ def emit(instr: Instruction): Unit = {
+ if (!instructionList.isEmpty)
+ emit(instr, instructionList.head.pos);
+ else
+ emit(instr, Position.NOPOS);
+ }
+
+ def emit(instr: Instruction, pos: Int) = {
+ assert (!closed || ignore, "BasicBlock closed");
+
+ if (!ignore) {
+ instr.pos = pos;
+ instructionList = instr :: instructionList;
+ _lastInstruction = instr;
+ }
}
/** Close the block */
@@ -136,6 +153,17 @@ trait BasicBlocks: ICodes {
instrs = toInstructionArray(instructionList.reverse);
}
+ /** Enter ignore mode: new 'emit'ted instructions will not be
+ * added to this basic block. It makes the generation of THROW
+ * and RETURNs easier.
+ */
+ def enterIgnoreMode = ignore = true;
+
+ def exitIgnoreMode = {
+ assert(ignore, "Exit ignore mode when not in ignore mode.");
+ ignore = false;
+ }
+
/** Return the last instruction of this basic block. */
def lastInstruction =
if (closed)
@@ -154,6 +182,7 @@ trait BasicBlocks: ICodes {
def isClosed = closed;
+ // TODO: Take care of exception handlers!
def successors : List[BasicBlock] = // here order will count
lastInstruction match {
case JUMP (where) => List(where);
@@ -161,6 +190,7 @@ trait BasicBlocks: ICodes {
case CZJUMP(success, failure, _, _) => failure::success::Nil;
case SWITCH(_,labels) => labels;
case RETURN(_) => Nil;
+ case THROW() => Nil;
case _ =>
global.abort("The last instruction is not a control flow instruction");
}
@@ -168,7 +198,6 @@ trait BasicBlocks: ICodes {
def predecessors: List[BasicBlock] = {
if (preds == null)
preds = code.blocks.elements.filter (p => (p.successors contains this)).toList;
-// global.log("Predecessors of " + this + ": " + preds);
preds
}
diff --git a/sources/scala/tools/nsc/backend/icode/Checkers.scala b/sources/scala/tools/nsc/backend/icode/Checkers.scala
index 2a1c802b23..4e3ae82f88 100644
--- a/sources/scala/tools/nsc/backend/icode/Checkers.scala
+++ b/sources/scala/tools/nsc/backend/icode/Checkers.scala
@@ -73,6 +73,13 @@ abstract class Checkers {
def check(c: Code): Unit = {
var worklist: Buffer[BasicBlock] = new ListBuffer();
+
+ def append(elems: List[BasicBlock]) = elems foreach appendBlock;
+ def appendBlock(bl: BasicBlock) =
+ if ( !worklist.exists(bl.==) )
+ worklist + bl;
+
+ in.clear; out.clear;
code = c;
worklist + c.startBlock;
c.blocks foreach ( bl => { in += bl -> emptyStack;
@@ -81,10 +88,11 @@ abstract class Checkers {
while (worklist.length > 0) {
val block = worklist(0); worklist.trimStart(1);
val output = check(block, in(block));
- if (output != out(block)) {
+ if (output != out(block) ||
+ (out(block) eq emptyStack)) {
log("Output changed for block: " + block.fullString);
out(block) = output;
- worklist ++ block.successors;
+ append(block.successors);
block.successors foreach meet;
}
}
@@ -99,17 +107,19 @@ abstract class Checkers {
val preds = bl.predecessors;
def meet2(s1: TypeStack, s2: TypeStack): TypeStack = {
- if (s1 == emptyStack) s2
- else if (s2 == emptyStack) s1
+ if (s1 eq emptyStack) s2
+ else if (s2 eq emptyStack) s1
else {
if (s1.length != s2.length)
- throw new CheckerError("Incompatible stacks: " + s1 + " and " + s2);
+ throw new CheckerError("Incompatible stacks: " + s1 + " and " + s2 + " in " + method + " at entry to block: " + bl);
new TypeStack(List.map2(s1.types, s2.types) (lub))
}
}
- if (preds != Nil)
+ if (preds != Nil) {
in(bl) = (preds map out.apply) reduceLeft meet2;
+ log("Input changed for block: " + bl +" to: " + in(bl));
+ }
}
@@ -122,6 +132,7 @@ abstract class Checkers {
* produced type stack.
*/
def check(b: BasicBlock, initial: TypeStack): TypeStack = {
+ log("** Checking block:\n" + b.fullString + " with initial stack:\n" + initial);
var stack = new TypeStack(initial);
this.typeStack = stack;
@@ -206,9 +217,11 @@ abstract class Checkers {
this.instruction = instr;
- log("PC: " + instr);
- log("stack: " + stack);
- log("================");
+ if (settings.debug.value) {
+ log("PC: " + instr);
+ log("stack: " + stack);
+ log("================");
+ }
instr match {
case THIS(clasz) =>
stack push toTypeKind(clasz.tpe);
@@ -242,9 +255,11 @@ abstract class Checkers {
val obj = stack.pop;
checkField(obj, field);
}
- stack.push(toTypeKind(field.info));
+ stack.push(toTypeKind(field.tpe));
case LOAD_MODULE(module) =>
+ checkBool((module.isModule || module.isModuleClass),
+ "Expected module: " + module + " flags: " + Flags.flagsToString(module.flags));
stack.push(toTypeKind(module.tpe));
case STORE_ARRAY_ITEM(kind) =>
@@ -271,7 +286,7 @@ abstract class Checkers {
case STORE_FIELD(field, isStatic) =>
if (isStatic) {
checkStack(1);
- val fieldType = toTypeKind(field.info);
+ val fieldType = toTypeKind(field.tpe);
val actualType = stack.pop;
if (!(actualType <:< fieldType))
typeError(fieldType, actualType);
@@ -280,7 +295,7 @@ abstract class Checkers {
stack.pop2 match {
case Pair(value, obj) =>
checkField(obj, field);
- val fieldType = toTypeKind(field.info);
+ val fieldType = toTypeKind(field.tpe);
if (!(value <:< fieldType))
typeError(fieldType, value);
}
@@ -343,9 +358,17 @@ abstract class Checkers {
}
stack push INT;
- case StringConcat(l, r) =>
- stack.pop2;
- stack push STRING;
+ case StartConcat =>
+ stack.push(ConcatClass);
+
+ case EndConcat =>
+ checkType(stack.pop, ConcatClass);
+ stack.push(STRING);
+
+ case StringConcat(el) =>
+ checkType(stack.pop, el);
+ checkType(stack.pop, ConcatClass);
+ stack push ConcatClass;
}
case CALL_METHOD(method, style) =>
@@ -363,7 +386,8 @@ abstract class Checkers {
"Static call to non-private method.");
checkMethodArgs(method);
checkMethod(stack.pop, method);
- stack.push(toTypeKind(method.info.resultType));
+ if (!method.isConstructor)
+ stack.push(toTypeKind(method.info.resultType));
} else {
checkStack(method.info.paramTypes.length);
checkMethodArgs(method);
@@ -395,12 +419,16 @@ abstract class Checkers {
val ref = stack.pop;
checkBool(ref.isReferenceType || ref.isArrayType,
"IS_INSTANCE on primitive type: " + ref);
+ checkBool(tpe.isReferenceType || tpe.isArrayType,
+ "IS_INSTANCE to primitive type: " + tpe);
stack.push(BOOL);
case CHECK_CAST(tpe) =>
val ref = stack.pop;
checkBool(ref.isReferenceType || ref.isArrayType,
- "IS_INSTANCE on primitive type: " + ref);
+ "CHECK_CAST on primitive type: " + ref);
+ checkBool(tpe.isReferenceType || tpe.isArrayType,
+ "CHECK_CAST to primitive type: " + tpe);
stack.push(tpe);
case SWITCH(tags, labels) =>
@@ -431,7 +459,16 @@ abstract class Checkers {
case RETURN(kind) =>
kind match {
case UNIT => ();
- case _ => checkStack(1); checkType(stack.pop, kind);
+
+ case REFERENCE(_) | ARRAY(_) =>
+ checkStack(1);
+ val top = stack.pop;
+ checkBool(top.isReferenceType || top.isArrayType,
+ "" + kind + " is a reference type, but " + top + " is not");
+ case _ =>
+ checkStack(1);
+ val top = stack.pop;
+ checkType(top, kind);
}
case THROW() =>
@@ -485,6 +522,7 @@ abstract class Checkers {
printed = printed + 1;
});
buf foreach System.out.println;
+ Console.println("at: " + clasz.cunit.position(buf.head.pos));
}
def error(msg: String, stack: TypeStack): Unit = {
@@ -497,5 +535,31 @@ abstract class Checkers {
/** Return true if k1 is a subtype of any of the following types. */
def isOneOf(k1: TypeKind, kinds: TypeKind*) =
kinds.exists( k => k1 <:< k);
+
+
+ /**
+ * Dummy TypeKind to represent the ConcatClass in a platform-independent
+ * way. For JVM it would have been a REFERENCE to 'StringBuffer'.
+ */
+ case object ConcatClass extends TypeKind {
+ override def toString() = "ConcatClass";
+
+ /**
+ * Approximate `lub'. The common type of two references is
+ * always AnyRef. For 'real' least upper bound wrt to subclassing
+ * use method 'lub'.
+ */
+ override def maxType(other: TypeKind): TypeKind =
+ other match {
+ case REFERENCE(_) => REFERENCE(definitions.AnyRefClass);
+ case _ =>
+ abort("Uncomparbale type kinds: ConcatClass with " + other);
+ }
+
+ /** Checks subtyping relationship. */
+ override def <:<(other: TypeKind): Boolean = (this eq other);
+
+ override def isReferenceType: Boolean = false;
+ }
}
}
diff --git a/sources/scala/tools/nsc/backend/icode/GenICode.scala b/sources/scala/tools/nsc/backend/icode/GenICode.scala
index 68ac59d21b..e170dfd5e7 100644
--- a/sources/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/sources/scala/tools/nsc/backend/icode/GenICode.scala
@@ -13,7 +13,6 @@ import scala.tools.nsc.symtab._;
/**
* TODO:
- * - record line number info
* - exception handling
* - synchronized blocks should add exception handlers that guarantee
* monitor releases in case of exceptions (like Java)?
@@ -96,7 +95,9 @@ abstract class GenICode extends SubComponent {
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
log("Entering method " + name);
val m = new IMethod(tree.symbol);
+ m.sourceFile = unit.source.toString();
ctx.clazz.addMethod(m);
+
var ctx1 = ctx.enterMethod(m, tree.asInstanceOf[DefDef]);
addMethodParams(ctx1, vparamss);
val resTpe = if (tree.symbol.isConstructor) UNIT
@@ -111,7 +112,7 @@ abstract class GenICode extends SubComponent {
rhs match {
case Block(_, Return(_)) => ();
case Return(_) => ();
- case _ => ctx1.bb.emit(RETURN(resTpe));
+ case _ => ctx1.bb.emit(RETURN(resTpe), tree.pos);
}
ctx1.bb.close;
} else
@@ -167,26 +168,26 @@ abstract class GenICode extends SubComponent {
case Assign(lhs @ Select(_, _), rhs) =>
if (isStaticSymbol(lhs.symbol)) {
val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info));
- ctx1.bb.emit(STORE_FIELD(lhs.symbol, true));
+ ctx1.bb.emit(STORE_FIELD(lhs.symbol, true), tree.pos);
ctx1
} else {
var ctx1 = genLoadQualifier(lhs, ctx);
ctx1 = genLoad(rhs, ctx1, toTypeKind(lhs.symbol.info));
- ctx1.bb.emit(STORE_FIELD(lhs.symbol, false));
+ ctx1.bb.emit(STORE_FIELD(lhs.symbol, false), tree.pos);
ctx1
}
- case Assign(lhs, rhs) =>
+ case Assign(lhs, rhs) =>
// assert(ctx.method.locals.contains(lhs.symbol) | ctx.clazz.fields.contains(lhs.symbol),
// "Assignment to inexistent local or field: " + lhs.symbol);
- val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info));
- val Some(l) = ctx.method.lookupLocal(lhs.symbol);
- ctx1.bb.emit(STORE_LOCAL(l, lhs.symbol.isValueParameter));
- ctx1
+ val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info));
+ val Some(l) = ctx.method.lookupLocal(lhs.symbol);
+ ctx1.bb.emit(STORE_LOCAL(l, lhs.symbol.isValueParameter), tree.pos);
+ ctx1
- case _ =>
- log("Passing " + tree + " to genLoad");
- genLoad(tree, ctx, UNIT);
+ case _ =>
+ log("Passing " + tree + " to genLoad");
+ genLoad(tree, ctx, UNIT);
}
/**
@@ -221,8 +222,8 @@ abstract class GenICode extends SubComponent {
ctx1 = genLoad(larg, ctx1, resKind);
code match {
case scalaPrimitives.POS => (); // nothing
- case scalaPrimitives.NEG => ctx1.bb.emit(CALL_PRIMITIVE(Negation(resKind)));
- case scalaPrimitives.NOT => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(NOT, resKind)));
+ case scalaPrimitives.NEG => ctx1.bb.emit(CALL_PRIMITIVE(Negation(resKind)), tree.pos);
+ case scalaPrimitives.NOT => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(NOT, resKind)), tree.pos);
case _ => abort("Unknown unary operation: " + fun.symbol.fullNameString + " code: " + code);
}
generatedType = resKind;
@@ -241,19 +242,19 @@ abstract class GenICode extends SubComponent {
generatedType = resKind;
code match {
- case scalaPrimitives.ADD => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(ADD, resKind)));
- case scalaPrimitives.SUB => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(SUB, resKind)));
- case scalaPrimitives.MUL => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(MUL, resKind)));
- case scalaPrimitives.DIV => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(DIV, resKind)));
- case scalaPrimitives.MOD => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(REM, resKind)));
- case scalaPrimitives.OR => ctx1.bb.emit(CALL_PRIMITIVE(Logical(OR, resKind)));
- case scalaPrimitives.XOR => ctx1.bb.emit(CALL_PRIMITIVE(Logical(XOR, resKind)));
- case scalaPrimitives.AND => ctx1.bb.emit(CALL_PRIMITIVE(Logical(AND, resKind)));
- case scalaPrimitives.LSL => ctx1.bb.emit(CALL_PRIMITIVE(Shift(LSL, resKind)));
+ case scalaPrimitives.ADD => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(ADD, resKind)), tree.pos);
+ case scalaPrimitives.SUB => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(SUB, resKind)), tree.pos);
+ case scalaPrimitives.MUL => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(MUL, resKind)), tree.pos);
+ case scalaPrimitives.DIV => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(DIV, resKind)), tree.pos);
+ case scalaPrimitives.MOD => ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(REM, resKind)), tree.pos);
+ case scalaPrimitives.OR => ctx1.bb.emit(CALL_PRIMITIVE(Logical(OR, resKind)), tree.pos);
+ case scalaPrimitives.XOR => ctx1.bb.emit(CALL_PRIMITIVE(Logical(XOR, resKind)), tree.pos);
+ case scalaPrimitives.AND => ctx1.bb.emit(CALL_PRIMITIVE(Logical(AND, resKind)), tree.pos);
+ case scalaPrimitives.LSL => ctx1.bb.emit(CALL_PRIMITIVE(Shift(LSL, resKind)), tree.pos);
generatedType = resKind;
- case scalaPrimitives.LSR => ctx1.bb.emit(CALL_PRIMITIVE(Shift(LSR, resKind)));
+ case scalaPrimitives.LSR => ctx1.bb.emit(CALL_PRIMITIVE(Shift(LSR, resKind)), tree.pos);
generatedType = resKind;
- case scalaPrimitives.ASR => ctx1.bb.emit(CALL_PRIMITIVE(Shift(ASR, resKind)));
+ case scalaPrimitives.ASR => ctx1.bb.emit(CALL_PRIMITIVE(Shift(ASR, resKind)), tree.pos);
generatedType = resKind;
case _ => abort("Unknown primitive: " + fun.symbol + "[" + code + "]");
}
@@ -283,61 +284,61 @@ abstract class GenICode extends SubComponent {
code match {
case ZARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(BOOL)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(BOOL)), tree.pos);
case BARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(BYTE)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(BYTE)), tree.pos);
case SARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(SHORT)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(SHORT)), tree.pos);
case CARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(CHAR)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(CHAR)), tree.pos);
case IARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(INT)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(INT)), tree.pos);
case LARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(LONG)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(LONG)), tree.pos);
case FARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(FLOAT)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(FLOAT)), tree.pos);
case DARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(DOUBLE)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(DOUBLE)), tree.pos);
case OARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(ANY_REF_CLASS)));
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(ANY_REF_CLASS)), tree.pos);
case ZARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(BOOL));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(BOOL), tree.pos);
case BARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(BYTE));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(BYTE), tree.pos);
case SARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(SHORT));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(SHORT), tree.pos);
case CARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(CHAR));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(CHAR), tree.pos);
case IARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(INT));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(INT), tree.pos);
case LARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(LONG));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(LONG), tree.pos);
case FARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(FLOAT));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(FLOAT), tree.pos);
case DARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(DOUBLE));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(DOUBLE), tree.pos);
case OARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(ANY_REF_CLASS));
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(ANY_REF_CLASS), tree.pos);
case ZARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(BOOL));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(BOOL), tree.pos);
case BARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(BYTE));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(BYTE), tree.pos);
case SARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(SHORT));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(SHORT), tree.pos);
case CARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(CHAR));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(CHAR), tree.pos);
case IARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(INT));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(INT), tree.pos);
case LARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(LONG));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(LONG), tree.pos);
case FARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(FLOAT));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(FLOAT), tree.pos);
case DARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(DOUBLE));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(DOUBLE), tree.pos);
case OARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(ANY_REF_CLASS));
+ ctx1.bb.emit(STORE_ARRAY_ITEM(ANY_REF_CLASS), tree.pos);
case _ =>
abort("Unknown operation on arrays: " + tree + " code: " + code);
@@ -357,19 +358,24 @@ abstract class GenICode extends SubComponent {
ctx1.labels += tree.symbol -> (new Label(tree.symbol) anchor ctx1.bb setParams (params map (.symbol)));
log("Adding label " + tree.symbol);
}
- ctx.bb.emit(JUMP(ctx1.bb));
+ ctx.bb.emit(JUMP(ctx1.bb), tree.pos);
ctx.bb.close;
genLoad(rhs, ctx1, toTypeKind(tree.symbol.info.resultType));
case ValDef(_, _, _, rhs) =>
- if (rhs == EmptyTree)
- log("Uninitialized variable " + tree + " at: " + unit.position(tree.pos));
+ var initialValue = rhs;
val sym = tree.symbol;
val local = new Local(sym, toTypeKind(sym.info));
ctx.method.addLocal(local);
- val ctx1 = genLoad(rhs, ctx, local.kind);
- if (rhs != EmptyTree)
- ctx1.bb.emit(STORE_LOCAL(local, false));
+
+ if (rhs == EmptyTree) {
+ log("Uninitialized variable " + tree + " at: " + unit.position(tree.pos));
+ initialValue = zeroOf(local.kind);
+ }
+
+ val ctx1 = genLoad(initialValue, ctx, local.kind);
+// if (rhs != EmptyTree)
+ ctx1.bb.emit(STORE_LOCAL(local, false), tree.pos);
generatedType = UNIT;
ctx1
@@ -380,24 +386,45 @@ abstract class GenICode extends SubComponent {
genCond(cond, ctx, thenCtx, elseCtx);
val ifKind = toTypeKind(tree.tpe);
- thenCtx = genLoad(thenp, thenCtx, ifKind);
- elseCtx = genLoad(elsep, elseCtx, ifKind);
- thenCtx.bb.emit(JUMP(contCtx.bb));
+ val thenKind = toTypeKind(thenp.tpe);
+ val elseKind = if (elsep == EmptyTree) UNIT else toTypeKind(elsep.tpe);
+
+ generatedType = ifKind;
+
+ // we need to drop unneeded results, if one branch gives
+ // unit and the other gives something on the stack, because
+ // the type of 'if' is scala.Any, and its erasure would be Object.
+ // But unboxed units are not Objects...
+ if (thenKind == UNIT || elseKind == UNIT) {
+ log("Will drop result from an if branch");
+ thenCtx = genLoad(thenp, thenCtx, UNIT);
+ elseCtx = genLoad(elsep, elseCtx, UNIT);
+ assert(expectedType == UNIT, "I produce UNIT in a context where " + expectedType + " is expected!");
+ generatedType = UNIT;
+ } else {
+ thenCtx = genLoad(thenp, thenCtx, ifKind);
+ elseCtx = genLoad(elsep, elseCtx, ifKind);
+ }
+
+ thenCtx.bb.emit(JUMP(contCtx.bb), thenp.pos);
thenCtx.bb.close;
- elseCtx.bb.emit(JUMP(contCtx.bb));
+ elseCtx.bb.emit(JUMP(contCtx.bb), elsep.pos);
elseCtx.bb.close;
contCtx;
case Return(expr) =>
- val ctx1 = genLoad(expr, ctx, expectedType);
- ctx1.bb.emit(RETURN(expectedType));
+ val returnedKind = toTypeKind(expr.tpe);
+ 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));
+ ctx.bb.emit(JUMP(ctx1.bb), tree.pos);
ctx.bb.close;
val currentHandler = ctx.handlers.head;
ctx1 = genLoad(block, ctx1, toTypeKind(block.tpe));
@@ -409,7 +436,8 @@ abstract class GenICode extends SubComponent {
case Throw(expr) =>
val ctx1 = genLoad(expr, ctx, THROWABLE);
- ctx1.bb.emit(THROW());
+ ctx1.bb.emit(THROW(), tree.pos);
+ ctx1.bb.enterIgnoreMode;
generatedType = SCALA_ALL;
ctx1;
@@ -418,54 +446,85 @@ abstract class GenICode extends SubComponent {
case Apply(TypeApply(fun, targs), _) =>
val sym = fun.symbol;
- val ctx1 = genLoadQualifier(fun, ctx);
-
- if (sym == definitions.Object_isInstanceOf) {
- ctx1.bb.emit(IS_INSTANCE(toTypeKind(targs.head.tpe)));
- generatedType = BOOL;
- } else if (sym == definitions.Object_asInstanceOf) {
- ctx1.bb.emit(CHECK_CAST(toTypeKind(targs.head.tpe)));
- generatedType = toTypeKind(targs.head.tpe);
- } else
+ var ctx1 = ctx;
+ var cast = false;
+
+ if (sym == definitions.Object_isInstanceOf)
+ cast = false
+ else if (sym == definitions.Object_asInstanceOf)
+ cast = true
+ else
abort("Unexpected type application " + fun + "[sym: " + sym + "]");
+
+ val Select(obj, _) = fun;
+ val l = toTypeKind(obj.tpe);
+ val r = toTypeKind(targs.head.tpe);
+
+ ctx1 = genLoadQualifier(fun, ctx);
+
+ if (l.isValueType && r.isValueType)
+ genConversion(l, r, ctx1, cast)
+ else if (l.isValueType) {
+ ctx1.bb.emit(DROP(l), fun.pos);
+ ctx1.bb.emit(CONSTANT(Constant(false)))
+ }
+ else if (r.isValueType)
+ genBoxedConversion(l, r, ctx1, cast)
+ else
+ genCast(l, r, ctx1, cast);
+
+ generatedType = if (cast) r else BOOL;
ctx1
- // super call
+ // 'super' call: Note: since constructors are supposed to
+ // return an instance of what they construct, we have to take
+ // special care. On JVM they are 'void', and Scala forbids (syntactically)
+ // to call super constructors explicitly and/or use their 'returned' value.
+ // therefore, we can ignore this fact, and generate code that leaves nothing
+ // on the stack (contrary to what the type in the AST says).
case Apply(fun @ Select(Super(_, mixin), _), args) =>
log("Call to super: " + tree);
val invokeStyle =
if (fun.symbol.isConstructor) Static(true) else SuperCall(mixin);
- ctx.bb.emit(THIS(ctx.clazz.symbol));
+ ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos);
val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx);
- ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle));
- generatedType = toTypeKind(fun.symbol.info.resultType);
+ ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle), tree.pos);
+ generatedType = if (fun.symbol.isConstructor)
+ UNIT
+ else
+ toTypeKind(fun.symbol.info.resultType);
ctx1
- // 'new' constructor call
+ // 'new' constructor call: Note: since constructors are
+ // thought to return an instance of what they construct,
+ // we have to 'simulate' it by DUPlicating the freshly created
+ // instance (on JVM, <init> methods return VOID).
case Apply(fun @ Select(New(tpt), nme.CONSTRUCTOR), args) =>
val ctor = fun.symbol;
assert(ctor.isClassConstructor,
"'new' call to non-constructor: " + tree);
generatedType = toTypeKind(tpt.tpe);
- assert(generatedType.isReferenceType || generatedType.isArrayType, "Non reference type cannot be instantiated: " + generatedType);
+ assert(generatedType.isReferenceType || generatedType.isArrayType,
+ "Non reference type cannot be instantiated: " + generatedType);
var ctx1 = ctx;
generatedType match {
case ARRAY(elem) =>
ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx);
- ctx1.bb.emit(CREATE_ARRAY(elem));
+ ctx1.bb.emit(CREATE_ARRAY(elem), tree.pos);
case REFERENCE(cls) =>
assert(ctor.owner == cls,
"Symbol " + ctor.owner.fullNameString + "is different than " + tpt);
- ctx.bb.emit(NEW(generatedType));
+ ctx1.bb.emit(NEW(generatedType), tree.pos);
+ ctx1.bb.emit(DUP(generatedType));
ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx);
- ctx1.bb.emit(CALL_METHOD(ctor, Static(true)));
+ ctx1.bb.emit(CALL_METHOD(ctor, Static(true)), tree.pos);
case _ =>
abort("Cannot instantiate " + tpt + "of kind: " + generatedType);
@@ -490,9 +549,9 @@ abstract class GenICode extends SubComponent {
}
val ctx1 = genLoadLabelArguments(args, label, ctx);
if (label.anchored)
- ctx1.bb.emit(JUMP(label.block));
+ ctx1.bb.emit(JUMP(label.block), tree.pos);
else
- ctx1.bb.emit(PJUMP(label));
+ ctx1.bb.emit(PJUMP(label), tree.pos);
ctx1.bb.close;
ctx1.newBlock;
@@ -517,19 +576,20 @@ abstract class GenICode extends SubComponent {
val afterCtx = ctx1.newBlock;
log("Passing " + tree + " to genCond");
genCond(tree, ctx1, trueCtx, falseCtx);
- trueCtx.bb.emit(CONSTANT(Constant(true)));
+ trueCtx.bb.emit(CONSTANT(Constant(true)), tree.pos);
trueCtx.bb.emit(JUMP(afterCtx.bb));
trueCtx.bb.close;
- falseCtx.bb.emit(CONSTANT(Constant(false)));
+ falseCtx.bb.emit(CONSTANT(Constant(false)), tree.pos);
falseCtx.bb.emit(JUMP(afterCtx.bb));
falseCtx.bb.close;
+ generatedType = BOOL;
ctx1 = afterCtx;
} else if (code == scalaPrimitives.SYNCHRONIZED) {
ctx1 = genLoadQualifier(fun, ctx1);
- ctx1.bb.emit(MONITOR_ENTER());
+ 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());
+ ctx1.bb.emit(MONITOR_EXIT(), tree.pos);
} else if (scalaPrimitives.isCoercion(code)) {
ctx1 = genLoad(receiver, ctx1, toTypeKind(receiver.tpe));
genCoercion(tree, ctx1, code);
@@ -555,7 +615,7 @@ abstract class GenICode extends SubComponent {
ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx1);
- ctx1.bb.emit(CALL_METHOD(sym, invokeStyle));
+ ctx1.bb.emit(CALL_METHOD(sym, invokeStyle), tree.pos);
generatedType = toTypeKind(sym.info.resultType);
ctx1
}
@@ -566,10 +626,10 @@ abstract class GenICode extends SubComponent {
"tree.symbol = " + tree.symbol + ", ctx.clazz.symbol = " + ctx.clazz.symbol);
if (tree.symbol.isModuleClass && tree.symbol != ctx.clazz.symbol) {
log("LOAD_MODULE from 'This'");
- ctx.bb.emit(LOAD_MODULE(tree.symbol));
+ ctx.bb.emit(LOAD_MODULE(tree.symbol), tree.pos);
generatedType = REFERENCE(tree.symbol);
} else {
- ctx.bb.emit(THIS(ctx.clazz.symbol));
+ ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos);
generatedType = REFERENCE(ctx.clazz.symbol);
}
ctx;
@@ -580,23 +640,23 @@ abstract class GenICode extends SubComponent {
" sym: " + tree.symbol +
" at: " + unit.position(tree.pos));
log("LOAD_MODULE from Select(<emptypackage>)");
- ctx.bb.emit(LOAD_MODULE(tree.symbol));
+ ctx.bb.emit(LOAD_MODULE(tree.symbol), tree.pos);
ctx
case Select(qualifier, selector) =>
val sym = tree.symbol;
- val generatedType = toTypeKind(sym.info);
+ generatedType = toTypeKind(sym.info);
if (sym.isModule) {
log("LOAD_MODULE from Select(qualifier, selector)");
- ctx.bb.emit(LOAD_MODULE(sym));
+ ctx.bb.emit(LOAD_MODULE(sym), tree.pos);
ctx
} else if (isStaticSymbol(sym)) {
- ctx.bb.emit(LOAD_FIELD(sym, true));
+ ctx.bb.emit(LOAD_FIELD(sym, true), tree.pos);
ctx
} else {
val ctx1 = genLoadQualifier(tree, ctx);
- ctx1.bb.emit(LOAD_FIELD(sym, false));
+ ctx1.bb.emit(LOAD_FIELD(sym, false), tree.pos);
ctx1
}
@@ -604,11 +664,11 @@ abstract class GenICode extends SubComponent {
if (!tree.symbol.isPackage) {
if (tree.symbol.isModule) {
log("LOAD_MODULE from Ident(name)");
- ctx.bb.emit(LOAD_MODULE(tree.symbol));
+ ctx.bb.emit(LOAD_MODULE(tree.symbol), tree.pos);
generatedType = toTypeKind(tree.symbol.info);
} else {
val Some(l) = ctx.method.lookupLocal(tree.symbol);
- ctx.bb.emit(LOAD_LOCAL(l, tree.symbol.isValueParameter));
+ ctx.bb.emit(LOAD_LOCAL(l, tree.symbol.isValueParameter), tree.pos);
generatedType = l.kind;
}
}
@@ -616,7 +676,7 @@ abstract class GenICode extends SubComponent {
case Literal(value) =>
if (value.tag != UnitTag)
- ctx.bb.emit(CONSTANT(value));
+ ctx.bb.emit(CONSTANT(value), tree.pos);
generatedType = toTypeKind(value.tpe);
ctx
@@ -638,12 +698,12 @@ abstract class GenICode extends SubComponent {
val elmKind = toTypeKind(tpt.tpe);
generatedType = ARRAY(elmKind);
- ctx1.bb.emit(CONSTANT(new Constant(elems.length)));
+ ctx1.bb.emit(CONSTANT(new Constant(elems.length)), tree.pos);
ctx1.bb.emit(CREATE_ARRAY(elmKind));
// inline array literals
var i = 0;
while (i < elems.length) {
- ctx.bb.emit(DUP(generatedType));
+ ctx1.bb.emit(DUP(generatedType), tree.pos);
ctx1.bb.emit(CONSTANT(new Constant(i)));
ctx1 = genLoad(elems(i), ctx1, elmKind);
ctx1.bb.emit(STORE_ARRAY_ITEM(elmKind));
@@ -670,7 +730,7 @@ abstract class GenICode extends SubComponent {
targets = tmpCtx.bb :: targets;
caseCtx = genLoad(body, tmpCtx , kind);
- caseCtx.bb.emit(JUMP(afterCtx.bb));
+ caseCtx.bb.emit(JUMP(afterCtx.bb), caze.pos);
caseCtx.bb.close;
case CaseDef(Ident(nme.WILDCARD), EmptyTree, body) =>
@@ -678,14 +738,14 @@ abstract class GenICode extends SubComponent {
default = tmpCtx.bb;
caseCtx = genLoad(body, tmpCtx , kind);
- caseCtx.bb.emit(JUMP(afterCtx.bb));
+ caseCtx.bb.emit(JUMP(afterCtx.bb), caze.pos);
caseCtx.bb.close;
case _ => abort("Invalid case statement in switch-like pattern match: " +
tree + " at: " + unit.position(tree.pos));
}
ctx1.bb.emit(SWITCH(tags.reverse map (x => List(x)),
- (default :: targets).reverse));
+ (default :: targets).reverse), tree.pos);
ctx1.bb.close;
afterCtx
@@ -697,10 +757,17 @@ abstract class GenICode extends SubComponent {
// emit conversion
if (!(generatedType <:< expectedType)) {
expectedType match {
- case UNIT => resCtx.bb.emit(DROP(generatedType));
- case _ => resCtx.bb.emit(CALL_PRIMITIVE(Conversion(generatedType, expectedType)));
+ case UNIT =>
+ resCtx.bb.emit(DROP(generatedType), tree.pos);
+ log("Dropped an " + generatedType);
+
+ case _ =>
+ assert(generatedType != UNIT, "Can't convert from UNIT to " + expectedType);
+ resCtx.bb.emit(CALL_PRIMITIVE(Conversion(generatedType, expectedType)), tree.pos);
}
- }
+ } else if (generatedType == SCALA_ALL && expectedType == UNIT)
+ resCtx.bb.emit(DROP(generatedType));
+
resCtx;
}
@@ -730,7 +797,7 @@ abstract class GenICode extends SubComponent {
while (arg != Nil) {
val Some(l) = ctx.method.lookupLocal(param.head);
ctx1 = genLoad(arg.head, ctx1, l.kind);
- ctx1.bb.emit(STORE_LOCAL(l, param.head.isValueParameter));
+ ctx1.bb.emit(STORE_LOCAL(l, param.head.isValueParameter), arg.head.pos);
arg = arg.tail;
param = param.tail;
}
@@ -751,6 +818,46 @@ abstract class GenICode extends SubComponent {
ctx1
}
+ def genConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = {
+ if (cast)
+ ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to)));
+ else {
+ ctx.bb.emit(DROP(from));
+ ctx.bb.emit(CONSTANT(Constant(from == to)));
+ }
+ }
+
+ def genBoxedConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = {
+ assert(to.isValueType, "Expecting conversion to value type: " + to);
+ val boxedCls = definitions.boxedClass(to.toType.symbol);
+ if (cast) {
+ ctx.bb.emit(CHECK_CAST(REFERENCE(boxedCls)));
+ ctx.bb.emit(LOAD_FIELD(definitions.getMember(boxedCls, "value"), false));
+ } else
+ ctx.bb.emit(IS_INSTANCE(REFERENCE(boxedCls)));
+ }
+
+ def genCast(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = {
+ if (cast)
+ ctx.bb.emit(CHECK_CAST(to));
+ else
+ ctx.bb.emit(IS_INSTANCE(to));
+ }
+
+ def zeroOf(k: TypeKind): Tree = k match {
+ case UNIT => Literal(());
+ case BOOL => Literal(false);
+ case BYTE => Literal(0: Byte);
+ case SHORT => Literal(0: Short);
+ case CHAR => Literal(0: Char);
+ case INT => Literal(0: Int);
+ case LONG => Literal(0: Long);
+ case FLOAT => Literal(0.0f);
+ case DOUBLE => Literal(0.0d);
+ case REFERENCE(cls) => Literal(null: Any);
+ case ARRAY(elem) => Literal(null: Any);
+ }
+
/** Is the given symbol a primitive operation? */
def isPrimitive(fun: Symbol): Boolean = {
import scalaPrimitives._;
@@ -767,30 +874,30 @@ abstract class GenICode extends SubComponent {
def genCoercion(tree: Tree, ctx: Context, code: Int) = {
import scalaPrimitives._;
code match {
- case B2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, SHORT)));
- case B2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, INT)));
- case B2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, LONG)));
- case B2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, FLOAT)));
- case B2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, DOUBLE)));
+ case B2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, SHORT)), tree.pos);
+ case B2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, INT)), tree.pos);
+ case B2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, LONG)), tree.pos);
+ case B2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, FLOAT)), tree.pos);
+ case B2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, DOUBLE)), tree.pos);
- case S2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, INT)));
- case S2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, LONG)));
- case S2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, FLOAT)));
- case S2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, DOUBLE)));
+ case S2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, INT)), tree.pos);
+ case S2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, LONG)), tree.pos);
+ case S2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, FLOAT)), tree.pos);
+ case S2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(SHORT, DOUBLE)), tree.pos);
- case C2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, INT)));
- case C2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, LONG)));
- case C2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, FLOAT)));
- case C2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, DOUBLE)));
+ case C2I => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, INT)), tree.pos);
+ case C2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, LONG)), tree.pos);
+ case C2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, FLOAT)), tree.pos);
+ case C2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(CHAR, DOUBLE)), tree.pos);
- case I2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, LONG)));
- case I2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, FLOAT)));
- case I2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, DOUBLE)));
+ case I2L => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, LONG)), tree.pos);
+ case I2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, FLOAT)), tree.pos);
+ case I2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(INT, DOUBLE)), tree.pos);
- case L2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, FLOAT)));
- case L2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, DOUBLE)));
+ case L2F => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, FLOAT)), tree.pos);
+ case L2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(LONG, DOUBLE)), tree.pos);
- case F2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(FLOAT, DOUBLE)));
+ case F2D => ctx.bb.emit(CALL_PRIMITIVE(Conversion(FLOAT, DOUBLE)), tree.pos);
case _ => abort("Unknown coercion primitive: " + code);
}
@@ -804,17 +911,38 @@ abstract class GenICode extends SubComponent {
assert(rarg.length == 1,
"Too many parameters for string concatenation");
- val lKind = toTypeKind(larg.tpe);
- val rKind = toTypeKind(rarg.head.tpe);
+ val concatenations = liftStringConcat(tree);
+ log("Lifted string concatenations for " + tree + "\n to: " + concatenations);
- ctx1 = genLoad(larg, ctx1, lKind);
- ctx1 = genLoad(rarg.head, ctx1, rKind);
- ctx1.bb.emit(CALL_PRIMITIVE(StringConcat(lKind, rKind)));
+ ctx1.bb.emit(CALL_PRIMITIVE(StartConcat), tree.pos);
+ for (val elem <- concatenations) {
+ val kind = toTypeKind(elem.tpe);
+ ctx1 = genLoad(elem, ctx1, kind);
+ ctx1.bb.emit(CALL_PRIMITIVE(StringConcat(kind)), elem.pos);
+ }
+ ctx1.bb.emit(CALL_PRIMITIVE(EndConcat), tree.pos);
ctx1;
}
/**
+ * Returns a list of trees that each should be concatenated, from
+ * left to right. It turns a chained call like "a".+("b").+("c") into
+ * a list of arguments.
+ */
+ def liftStringConcat(tree: Tree): List[Tree] = tree match {
+ case Apply(fun @ Select(larg, method), rarg) =>
+ if (isPrimitive(fun.symbol) &&
+ scalaPrimitives.getPrimitive(fun.symbol) == scalaPrimitives.CONCAT)
+ liftStringConcat(larg) ::: rarg
+ else
+ List(tree);
+ case _ =>
+ List(tree);
+ }
+
+
+ /**
* Traverse the tree and store label stubs in the contxt. This is
* necessary to handle forward jumps, because at a label application
* with arguments, the symbols of the corresponding LabelDef parameters
@@ -864,7 +992,7 @@ abstract class GenICode extends SubComponent {
val kind = getMaxType(l.tpe :: r.tpe :: Nil);
var ctx1 = genLoad(l, ctx, kind);
ctx1 = genLoad(r, ctx1, kind);
- ctx1.bb.emit(CJUMP(thenCtx.bb, elseCtx.bb, op, kind));
+ ctx1.bb.emit(CJUMP(thenCtx.bb, elseCtx.bb, op, kind), r.pos);
ctx1.bb.close;
}
@@ -883,8 +1011,12 @@ abstract class GenICode extends SubComponent {
} else if ((code == scalaPrimitives.EQ ||
code == scalaPrimitives.NE)) {
val Select(leftArg, _) = fun;
- if (toTypeKind(leftArg.tpe).isReferenceType)
- genEqEqPrimitive(leftArg, args.head, ctx, thenCtx, elseCtx);
+ if (toTypeKind(leftArg.tpe).isReferenceType) {
+ if (code == scalaPrimitives.EQ)
+ genEqEqPrimitive(leftArg, args.head, ctx, thenCtx, elseCtx);
+ else
+ genEqEqPrimitive(leftArg, args.head, ctx, elseCtx, thenCtx);
+ }
else
genComparisonOp(leftArg, args.head, code);
} else if (scalaPrimitives.isComparisonOp(code)) {
@@ -908,14 +1040,14 @@ abstract class GenICode extends SubComponent {
case _ =>
var ctx1 = genLoad(tree, ctx, BOOL);
- ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL));
+ ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL), tree.pos);
ctx1.bb.close;
}
}
case _ =>
var ctx1 = genLoad(tree, ctx, BOOL);
- ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL));
+ ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL), tree.pos);
ctx1.bb.close;
}
}
@@ -932,7 +1064,7 @@ abstract class GenICode extends SubComponent {
var eqEqTempLocal: Local = null;
ctx.method.lookupLocal(eqEqTemp) match {
- case Some(local) => eqEqTempVar = local.sym;
+ case Some(local) => eqEqTempVar = local.sym; eqEqTempLocal = local;
case None =>
eqEqTempVar = ctx.method.symbol.newVariable(l.pos, eqEqTemp);
eqEqTempVar.setInfo(definitions.AnyRefClass.typeConstructor);
@@ -944,17 +1076,17 @@ abstract class GenICode extends SubComponent {
ctx1 = genLoad(r, ctx1, ANY_REF_CLASS);
val tmpNullCtx = ctx1.newBlock;
val tmpNonNullCtx = ctx1.newBlock;
- ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal, false));
+ ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal, false), l.pos);
ctx1.bb.emit(DUP(ANY_REF_CLASS));
ctx1.bb.emit(CZJUMP(tmpNullCtx.bb, tmpNonNullCtx.bb, EQ, ANY_REF_CLASS));
ctx1.bb.close;
- tmpNullCtx.bb.emit(DROP(ANY_REF_CLASS)); // type of AnyRef
+ tmpNullCtx.bb.emit(DROP(ANY_REF_CLASS), l.pos); // type of AnyRef
tmpNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal, false));
tmpNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS));
tmpNullCtx.bb.close;
- tmpNonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal, false));
+ tmpNonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal, false), l.pos);
tmpNonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic));
tmpNonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL));
tmpNonNullCtx.bb.close;
diff --git a/sources/scala/tools/nsc/backend/icode/Linearizers.scala b/sources/scala/tools/nsc/backend/icode/Linearizers.scala
index 8727f1b95b..44fbcceeb3 100644
--- a/sources/scala/tools/nsc/backend/icode/Linearizers.scala
+++ b/sources/scala/tools/nsc/backend/icode/Linearizers.scala
@@ -52,6 +52,8 @@ trait Linearizers: ICodes {
add(labels);
case RETURN(_) =>
()
+ case THROW() =>
+ ()
}
/**
diff --git a/sources/scala/tools/nsc/backend/icode/Members.scala b/sources/scala/tools/nsc/backend/icode/Members.scala
index 3d8798d0f9..14995a671d 100644
--- a/sources/scala/tools/nsc/backend/icode/Members.scala
+++ b/sources/scala/tools/nsc/backend/icode/Members.scala
@@ -156,6 +156,7 @@ trait Members: ICodes {
class IMethod(val symbol: Symbol) {
var code: Code = null;
var exh: List[ExceptionHandler] = _;
+ var sourceFile: String = _;
/** local variables and method parameters */
var locals: List[Local] = Nil;
diff --git a/sources/scala/tools/nsc/backend/icode/Opcodes.scala b/sources/scala/tools/nsc/backend/icode/Opcodes.scala
index f0fbf05959..6df4813a8e 100644
--- a/sources/scala/tools/nsc/backend/icode/Opcodes.scala
+++ b/sources/scala/tools/nsc/backend/icode/Opcodes.scala
@@ -9,6 +9,7 @@
package scala.tools.nsc.backend.icode;
import scala.tools.nsc.ast._;
+import scala.tools.util.Position;
/*
A pattern match
@@ -63,6 +64,9 @@ import scala.tools.nsc.ast._;
/** This method returns the difference of size of the stack when the instruction is used */
def difference = produced-consumed;
+
+ /** The corresponding position in the source file */
+ var pos: Int = Position.NOPOS;
}
object opcodes {
@@ -186,16 +190,18 @@ import scala.tools.nsc.ast._;
override def toString(): String ="CALL_PRIMITIVE "+primitive.toString();
override def consumed = primitive match {
- case (Negation(_)) => 1;
- case (Test(_,_,true)) => 1;
- case (Test(_,_,false)) => 2;
- case (Comparison(_,_)) => 2;
- case (Arithmetic(_,_)) => 2;
- case (Logical(_,_)) => 2;
- case (Shift(_,_)) => 2;
- case (Conversion(_,_)) => 1;
- case (ArrayLength(_)) => 1;
- case (StringConcat(_,_)) => 2;
+ case Negation(_) => 1;
+ case Test(_,_,true) => 1;
+ case Test(_,_,false) => 2;
+ case Comparison(_,_) => 2;
+ case Arithmetic(_,_) => 2;
+ case Logical(_,_) => 2;
+ case Shift(_,_) => 2;
+ case Conversion(_,_) => 1;
+ case ArrayLength(_) => 1;
+ case StringConcat(_) => 2;
+ case StartConcat => 0;
+ case EndConcat => 1;
}
override def produced = 1;
}
diff --git a/sources/scala/tools/nsc/backend/icode/Primitives.scala b/sources/scala/tools/nsc/backend/icode/Primitives.scala
index 6f77b21bc4..5cebb0edaf 100644
--- a/sources/scala/tools/nsc/backend/icode/Primitives.scala
+++ b/sources/scala/tools/nsc/backend/icode/Primitives.scala
@@ -57,11 +57,21 @@ import java.io.PrintWriter;
// jvm : arraylength
case class ArrayLength(kind: TypeKind) extends Primitive;
- // type : (lf,rg) => STR
+ // type : (buf,el) => buf
// range: lf,rg <- { BOOL, Ix, Ux, Rx, REF, STR }
- // jvm : -
- case class StringConcat(lf: TypeKind, rg: TypeKind) extends Primitive;
-
+ // jvm : It should call the appropiate 'append' method on StringBuffer
+ case class StringConcat(el: TypeKind) extends Primitive;
+
+ /** Signals the beginning of a series of concatenations.
+ * On the JVM platform, it should create a new StringBuffer
+ */
+ case object StartConcat extends Primitive;
+
+ /**
+ * type: (buf) => STR
+ * jvm : It should turn the StringBuffer into a String.
+ */
+ case object EndConcat extends Primitive;
/** Pretty printer for primitives */
class PrimitivePrinter(out: PrintWriter) {
diff --git a/sources/scala/tools/nsc/backend/icode/TypeKinds.scala b/sources/scala/tools/nsc/backend/icode/TypeKinds.scala
index 6b23b8c082..a552537212 100644
--- a/sources/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/sources/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -69,6 +69,8 @@ import scala.collection.mutable.{Map, HashMap};
def isReferenceType: Boolean = false;
def isArrayType: Boolean = false;
+ def isValueType: Boolean = !isReferenceType && !isArrayType;
+
def isIntType: Boolean = this match {
case BYTE | SHORT | INT | LONG | CHAR => true;
@@ -109,6 +111,8 @@ import scala.collection.mutable.{Map, HashMap};
(b.isReferenceType || b.isArrayType))
toTypeKind(lub0(a.toType, b.toType))
else if (a == b) a
+ else if (a == REFERENCE(definitions.AllClass)) b
+ else if (b == REFERENCE(definitions.AllClass)) a
else throw new CheckerError("Incompatible types: " + a + " with " + b);
}
@@ -133,7 +137,7 @@ import scala.collection.mutable.{Map, HashMap};
override def maxType(other: TypeKind): TypeKind =
other match {
case INT => INT;
- case SHORT | INT | LONG | FLOAT | DOUBLE => other;
+ case BYTE | SHORT | INT | LONG | FLOAT | DOUBLE => other;
case _ => abort("Uncomparbale type kinds: BYTE with " + other);
}
}
@@ -313,6 +317,17 @@ import scala.collection.mutable.{Map, HashMap};
REFERENCE(sym);
}
+ case ClassInfoType(_, _, sym) =>
+ Console.println("Got a ClassInfoType!");
+ primitiveTypeMap get sym match {
+ case Some(k) => k;
+ case None =>
+ if (sym == definitions.ArrayClass)
+ abort("ClassInfoType to ArrayClass!");
+ else
+ REFERENCE(sym);
+ }
+
case _ => abort("Unknown type: " + t);
}
diff --git a/sources/scala/tools/nsc/backend/icode/TypeStacks.scala b/sources/scala/tools/nsc/backend/icode/TypeStacks.scala
index 5d2267f2ec..c7acd3b908 100644
--- a/sources/scala/tools/nsc/backend/icode/TypeStacks.scala
+++ b/sources/scala/tools/nsc/backend/icode/TypeStacks.scala
@@ -19,7 +19,6 @@ trait TypeStacks: ICodes {
type Rep = List[TypeKind];
class TypeStack {
-
var types: Rep = Nil;
def this(stack: Rep) = {
diff --git a/sources/scala/tools/nsc/backend/jvm/GenJVM.scala b/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
index dd06a6e6fd..4b0621e6d0 100644
--- a/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/sources/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -11,6 +11,7 @@ import java.io.File;
import scala.collection.mutable.{Map, HashMap};
import scala.tools.nsc.symtab._;
+import scala.tools.util.Position;
import ch.epfl.lamp.fjbg._;
@@ -32,7 +33,8 @@ abstract class GenJVM extends SubComponent {
def name = phaseName;
override def newFlags = phaseNewFlags;
- val codeGenerator = new GenJVM;
+ override def erasedTypes = true;
+ val codeGenerator = new BytecodeGenerator;
override def run: Unit =
classes foreach codeGenerator.genClass;
@@ -44,13 +46,13 @@ abstract class GenJVM extends SubComponent {
/**
* Java bytecode generator.
*
- * TODO: take care of different size in local variables (LOAD/STORE_LOCAL)
*/
- class GenJVM {
+ class BytecodeGenerator {
val MIN_SWITCH_DENSITY = 0.7;
val MODULE_INSTANCE_NAME = "MODULE$";
val JAVA_LANG_STRINGBUFFER = "java.lang.StringBuffer";
val stringBufferType = new JObjectType(JAVA_LANG_STRINGBUFFER);
+ val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY);
var clasz: IClass = _;
var method: IMethod = _;
@@ -89,16 +91,18 @@ abstract class GenJVM extends SubComponent {
if (isTopLevelModule(c.symbol)) {
addModuleInstanceField;
- dumpMirrorClass;
+ addStaticInit(jclass);
+
+ if (c.symbol.linkedClass != NoSymbol)
+ log("No mirror class for module with linked class: " + c.symbol.fullNameString);
+ else
+ dumpMirrorClass;
}
jclass.writeTo(getFile(jclass, ".class"));
}
def isTopLevelModule(sym: Symbol): Boolean = {
- log("Symbol: " + sym + " isNestedClass? " + atPhase(currentRun.erasurePhase)(sym.isNestedClass) +
- " hasFlag LIFTED? " + sym.hasFlag(Flags.LIFTED));
-
sym.isModuleClass && !sym.isImplClass && !sym.hasFlag(Flags.LIFTED) /* && !atPhase(currentRun.erasurePhase)(sym.isNestedClass) */
}
@@ -110,7 +114,7 @@ abstract class GenJVM extends SubComponent {
}
def genMethod(m: IMethod): Unit = {
- log("Adding method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) +
+ log("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) +
" owner: " + m.symbol.owner);
method = m;
computeLocalVarsIndex(m);
@@ -119,12 +123,20 @@ abstract class GenJVM extends SubComponent {
if (m.symbol.isClassConstructor)
resTpe = JType.VOID;
- jmethod = jclass.addNewMethod(javaFlags(m.symbol),
+ var flags = javaFlags(m.symbol);
+ if (jclass.isInterface())
+ flags = flags | JAccessFlags.ACC_ABSTRACT;
+
+ jmethod = jclass.addNewMethod(flags,
javaName(m.symbol),
resTpe,
javaTypes(m.params map (.kind)),
javaNames(m.params map (.sym)));
+ if (m.symbol.hasFlag(Flags.BRIDGE))
+ jmethod.addAttribute(fjbgContext.JOtherAttribute(jclass, jmethod, "Bridge",
+ new Array[Byte](0)));
+
if (!jmethod.isAbstract()) {
for (val local <- m.locals; !local.sym.isValueParameter)
jmethod.addNewLocalVariable(javaType(local.kind), javaName(local.sym));
@@ -195,7 +207,6 @@ abstract class GenJVM extends SubComponent {
mirrorCode.emitRETURN(mirrorMethod.getReturnType());
}
- addStaticInit(jclass); // should be the current module class
mirrorClass.writeTo(getFile(mirrorClass, ".class"));
}
@@ -212,6 +223,11 @@ abstract class GenJVM extends SubComponent {
def genBlock(b: BasicBlock): Unit = {
labels(b).anchorToNext();
+ log("Generating code for block: " + b + " at pc: " + labels(b).getAnchor());
+ var lastMappedPC = 0;
+ var lastLineNr = 0;
+ var crtPC = 0;
+
b traverse ( instr => {
instr match {
case THIS(clasz) =>
@@ -223,6 +239,7 @@ abstract class GenJVM extends SubComponent {
case BooleanTag => jcode.emitPUSH(const.booleanValue);
case ByteTag => jcode.emitPUSH(const.byteValue);
case ShortTag => jcode.emitPUSH(const.shortValue);
+ case CharTag => jcode.emitPUSH(const.charValue);
case IntTag => jcode.emitPUSH(const.intValue);
case LongTag => jcode.emitPUSH(const.longValue);
case FloatTag => jcode.emitPUSH(const.floatValue);
@@ -256,7 +273,7 @@ abstract class GenJVM extends SubComponent {
javaType(field));
case LOAD_MODULE(module) =>
- assert(module.isModule);
+ assert(module.isModule || module.isModuleClass, "Expected module: " + module);
log("genearting LOAD_MODULE for: " + module + " flags: " +
Flags.flagsToString(module.flags));
jcode.emitGETSTATIC(javaName(module) /* + "$" */ ,
@@ -321,13 +338,17 @@ abstract class GenJVM extends SubComponent {
case NEW(REFERENCE(cls)) =>
val className = javaName(cls);
jcode.emitNEW(className);
- jcode.emitDUP();
+// jcode.emitDUP();
// jcode.emitINVOKESPECIAL(className,
// JMethod.INSTANCE_CONSTRUCTOR_NAME,
// javaType(ctor).asInstanceOf[JMethodType]);
- case CREATE_ARRAY(elem) =>
- jcode.emitNEWARRAY(javaType(elem));
+ case CREATE_ARRAY(elem) => elem match {
+ case REFERENCE(_) | ARRAY(_) =>
+ jcode.emitANEWARRAY(javaType(elem).asInstanceOf[JReferenceType]);
+ case _ =>
+ jcode.emitNEWARRAY(javaType(elem));
+ }
case IS_INSTANCE(tpe) =>
tpe match {
@@ -354,6 +375,7 @@ abstract class GenJVM extends SubComponent {
caze = caze.tail;
}
val branchArray = new Array[JCode$Label](tagArray.length);
+ log("Emitting SWITHCH:\ntags: " + tags + "\nbranches: " + branches);
jcode.emitSWITCH(tagArray,
(branches map labels dropRight 1).copyToArray(branchArray, 0),
labels(branches.last),
@@ -409,10 +431,10 @@ abstract class GenJVM extends SubComponent {
jcode.emitATHROW();
case DROP(kind) =>
-// kind match {
-// case LONG | DOUBLE => jcode.emitPOP2();
-// case _ => jcode.emitPOP();
-// }
+ kind match {
+ case LONG | DOUBLE => jcode.emitPOP2();
+ case _ => jcode.emitPOP();
+ }
case DUP(kind) =>
kind match {
@@ -427,6 +449,16 @@ abstract class GenJVM extends SubComponent {
case MONITOR_EXIT() =>
jcode.emitMONITOREXIT();
}
+
+ crtPC = jcode.getPC();
+ val crtLine = Position.line(instr.pos);
+ if (crtLine != lastLineNr &&
+ crtPC > lastMappedPC) {
+ jcode.completeLineNumber(lastMappedPC, crtPC, crtLine);
+ lastMappedPC = crtPC;
+ lastLineNr = crtLine;
+ }
+
});
}
@@ -497,22 +529,87 @@ abstract class GenJVM extends SubComponent {
case _ => abort("Unknown arithmetic primitive " + primitive );
}
+ case Logical(op, kind) => Pair(op, kind) match {
+ case Pair(AND, LONG) =>
+ jcode.emitLAND();
+ case Pair(AND, INT) =>
+ jcode.emitIAND();
+ case Pair(AND, _) =>
+ jcode.emitIAND();
+ jcode.emitT2T(javaType(INT), javaType(kind));
+
+ case Pair(OR, LONG) =>
+ jcode.emitLOR();
+ case Pair(OR, INT) =>
+ jcode.emitIOR();
+ case Pair(OR, _) =>
+ jcode.emitIOR();
+ jcode.emitT2T(javaType(INT), javaType(kind));
+
+ case Pair(XOR, LONG) =>
+ jcode.emitLXOR();
+ case Pair(XOR, INT) =>
+ jcode.emitIXOR();
+ case Pair(XOR, _) =>
+ jcode.emitIXOR();
+ jcode.emitT2T(javaType(INT), javaType(kind));
+ }
+
+ case Shift(op, kind) => Pair(op, kind) match {
+ case Pair(LSL, LONG) =>
+ jcode.emitLSHL();
+ case Pair(LSL, INT) =>
+ jcode.emitISHL();
+ case Pair(LSL, _) =>
+ jcode.emitISHL();
+ jcode.emitT2T(javaType(INT), javaType(kind));
+
+ case Pair(ASR, LONG) =>
+ jcode.emitLSHR();
+ case Pair(ASR, INT) =>
+ jcode.emitISHR();
+ case Pair(ASR, _) =>
+ jcode.emitISHR();
+ jcode.emitT2T(javaType(INT), javaType(kind));
+
+ case Pair(LSR, LONG) =>
+ jcode.emitLUSHR();
+ case Pair(LSR, INT) =>
+ jcode.emitIUSHR();
+ case Pair(LSR, _) =>
+ jcode.emitIUSHR();
+ jcode.emitT2T(javaType(INT), javaType(kind));
+ }
+
case Conversion(src, dst) =>
+ log("Converting from: " + src + " to: " + dst);
jcode.emitT2T(javaType(src), javaType(dst));
- case StringConcat(lf, rg) =>
-// jcode.emitNEW(JAVA_LANG_STRINGBUFFER);
-// jcode.emitDUP();
-// jcode.emitINVOKESPECIAL(JAVA_LANG_STRINGBUFFER,
-// JMethod.INSTANCE_CONSTRUCTOR_NAME,
-// JMethodType.ARGLESS_VOID_FUNCTION);
-// jcode.emitINVOKEVIRTUAL(JAVA_LANG_STRINGBUFFER,
-// "append",
-// new JMethodType(stringBufferType,
-// javaType(lf)));
+ case ArrayLength(_) =>
+ jcode.emitARRAYLENGTH();
+ case StartConcat =>
+ jcode.emitNEW(JAVA_LANG_STRINGBUFFER);
+ jcode.emitDUP();
+ jcode.emitINVOKESPECIAL(JAVA_LANG_STRINGBUFFER,
+ JMethod.INSTANCE_CONSTRUCTOR_NAME,
+ JMethodType.ARGLESS_VOID_FUNCTION);
- case _ => log("Unimplemented primitive " + primitive);
+ case StringConcat(el) =>
+ val jtype = el match {
+ case REFERENCE(_) | ARRAY(_)=> JObjectType.JAVA_LANG_OBJECT;
+ case _ => javaType(el);
+ }
+ jcode.emitINVOKEVIRTUAL(JAVA_LANG_STRINGBUFFER,
+ "append",
+ new JMethodType(stringBufferType,
+ Predef.Array(jtype)));
+ case EndConcat =>
+ jcode.emitINVOKEVIRTUAL(JAVA_LANG_STRINGBUFFER,
+ "toString",
+ toStringType);
+
+ case _ => abort("Unimplemented primitive " + primitive);
}
}
@@ -528,6 +625,7 @@ abstract class GenJVM extends SubComponent {
def makeLabels(bs: List[BasicBlock]) = {
labels.clear;
+ log("Making labels for: " + method);
bs foreach (bb => labels += bb -> jcode.newLabel() );
}