From eca1e7ffa871031e5514792430d1f788afc4eb09 Mon Sep 17 00:00:00 2001 From: schinz Date: Thu, 10 Jul 2003 13:20:42 +0000 Subject: - renamed GenJVM[Phase].java to GenJVMBCEL[Phas... - renamed GenJVM[Phase].java to GenJVMBCEL[Phase].java --- sources/scalac/backend/jvm/GenJVMBCEL.java | 1566 +++++++++++++++++++++++ sources/scalac/backend/jvm/GenJVMBCELPhase.java | 39 + 2 files changed, 1605 insertions(+) create mode 100644 sources/scalac/backend/jvm/GenJVMBCEL.java create mode 100644 sources/scalac/backend/jvm/GenJVMBCELPhase.java (limited to 'sources') 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/**/ 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, + "", + 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/**/ 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, + "", + 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("")) + 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/**/ 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/**/ = 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); + } +} -- cgit v1.2.3