summaryrefslogtreecommitdiff
path: root/sources/scalac
diff options
context:
space:
mode:
authorschinz <schinz@epfl.ch>2003-07-10 13:23:24 +0000
committerschinz <schinz@epfl.ch>2003-07-10 13:23:24 +0000
commitbdf7315e7f0c8e6da4ab6cdd0da76e15282a4b2f (patch)
treea88e7ac509e6683926921a7b79ea3421e3433c7c /sources/scalac
parent61393510099ca97eb702cb47f78138b2fc162854 (diff)
downloadscala-bdf7315e7f0c8e6da4ab6cdd0da76e15282a4b2f.tar.gz
scala-bdf7315e7f0c8e6da4ab6cdd0da76e15282a4b2f.tar.bz2
scala-bdf7315e7f0c8e6da4ab6cdd0da76e15282a4b2f.zip
- introduced the new JVM backend as default, wh...
- introduced the new JVM backend as default, which uses FJBG instead of BCEL to generate bytecode
Diffstat (limited to 'sources/scalac')
-rw-r--r--sources/scalac/Global.java14
-rw-r--r--sources/scalac/PhaseRepository.java3
-rw-r--r--sources/scalac/backend/jvm/GenJVM.java2193
-rw-r--r--sources/scalac/backend/jvm/GenJVMPhase.java7
4 files changed, 1096 insertions, 1121 deletions
diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java
index 4a7a92e14a..ce18aa3bbe 100644
--- a/sources/scalac/Global.java
+++ b/sources/scalac/Global.java
@@ -113,12 +113,14 @@ public class Global {
*/
public static final String TARGET_INT;
public static final String TARGET_JVM;
+ public static final String TARGET_JVM_BCEL;
public static final String TARGET_MSIL;
public static final String[] TARGETS = new String[] {
- TARGET_INT = "int".intern(),
- TARGET_JVM = "jvm".intern(),
- TARGET_MSIL = "msil".intern(),
+ TARGET_INT = "int".intern(),
+ TARGET_JVM = "jvm".intern(),
+ TARGET_JVM_BCEL = "jvm-bcel".intern(),
+ TARGET_MSIL = "msil".intern(),
};
/** tree printers
@@ -194,11 +196,15 @@ public class Global {
phases.add(PHASE.ADDINTERFACES);
phases.add(PHASE.EXPANDMIXIN);
phases.add(PHASE.ERASURE);
- if (target == TARGET_INT || target == TARGET_MSIL || target == TARGET_JVM) {
+ if (target == TARGET_INT
+ || target == TARGET_MSIL
+ || target == TARGET_JVM
+ || target == TARGET_JVM_BCEL) {
phases.add(PHASE.ADDCONSTRUCTORS);
}
if (target == TARGET_MSIL) phases.add(PHASE.GENMSIL);
if (target == TARGET_JVM) phases.add(PHASE.GENJVM);
+ if (target == TARGET_JVM_BCEL) phases.add(PHASE.GENJVM_BCEL);
phases.add(PHASE.TERMINAL);
this.phases = new PhaseDescriptor[phases.size()];
for (int i = 0; i < phases.size(); i++) {
diff --git a/sources/scalac/PhaseRepository.java b/sources/scalac/PhaseRepository.java
index 3544193a9c..c730479d87 100644
--- a/sources/scalac/PhaseRepository.java
+++ b/sources/scalac/PhaseRepository.java
@@ -24,6 +24,7 @@ import scalac.transformer.AddConstructorsPhase;
import scalac.optimizer.OptimizePhase;
*/
import scalac.backend.jvm.GenJVMPhase;
+import scalac.backend.jvm.GenJVMBCELPhase;
import scalac.backend.msil.GenMSILPhase;
public class PhaseRepository {
@@ -55,6 +56,7 @@ public class PhaseRepository {
ERASURE = new ErasurePhase(),
ADDCONSTRUCTORS = new AddConstructorsPhase(),
GENJVM = new GenJVMPhase(),
+ GENJVM_BCEL = new GenJVMBCELPhase(),
GENMSIL = new GenMSILPhase(),
TERMINAL = PhaseDescriptor.TERMINAL,
};
@@ -80,6 +82,7 @@ public class PhaseRepository {
public final ErasurePhase ERASURE;
public final AddConstructorsPhase ADDCONSTRUCTORS;
public final GenJVMPhase GENJVM;
+ public final GenJVMBCELPhase GENJVM_BCEL;
public final GenMSILPhase GENMSIL;
public final PhaseDescriptor TERMINAL;
diff --git a/sources/scalac/backend/jvm/GenJVM.java b/sources/scalac/backend/jvm/GenJVM.java
index aa5998caa8..eebc1fec99 100644
--- a/sources/scalac/backend/jvm/GenJVM.java
+++ b/sources/scalac/backend/jvm/GenJVM.java
@@ -4,13 +4,8 @@
** /_____/\____/\___/\____/____/ **
\* */
-// $OldId: GenJVM.java,v 1.29 2003/02/05 09:32:17 schinz Exp $
// $Id$
-// TODO: create arrays with ANEWARRAY & friends
-
-// TODO: (maybe) add InnerClass attributes to .class files
-
package scalac.backend.jvm;
import ch.epfl.lamp.util.Position;
@@ -23,18 +18,38 @@ import scalac.symtab.*;
import scalac.symtab.classfile.ClassfileConstants;
import scalac.transformer.*;
-import org.apache.bcel.*;
-import org.apache.bcel.generic.*;
-import org.apache.bcel.classfile.*;
-import org.apache.bcel.generic.Type;
+import ch.epfl.lamp.fjbg.*;
import java.util.*;
import java.io.*;
+/* Several things which are done here should in fact be done in
+ * previous phases, namely:
+ *
+ * - code linearisation (i.e. representation of code as a list of
+ * instructions),
+ *
+ * - removal of implicit "this" selection,
+ *
+ * - removal of implicit "unit" values,
+ *
+ * - removal of implicit conversion,
+ *
+ * - removal of "if"s without explicit "else" part,
+ *
+ * - expansion of "==",
+ *
+ * - introduction of a special primitive for string concatenation,
+ *
+ * - initialisation of module instance variable.
+ */
+
+// TODO generate line numbers
+
/**
* Backend generating JVM byte-codes.
*
- * @version 1.0
+ * @version 2.0
* @author Michel Schinz
*/
@@ -44,31 +59,34 @@ class GenJVM {
protected final static String JAVA_LANG_STRINGBUFFER = "java.lang.StringBuffer";
protected final static String SCALA_RUNTIME_RUNTIME = "scala.runtime.RunTime";
protected final static String SCALA_UNIT = "scala.Unit";
+ protected final static String SCALA_UNIT_VALUE = "UNIT_VAL";
protected final static String MODULE_INSTANCE_FIELD_NAME = "MODULE$";
- protected final static String VOID_NO_ARGS_SIG =
- Type.getMethodSignature(Type.VOID, Type.NO_ARGS);
- protected final static String[] EMPTY_STRING_ARRAY = new String[0];
-
- protected final static String UNIT_SIG =
- (new ObjectType(SCALA_UNIT)).getSignature();
protected final static String CONSTRUCTOR_STRING =
- Constants.CONSTRUCTOR_NAME;
+ "<init>"; // TODO get it from FJBG
protected final static Name CONSTRUCTOR_NAME =
Name.fromString(CONSTRUCTOR_STRING);
- protected Unit unit = null;
- protected String sourceFileName = null;
-
- // Shortcut names for interfaces.
- protected final static InstructionConstants ic = null;
- protected final static Constants cst = null;
+ protected final JObjectType JAVA_LANG_OBJECT_T =
+ new JObjectType(JAVA_LANG_OBJECT);
+ protected final JObjectType JAVA_LANG_STRING_T =
+ new JObjectType(JAVA_LANG_STRING);
+ protected final JObjectType JAVA_LANG_STRINGBUFFER_T =
+ new JObjectType (JAVA_LANG_STRINGBUFFER);
+ protected final JObjectType JAVA_LANG_THROWABLE_T =
+ new JObjectType("java.lang.Throwable");
+ protected final JObjectType SCALA_UNIT_T =
+ new JObjectType(SCALA_UNIT);
protected final Global global;
protected final Definitions defs;
protected final Primitives prims;
+ static {
+ JFactory.setInstance(new JFactory());
+ }
+
public GenJVM(Global global) {
this.global = global;
this.defs = global.definitions;
@@ -77,166 +95,139 @@ class GenJVM {
initArithPrimMap();
}
+ /// Code generation
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Generate code for the given unit.
+ */
public void translate(Unit unit) {
- this.unit = unit;
- sourceFileName = unit.source.toString();
for (int i = 0; i < unit.body.length; ++i)
- gen(unit.body[i]);
- sourceFileName = null;
- this.unit = null;
- }
-
- // Context
- protected ClassGen currClass = null;
- protected String currClassName = null;
- protected ConstantPoolGen currPool = null;
- protected MethodGen currMethod = null;
- protected InstructionList currIL = null;
- protected Map currLocals = null;
- protected boolean isModuleClass = false;
-
- static class InstrContext {
- public case Empty;
- public case New;
- public case Assign;
- public case If(InstructionHandle target, boolean when);
- }
-
- // Line numbers attribution
- protected HashMap/*<InstructionHandle,Integer>*/ lineAttributedInstrs;
-
- protected void gen(Tree tree) {
- gen(tree, cst.T_VOID, InstrContext.Empty);
- }
-
- protected void gen(Tree tree, byte expectedType) {
- gen(tree, expectedType, InstrContext.Empty);
- }
-
- protected void gen(Tree tree, InstrContext ctx) {
- gen(tree, cst.T_VOID, ctx);
- }
-
- protected void gen(Tree[] trees) {
- for (int i = 0; i < trees.length; ++i)
- gen(trees[i]);
- }
-
- protected void gen(Tree[] trees, byte expectedType) {
- for (int i = 0; i < trees.length; ++i)
- gen(trees[i], expectedType);
+ gen(Context.EMPTY.withSourceFileName(unit.source.toString()),
+ unit.body[i]);
}
- protected void gen(Tree[] trees, InstrContext ctx) {
- for (int i = 0; i < trees.length; ++i)
- gen(trees[i], ctx);
- }
-
- protected void gen(Tree[] trees, byte expectedType, InstrContext ctx) {
- for (int i = 0; i < trees.length; ++i)
- gen(trees[i], expectedType, ctx);
- }
-
- protected void gen(Tree tree, byte expectedType, InstrContext ctx) {
+ /**
+ * Generate code to perform the side effects associated with the
+ * given tree (i.e. no value should remain on the stack
+ * afterwards).
+ */
+ protected void gen(Context ctx, Tree tree) {
Symbol sym = tree.symbol();
- byte generatedType = cst.T_VOID;
-
- // Remember first instruction associated to this tree, to
- // generate line numbers.
- InstructionHandle startHandle;
- if (currIL != null)
- startHandle = currIL.getEnd();
- else
- startHandle = null;
switch (tree) {
case PackageDef(_, Tree.Template impl):
- gen(impl);
+ gen(ctx, impl);
break;
case ClassDef(_, _, _, _, _, Tree.Template impl) : {
Tree.ClassDef classDef = (Tree.ClassDef)tree;
- boolean oldIsModuleClass = isModuleClass;
- isModuleClass = Modifiers.Helper.isModClass(sym.flags);
- enterClass(sym);
+ Context ctx1 = enterClass(ctx, sym);
- addValueClassMembers(classDef);
- if (isModuleClass)
- addModuleInstanceField();
+ addValueClassMembers(ctx1, classDef);
+ if (ctx1.isModuleClass)
+ addModuleInstanceField(ctx1);
- gen(impl);
- leaveClass(sym);
- isModuleClass = oldIsModuleClass;
+ gen(ctx1, impl);
+ leaveClass(ctx1, sym);
} break;
case Template(_, Tree[] body):
- gen(body);
+ gen(ctx, body);
break;
case ValDef(_, Name name, _, Tree rhs): {
- if (currMethod == null)
+ if (ctx.method == null)
break; // ignore ValDefs in classes, handled elsewhere
- Type valType = typeStoJ(sym.info());
- LocalVariableGen lGen = currMethod.addLocalVariable(name.toString(),
- valType,
- currIL.getEnd(),
- null);
- int index = lGen.getIndex();
+ JType valType = typeStoJ(sym.info());
+ JLocalVariable var =
+ ctx.method.addNewLocalVariable(valType, name.toString());
+ ctx.locals.put(sym, new Integer(var.getIndex()));
if (rhs != Tree.Empty)
- gen(rhs, valType.getType());
+ genLoad(ctx, rhs, valType);
else {
- switch (valType.getType()) {
- case cst.T_BOOLEAN:
- case cst.T_BYTE:
- case cst.T_CHAR:
- case cst.T_SHORT:
- case cst.T_INT:
- currIL.append(new PUSH(currPool, 0)); break;
- case cst.T_LONG:
- currIL.append(new PUSH(currPool, 0L)); break;
- case cst.T_FLOAT:
- currIL.append(new PUSH(currPool, 0F)); break;
- case cst.T_DOUBLE:
- currIL.append(new PUSH(currPool, 0D)); break;
+ switch (valType.getTag()) {
+ case JType.T_BOOLEAN:
+ case JType.T_BYTE:
+ case JType.T_CHAR:
+ case JType.T_SHORT:
+ case JType.T_INT:
+ ctx.code.emitPUSH(0); break;
+ case JType.T_LONG:
+ ctx.code.emitPUSH(0L); break;
+ case JType.T_FLOAT:
+ ctx.code.emitPUSH(0F); break;
+ case JType.T_DOUBLE:
+ ctx.code.emitPUSH(0D); break;
default:
- currIL.append(ic.ACONST_NULL); break;
+ ctx.code.emitACONST_NULL(); break;
}
}
- currIL.append(new Generic_STORE(index, valType));
-
- currLocals.put(sym, new Integer(index));
+ ctx.code.emitSTORE(var);
} break;
case DefDef(_, _, _, _, _, Tree rhs): {
- enterMethod((Tree.DefDef)tree);
+ Tree.DefDef defDef = (Tree.DefDef)tree;
+ Context ctx1 = enterMethod(ctx, defDef);
if (! Modifiers.Helper.isAbstract(sym.flags)) {
- Type retType = currMethod.getReturnType();
- gen(rhs, retType.getType());
- currIL.append(new Generic_RETURN(retType));
+ JType retType = ctx1.method.getReturnType();
+ genLoad(ctx1, rhs, retType);
+ ctx1.code.emitRETURN(retType);
}
- leaveMethod();
+ leaveMethod(ctx1);
} break;
case LabelDef(_, _):
global.fail("not implemented yet " + tree);
break;
+ case Typed(Tree expr, _):
+ gen(ctx, expr);
+ break;
+
+ case Empty:
+ case TypeDef(_, _, _, _):
+ case TypeApply(_, _):
+ case FunType(_, _):
+ case CompoundType(_, _):
+ case AppliedType(_,_):
+ break;
+
+ default:
+ genLoad(ctx, tree, JType.VOID);
+ }
+ }
+
+ protected void gen(Context ctx, Tree[] trees) {
+ for (int i = 0; i < trees.length; ++i)
+ gen(ctx, trees[i]);
+ }
+
+ /**
+ * Generate code to load the value of the given tree on the
+ * stack, and make sure it is of the given expected type.
+ */
+ protected JType genLoad(Context ctx, Tree tree, JType expectedType) {
+ JType generatedType = null;
+ Symbol sym = tree.symbol();
+
+ switch (tree) {
case Block(Tree[] stats): {
int statsNum = stats.length;
for (int i = 0; i < statsNum - 1; ++i)
- gen(stats[i], cst.T_VOID);
+ gen(ctx, stats[i]);
if (statsNum == 0)
- maybeLoadUnit(expectedType);
+ maybeGenLoadUnit(ctx, expectedType);
else
- gen(stats[stats.length - 1], expectedType, ctx);
+ genLoad(ctx, stats[stats.length - 1], expectedType);
generatedType = expectedType;
} break;
case Typed(Tree expr, _):
- gen(expr, expectedType, ctx);
+ genLoad(ctx, expr, expectedType);
generatedType = expectedType;
break;
@@ -245,227 +236,239 @@ class GenJVM {
assert templ.parents.length == 1;
String className = javaName(tree.type.symbol());
- currIL.append(new NEW(currPool.addClass(className)));
- currIL.append(ic.DUP);
- gen(templ.parents[0], InstrContext.New);
-
- generatedType = cst.T_OBJECT;
+ ctx.code.emitNEW(className);
+ ctx.code.emitDUP();
+ gen(ctx, templ.parents[0]);
+ generatedType = new JObjectType(className);
} break;
case Apply(TypeApply(Tree fun, Tree[] args), _): {
- Type type = typeStoJ(args[0].type);
- int typeIndex;
- if (type instanceof ObjectType)
- typeIndex = currPool.addClass((ObjectType)type);
- else if (type instanceof ArrayType)
- typeIndex = currPool.addArrayClass((ArrayType)type);
- else
- throw global.fail("unexpected type " + type);
-
- genLoadQualifier(fun);
+ genLoadQualifier(ctx, fun);
+ JType type = typeStoJ(args[0].type);
if (fun.symbol() == defs.IS) {
- currIL.append(new INSTANCEOF(typeIndex));
- generatedType = cst.T_BOOLEAN;
+ ctx.code.emitINSTANCEOF((JReferenceType)type);
+ generatedType = JType.BOOLEAN;
} else if (fun.symbol() == defs.AS) {
- currIL.append(new CHECKCAST(typeIndex));
- generatedType = type.getType();
+ ctx.code.emitCHECKCAST((JReferenceType)type);
+ generatedType = type;
} else
global.fail("unexpected type application");
} break;
case Apply(Tree fun, Tree[] args): {
- if (isPrimitive(fun.symbol())) {
- Tree.Select selectFun = (Tree.Select)fun;
+ if (isKnownPrimitive(fun.symbol())) {
Primitive prim = prims.getPrimitive(fun.symbol());
- if (prim == Primitive.CONCAT) {
- genStringConcatenation(liftStringConcatenations(tree));
- generatedType = cst.T_OBJECT;
- } else {
- Tree[] allArgs = new Tree[args.length + 1];
- allArgs[0] = unbox(selectFun.qualifier);
- System.arraycopy(args, 0, allArgs, 1, args.length);
- generatedType = genPrimitive(prim,
- allArgs,
- typeStoJ(tree.type).getType(),
- expectedType,
- ctx);
+ switch (prim) {
+ case CONCAT:
+ genStringConcatenation(ctx, liftStringConcatenations(tree));
+ generatedType = JAVA_LANG_STRING_T;
+ break;
+
+ case POS: case NEG:
+ case ADD: case SUB: case MUL: case DIV: case MOD:
+ case NOT: case OR : case XOR: case AND:
+ case LSL: case LSR: case ASR:
+ Tree[] allArgs = extractPrimitiveArgs((Tree.Apply)tree);
+ JType resType = typeStoJ(tree.type);
+ genArithPrim(ctx, prim, allArgs, resType, expectedType);
+ generatedType = resType;
+ break;
+
+ case EQ: case NE: case LT: case LE: case GE: case GT:
+ case ZNOT: case ZOR: case ZAND:
+ JLabel falseLabel = new JLabel();
+ JLabel afterLabel = new JLabel();
+ genCond(ctx, tree, falseLabel, false);
+ ctx.code.emitICONST_1();
+ ctx.code.emitGOTO(afterLabel);
+ ctx.code.anchorLabelToNext(falseLabel);
+ ctx.code.emitICONST_0();
+ ctx.code.anchorLabelToNext(afterLabel);
+ generatedType = JType.BOOLEAN;
+ break;
+
+ case THROW:
+ assert args.length == 0;
+ genThrow(ctx, ((Tree.Select)fun).qualifier);
+ // We pretend that we generated something of the
+ // expected type, to avoid trying to generate
+ // bogus conversions.
+ generatedType = expectedType;
+ break;
+
+ case NEW_ZARRAY : case NEW_BARRAY : case NEW_SARRAY :
+ case NEW_CARRAY : case NEW_IARRAY : case NEW_LARRAY :
+ case NEW_FARRAY : case NEW_DARRAY :
+ assert args.length == 1;
+ genArrayCreate(ctx, prim, args[0]);
+ generatedType = JAVA_LANG_OBJECT_T; // TODO refine
+ break;
+
+ case ZARRAY_SET : case BARRAY_SET : case SARRAY_SET :
+ case CARRAY_SET : case IARRAY_SET : case LARRAY_SET :
+ case FARRAY_SET : case DARRAY_SET : case OARRAY_SET :
+ assert args.length == 3;
+ genArrayUpdate(ctx, args[0], args[1], args[2]);
+ generatedType = JType.VOID;
+ break;
+
+ case ZARRAY_GET : case BARRAY_GET : case SARRAY_GET :
+ case CARRAY_GET : case IARRAY_GET : case LARRAY_GET :
+ case FARRAY_GET : case DARRAY_GET : case OARRAY_GET :
+ assert args.length == 2 : "get - " + args.length;
+ genArrayAccess(ctx, args[0], args[1]);
+ generatedType = getArrayElementType(args[0]);
+ break;
+
+ case ZARRAY_LENGTH : case BARRAY_LENGTH : case SARRAY_LENGTH :
+ case CARRAY_LENGTH : case IARRAY_LENGTH : case LARRAY_LENGTH :
+ case FARRAY_LENGTH : case DARRAY_LENGTH : case OARRAY_LENGTH :
+ assert args.length == 1 : args.length;
+ genArrayLength(ctx, args[0]);
+ generatedType = JType.INT;
+ break;
+
+ case AS_UVALUE :
+ assert args.length == 0;
+ gen(ctx, ((Tree.Select)fun).qualifier);
+ return JType.VOID;
+
+ default:
+ throw Debug.abort("unknown primitive ", prim);
}
} else {
Symbol funSym = fun.symbol();
- Type[] argTypes = argTypesStoJ(funSym.info());
- Type retType = retTypeStoJ(funSym.info());
+ JMethodType funType = (JMethodType)typeStoJ(funSym.info());
+ JType[] argTypes = funType.getArgumentTypes();
+
+ boolean isConstrCall = (funSym.name == CONSTRUCTOR_NAME);
+ boolean isSuperCall;
+ switch (fun) {
+ case Select(Super(_), _): isSuperCall = true; break;
+ default: isSuperCall = false; break;
+ }
+
boolean isStatic = isStaticMember(funSym);
- if (!isStatic && ctx != InstrContext.New)
- genLoadQualifier(fun);
+ if (!(isStatic || (isConstrCall && !isSuperCall)))
+ genLoadQualifier(ctx, fun);
for (int i = 0; i < args.length; ++i)
- gen(args[i], argTypes[i].getType());
-
- String className = javaName(funSym.owner());
- String methodName = funSym.name.toString();
- String methodSig = Type.getMethodSignature(retType, argTypes);
-
- if (funSym.owner().isInterface()) {
- int methodIndex =
- currPool.addInterfaceMethodref(className, methodName, methodSig);
- int argsSize = 1;
-
- for (int i = 0; i < args.length; ++i)
- argsSize += argTypes[i].getSize();
- currIL.append(new INVOKEINTERFACE(methodIndex, argsSize));
- } else {
- int methodIndex =
- currPool.addMethodref(className, methodName, methodSig);
- boolean isConstrCall = (funSym.name == CONSTRUCTOR_NAME);
- boolean isSuperCall;
- switch (fun) {
- case Select(Super(_), _): isSuperCall = true; break;
- default: isSuperCall = false; break;
- }
+ genLoad(ctx, args[i], argTypes[i]);
+
+ String clsName = javaName(funSym.owner());
+ String mthName = funSym.name.toString();
+ if (funSym.owner().isInterface())
+ ctx.code.emitINVOKEINTERFACE(clsName, mthName, funType);
+ else {
if (isConstrCall || isSuperCall) {
- currIL.append(new INVOKESPECIAL(methodIndex));
- if (isConstrCall && isSuperCall && isModuleClass) {
+ ctx.code.emitINVOKESPECIAL(clsName, mthName, funType);
+ if (isConstrCall && isSuperCall && ctx.isModuleClass) {
// Initialise module instance field ASAP
- String currClassSig =
- new ObjectType(currClassName).getSignature();
- int fieldRef =
- currPool.addFieldref(currClassName,
- MODULE_INSTANCE_FIELD_NAME,
- currClassSig);
- currIL.append(ic.THIS);
- currIL.append(new PUTSTATIC(fieldRef));
+ ctx.code.emitALOAD_0();
+ ctx.code.emitPUTSTATIC(ctx.clazz.getName(),
+ MODULE_INSTANCE_FIELD_NAME,
+ ctx.clazz.getType());
}
} else if (isStatic)
- currIL.append(new INVOKESTATIC(methodIndex));
+ ctx.code.emitINVOKESTATIC(clsName, mthName, funType);
else
- currIL.append(new INVOKEVIRTUAL(methodIndex));
+ ctx.code.emitINVOKEVIRTUAL(clsName, mthName, funType);
}
-
- generatedType = retType.getType();
+ generatedType = funType.getReturnType();
}
} break;
case Ident(Name name): {
- Type type = typeStoJ(sym.info());
+ JType type = typeStoJ(sym.info());
if (sym.isModule())
- generatedType = genLoadModule(sym);
+ generatedType = genLoadModule(ctx, sym);
else if (sym == defs.NULL) {
- currIL.append(ic.ACONST_NULL);
+ ctx.code.emitACONST_NULL();
generatedType = expectedType;
} else if (sym.owner().isClass()) {
- currIL.append(ic.THIS);
- int fieldIdx = currPool.addFieldref(currClassName,
- name.toString(),
- type.getSignature());
- if (ctx == InstrContext.Assign) {
- currIL.append(new PUTFIELD(fieldIdx));
- generatedType = cst.T_VOID;
- } else {
- currIL.append(new GETFIELD(fieldIdx));
- generatedType = type.getType();
- }
+ ctx.code.emitALOAD_0();
+ ctx.code.emitGETFIELD(ctx.clazz.getName(), name.toString(), type);
+ generatedType = type;
} else {
- assert currLocals.containsKey(sym)
- : Debug.show(sym) + " not in " + currLocals;
- int pos = ((Integer)currLocals.get(sym)).intValue();
- if (ctx == InstrContext.Assign) {
- currIL.append(new Generic_STORE(pos, type));
- generatedType = cst.T_VOID;
- } else {
- currIL.append(new Generic_LOAD(pos, type));
- generatedType = type.getType();
- }
+ assert ctx.locals.containsKey(sym)
+ : Debug.show(sym) + " not in " + ctx.locals;
+ int index = ((Integer)(ctx.locals.get(sym))).intValue();
+ ctx.code.emitLOAD(index, type);
+ generatedType = type;
}
} break;
case Select(Tree qualifier, Name selector): {
if (sym.isModule())
- generatedType = genLoadModule(sym);
+ generatedType = genLoadModule(ctx, sym);
else {
- Type fieldType = typeStoJ(sym.info());
- int fieldIdx = currPool.addFieldref(javaName(sym.owner()),
- selector.toString(),
- fieldType.getSignature());
- if (isStaticMember(sym)) {
- if (ctx == InstrContext.Assign) {
- currIL.append(new PUTSTATIC(fieldIdx));
- generatedType = cst.T_VOID;
- } else {
- currIL.append(new GETSTATIC(fieldIdx));
- generatedType = fieldType.getType();
- }
- } else {
- genLoadQualifier(tree);
- if (ctx == InstrContext.Assign) {
- currIL.append(new PUTFIELD(fieldIdx));
- generatedType = cst.T_VOID;
- } else {
- currIL.append(new GETFIELD(fieldIdx));
- generatedType = fieldType.getType();
- }
+ JType fieldType = typeStoJ(sym.info());
+ String className = javaName(sym.owner());
+ String fieldName = selector.toString();
+ if (isStaticMember(sym))
+ ctx.code.emitGETSTATIC(className, fieldName, fieldType);
+ else {
+ genLoadQualifier(ctx, tree);
+ ctx.code.emitGETFIELD(className, fieldName, fieldType);
}
+ generatedType = fieldType;
}
} break;
case Assign(Tree lhs, Tree rhs): {
- gen(lhs, InstrContext.Assign);
- InstructionHandle storeHandle = currIL.getEnd();
- gen(rhs, typeStoJ(lhs.symbol().info()).getType());
- // Work around BCEL bug (see below)
- currIL.move(storeHandle, currIL.append(ic.NOP).getPrev());
+ genStorePrologue(ctx, lhs);
+ genLoad(ctx, rhs, typeStoJ(lhs.symbol().info()));
+ genStoreEpilogue(ctx, lhs);
+ generatedType = JType.VOID;
} break;
case If(Tree cond, Tree thenp, Tree elsep): {
- byte finalType = typeStoJ(tree.type).getType();
-
- InstructionHandle fakeElseH = currIL.append(ic.NOP);
- gen(cond, cst.T_VOID, new InstrContext.If(fakeElseH, false));
- InstructionHandle thenH = currIL.append(ic.NOP);
- gen(thenp, finalType);
- BranchInstruction gotoAfter = new GOTO(null);
- currIL.append(gotoAfter);
- InstructionHandle elseH = currIL.append(ic.NOP);
+ JType finalType = typeStoJ(tree.type);
+
+ JLabel elseLabel = new JLabel();
+ genCond(ctx, cond, elseLabel, false);
+ genLoad(ctx, thenp, finalType);
+ JLabel afterLabel = new JLabel();
+ ctx.code.emitGOTO(afterLabel);
+ ctx.code.anchorLabelToNext(elseLabel);
if (elsep == Tree.Empty)
- maybeLoadUnit(finalType);
+ maybeGenLoadUnit(ctx, finalType);
else
- gen(elsep, finalType);
- gotoAfter.setTarget(currIL.append(ic.NOP));
- // We cannot move the instructions sooner because BCEL has
- // a bug which makes it impossible to move instructions at
- // the end of the list.
- currIL.move(fakeElseH, elseH);
+ genLoad(ctx, elsep, finalType);
+ ctx.code.anchorLabelToNext(afterLabel);
generatedType = finalType;
} break;
case This(_):
- currIL.append(ic.THIS);
- generatedType = cst.T_OBJECT;
+ case Super(_):
+ ctx.code.emitALOAD_0();
+ generatedType = JAVA_LANG_OBJECT_T;
break;
case Literal(Object value):
if (value instanceof Integer) {
- generatedType = cst.T_INT;
- currIL.append(new PUSH(currPool, (Integer)value));
+ generatedType = JType.INT;
+ ctx.code.emitPUSH((Integer)value);
} else if (value instanceof Long) {
- generatedType = cst.T_LONG;
- currIL.append(new PUSH(currPool, (Long)value));
+ generatedType = JType.LONG;
+ ctx.code.emitPUSH((Long)value);
} else if (value instanceof Float) {
- generatedType = cst.T_FLOAT;
- currIL.append(new PUSH(currPool, (Float)value));
+ generatedType = JType.FLOAT;
+ ctx.code.emitPUSH((Float)value);
} else if (value instanceof Double) {
- generatedType = cst.T_DOUBLE;
- currIL.append(new PUSH(currPool, (Double)value));
+ generatedType = JType.DOUBLE;
+ ctx.code.emitPUSH((Double)value);
} else if (value instanceof Character) {
- generatedType = cst.T_CHAR;
- currIL.append(new PUSH(currPool, (Character)value));
+ generatedType = JType.CHAR;
+ ctx.code.emitPUSH((Character)value);
} else if (value instanceof String) {
- generatedType = cst.T_OBJECT;
- currIL.append(new PUSH(currPool, (String)value));
+ generatedType = JAVA_LANG_STRING_T;
+ ctx.code.emitPUSH((String)value);
} else if (value instanceof Boolean) {
- generatedType = cst.T_BOOLEAN;
- currIL.append(new PUSH(currPool, (Boolean)value));
+ generatedType = JType.BOOLEAN;
+ ctx.code.emitPUSH((Boolean)value);
} else
throw global.fail("unknown literal " + value);
break;
@@ -476,10 +479,10 @@ class GenJVM {
case FunType(_, _):
case CompoundType(_, _):
case AppliedType(_,_):
+ generatedType = JType.VOID;
break;
case Sequence(_):
- case Super(_):
case ModuleDef(_,_,_,_):
case PatDef(_,_,_):
case Import(_, _):
@@ -494,376 +497,250 @@ class GenJVM {
}
// Pop unneeded result from stack, or widen it if needed.
- if (expectedType == cst.T_VOID && generatedType != cst.T_VOID) {
- if (generatedType == cst.T_LONG || generatedType == cst.T_DOUBLE)
- currIL.append(ic.POP2);
- else {
- switch (ctx) {
- case If(InstructionHandle target, boolean when):
- assert generatedType == cst.T_BOOLEAN : generatedType;
- currIL.append(when ? new IFNE(target) : new IFEQ(target));
- break;
- default:
- currIL.append(ic.POP);
- }
- }
- } else if (! (expectedType == cst.T_VOID
+ if (expectedType == JType.VOID && generatedType != JType.VOID) {
+ if (generatedType == JType.LONG || generatedType == JType.DOUBLE)
+ ctx.code.emitPOP2();
+ else
+ ctx.code.emitPOP();
+ } else if (! (expectedType == JType.VOID
|| generatedType == expectedType
- || (generatedType == cst.T_ARRAY
- && expectedType == cst.T_OBJECT)))
- genWidenConversion(generatedType, expectedType);
-
- // Associate line numbers to instructions we just generated.
- if (currIL != null) {
- InstructionHandle ih =
- (startHandle == null ? currIL.getStart() : startHandle);
- int prevLine = -1;
- while (ih != null) {
- if (lineAttributedInstrs.containsKey(ih))
- prevLine = ((Integer)lineAttributedInstrs.get(ih)).intValue();
- else {
- int line = Position.line(tree.pos);
- lineAttributedInstrs.put(ih, new Integer(line));
- if (line != prevLine) {
- currMethod.addLineNumber(ih, line);
- prevLine = line;
- }
- }
- ih = ih.getNext();
- }
- }
- }
-
- protected Tree unbox(Tree tree) {
- switch (tree) {
- case Apply(Tree fun, Tree[] args):
- if (prims.getPrimitive(fun.symbol()) == Primitive.BOX) {
- assert args.length == 1;
- return args[0];
- } else
- return tree;
- case Block(Tree[] stats):
- if (stats.length == 2
- && prims.getPrimitive(stats[1].symbol()) == Primitive.BOX) {
- return stats[0];
- } else
- return tree;
- default:
- return tree;
- }
- }
+ || generatedType.isReferenceType()))
+ genWidenConversion(ctx, generatedType, expectedType);
- // Add field containing module instance, and code to
- // initialize it, to current class.
- protected void addModuleInstanceField() {
- FieldGen instanceField =
- new FieldGen(cst.ACC_PUBLIC
- | cst.ACC_FINAL
- | cst.ACC_STATIC,
- new ObjectType(currClassName),
- MODULE_INSTANCE_FIELD_NAME,
- currPool);
- currClass.addField(instanceField.getField());
-
- InstructionList initIL = new InstructionList();
-
- int constrRef = currPool.addMethodref(currClassName,
- CONSTRUCTOR_STRING,
- VOID_NO_ARGS_SIG);
-
- initIL.append(new NEW(currPool.addClass(currClassName)));
- initIL.append(new INVOKESPECIAL(constrRef));
- initIL.append(ic.RETURN);
-
- MethodGen initMethod =
- new MethodGen(cst.ACC_PUBLIC | cst.ACC_STATIC,
- Type.VOID, Type.NO_ARGS, Strings.NONE,
- "<clinit>",
- currClassName,
- initIL,
- currPool);
- initMethod.setMaxStack();
- currClass.addMethod(initMethod.getMethod());
+ return expectedType;
}
- // Add value members (i.e. fields) to current class.
- protected void addValueClassMembers(Tree.ClassDef cDef) {
- Symbol cSym = cDef.symbol();
- Scope.SymbolIterator memberIt =
- new Scope.UnloadIterator(cSym.members().iterator());
- while (memberIt.hasNext()) {
- Symbol member = memberIt.next();
- if (member.isTerm() && !member.isMethod()) {
- FieldGen fGen = new FieldGen(modifiersStoJ(member.flags),
- typeStoJ(member.info()),
- member.name.toString(),
- currPool);
- currClass.addField(fGen.getField());
- }
- }
+ /**
+ * Generate code to load the module represented by the given
+ * symbol.
+ */
+ protected JType genLoadModule(Context ctx, Symbol sym) {
+ String javaSymName = javaName(sym);
+ JType type = typeStoJ(sym.info());
+ if (javaSymName.equals(ctx.clazz.getName()))
+ ctx.code.emitALOAD_0();
+ else
+ ctx.code.emitGETSTATIC(javaSymName,
+ MODULE_INSTANCE_FIELD_NAME,
+ type);
+ return type;
}
- protected void maybeLoadUnit(byte expectedType) {
- if (expectedType == cst.T_OBJECT) {
- int unitFieldRef = currPool.addFieldref(SCALA_RUNTIME_RUNTIME,
- "UNIT_VAL",
- UNIT_SIG);
- currIL.append(new GETSTATIC(unitFieldRef));
+ /**
+ * Generate code to load the qualifier of the given tree, which
+ * can be implicitely "this".
+ */
+ protected void genLoadQualifier(Context ctx, Tree tree) {
+ switch (tree) {
+ case Ident(_):
+ ctx.code.emitALOAD_0();
+ break;
+ case Select(Tree qualifier, _):
+ genLoad(ctx, qualifier, JAVA_LANG_OBJECT_T);
+ break;
+ default:
+ throw global.fail("unknown qualifier");
}
}
- protected byte genLoadModule(Symbol sym) {
- String javaSymName = javaName(sym.moduleClass());
- if (javaSymName.equals(currClassName))
- currIL.append(ic.THIS);
- else {
- int moduleInstIdx =
- currPool.addFieldref(javaSymName,
- MODULE_INSTANCE_FIELD_NAME,
- typeStoJ(sym.info()).getSignature());
- currIL.append(new GETSTATIC(moduleInstIdx));
- }
- return cst.T_OBJECT;
+ /**
+ * Generate code to load the Unit value, iff the given type is an
+ * object type (i.e. something really has to be loaded on stack).
+ */
+ protected void maybeGenLoadUnit(Context ctx, JType type) {
+ if (type != JType.VOID)
+ ctx.code.emitGETSTATIC(SCALA_RUNTIME_RUNTIME,
+ SCALA_UNIT_VALUE,
+ SCALA_UNIT_T);
}
- protected void genLoadQualifier(Tree tree) {
+ /**
+ * Generate code to prepare the storage of a value in the location
+ * represented by the tree.
+ */
+ protected void genStorePrologue(Context ctx, Tree tree) {
+ Symbol sym = tree.symbol();
switch (tree) {
- case Select(Super(_), _):
case Ident(_):
- currIL.append(ic.THIS);
+ if (sym.owner().isClass())
+ ctx.code.emitALOAD_0();
break;
case Select(Tree qualifier, _):
- gen(qualifier, cst.T_OBJECT);
+ if (!isStaticMember(sym))
+ genLoadQualifier(ctx, tree);
break;
default:
- throw global.fail("unknown qualifier");
+ throw global.fail("unexpected left-hand side", tree);
}
}
- protected boolean isStaticMember(Symbol sym) {
- return (sym.name != CONSTRUCTOR_NAME)
- && sym.owner().isModuleClass()
- && sym.owner().isJava();
+ /**
+ * Generate code to perform the storage of the value on top of
+ * stack in the location represented by the tree.
+ */
+ protected void genStoreEpilogue(Context ctx, Tree tree) {
+ Symbol sym = tree.symbol();
+ if (sym.owner().isClass()) {
+ String ownerName = javaName(sym.owner());
+ if (isStaticMember(sym))
+ ctx.code.emitPUTSTATIC(ownerName,
+ sym.name.toString(),
+ typeStoJ(sym.info()));
+ else
+ ctx.code.emitPUTFIELD(ownerName,
+ sym.name.toString(),
+ typeStoJ(sym.info()));
+ } else {
+ assert ctx.locals.containsKey(sym)
+ : Debug.show(sym) + " not in " + ctx.locals;
+ int index = ((Integer)(ctx.locals.get(sym))).intValue();
+ ctx.code.emitSTORE(index, typeStoJ(sym.info()));
+ }
}
- protected boolean isPrimitive(Symbol sym) {
- if (prims.isPrimitive(sym)) {
- switch (prims.getPrimitive(sym)) {
- case POS : case NEG :
- case ADD : case SUB : case MUL : case DIV : case MOD :
- case NOT : case OR : case XOR : case AND :
- case LSL : case LSR : case ASR :
- case EQ : case NE : case LT : case LE : case GE : case GT :
- case ZNOT : case ZOR : case ZAND :
- case NEW_ZARRAY : case NEW_BARRAY : case NEW_SARRAY :
- case NEW_CARRAY : case NEW_IARRAY : case NEW_LARRAY :
- case NEW_FARRAY : case NEW_DARRAY :
- case ZARRAY_GET : case BARRAY_GET : case SARRAY_GET :
- case CARRAY_GET : case IARRAY_GET : case LARRAY_GET :
- case FARRAY_GET : case DARRAY_GET : case OARRAY_GET :
- case ZARRAY_SET : case BARRAY_SET : case SARRAY_SET :
- case CARRAY_SET : case IARRAY_SET : case LARRAY_SET :
- case FARRAY_SET : case DARRAY_SET : case OARRAY_SET :
- case ZARRAY_LENGTH : case BARRAY_LENGTH : case SARRAY_LENGTH :
- case CARRAY_LENGTH : case IARRAY_LENGTH : case LARRAY_LENGTH :
- case FARRAY_LENGTH : case DARRAY_LENGTH : case OARRAY_LENGTH :
- case IS : case AS :
- case CONCAT :
- case THROW :
- case AS_UVALUE :
- return true;
-
- case AS_ZVALUE : case AS_BVALUE : case AS_SVALUE :
- case AS_CVALUE : case AS_IVALUE : case AS_LVALUE :
- case AS_FVALUE : case AS_DVALUE :
- case AS_ZARRAY : case AS_BARRAY : case AS_SARRAY :
- case AS_CARRAY : case AS_IARRAY : case AS_LARRAY :
- case AS_FARRAY : case AS_DARRAY : case AS_OARRAY :
- case NEW_OARRAY :
- case EQUALS :
- case HASHCODE :
- case TOSTRING :
- case BOX :
- case APPLY : case UPDATE : case LENGTH :
- return false;
- default:
- throw Debug.abort("unknown primitive", sym);
+ /**
+ * Generate code to evaluate the condition associated with the
+ * given tree and jump to the target when the condition is equal
+ * to the given value.
+ */
+ protected void genCond(Context ctx,
+ Tree tree,
+ JLabel target,
+ boolean when) {
+ switch (tree) {
+ case Apply(Tree fun, Tree[] args):
+ if (isKnownPrimitive(fun.symbol())) {
+ Primitive prim = prims.getPrimitive(fun.symbol());
+ Tree[] allArgs = extractPrimitiveArgs((Tree.Apply)tree);
+
+ switch (prim) {
+ case EQ: case NE: case LT: case LE: case GE: case GT:
+ assert allArgs.length == 2;
+ genCompPrim(ctx, prim, allArgs, target, when);
+ return;
+
+ case ZNOT:
+ assert allArgs.length == 1;
+ genCond(ctx, allArgs[0], target, !when);
+ return;
+
+ case ZOR:
+ case ZAND:
+ JLabel afterLabel = new JLabel();
+ if (when ^ (prim == Primitive.ZAND)) {
+ // x || y jump if true -or- x && y jump if false
+ genCond(ctx, allArgs[0], target, when);
+ genCond(ctx, allArgs[1], target, when);
+ } else {
+ // x || y jump if false -or- x && y jump if true
+ genCond(ctx, allArgs[0], afterLabel, !when);
+ genCond(ctx, allArgs[1], target, when);
+ }
+ ctx.code.anchorLabelToNext(afterLabel);
+ return;
+ }
}
- } else
- return false;
- }
-
- protected byte genPrimitive(Primitive prim,
- Tree[] args,
- byte resType,
- byte expectedType,
- InstrContext ctx) {
- switch (prim) {
- case POS: case NEG:
- case ADD: case SUB: case MUL: case DIV: case MOD:
- case NOT: case OR : case XOR: case AND:
- case LSL: case LSR: case ASR:
- return genArithPrim(prim, args, resType, expectedType, ctx);
- case EQ: case NE: case LT: case LE: case GE: case GT:
- case ZNOT: case ZOR: case ZAND:
- return genCompOrLogicalPrim(prim, args, resType, expectedType, ctx);
- case THROW:
- assert args.length == 1;
- return genThrow(args[0]);
- case NEW_ZARRAY :
- case NEW_BARRAY :
- case NEW_SARRAY :
- case NEW_CARRAY :
- case NEW_IARRAY :
- case NEW_LARRAY :
- case NEW_FARRAY :
- case NEW_DARRAY :
- return genArrayCreate(prim, args[1]);
-// case NEW_OARRAY :
-// return genArrayCreate(prim, args[1], args[2]);
- case ZARRAY_SET : case BARRAY_SET : case SARRAY_SET :
- case CARRAY_SET : case IARRAY_SET : case LARRAY_SET :
- case FARRAY_SET : case DARRAY_SET : case OARRAY_SET :
- assert args.length == 4;
- return genArrayUpdate(args[1], args[2], args[3]);
- case ZARRAY_GET : case BARRAY_GET : case SARRAY_GET :
- case CARRAY_GET : case IARRAY_GET : case LARRAY_GET :
- case FARRAY_GET : case DARRAY_GET : case OARRAY_GET :
- assert args.length == 3 : "get - " + args.length;
- return genArrayAccess(args[1], args[2]);
- case ZARRAY_LENGTH : case BARRAY_LENGTH : case SARRAY_LENGTH :
- case CARRAY_LENGTH : case IARRAY_LENGTH : case LARRAY_LENGTH :
- case FARRAY_LENGTH : case DARRAY_LENGTH : case OARRAY_LENGTH :
- assert args.length == 2 : args.length;
- return genArrayLength(args[1]);
- case AS_UVALUE :
- assert args.length == 1;
- gen(args[0], cst.T_VOID);
- return cst.T_VOID;
- default:
- throw Debug.abort("unknown primitive ", prim);
}
+ // Default case: the condition is not a comparison or logical
+ // primitive.
+ genLoad(ctx, tree, JType.BOOLEAN);
+ if (when)
+ ctx.code.emitIFNE(target);
+ else
+ ctx.code.emitIFEQ(target);
}
protected Map/*<Primitive, Instruction>*/ arithPrimMap;
protected void addPrim(Primitive prim,
- Instruction z,
- Instruction i,
- Instruction l,
- Instruction f,
- Instruction d) {
- arithPrimMap.put(prim, new Instruction[] { z, i, l, f, d });
+ JOpcode z,
+ JOpcode i,
+ JOpcode l,
+ JOpcode f,
+ JOpcode d) {
+ arithPrimMap.put(prim, new JOpcode[] { z, i, l, f, d });
}
protected void initArithPrimMap() {
arithPrimMap = new HashMap();
- /* boolean int ... long float double */
- addPrim(Primitive.ADD , null, ic.IADD , ic.LADD , ic.FADD , ic.DADD);
- addPrim(Primitive.SUB , null, ic.ISUB , ic.LSUB , ic.FSUB , ic.DSUB);
- addPrim(Primitive.MUL , null, ic.IMUL , ic.LMUL , ic.FMUL , ic.DMUL);
- addPrim(Primitive.DIV , null, ic.IDIV , ic.LDIV , ic.FDIV , ic.DDIV);
- addPrim(Primitive.MOD , null, ic.IREM , ic.LREM , ic.FREM , ic.DREM);
- addPrim(Primitive.AND , ic.IAND, ic.IAND , ic.LAND , null , null);
- addPrim(Primitive.OR , ic.IOR, ic.IOR , ic.LOR , null , null);
- addPrim(Primitive.XOR , ic.IXOR, ic.IXOR , ic.LXOR , null , null);
- addPrim(Primitive.LSL , null, ic.ISHL , ic.LSHL , null , null);
- addPrim(Primitive.LSR , null, ic.IUSHR , ic.LUSHR , null , null);
- addPrim(Primitive.ASR , null, ic.ISHR , ic.LSHR , null , null);
- addPrim(Primitive.POS , null, null , null , null , null);
- addPrim(Primitive.NEG , null, ic.INEG , ic.LNEG , ic.FNEG , ic.DNEG);
+ /* boolean, int & al., long, float, double */
+ addPrim(Primitive.ADD,
+ null, JOpcode.IADD, JOpcode.LADD, JOpcode.FADD, JOpcode.DADD);
+ addPrim(Primitive.SUB,
+ null, JOpcode.ISUB, JOpcode.LSUB, JOpcode.FSUB, JOpcode.DSUB);
+ addPrim(Primitive.MUL,
+ null, JOpcode.IMUL, JOpcode.LMUL, JOpcode.FMUL, JOpcode.DMUL);
+ addPrim(Primitive.DIV,
+ null, JOpcode.IDIV, JOpcode.LDIV, JOpcode.FDIV, JOpcode.DDIV);
+ addPrim(Primitive.MOD,
+ null, JOpcode.IREM, JOpcode.LREM, JOpcode.FREM, JOpcode.DREM);
+ addPrim(Primitive.AND,
+ JOpcode.IAND, JOpcode.IAND, JOpcode.LAND, null, null);
+ addPrim(Primitive.OR,
+ JOpcode.IOR, JOpcode.IOR, JOpcode.LOR, null, null);
+ addPrim(Primitive.XOR,
+ JOpcode.IXOR, JOpcode.IXOR, JOpcode.LXOR, null, null);
+ addPrim(Primitive.LSL,
+ null, JOpcode.ISHL, JOpcode.LSHL, null, null);
+ addPrim(Primitive.LSR,
+ null, JOpcode.IUSHR, JOpcode.LUSHR, null, null);
+ addPrim(Primitive.ASR,
+ null, JOpcode.ISHR, JOpcode.LSHR, null, null);
+ addPrim(Primitive.POS,
+ null, null, null, null, null);
+ addPrim(Primitive.NEG,
+ null, JOpcode.INEG, JOpcode.LNEG, JOpcode.FNEG, JOpcode.DNEG);
}
- protected byte genArithPrim(Primitive prim,
+ /**
+ * Generate code for the given arithmetic primitive, applied on
+ * the given arguments.
+ */
+ protected void genArithPrim(Context ctx,
+ Primitive prim,
Tree[] args,
- byte resType,
- byte expectedType,
- InstrContext ctx) {
+ JType resType,
+ JType expectedType) {
int arity = args.length;
int resTypeIdx = getTypeIndex(resType);
for (int i = 0; i < arity; ++i)
- gen(args[i], resType);
+ genLoad(ctx, args[i], resType);
if (prim == Primitive.NOT) {
- assert resType == cst.T_INT || resType == cst.T_LONG;
- boolean isLong = (resType == cst.T_LONG);
- if (isLong) {
- currIL.append(new PUSH(currPool, -1L));
- currIL.append(ic.LXOR);
+ if (resType == JType.LONG) {
+ ctx.code.emitPUSH(-1L);
+ ctx.code.emitLXOR();
} else {
- currIL.append(new PUSH(currPool, -1));
- currIL.append(ic.IXOR);
+ assert resType == JType.INT;
+ ctx.code.emitPUSH(-1);
+ ctx.code.emitIXOR();
}
} else {
assert arithPrimMap.containsKey(prim);
- Instruction primInst = ((Instruction[])arithPrimMap.get(prim))[resTypeIdx];
+ JOpcode primInst = ((JOpcode[])arithPrimMap.get(prim))[resTypeIdx];
if (primInst != null)
- currIL.append(primInst);
- }
- return resType;
- }
-
- protected byte genCompOrLogicalPrim(Primitive prim,
- Tree[] args,
- byte resType,
- byte expectedType,
- InstrContext ctx) {
- // Ensure that all comparisons happen in the context of an
- // "if".
- InstructionHandle target;
- boolean when;
- InstructionList epilogue = new InstructionList();
- byte realResType;
- switch (ctx) {
- case InstrContext.If(InstructionHandle t, boolean w):
- target = t; when = w; realResType = cst.T_VOID; break;
- default:
- epilogue.append(ic.ICONST_1);
- BranchInstruction gotoAfter = new GOTO(null);
- epilogue.append(gotoAfter);
- target = epilogue.append(ic.ICONST_0);
- gotoAfter.setTarget(epilogue.append(ic.NOP));
- when = false;
- realResType = cst.T_BOOLEAN;
- break;
- }
-
- if (prim == Primitive.ZNOT
- || prim == Primitive.ZOR
- || prim == Primitive.ZAND)
- genLogicalPrim(prim, args, resType, expectedType, target, when);
- else
- genCompPrim(prim, args, resType, expectedType, target, when);
-
- currIL.append(epilogue);
- return realResType;
- }
-
- protected byte getMaxType(Tree[] trees) {
- byte maxType = cst.T_BOOLEAN;
- int maxTypeIdx = getTypeIndex(maxType);
-
- for (int i = 0; i < trees.length; ++i) {
- byte argType = typeStoJ(trees[i].type).getType();
- if (getTypeIndex(argType) > maxTypeIdx) {
- maxType = argType;
- maxTypeIdx = getTypeIndex(maxType);
- }
+ ctx.code.emit(primInst);
}
- return maxType;
}
+ /** Counter for temporary variables */
protected static int tempCounter = 1;
- protected void genCompPrim(Primitive prim,
+
+ /**
+ * Generate code for the given comparison primitive, applied on
+ * the given arguments.
+ */
+ protected void genCompPrim(Context ctx,
+ Primitive prim,
Tree[] args,
- byte resType,
- byte expectedType,
- InstructionHandle target,
+ JLabel target,
boolean when) {
- byte maxType = getMaxType(args);
+ JType maxType = getMaxType(args);
int maxTypeIdx = getTypeIndex(maxType);
- int intTypeIdx = getTypeIndex(Type.INT);
+ int intTypeIdx = getTypeIndex(JType.INT);
boolean intCompareWithZero = false;
+ // Generate code for all arguments, while detecting
+ // comparisons with 0, which can be optimised.
for (int i = 0; i < args.length; ++i) {
boolean isIntZero = false;
if (maxTypeIdx <= intTypeIdx) {
@@ -885,154 +762,175 @@ class GenJVM {
}
}
if (intCompareWithZero || !isIntZero)
- gen(args[i], maxType);
+ genLoad(ctx, args[i], maxType);
intCompareWithZero |= isIntZero;
}
- if (maxType == cst.T_OBJECT) {
+ if (maxType.isReferenceType()) {
+ // Comparison between two references. We inline the code
+ // for the predefined (and final) "=="/"!=" operators,
+ // which check for null values and then forward the call
+ // to "equals". "==" could be defined as follows, if
+ // "null" was an object:
+ // final def ==(other: Any): boolean =
+ // if (this == null) other == null else this.equals(other)
assert prim == Primitive.EQ || prim == Primitive.NE;
- LocalVariableGen lGen =
- currMethod.addLocalVariable("temp" + tempCounter++,
- Type.OBJECT,
- currIL.getEnd(),
- null);
- currIL.append(new ASTORE(lGen.getIndex()));
- currIL.append(ic.DUP);
- BranchInstruction ifNonNull = new IFNONNULL(null);
- currIL.append(ifNonNull);
- currIL.append(ic.POP);
- currIL.append(new ALOAD(lGen.getIndex()));
+ // TODO we should be able to create only one such variable
+ // per method.
+ JLocalVariable var =
+ ctx.method.addNewLocalVariable(JObjectType.JAVA_LANG_OBJECT,
+ "temp" + tempCounter++);
+ ctx.code.emitSTORE(var);
+ ctx.code.emitDUP();
+ JLabel ifNonNullLabel = new JLabel();
+ ctx.code.emitIFNONNULL(ifNonNullLabel);
+ ctx.code.emitPOP();
+ ctx.code.emitLOAD(var);
if (when ^ (prim != Primitive.EQ))
- currIL.append(new IFNULL(target));
+ ctx.code.emitIFNULL(target);
else
- currIL.append(new IFNONNULL(target));
- BranchInstruction gotoAfter = new GOTO(null);
- currIL.append(gotoAfter);
- InstructionHandle nonNullHandle =
- currIL.append(new ALOAD(lGen.getIndex()));
- ifNonNull.setTarget(nonNullHandle);
- lGen.setEnd(nonNullHandle);
- String equalsSig =
- Type.getMethodSignature(Type.BOOLEAN,
- new Type[] { Type.OBJECT });
- int equalsIndex =
- currPool.addMethodref(JAVA_LANG_OBJECT, "equals", equalsSig);
- currIL.append(new INVOKEVIRTUAL(equalsIndex));
+ ctx.code.emitIFNONNULL(target);
+ JLabel afterLabel = new JLabel();
+ ctx.code.emitGOTO(afterLabel);
+ ctx.code.anchorLabelToNext(ifNonNullLabel);
+ ctx.code.emitLOAD(var);
+ JMethodType equalsType =
+ new JMethodType(JType.BOOLEAN,
+ new JType[] { JObjectType.JAVA_LANG_OBJECT });
+ ctx.code.emitINVOKEVIRTUAL(JAVA_LANG_OBJECT, "equals", equalsType);
if (when ^ (prim != Primitive.EQ))
- currIL.append(new IFNE(target));
+ ctx.code.emitIFNE(target);
else
- currIL.append(new IFEQ(target));
- gotoAfter.setTarget(currIL.append(ic.NOP));
+ ctx.code.emitIFEQ(target);
+ ctx.code.anchorLabelToNext(afterLabel);
} else if (maxTypeIdx <= intTypeIdx && !intCompareWithZero) {
+ // Comparison between ints, no zeros involved
switch (maybeNegatedPrim(prim, !when)) {
- case LT: currIL.append(new IF_ICMPLT(target)); break;
- case LE: currIL.append(new IF_ICMPLE(target)); break;
- case EQ: currIL.append(new IF_ICMPEQ(target)); break;
- case NE: currIL.append(new IF_ICMPNE(target)); break;
- case GE: currIL.append(new IF_ICMPGE(target)); break;
- case GT: currIL.append(new IF_ICMPGT(target)); break;
+ case LT: ctx.code.emitIF_ICMPLT(target); break;
+ case LE: ctx.code.emitIF_ICMPLE(target); break;
+ case EQ: ctx.code.emitIF_ICMPEQ(target); break;
+ case NE: ctx.code.emitIF_ICMPNE(target); break;
+ case GE: ctx.code.emitIF_ICMPGE(target); break;
+ case GT: ctx.code.emitIF_ICMPGT(target); break;
default: throw global.fail("unknown primitive " + prim);
}
} else {
- switch (maxType) {
- case cst.T_LONG: currIL.append(ic.LCMP); break;
- case cst.T_FLOAT: currIL.append(ic.FCMPG); break;
- case cst.T_DOUBLE: currIL.append(ic.DCMPG); break;
+ // Comparison between longs, floats or double, or between
+ // one int and zero.
+ switch (maxType.getTag()) {
+ case JType.T_LONG: ctx.code.emitLCMP(); break;
+ case JType.T_FLOAT: ctx.code.emitFCMPG(); break;
+ case JType.T_DOUBLE: ctx.code.emitDCMPG(); break;
default:
; // do nothing (int comparison with 0)
}
switch (maybeNegatedPrim(prim, !when)) {
- case LT: currIL.append(new IFLT(target)); break;
- case LE: currIL.append(new IFLE(target)); break;
- case EQ: currIL.append(new IFEQ(target)); break;
- case NE: currIL.append(new IFNE(target)); break;
- case GE: currIL.append(new IFGE(target)); break;
- case GT: currIL.append(new IFGT(target)); break;
+ case LT: ctx.code.emitIFLT(target); break;
+ case LE: ctx.code.emitIFLE(target); break;
+ case EQ: ctx.code.emitIFEQ(target); break;
+ case NE: ctx.code.emitIFNE(target); break;
+ case GE: ctx.code.emitIFGE(target); break;
+ case GT: ctx.code.emitIFGT(target); break;
default: throw global.fail("unknown primitive " + prim);
}
}
}
- protected Primitive maybeNegatedPrim(Primitive prim, boolean negate) {
- return negate ? prim.negate() : prim;
+ /**
+ * Generate code to throw the value returned by the argument.
+ */
+ protected void genThrow(Context ctx, Tree arg) {
+ genLoad(ctx, arg, JAVA_LANG_OBJECT_T);
+ ctx.code.emitCHECKCAST(JAVA_LANG_THROWABLE_T);
+ ctx.code.emitATHROW();
}
- protected void genLogicalPrim(Primitive prim,
- Tree[] args,
- byte resType,
- byte expectedType,
- InstructionHandle target,
- boolean when) {
- if (prim == Primitive.ZNOT)
- gen(args[0], new InstrContext.If(target, !when));
- else {
- InstructionHandle fakeAfterH = currIL.append(ic.NOP);
- if (when ^ (prim == Primitive.ZAND)) {
- // x || y jump if true or x && y jump if false
- gen(args[0], new InstrContext.If(target, when));
- gen(args[1], new InstrContext.If(target, when));
- } else {
- // x || y jump if false or x && y jump if true
- gen(args[0], new InstrContext.If(fakeAfterH, !when));
- gen(args[1], new InstrContext.If(target, when));
- currIL.move(fakeAfterH, currIL.append(ic.NOP).getPrev());
- }
- }
- }
+ protected JOpcode[][] WIDENING_CONVERSION_TABLE = {
+ /* bool int long float double */
+ /* boolean */ { null, null, null, null, null },
+ /* int ... */ { null, null, JOpcode.I2L, JOpcode.I2F, JOpcode.I2D },
+ /* long */ { null, null, null, JOpcode.L2F, JOpcode.L2D },
+ /* float */ { null, null, null, null, JOpcode.F2D },
+ /* double */ { null, null, null, null, null }
+ };
- protected byte genThrow(Tree arg) {
- gen(arg, cst.T_OBJECT);
- currIL.append(new CHECKCAST(currPool.addClass("java.lang.Throwable")));
- currIL.append(ic.ATHROW);
- return cst.T_OBJECT;
+ protected void genWidenConversion(Context ctx, JType from, JType to) {
+ int fromIdx = getTypeIndex(from);
+ int toIdx = getTypeIndex(to);
+
+ assert (fromIdx <= 4 && toIdx <= 4) : from + " -> " + to;
+ JOpcode instr = WIDENING_CONVERSION_TABLE[fromIdx][toIdx];
+ if (instr != null)
+ ctx.code.emit(instr);
}
- protected byte genArrayCreate(Primitive prim, Tree size) {
- gen(size, cst.T_INT);
- byte type;
+ /// Arrays
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Generate code to create an array, whose size will be
+ * dynamically computed.
+ */
+ protected void genArrayCreate(Context ctx, Primitive prim, Tree size) {
+ genLoad(ctx, size, JType.INT);
+ JType type;
switch (prim) {
- case NEW_ZARRAY : type = cst.T_BOOLEAN; break;
- case NEW_BARRAY : type = cst.T_BYTE; break;
- case NEW_SARRAY : type = cst.T_SHORT; break;
- case NEW_CARRAY : type = cst.T_CHAR; break;
- case NEW_IARRAY : type = cst.T_INT; break;
- case NEW_LARRAY : type = cst.T_LONG; break;
- case NEW_FARRAY : type = cst.T_FLOAT; break;
- case NEW_DARRAY : type = cst.T_DOUBLE; break;
+ case NEW_ZARRAY : type = JType.BOOLEAN; break;
+ case NEW_BARRAY : type = JType.BYTE; break;
+ case NEW_SARRAY : type = JType.SHORT; break;
+ case NEW_CARRAY : type = JType.CHAR; break;
+ case NEW_IARRAY : type = JType.INT; break;
+ case NEW_LARRAY : type = JType.LONG; break;
+ case NEW_FARRAY : type = JType.FLOAT; break;
+ case NEW_DARRAY : type = JType.DOUBLE; break;
default: throw Debug.abort("unexpected primitive", prim);
}
- currIL.append(new NEWARRAY(type));
- return cst.T_ARRAY;
+ ctx.code.emitNEWARRAY(type);
}
- protected byte genArrayUpdate(Tree array, Tree index, Tree value) {
- ArrayType arrayType = (ArrayType)typeStoJ(array.type);
- Type elemType = arrayType.getElementType();
- gen(array, cst.T_ARRAY);
- gen(index, cst.T_INT);
- if (elemType instanceof BasicType)
+ /**
+ * Generate code to update an array.
+ */
+ protected void genArrayUpdate(Context ctx, Tree array, Tree index, Tree value) {
+ genLoad(ctx, array, JAVA_LANG_OBJECT_T);
+ genLoad(ctx, index, JType.INT);
+ JType elemType = getArrayElementType(array);
+ if (elemType.isValueType())
value = unbox(value);
- gen(value, elemType.getType());
- currIL.append(new Generic_ASTORE(elemType));
- return cst.T_VOID;
+ genLoad(ctx, value, elemType);
+ ctx.code.emitASTORE(elemType);
+ }
+
+ /**
+ * Generate code to load an element of an array.
+ */
+ protected void genArrayAccess(Context ctx, Tree array, Tree index) {
+ genLoad(ctx, array, JAVA_LANG_OBJECT_T);
+ genLoad(ctx, index, JType.INT);
+ ctx.code.emitALOAD(getArrayElementType(array));
}
- protected byte genArrayAccess(Tree array, Tree index) {
- ArrayType arrayType = (ArrayType)typeStoJ(array.type);
- Type elemType = arrayType.getElementType();
- gen(array, cst.T_ARRAY);
- gen(index, cst.T_INT);
- currIL.append(new Generic_ALOAD(elemType));
- return elemType.getType();
+ /**
+ * Generate code to load the length of an array.
+ */
+ protected void genArrayLength(Context ctx, Tree array) {
+ genLoad(ctx, array, JAVA_LANG_OBJECT_T);
+ ctx.code.emitARRAYLENGTH();
}
- protected byte genArrayLength(Tree array) {
- gen(array, cst.T_ARRAY);
- currIL.append(ic.ARRAYLENGTH);
- return cst.T_INT;
+ /**
+ * Return the Java type of the elements of the array represented
+ * by the given tree.
+ */
+ protected JType getArrayElementType(Tree array) {
+ JArrayType arrayType = (JArrayType)typeStoJ(array.type);
+ return arrayType.getElementType();
}
+ /// String concatenation
+ //////////////////////////////////////////////////////////////////////
+
protected Tree[] liftStringConcatenations(Tree tree) {
LinkedList accu = new LinkedList();
liftStringConcatenations(tree, accu);
@@ -1055,338 +953,355 @@ class GenJVM {
}
}
- protected void genStringConcatenation(Tree[] elements) {
- ObjectType strBufType = new ObjectType (JAVA_LANG_STRINGBUFFER);
-
- int constRef = currPool.addMethodref(JAVA_LANG_STRINGBUFFER,
- "<init>",
- VOID_NO_ARGS_SIG);
- currIL.append (new NEW (currPool.addClass (JAVA_LANG_STRINGBUFFER)));
- currIL.append (ic.DUP);
- currIL.append (new INVOKESPECIAL (constRef));
-
+ /**
+ * Generate code to concatenate a list of expressions which return
+ * strings.
+ */
+ protected void genStringConcatenation(Context ctx, Tree[] elements) {
+ // Create string buffer
+ ctx.code.emitNEW(JAVA_LANG_STRINGBUFFER);
+ ctx.code.emitDUP();
+ ctx.code.emitINVOKESPECIAL(JAVA_LANG_STRINGBUFFER,
+ "<init>",
+ JMethodType.ARGLESS_VOID_FUNCTION);
+
+ // Append all strings
for (int i = 0; i < elements.length; ++i) {
- Type elemType = typeStoJ(elements[i].type);
- if (!elemType.equals(Type.STRING)
- && elemType.getType() == cst.T_OBJECT)
- elemType = Type.OBJECT;
- String appendSig =
- Type.getMethodSignature(strBufType, new Type[] { elemType });
- int appendRef =
- currPool.addMethodref(JAVA_LANG_STRINGBUFFER, "append", appendSig);
- gen(elements[i], elemType.getType());
- currIL.append(new INVOKEVIRTUAL(appendRef));
+ JType elemType = typeStoJ(elements[i].type);
+ if (!elemType.equals(JObjectType.JAVA_LANG_STRING)
+ && elemType.isObjectType())
+ elemType = JObjectType.JAVA_LANG_OBJECT;
+ genLoad(ctx, elements[i], elemType);
+ ctx.code.emitINVOKEVIRTUAL(JAVA_LANG_STRINGBUFFER,
+ "append",
+ new JMethodType(JAVA_LANG_STRINGBUFFER_T,
+ new JType[] { elemType }));
}
- String toStringSig = Type.getMethodSignature (Type.STRING, Type.NO_ARGS);
- final int toStringRef =
- currPool.addMethodref (JAVA_LANG_STRINGBUFFER, "toString", toStringSig);
- currIL.append (new INVOKEVIRTUAL (toStringRef));
+ // Get resulting string
+ ctx.code.emitINVOKEVIRTUAL(JAVA_LANG_STRINGBUFFER,
+ "toString",
+ new JMethodType(JObjectType.JAVA_LANG_STRING,
+ JType.EMPTY_ARRAY));
}
- protected int getTypeIndex(Type tp) {
- return getTypeIndex(tp.getType());
+ /// Primitives
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Return true iff the given symbol is a primitive, AND that
+ * primitive is recognized by this back-end.
+ */
+ protected boolean isKnownPrimitive(Symbol sym) {
+ if (prims.isPrimitive(sym)) {
+ switch (prims.getPrimitive(sym)) {
+ case POS : case NEG :
+ case ADD : case SUB : case MUL : case DIV : case MOD :
+ case NOT : case OR : case XOR : case AND :
+ case LSL : case LSR : case ASR :
+ case EQ : case NE : case LT : case LE : case GE : case GT :
+ case ZNOT : case ZOR : case ZAND :
+ case NEW_ZARRAY : case NEW_BARRAY : case NEW_SARRAY :
+ case NEW_CARRAY : case NEW_IARRAY : case NEW_LARRAY :
+ case NEW_FARRAY : case NEW_DARRAY :
+ case ZARRAY_GET : case BARRAY_GET : case SARRAY_GET :
+ case CARRAY_GET : case IARRAY_GET : case LARRAY_GET :
+ case FARRAY_GET : case DARRAY_GET : case OARRAY_GET :
+ case ZARRAY_SET : case BARRAY_SET : case SARRAY_SET :
+ case CARRAY_SET : case IARRAY_SET : case LARRAY_SET :
+ case FARRAY_SET : case DARRAY_SET : case OARRAY_SET :
+ case ZARRAY_LENGTH : case BARRAY_LENGTH : case SARRAY_LENGTH :
+ case CARRAY_LENGTH : case IARRAY_LENGTH : case LARRAY_LENGTH :
+ case FARRAY_LENGTH : case DARRAY_LENGTH : case OARRAY_LENGTH :
+ case IS : case AS :
+ case CONCAT :
+ case THROW :
+ case AS_UVALUE :
+ return true;
+
+ case AS_ZVALUE : case AS_BVALUE : case AS_SVALUE :
+ case AS_CVALUE : case AS_IVALUE : case AS_LVALUE :
+ case AS_FVALUE : case AS_DVALUE :
+ case AS_ZARRAY : case AS_BARRAY : case AS_SARRAY :
+ case AS_CARRAY : case AS_IARRAY : case AS_LARRAY :
+ case AS_FARRAY : case AS_DARRAY : case AS_OARRAY :
+ case NEW_OARRAY :
+ case EQUALS :
+ case HASHCODE :
+ case TOSTRING :
+ case BOX :
+ case APPLY : case UPDATE : case LENGTH :
+ return false;
+ default:
+ throw Debug.abort("unknown primitive", sym);
+ }
+ } else
+ return false;
}
- protected int getTypeIndex(byte tp) {
- switch (tp) {
- case cst.T_BOOLEAN: return 0;
- case cst.T_BYTE:
- case cst.T_CHAR:
- case cst.T_SHORT:
- case cst.T_INT: return 1;
- case cst.T_LONG: return 2;
- case cst.T_FLOAT: return 3;
- case cst.T_DOUBLE: return 4;
- case cst.T_ARRAY:
- case cst.T_OBJECT: return 5;
- default: return -1;
- }
+ /**
+ * Negate the given primitive only if the second argument is
+ * true, otherwise return it as is.
+ */
+ protected Primitive maybeNegatedPrim(Primitive prim, boolean negate) {
+ return negate ? prim.negate() : prim;
}
- protected Instruction[][] WIDENING_CONVERSION_TABLE = {
- /* bool int long float double */
- /* boolean */ { null, null , null , null , null },
- /* int ... */ { null, null , ic.I2L , ic.I2F , ic.I2D },
- /* long */ { null, null , null , ic.L2F , ic.L2D },
- /* float */ { null, null , null , null , ic.F2D },
- /* double */ { null, null , null , null , null }
- };
+ /**
+ * Return all the arguments associated with the primitive
+ * represented by the given function call.
+ */
+ protected Tree[] extractPrimitiveArgs(Tree.Apply call) {
+ Tree[] allArgs = new Tree[call.args.length + 1];
+ allArgs[0] = unbox(((Tree.Select)(call.fun)).qualifier);
+ System.arraycopy(call.args, 0, allArgs, 1, call.args.length);
+ return allArgs;
+ }
- protected void genWidenConversion(byte origType, byte finalType) {
- int origIdx = getTypeIndex(origType);
- int finalIdx = getTypeIndex(finalType);
+ /**
+ * Return the unboxed version of the given tree.
+ */
+ protected Tree unbox(Tree tree) {
+ switch (tree) {
+ case Apply(Tree fun, Tree[] args):
+ if (prims.getPrimitive(fun.symbol()) == Primitive.BOX) {
+ assert args.length == 1;
+ return args[0];
+ } else
+ return tree;
+ case Block(Tree[] stats):
+ if (stats.length == 2
+ && prims.getPrimitive(stats[1].symbol()) == Primitive.BOX) {
+ return stats[0];
+ } else
+ return tree;
+ default:
+ return tree;
+ }
+ }
- assert (origIdx <= 4 && finalIdx <= 4)
- : cst.TYPE_NAMES[origType] + " -> " + cst.TYPE_NAMES[finalType];
- Instruction instr = WIDENING_CONVERSION_TABLE[origIdx][finalIdx];
- if (instr != null)
- currIL.append(instr);
+ /// Modules
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add field containing module instance, and code to initialize
+ * it, to current class.
+ */
+ protected void addModuleInstanceField(Context ctx) {
+ ctx.clazz.addNewField(JAccessFlags.ACC_PUBLIC
+ | JAccessFlags.ACC_FINAL
+ | JAccessFlags.ACC_STATIC,
+ MODULE_INSTANCE_FIELD_NAME,
+ ctx.clazz.getType());
+
+ JMethod initMethod =
+ ctx.clazz.addNewMethod(JAccessFlags.ACC_PUBLIC
+ | JAccessFlags.ACC_STATIC,
+ "<clinit>",
+ JType.VOID,
+ JType.EMPTY_ARRAY,
+ Strings.EMPTY_ARRAY);
+ JExtendedCode code = (JExtendedCode)initMethod.getCode();
+
+ code.emitNEW(ctx.clazz.getName());
+ code.emitINVOKESPECIAL(ctx.clazz.getName(),
+ CONSTRUCTOR_STRING,
+ JMethodType.ARGLESS_VOID_FUNCTION);
+ // The field is initialised by the constructor, so we don't
+ // need to do it here, creating the instance is sufficient.
+ code.emitRETURN();
}
- protected void dumpModuleMainClass(ClassGen modClassGen) {
- String moduleName = modClassGen.getClassName();
- String mainClassName = moduleName.substring(0, moduleName.length() - 1);
- ClassGen mainClassGen = new ClassGen(mainClassName,
- JAVA_LANG_OBJECT,
- sourceFileName,
- cst.ACC_SUPER
- | cst.ACC_PUBLIC
- | cst.ACC_FINAL,
- Strings.NONE);
- ConstantPoolGen mainPool = mainClassGen.getConstantPool();
-
- Method[] methods = modClassGen.getMethods();
+ /**
+ * Create a class which mirrors all public methods of the given
+ * module class as static methods, to enable the use of the module
+ * from Java.
+ */
+ protected void dumpModuleMirrorClass(Context ctx, JClass modClass) {
+ String mirrorName = modClass.getName();
+ String mainClassName = mirrorName.substring(0, mirrorName.length() - 1);
+
+ JClass mainClass = new JClass(JAccessFlags.ACC_SUPER
+ | JAccessFlags.ACC_PUBLIC
+ | JAccessFlags.ACC_FINAL,
+ mainClassName,
+ JAVA_LANG_OBJECT,
+ JClass.NO_INTERFACES,
+ ctx.sourceFileName);
+
+ JMethod[] methods = modClass.getMethods();
for (int i = 0; i < methods.length; ++i) {
- Method m = methods[i];
+ JMethod m = methods[i];
if (m.isProtected() || m.isPrivate() || m.isStatic()
|| m.getName().equals("<init>"))
continue;
- MethodGen mGen = new MethodGen(m, moduleName, mainPool);
-
- Type[] argTypes = mGen.getArgumentTypes();
- Type retType = mGen.getReturnType();
-
- InstructionList mainIL = new InstructionList();
- MethodGen mainMGen = new MethodGen(m.getAccessFlags() | cst.ACC_STATIC,
- retType,
- argTypes, mGen.getArgumentNames(),
- mGen.getName(),
- mainClassName,
- mainIL,
- mainPool);
- int moduleFieldIndex =
- mainPool.addFieldref(moduleName,
- MODULE_INSTANCE_FIELD_NAME,
- (new ObjectType(moduleName)).getSignature());
- int mIndex = mainPool.addMethodref(mGen);
+ JType retType = m.getReturnType();
+ JType[] argTypes = m.getArgumentTypes();
+ JMethod mirror =
+ mainClass.addNewMethod(m.getAccessFlags()
+ | JAccessFlags.ACC_STATIC,
+ m.getName(),
+ retType,
+ argTypes,
+ m.getArgumentNames());
+ JExtendedCode mirrorCode = (JExtendedCode)mirror.getCode();
- mainIL.append(new GETSTATIC(moduleFieldIndex));
- int pos = 0;
+ mirrorCode.emitGETSTATIC(mirrorName,
+ MODULE_INSTANCE_FIELD_NAME,
+ new JObjectType(mirrorName));
+ int index = 0;
for (int j = 0; j < argTypes.length; ++j) {
- mainIL.append(new Generic_LOAD(pos, argTypes[j]));
- pos += argTypes[j].getSize();
+ mirrorCode.emitLOAD(index, argTypes[j]);
+ index += argTypes[j].getSize();
}
- mainIL.append(new INVOKEVIRTUAL(mIndex));
- mainIL.append(new Generic_RETURN(retType));
- mainMGen.setMaxStack();
- mainClassGen.addMethod(mainMGen.getMethod());
+ mirrorCode.emitINVOKE(m);
+ mirrorCode.emitRETURN(retType);
}
- addScalaAttr(mainClassGen);
- JavaClass mainClass = mainClassGen.getJavaClass();
+ addScalaAttr(mainClass);
try {
- mainClass.dump(javaFileName(mainClassName));
- } catch (java.io.IOException e) {
- throw global.fail(e.getMessage());
- }
- }
-
-
- protected void addScalaAttr(ClassGen classGen) {
- ConstantPoolGen poolGen = classGen.getConstantPool();
-
- int scalaNameIndex =
- poolGen.addUtf8(ClassfileConstants.SCALA_N.toString());
- Unknown scalaAttr = new Unknown(scalaNameIndex,
- 0,
- null,
- poolGen.getConstantPool());
-
- classGen.addAttribute(scalaAttr);
- }
-
- // Context manipulation
-
- protected LinkedList/*<ClassGen>*/ classStack = new LinkedList();
-
- protected void enterClass(Symbol cSym) {
- String javaName = javaName(cSym);
-
- scalac.symtab.Type[] baseTps = cSym.info().parents();
- assert baseTps.length > 0 : Debug.show(cSym);
-
- int offset;
- String superClassName;
- if (cSym.isInterface()) {
- offset = baseTps[0].isSameAs(defs.ANY_TYPE) ? 1 : 0;
- superClassName = JAVA_LANG_OBJECT;
- } else {
- offset = 1;
- superClassName = javaName(baseTps[0].symbol());
- }
- String[] interfaceNames = new String[baseTps.length - offset];
- for (int i = offset; i < baseTps.length; ++i) {
- Symbol baseSym = baseTps[i].symbol();
- assert baseSym.isInterface() : cSym + " implements " + baseSym;
- interfaceNames[i - offset] = javaName(baseSym);
- }
-
- ClassGen cGen = new ClassGen(javaName,
- superClassName,
- sourceFileName,
- modifiersStoJ(cSym.flags) | cst.ACC_SUPER,
- interfaceNames);
- classStack.addFirst(cGen);
- updateClassContext();
- }
-
- protected HashSet seenClasses = new HashSet();
- protected void leaveClass(Symbol cSym) {
- if (isModuleClass) {
- if (!seenClasses.contains(cSym.fullName()))
- dumpModuleMainClass(currClass);
- } else
- seenClasses.add(cSym.fullName());
-
- addScalaAttr(currClass);
- JavaClass cls = currClass.getJavaClass();
- try {
- String fileName = javaFileName(cls.getClassName());
- cls.dump(fileName);
+ String fileName = javaFileName(mainClassName);
+ mainClass.writeTo(fileName);
global.operation("wrote " + fileName);
} catch (java.io.IOException e) {
throw global.fail(e.getMessage());
}
- classStack.removeFirst();
- updateClassContext();
}
- protected void updateClassContext() {
- if (classStack.isEmpty()) {
- currClass = null;
- currClassName = null;
- currPool = null;
- } else {
- ClassGen cGen = (ClassGen)classStack.getFirst();
- currClass = cGen;
- currClassName = currClass.getClassName();
- currPool = currClass.getConstantPool();
- }
+ /**
+ * Add the "Scala" attribute to the given class, in which the
+ * symbol table is saved.
+ */
+ protected void addScalaAttr(JClass cls) {
+ // TODO
+// ConstantPoolGen poolGen = classGen.getConstantPool();
+
+// int scalaNameIndex =
+// poolGen.addUtf8(ClassfileConstants.SCALA_N.toString());
+// Unknown scalaAttr = new Unknown(scalaNameIndex,
+// 0,
+// null,
+// poolGen.getConstantPool());
+
+// classGen.addAttribute(scalaAttr);
}
- protected void enterMethod(Tree.DefDef dDef) {
- Symbol dSym = dDef.symbol();
+ /// Names
+ //////////////////////////////////////////////////////////////////////
- global.log("entering method " + Debug.toString(dSym)
- + " (type: " + Debug.toString(dSym.info()) + ")");
-
- Map locals;
- if (currLocals == null)
- locals = new HashMap();
- else
- locals = new HashMap(currLocals);
-
- Tree.ValDef[] args = dDef.vparams[0];
- int argsNum = args.length;
-
- Type[] argTypes = new Type[argsNum];
- String[] argNames = new String[argsNum];
- for (int i = 0, pos = 1; i < argsNum; ++i) {
- argTypes[i] = typeStoJ(args[i].symbol().info());
- argNames[i] = args[i].name.toString();
- locals.put(args[i].symbol(), new Integer(pos));
- pos += argTypes[i].getSize();
+ /**
+ * Return a Java-compatible version of the name of the given
+ * symbol. The returned name is mangled and includes the names of
+ * the owners.
+ */
+ protected String javaName(Symbol sym) {
+ assert sym.isClass() || sym.isModule() : Debug.show(sym);
+ if (sym == defs.ANY_CLASS || sym == defs.ANYREF_CLASS)
+ return JAVA_LANG_OBJECT;
+ else {
+ StringBuffer buf = new StringBuffer(sym.name.toString());
+ if ((sym.isModule() || sym.isModuleClass()) && !sym.isJava())
+ buf.append('$');
+ for (sym = sym.owner(); !sym.isPackage(); sym = sym.owner()) {
+ buf.insert(0, '$');
+ buf.insert(0, sym.name);
+ }
+ if (!sym.isRoot()) {
+ buf.insert(0, '.');
+ buf.insert(0, sym.fullName());
+ }
+ return buf.toString();
}
-
- MethodGen mGen = new MethodGen(modifiersStoJ(dDef.mods),
- retTypeStoJ(dSym.info()),
- argTypes,
- argNames,
- dDef.name.toString(),
- currClassName,
- new InstructionList(),
- currPool);
-
- currMethod = mGen;
- currLocals = locals;
- currIL = currMethod.getInstructionList();
-
- lineAttributedInstrs = new HashMap();
}
- protected void leaveMethod() {
- global.log(" leaving method");
-
- currMethod.setMaxStack();
- currMethod.removeNOPs();
- currClass.addMethod(currMethod.getMethod());
-
- currMethod = null;
- currLocals = null;
- currIL = null;
+ /**
+ * Return the name of the file in which to store the given class.
+ */
+ protected String javaFileName(String className) {
+ StringTokenizer tokens = new StringTokenizer(className, ".");
+ File file = new File(global.outpath);
+ while (tokens.hasMoreElements())
+ file = new File(file, tokens.nextToken());
- lineAttributedInstrs = null;
+ return file.getPath() + ".class";
}
+ /// Types
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Return the Java modifiers corresponding to the given Scala
+ * modifiers.
+ */
protected int modifiersStoJ(int flags) {
int jFlags = 0;
if (Modifiers.Helper.isPrivate(flags))
- jFlags |= cst.ACC_PRIVATE;
- else if (Modifiers.Helper.isProtected(flags))
- jFlags |= cst.ACC_PROTECTED;
+ jFlags |= JAccessFlags.ACC_PRIVATE;
else
- jFlags |= cst.ACC_PUBLIC;
+ jFlags |= JAccessFlags.ACC_PUBLIC;
if (Modifiers.Helper.isAbstract(flags))
- jFlags |= cst.ACC_ABSTRACT;
+ jFlags |= JAccessFlags.ACC_ABSTRACT;
if (Modifiers.Helper.isInterface(flags))
- jFlags |= cst.ACC_INTERFACE;
+ jFlags |= JAccessFlags.ACC_INTERFACE;
if (Modifiers.Helper.isFinal(flags)
- && !(Modifiers.Helper.isAbstract(flags) || Modifiers.Helper.isInterface(flags)))
- jFlags |= cst.ACC_FINAL;
+ && !(Modifiers.Helper.isAbstract(flags)
+ || Modifiers.Helper.isInterface(flags)))
+ jFlags |= JAccessFlags.ACC_FINAL;
return jFlags;
}
- protected boolean isUnboxedType(scalac.symtab.Type tp) {
- switch (tp) {
- case UnboxedType(_):
- case UnboxedArrayType(_): return true;
- default: return false;
- }
- }
-
protected HashMap typeMap/*<Symbol,Type>*/ = new HashMap();
protected void initTypeMap() {
- typeMap.put(defs.ANY_CLASS, Type.OBJECT);
- typeMap.put(defs.ANYREF_CLASS, Type.OBJECT);
+ typeMap.put(defs.ANY_CLASS, JObjectType.JAVA_LANG_OBJECT);
+ typeMap.put(defs.ANYREF_CLASS, JObjectType.JAVA_LANG_OBJECT);
}
- protected Type typeStoJ(scalac.symtab.Type tp) {
+
+ /**
+ * Return the Java type corresponding to the given Scala type.
+ */
+ protected JType typeStoJ(Type tp) {
switch (tp) {
case UnboxedType(TypeTags.BYTE):
- return Type.BYTE;
+ return JType.BYTE;
case UnboxedType(TypeTags.CHAR):
- return Type.CHAR;
+ return JType.CHAR;
case UnboxedType(TypeTags.SHORT):
- return Type.SHORT;
+ return JType.SHORT;
case UnboxedType(TypeTags.INT):
- return Type.INT;
+ return JType.INT;
case UnboxedType(TypeTags.LONG):
- return Type.LONG;
+ return JType.LONG;
case UnboxedType(TypeTags.FLOAT):
- return Type.FLOAT;
+ return JType.FLOAT;
case UnboxedType(TypeTags.DOUBLE):
- return Type.DOUBLE;
+ return JType.DOUBLE;
case UnboxedType(TypeTags.BOOLEAN):
- return Type.BOOLEAN;
+ return JType.BOOLEAN;
case UnboxedType(TypeTags.UNIT):
- return Type.VOID;
+ return JType.VOID;
case UnboxedType(TypeTags.STRING):
- return Type.STRING;
- case UnboxedArrayType(scalac.symtab.Type elementType):
- return new ArrayType(typeStoJ(elementType), 1);
+ return JObjectType.JAVA_LANG_STRING;
+ case UnboxedArrayType(Type elementType):
+ return new JArrayType(typeStoJ(elementType));
+ case MethodType(Symbol[] vparams, Type result): {
+ JType[] argTypes = new JType[vparams.length];
+ for (int i = 0; i < vparams.length; ++i)
+ argTypes[i] = typeStoJ(vparams[i].info());
+ return new JMethodType(typeStoJ(result), argTypes);
+ }
default: {
Symbol sym = tp.symbol();
if (sym == Symbol.NONE)
throw global.fail("invalid type ", tp);
else if (typeMap.containsKey(sym))
- return (Type)typeMap.get(sym);
+ return (JType)typeMap.get(sym);
else {
- Type jTp = new ObjectType(javaName(sym));
+ JType jTp = new JObjectType(javaName(sym));
typeMap.put(sym, jTp);
return jTp;
}
@@ -1394,175 +1309,221 @@ class GenJVM {
}
}
- protected Type[] argTypesStoJ(scalac.symtab.Type tp) {
- switch (tp) {
- case MethodType(Symbol[] vparams, _):
- Type[] argTypes = new Type[vparams.length];
- for (int i = 0; i < vparams.length; ++i)
- argTypes[i] = typeStoJ(vparams[i].info());
- return argTypes;
- default:
- throw global.fail("invalid method type", tp);
- }
+ /**
+ * Return the "index" of the given type. This index encodes the
+ * level in the hierarchy of basic types, with arrays and objects
+ * on top of everything.
+ */
+ protected int getTypeIndex(JType tp) {
+ return getTypeIndex(tp.getTag());
}
- protected Type retTypeStoJ(scalac.symtab.Type tp) {
+ /**
+ * Return the "index" of the given type.
+ */
+ protected int getTypeIndex(int tp) {
switch (tp) {
- case MethodType(_, _):
- return typeStoJ(tp.resultType());
- default:
- throw global.fail("invalid method type", tp);
+ case JType.T_BOOLEAN: return 0;
+ case JType.T_BYTE:
+ case JType.T_CHAR:
+ case JType.T_SHORT:
+ case JType.T_INT: return 1;
+ case JType.T_LONG: return 2;
+ case JType.T_FLOAT: return 3;
+ case JType.T_DOUBLE: return 4;
+ case JType.T_ARRAY:
+ case JType.T_OBJECT: return 5;
+ default: return -1;
}
}
- protected String javaName(Symbol sym) {
- assert sym.isClass() : Debug.show(sym);
- if (sym == defs.ANY_CLASS || sym == defs.ANYREF_CLASS)
- return JAVA_LANG_OBJECT;
- else {
- StringBuffer buf = new StringBuffer(sym.name.toString());
- if ((sym.isModule() || sym.isModuleClass()) && !sym.isJava())
- buf.append('$');
- for (sym = sym.owner(); !sym.isPackage(); sym = sym.owner()) {
- buf.insert(0, '$');
- buf.insert(0, sym.name);
- }
- if (!sym.isRoot()) {
- buf.insert(0, '.');
- buf.insert(0, sym.fullName());
+ /**
+ * Return the maximum of the types of all the given trees. All
+ * reference types are considered to be equivalent, and if several
+ * reference types are present in the trees, any one of them is
+ * returned.
+ */
+ protected JType getMaxType(Tree[] trees) {
+ JType maxType = JType.BOOLEAN;
+ int maxTypeIdx = getTypeIndex(maxType);
+
+ for (int i = 0; i < trees.length; ++i) {
+ JType argType = typeStoJ(trees[i].type);
+ if (getTypeIndex(argType) > maxTypeIdx) {
+ maxType = argType;
+ maxTypeIdx = getTypeIndex(maxType);
}
- return buf.toString();
}
+ return maxType;
}
- protected String javaFileName(String className) {
- StringTokenizer tokens = new StringTokenizer(className, ".");
- File file = new File(global.outpath);
- while (tokens.hasMoreElements())
- file = new File(file, tokens.nextToken());
+ /// Context
+ //////////////////////////////////////////////////////////////////////
- return file.getPath() + ".class";
- }
+ /**
+ * Record the entry into a class, and return the appropriate
+ * context.
+ */
+ protected Context enterClass(Context ctx, Symbol cSym) {
+ String javaName = javaName(cSym);
- // Generic instructions
- static class Generic_RETURN implements CompoundInstruction {
- private ReturnInstruction inst;
-
- public Generic_RETURN(Type type) {
- switch (type.getType()) {
- case cst.T_VOID: inst = ic.RETURN; break;
- case cst.T_BOOLEAN:
- case cst.T_BYTE:
- case cst.T_CHAR:
- case cst.T_SHORT:
- case cst.T_INT: inst = ic.IRETURN; break;
- case cst.T_LONG: inst = ic.LRETURN; break;
- case cst.T_FLOAT: inst = ic.FRETURN; break;
- case cst.T_DOUBLE: inst = ic.DRETURN; break;
- case cst.T_ARRAY:
- case cst.T_OBJECT: inst = ic.ARETURN; break;
- default: throw Debug.abort("unexpected type " + type.getType());
- }
- }
+ scalac.symtab.Type[] baseTps = cSym.info().parents();
+ assert baseTps.length > 0 : Debug.show(cSym);
- public InstructionList getInstructionList() {
- return new InstructionList(inst);
+ int offset;
+ String superClassName;
+ if (cSym.isInterface()) {
+ offset = baseTps[0].isSameAs(defs.ANY_TYPE) ? 1 : 0;
+ superClassName = JAVA_LANG_OBJECT;
+ } else {
+ offset = 1;
+ superClassName = javaName(baseTps[0].symbol());
}
+ String[] interfaceNames = new String[baseTps.length - offset];
+ for (int i = offset; i < baseTps.length; ++i) {
+ Symbol baseSym = baseTps[i].symbol();
+ assert baseSym.isInterface() : cSym + " implements " + baseSym;
+ interfaceNames[i - offset] = javaName(baseSym);
+ }
+
+ JClass cls = new JClass(modifiersStoJ(cSym.flags)
+ | JAccessFlags.ACC_SUPER,
+ javaName,
+ superClassName,
+ interfaceNames,
+ ctx.sourceFileName);
+
+ return ctx.withClass(cls, cSym.isModuleClass());
}
- static class Generic_LOAD implements CompoundInstruction {
- private LoadInstruction inst;
-
- public Generic_LOAD(int pos, Type type) {
- switch (type.getType()) {
- case cst.T_BOOLEAN:
- case cst.T_BYTE:
- case cst.T_CHAR:
- case cst.T_SHORT:
- case cst.T_INT: inst = new ILOAD(pos); break;
- case cst.T_LONG: inst = new LLOAD(pos); break;
- case cst.T_FLOAT: inst = new FLOAD(pos); break;
- case cst.T_DOUBLE: inst = new DLOAD(pos); break;
- case cst.T_ARRAY:
- case cst.T_OBJECT: inst = new ALOAD(pos); break;
- default: throw Debug.abort("unexpected type");
- }
- }
+ protected HashSet seenClasses = new HashSet();
+ protected void leaveClass(Context ctx, Symbol cSym) {
+ if (ctx.isModuleClass && !seenClasses.contains(cSym.fullName()))
+ dumpModuleMirrorClass(ctx, ctx.clazz);
+ seenClasses.add(cSym.fullName());
- public InstructionList getInstructionList() {
- return new InstructionList(inst);
+ addScalaAttr(ctx.clazz);
+ try {
+ String fileName = javaFileName(ctx.clazz.getName());
+ ctx.clazz.writeTo(fileName);
+ global.operation("wrote " + fileName);
+ } catch (java.io.IOException e) {
+ throw global.fail(e.getMessage());
}
}
- static class Generic_STORE implements CompoundInstruction {
- private StoreInstruction inst;
-
- public Generic_STORE(int pos, Type type) {
- switch (type.getType()) {
- case cst.T_BOOLEAN:
- case cst.T_BYTE:
- case cst.T_CHAR:
- case cst.T_SHORT:
- case cst.T_INT: inst = new ISTORE(pos); break;
- case cst.T_LONG: inst = new LSTORE(pos); break;
- case cst.T_FLOAT: inst = new FSTORE(pos); break;
- case cst.T_DOUBLE: inst = new DSTORE(pos); break;
- case cst.T_ARRAY:
- case cst.T_OBJECT: inst = new ASTORE(pos); break;
- default: throw Debug.abort("unexpected type", type);
- }
- }
+ /**
+ * Record the entry into a method, and return the appropriate
+ * context.
+ */
+ protected Context enterMethod(Context ctx, Tree.DefDef mDef) {
+ Symbol mSym = mDef.symbol();
+
+ global.log("entering method " + Debug.toString(mSym)
+ + " (type: " + Debug.toString(mSym.info()) + ")");
+
+ Map locals = new HashMap();
+
+ Tree.ValDef[] args = mDef.vparams[0];
+ int argsNum = args.length;
- public InstructionList getInstructionList() {
- return new InstructionList(inst);
+ JType[] argTypes = new JType[argsNum];
+ String[] argNames = new String[argsNum];
+ for (int i = 0, pos = 1; i < argsNum; ++i) {
+ argTypes[i] = typeStoJ(args[i].symbol().info());
+ argNames[i] = args[i].name.toString();
+ locals.put(args[i].symbol(), new Integer(pos));
+ pos += argTypes[i].getSize();
}
+
+ JMethod method =
+ ctx.clazz.addNewMethod(modifiersStoJ(mSym.flags),
+ mSym.name.toString(),
+ typeStoJ(mSym.info().resultType()),
+ argTypes,
+ argNames);
+
+ return ctx.withMethod(method, locals);
}
- static class Generic_ALOAD implements CompoundInstruction {
- private ArrayInstruction inst;
-
- public Generic_ALOAD(Type type) {
- switch (type.getType()) {
- case cst.T_BOOLEAN:
- case cst.T_BYTE: inst = ic.BALOAD; break;
- case cst.T_CHAR: inst = ic.CALOAD; break;
- case cst.T_SHORT: inst = ic.SALOAD; break;
- case cst.T_INT: inst = ic.IALOAD; break;
- case cst.T_LONG: inst = ic.LALOAD; break;
- case cst.T_FLOAT: inst = ic.FALOAD; break;
- case cst.T_DOUBLE: inst = ic.DALOAD; break;
- case cst.T_ARRAY:
- case cst.T_OBJECT: inst = ic.AALOAD; break;
- default: throw Debug.abort("unexpected type");
- }
- }
+ protected void leaveMethod(Context ctx) {
+ global.log(" leaving method ");
+ }
- public InstructionList getInstructionList() {
- return new InstructionList(inst);
+ /// Misc.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add value members (i.e. fields) to current class.
+ */
+ protected void addValueClassMembers(Context ctx, Tree.ClassDef cDef) {
+ Symbol cSym = cDef.symbol();
+ Scope.SymbolIterator memberIt =
+ new Scope.UnloadIterator(cSym.members().iterator());
+ while (memberIt.hasNext()) {
+ Symbol member = memberIt.next();
+ if (member.isTerm() && !member.isMethod())
+ ctx.clazz.addNewField(modifiersStoJ(member.flags),
+ member.name.toString(),
+ typeStoJ(member.info()));
}
}
- static class Generic_ASTORE implements CompoundInstruction {
- private ArrayInstruction inst;
-
- public Generic_ASTORE(Type type) {
- switch (type.getType()) {
- case cst.T_BOOLEAN:
- case cst.T_BYTE: inst = ic.BASTORE; break;
- case cst.T_CHAR: inst = ic.CASTORE; break;
- case cst.T_SHORT: inst = ic.SASTORE; break;
- case cst.T_INT: inst = ic.IASTORE; break;
- case cst.T_LONG: inst = ic.LASTORE; break;
- case cst.T_FLOAT: inst = ic.FASTORE; break;
- case cst.T_DOUBLE: inst = ic.DASTORE; break;
- case cst.T_ARRAY:
- case cst.T_OBJECT: inst = ic.AASTORE; break;
- default: throw Debug.abort("unexpected type");
- }
- }
+ /**
+ * Return true iff the given symbol is a static (in the Java
+ * sense) member of its owner.
+ */
+ protected boolean isStaticMember(Symbol sym) {
+ return (sym.name != CONSTRUCTOR_NAME)
+ && sym.owner().isModuleClass()
+ && sym.owner().isJava();
+ }
+}
- public InstructionList getInstructionList() {
- return new InstructionList(inst);
- }
+/**
+ * A compilation context, which records information about the class
+ * and the method currently being generated.
+ */
+class Context {
+ public final String sourceFileName;
+ public final JClass clazz;
+ public final JMethod method;
+ public final JExtendedCode code;
+ public final Map/*<Symbol,JLocalVariable>*/ locals;
+ public final boolean isModuleClass;
+
+ public final static Context EMPTY = new Context(null, null, null, null, false);
+
+ private Context(String sourceFileName,
+ JClass clazz,
+ JMethod method,
+ Map locals,
+ boolean isModuleClass) {
+ this.sourceFileName = sourceFileName;
+ this.clazz = clazz;
+ this.method = method;
+ if (method == null || method.isAbstract())
+ this.code = null;
+ else
+ this.code = (JExtendedCode)method.getCode();
+ this.locals = locals;
+ this.isModuleClass = isModuleClass;
+ }
+
+ public Context withSourceFileName(String sourceFileName) {
+ return new Context(sourceFileName, null, null, null, false);
+ }
+
+ public Context withClass(JClass clazz, boolean isModuleClass) {
+ return new Context(this.sourceFileName, clazz, null, null, isModuleClass);
+ }
+
+ public Context withMethod(JMethod method, Map locals) {
+ assert this.clazz == method.getOwner();
+ return new Context(this.sourceFileName,
+ this.clazz,
+ method,
+ locals,
+ this.isModuleClass);
}
}
diff --git a/sources/scalac/backend/jvm/GenJVMPhase.java b/sources/scalac/backend/jvm/GenJVMPhase.java
index c45e2935c6..6087cfb2e1 100644
--- a/sources/scalac/backend/jvm/GenJVMPhase.java
+++ b/sources/scalac/backend/jvm/GenJVMPhase.java
@@ -4,7 +4,6 @@
** /_____/\____/\___/\____/____/ **
\* */
-// $OldId: GenJVMPhase.java,v 1.1 2002/09/03 12:13:08 schinz Exp $
// $Id$
package scalac.backend.jvm;
@@ -14,6 +13,12 @@ import scalac.Unit;
import scalac.PhaseDescriptor;
import scalac.ApplicationError;
+/**
+ * Phase to generate Java bytecodes using the FJBG library.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
public class GenJVMPhase extends PhaseDescriptor {