summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authorschinz <schinz@epfl.ch>2003-07-10 13:20:42 +0000
committerschinz <schinz@epfl.ch>2003-07-10 13:20:42 +0000
commiteca1e7ffa871031e5514792430d1f788afc4eb09 (patch)
treec5ce84df4e612f045278e2dd8f5743946526bbc2 /sources
parent0e5eaf6fbd4e15a7d8fee50363d67a5bd1f81829 (diff)
downloadscala-eca1e7ffa871031e5514792430d1f788afc4eb09.tar.gz
scala-eca1e7ffa871031e5514792430d1f788afc4eb09.tar.bz2
scala-eca1e7ffa871031e5514792430d1f788afc4eb09.zip
- renamed GenJVM[Phase].java to GenJVMBCEL[Phas...
- renamed GenJVM[Phase].java to GenJVMBCEL[Phase].java
Diffstat (limited to 'sources')
-rw-r--r--sources/scalac/backend/jvm/GenJVMBCEL.java1566
-rw-r--r--sources/scalac/backend/jvm/GenJVMBCELPhase.java39
2 files changed, 1605 insertions, 0 deletions
diff --git a/sources/scalac/backend/jvm/GenJVMBCEL.java b/sources/scalac/backend/jvm/GenJVMBCEL.java
new file mode 100644
index 0000000000..8c6634ba0a
--- /dev/null
+++ b/sources/scalac/backend/jvm/GenJVMBCEL.java
@@ -0,0 +1,1566 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $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;
+
+import scalac.*;
+import scalac.backend.*;
+import scalac.util.*;
+import scalac.ast.*;
+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 java.util.*;
+import java.io.*;
+
+/**
+ * Backend generating JVM byte-codes.
+ *
+ * @version 1.0
+ * @author Michel Schinz
+ */
+
+class GenJVMBCEL {
+ protected final static String JAVA_LANG_OBJECT = "java.lang.Object";
+ protected final static String JAVA_LANG_STRING = "java.lang.String";
+ 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 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;
+ 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 Global global;
+ protected final Definitions defs;
+ protected final Primitives prims;
+
+ public GenJVMBCEL(Global global) {
+ this.global = global;
+ this.defs = global.definitions;
+ this.prims = global.primitives;
+ initTypeMap();
+ initArithPrimMap();
+ }
+
+ 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);
+ }
+
+ 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) {
+ 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);
+ break;
+
+ case ClassDef(_, _, _, _, _, Tree.Template impl) : {
+ Tree.ClassDef classDef = (Tree.ClassDef)tree;
+
+ boolean oldIsModuleClass = isModuleClass;
+ isModuleClass = Modifiers.Helper.isModClass(sym.flags);
+ enterClass(sym);
+
+ addValueClassMembers(classDef);
+ if (isModuleClass)
+ addModuleInstanceField();
+
+ gen(impl);
+ leaveClass(sym);
+ isModuleClass = oldIsModuleClass;
+ } break;
+
+ case Template(_, Tree[] body):
+ gen(body);
+ break;
+
+ case ValDef(_, Name name, _, Tree rhs): {
+ if (currMethod == 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();
+
+ if (rhs != Tree.Empty)
+ gen(rhs, valType.getType());
+ 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;
+ default:
+ currIL.append(ic.ACONST_NULL); break;
+ }
+ }
+ currIL.append(new Generic_STORE(index, valType));
+
+ currLocals.put(sym, new Integer(index));
+ } break;
+
+ case DefDef(_, _, _, _, _, Tree rhs): {
+ enterMethod((Tree.DefDef)tree);
+ if (! Modifiers.Helper.isAbstract(sym.flags)) {
+ Type retType = currMethod.getReturnType();
+ gen(rhs, retType.getType());
+ currIL.append(new Generic_RETURN(retType));
+ }
+ leaveMethod();
+ } break;
+
+ case LabelDef(_, _):
+ global.fail("not implemented yet " + tree);
+ break;
+
+ case Block(Tree[] stats): {
+ int statsNum = stats.length;
+ for (int i = 0; i < statsNum - 1; ++i)
+ gen(stats[i], cst.T_VOID);
+ if (statsNum == 0)
+ maybeLoadUnit(expectedType);
+ else
+ gen(stats[stats.length - 1], expectedType, ctx);
+ generatedType = expectedType;
+ } break;
+
+ case Typed(Tree expr, _):
+ gen(expr, expectedType, ctx);
+ generatedType = expectedType;
+ break;
+
+ case New(Tree.Template templ): {
+ assert templ.body.length == 0;
+ 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;
+ } 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);
+
+ if (fun.symbol() == defs.IS) {
+ currIL.append(new INSTANCEOF(typeIndex));
+ generatedType = cst.T_BOOLEAN;
+ } else if (fun.symbol() == defs.AS) {
+ currIL.append(new CHECKCAST(typeIndex));
+ generatedType = type.getType();
+ } else
+ global.fail("unexpected type application");
+ } break;
+
+ case Apply(Tree fun, Tree[] args): {
+ if (isPrimitive(fun.symbol())) {
+ Tree.Select selectFun = (Tree.Select)fun;
+ 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);
+ }
+ } else {
+ Symbol funSym = fun.symbol();
+ Type[] argTypes = argTypesStoJ(funSym.info());
+ Type retType = retTypeStoJ(funSym.info());
+ boolean isStatic = isStaticMember(funSym);
+ if (!isStatic && ctx != InstrContext.New)
+ genLoadQualifier(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;
+ }
+
+ if (isConstrCall || isSuperCall) {
+ currIL.append(new INVOKESPECIAL(methodIndex));
+ if (isConstrCall && isSuperCall && 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));
+ }
+ } else if (isStatic)
+ currIL.append(new INVOKESTATIC(methodIndex));
+ else
+ currIL.append(new INVOKEVIRTUAL(methodIndex));
+ }
+
+ generatedType = retType.getType();
+ }
+ } break;
+
+ case Ident(Name name): {
+ Type type = typeStoJ(sym.info());
+ if (sym.isModule())
+ generatedType = genLoadModule(sym);
+ else if (sym == defs.NULL) {
+ currIL.append(ic.ACONST_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();
+ }
+ } 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();
+ }
+ }
+ } break;
+
+ case Select(Tree qualifier, Name selector): {
+ if (sym.isModule())
+ generatedType = genLoadModule(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();
+ }
+ }
+ }
+ } 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());
+ } 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);
+ if (elsep == Tree.Empty)
+ maybeLoadUnit(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);
+ generatedType = finalType;
+ } break;
+
+ case This(_):
+ currIL.append(ic.THIS);
+ generatedType = cst.T_OBJECT;
+ break;
+
+ case Literal(Object value):
+ if (value instanceof Integer) {
+ generatedType = cst.T_INT;
+ currIL.append(new PUSH(currPool, (Integer)value));
+ } else if (value instanceof Long) {
+ generatedType = cst.T_LONG;
+ currIL.append(new PUSH(currPool, (Long)value));
+ } else if (value instanceof Float) {
+ generatedType = cst.T_FLOAT;
+ currIL.append(new PUSH(currPool, (Float)value));
+ } else if (value instanceof Double) {
+ generatedType = cst.T_DOUBLE;
+ currIL.append(new PUSH(currPool, (Double)value));
+ } else if (value instanceof Character) {
+ generatedType = cst.T_CHAR;
+ currIL.append(new PUSH(currPool, (Character)value));
+ } else if (value instanceof String) {
+ generatedType = cst.T_OBJECT;
+ currIL.append(new PUSH(currPool, (String)value));
+ } else if (value instanceof Boolean) {
+ generatedType = cst.T_BOOLEAN;
+ currIL.append(new PUSH(currPool, (Boolean)value));
+ } else
+ throw global.fail("unknown literal " + value);
+ break;
+
+ case Empty:
+ case TypeDef(_, _, _, _):
+ case TypeApply(_, _):
+ case FunType(_, _):
+ case CompoundType(_, _):
+ case AppliedType(_,_):
+ break;
+
+ case Sequence(_):
+ case Super(_):
+ case ModuleDef(_,_,_,_):
+ case PatDef(_,_,_):
+ case Import(_, _):
+ case CaseDef(_, _, _):
+ case Visitor(_):
+ case Function(_, _):
+ throw global.fail("unexpected node", tree);
+ case Bad():
+ throw global.fail("bad tree");
+ default:
+ throw global.fail("unknown node", tree);
+ }
+
+ // 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
+ || 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;
+ }
+ }
+
+ // 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.EMPTY_ARRAY,
+ "<clinit>",
+ currClassName,
+ initIL,
+ currPool);
+ initMethod.setMaxStack();
+ currClass.addMethod(initMethod.getMethod());
+ }
+
+ // 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());
+ }
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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;
+ }
+
+ protected void genLoadQualifier(Tree tree) {
+ switch (tree) {
+ case Select(Super(_), _):
+ case Ident(_):
+ currIL.append(ic.THIS);
+ break;
+ case Select(Tree qualifier, _):
+ gen(qualifier, cst.T_OBJECT);
+ break;
+ default:
+ throw global.fail("unknown qualifier");
+ }
+ }
+
+ protected boolean isStaticMember(Symbol sym) {
+ return (sym.name != CONSTRUCTOR_NAME)
+ && sym.owner().isModuleClass()
+ && sym.owner().isJava();
+ }
+
+ 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);
+ }
+ } 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);
+ }
+ }
+
+ 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 });
+ }
+
+ 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);
+ }
+
+ protected byte genArithPrim(Primitive prim,
+ Tree[] args,
+ byte resType,
+ byte expectedType,
+ InstrContext ctx) {
+ int arity = args.length;
+ int resTypeIdx = getTypeIndex(resType);
+
+ for (int i = 0; i < arity; ++i)
+ gen(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);
+ } else {
+ currIL.append(new PUSH(currPool, -1));
+ currIL.append(ic.IXOR);
+ }
+ } else {
+ assert arithPrimMap.containsKey(prim);
+ Instruction primInst = ((Instruction[])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);
+ }
+ }
+ return maxType;
+ }
+
+ protected static int tempCounter = 1;
+ protected void genCompPrim(Primitive prim,
+ Tree[] args,
+ byte resType,
+ byte expectedType,
+ InstructionHandle target,
+ boolean when) {
+ byte maxType = getMaxType(args);
+ int maxTypeIdx = getTypeIndex(maxType);
+ int intTypeIdx = getTypeIndex(Type.INT);
+ boolean intCompareWithZero = false;
+ for (int i = 0; i < args.length; ++i) {
+ boolean isIntZero = false;
+ if (maxTypeIdx <= intTypeIdx) {
+ switch (args[i]) {
+ case Literal(Object val):
+ int intVal;
+ if (val instanceof Number)
+ intVal = ((Number)val).intValue();
+ else if (val instanceof Character)
+ intVal = ((Character)val).charValue();
+ else if (val instanceof Boolean)
+ intVal = ((Boolean)val).booleanValue() ? 1 : 0;
+ else
+ throw Debug.abort("unknown literal", val);
+ if (intVal == 0) {
+ isIntZero = true;
+ if (i == 0) prim = prim.swap();
+ }
+ }
+ }
+ if (intCompareWithZero || !isIntZero)
+ gen(args[i], maxType);
+ intCompareWithZero |= isIntZero;
+ }
+
+ if (maxType == cst.T_OBJECT) {
+ 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()));
+ if (when ^ (prim != Primitive.EQ))
+ currIL.append(new IFNULL(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));
+ if (when ^ (prim != Primitive.EQ))
+ currIL.append(new IFNE(target));
+ else
+ currIL.append(new IFEQ(target));
+ gotoAfter.setTarget(currIL.append(ic.NOP));
+ } else if (maxTypeIdx <= intTypeIdx && !intCompareWithZero) {
+ 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;
+ 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;
+ 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;
+ default: throw global.fail("unknown primitive " + prim);
+ }
+ }
+ }
+
+ protected Primitive maybeNegatedPrim(Primitive prim, boolean negate) {
+ return negate ? prim.negate() : prim;
+ }
+
+ 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 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 byte genArrayCreate(Primitive prim, Tree size) {
+ gen(size, cst.T_INT);
+ byte 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;
+ default: throw Debug.abort("unexpected primitive", prim);
+ }
+ currIL.append(new NEWARRAY(type));
+ return cst.T_ARRAY;
+ }
+
+ 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)
+ value = unbox(value);
+ gen(value, elemType.getType());
+ currIL.append(new Generic_ASTORE(elemType));
+ return cst.T_VOID;
+ }
+
+ 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();
+ }
+
+ protected byte genArrayLength(Tree array) {
+ gen(array, cst.T_ARRAY);
+ currIL.append(ic.ARRAYLENGTH);
+ return cst.T_INT;
+ }
+
+ protected Tree[] liftStringConcatenations(Tree tree) {
+ LinkedList accu = new LinkedList();
+ liftStringConcatenations(tree, accu);
+ return (Tree[])accu.toArray(new Tree[accu.size()]);
+ }
+
+ protected void liftStringConcatenations(Tree tree, LinkedList accu) {
+ switch (tree) {
+ case Apply(Select(Tree qualifier, Name selector), Tree[] args): {
+ Symbol funSym = ((Tree.Apply)tree).fun.symbol();
+ if (prims.isPrimitive(funSym)
+ && prims.getPrimitive(funSym) == Primitive.CONCAT) {
+ liftStringConcatenations(qualifier, accu);
+ liftStringConcatenations(args[0], accu);
+ } else
+ accu.addLast(tree);
+ } break;
+ default:
+ accu.addLast(tree);
+ }
+ }
+
+ 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));
+
+ 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));
+ }
+
+ String toStringSig = Type.getMethodSignature (Type.STRING, Type.NO_ARGS);
+ final int toStringRef =
+ currPool.addMethodref (JAVA_LANG_STRINGBUFFER, "toString", toStringSig);
+ currIL.append (new INVOKEVIRTUAL (toStringRef));
+ }
+
+ protected int getTypeIndex(Type tp) {
+ return getTypeIndex(tp.getType());
+ }
+
+ 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;
+ }
+ }
+
+ 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 }
+ };
+
+ protected void genWidenConversion(byte origType, byte finalType) {
+ int origIdx = getTypeIndex(origType);
+ int finalIdx = getTypeIndex(finalType);
+
+ 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);
+ }
+
+ 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.EMPTY_ARRAY);
+ ConstantPoolGen mainPool = mainClassGen.getConstantPool();
+
+ Method[] methods = modClassGen.getMethods();
+ for (int i = 0; i < methods.length; ++i) {
+ Method 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);
+
+ mainIL.append(new GETSTATIC(moduleFieldIndex));
+ int pos = 0;
+ for (int j = 0; j < argTypes.length; ++j) {
+ mainIL.append(new Generic_LOAD(pos, argTypes[j]));
+ pos += argTypes[j].getSize();
+ }
+ mainIL.append(new INVOKEVIRTUAL(mIndex));
+ mainIL.append(new Generic_RETURN(retType));
+ mainMGen.setMaxStack();
+ mainClassGen.addMethod(mainMGen.getMethod());
+ }
+
+ addScalaAttr(mainClassGen);
+ JavaClass mainClass = mainClassGen.getJavaClass();
+ 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);
+ 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();
+ }
+ }
+
+ protected void enterMethod(Tree.DefDef dDef) {
+ Symbol dSym = dDef.symbol();
+
+ 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();
+ }
+
+ 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;
+
+ lineAttributedInstrs = null;
+ }
+
+ protected int modifiersStoJ(int flags) {
+ int jFlags = 0;
+
+ if (Modifiers.Helper.isPrivate(flags))
+ jFlags |= cst.ACC_PRIVATE;
+ else
+ jFlags |= cst.ACC_PUBLIC;
+
+ if (Modifiers.Helper.isAbstract(flags))
+ jFlags |= cst.ACC_ABSTRACT;
+ if (Modifiers.Helper.isInterface(flags))
+ jFlags |= cst.ACC_INTERFACE;
+
+ if (Modifiers.Helper.isFinal(flags)
+ && !(Modifiers.Helper.isAbstract(flags)
+ || Modifiers.Helper.isInterface(flags)))
+ jFlags |= cst.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);
+ }
+ protected Type typeStoJ(scalac.symtab.Type tp) {
+ switch (tp) {
+ case UnboxedType(TypeTags.BYTE):
+ return Type.BYTE;
+ case UnboxedType(TypeTags.CHAR):
+ return Type.CHAR;
+ case UnboxedType(TypeTags.SHORT):
+ return Type.SHORT;
+ case UnboxedType(TypeTags.INT):
+ return Type.INT;
+ case UnboxedType(TypeTags.LONG):
+ return Type.LONG;
+ case UnboxedType(TypeTags.FLOAT):
+ return Type.FLOAT;
+ case UnboxedType(TypeTags.DOUBLE):
+ return Type.DOUBLE;
+ case UnboxedType(TypeTags.BOOLEAN):
+ return Type.BOOLEAN;
+ case UnboxedType(TypeTags.UNIT):
+ return Type.VOID;
+ case UnboxedType(TypeTags.STRING):
+ return Type.STRING;
+ case UnboxedArrayType(scalac.symtab.Type elementType):
+ return new ArrayType(typeStoJ(elementType), 1);
+ 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);
+ else {
+ Type jTp = new ObjectType(javaName(sym));
+ typeMap.put(sym, jTp);
+ return jTp;
+ }
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+
+ protected Type retTypeStoJ(scalac.symtab.Type tp) {
+ switch (tp) {
+ case MethodType(_, _):
+ return typeStoJ(tp.resultType());
+ default:
+ throw global.fail("invalid method type", tp);
+ }
+ }
+
+ 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 buf.toString();
+ }
+ }
+
+ 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());
+
+ return file.getPath() + ".class";
+ }
+
+ // 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());
+ }
+ }
+
+ public InstructionList getInstructionList() {
+ return new InstructionList(inst);
+ }
+ }
+
+ 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");
+ }
+ }
+
+ public InstructionList getInstructionList() {
+ return new InstructionList(inst);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ public InstructionList getInstructionList() {
+ return new InstructionList(inst);
+ }
+ }
+
+ 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");
+ }
+ }
+
+ public InstructionList getInstructionList() {
+ return new InstructionList(inst);
+ }
+ }
+
+ 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");
+ }
+ }
+
+ public InstructionList getInstructionList() {
+ return new InstructionList(inst);
+ }
+ }
+}
diff --git a/sources/scalac/backend/jvm/GenJVMBCELPhase.java b/sources/scalac/backend/jvm/GenJVMBCELPhase.java
new file mode 100644
index 0000000000..4ef402fd86
--- /dev/null
+++ b/sources/scalac/backend/jvm/GenJVMBCELPhase.java
@@ -0,0 +1,39 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+package scalac.backend.jvm;
+
+import scalac.Global;
+import scalac.Unit;
+import scalac.PhaseDescriptor;
+import scalac.ApplicationError;
+
+
+public class GenJVMBCELPhase extends PhaseDescriptor {
+
+ public String name () {
+ return "genjvm-bcel";
+ }
+
+ public String description () {
+ return "generate JVM bytecodes";
+ }
+
+ public String taskDescription() {
+ return "generated JVM code";
+ }
+
+ public void apply(Global global) {
+ for (int i = 0; i < global.units.length; i++)
+ apply(global.units[i]);
+ }
+
+ public void apply(Unit unit) {
+ new GenJVMBCEL(unit.global).translate(unit);
+ }
+}