summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authorNAME <USER@epfl.ch>2004-01-30 13:07:45 +0000
committerNAME <USER@epfl.ch>2004-01-30 13:07:45 +0000
commitbec9884b00d60a79671e51a5a65b1717f753f981 (patch)
tree0a8d4bfa78fbe173ddaf6a8fa8f1e34902f8ee84 /sources
parent0bc48e99d91c250590e6ec1ed376aec348df5cb4 (diff)
downloadscala-bec9884b00d60a79671e51a5a65b1717f753f981.tar.gz
scala-bec9884b00d60a79671e51a5a65b1717f753f981.tar.bz2
scala-bec9884b00d60a79671e51a5a65b1717f753f981.zip
Added intermediate code and corresponding jvm b...
Added intermediate code and corresponding jvm backend
Diffstat (limited to 'sources')
-rw-r--r--sources/scala/tools/scalac/CompilerPhases.scala4
-rw-r--r--sources/scala/tools/scalac/backend/GenJVMFromICode.scala753
-rw-r--r--sources/scala/tools/scalac/backend/GenJVMFromICodePhase.scala33
-rw-r--r--sources/scala/tools/scalac/icode/IBasicBlock.scala111
-rw-r--r--sources/scala/tools/scalac/icode/ICInstruction.scala355
-rw-r--r--sources/scala/tools/scalac/icode/ICTypeStack.scala145
-rw-r--r--sources/scala/tools/scalac/icode/ICode.scala486
-rw-r--r--sources/scala/tools/scalac/icode/ICodePhase.scala65
-rw-r--r--sources/scala/tools/scalac/icode/ICodePrinter.scala72
-rw-r--r--sources/scalac/CompilerPhases.java16
-rw-r--r--sources/scalac/Global.java23
-rw-r--r--sources/scalac/atree/AMethod.java5
-rw-r--r--sources/scalac/atree/AShiftOp.java14
-rw-r--r--sources/scalac/atree/ATreeTyper.java32
-rw-r--r--sources/scalac/transformer/ICodePhase.java59
15 files changed, 2161 insertions, 12 deletions
diff --git a/sources/scala/tools/scalac/CompilerPhases.scala b/sources/scala/tools/scalac/CompilerPhases.scala
index 59ce0bf084..462b0d7327 100644
--- a/sources/scala/tools/scalac/CompilerPhases.scala
+++ b/sources/scala/tools/scalac/CompilerPhases.scala
@@ -22,6 +22,10 @@ class CompilerPhases extends scalac_CompilerPhases {
Class.forName("scala.tools.scalac.typechecker.AnalyzerPhase$class");
protected override def TRANSMATCH_PHASE(): Class =
Class.forName("scala.tools.scalac.transformer.TransMatchPhase$class");
+ protected override def ICODE_PHASE(): Class =
+ Class.forName("scala.tools.scalac.icode.ICodePhase$class");
+ protected override def GENJVMFROMICODE_PHASE(): Class =
+ Class.forName("scala.tools.scalac.backend.GenJVMFromICodePhase$class");
}
}
diff --git a/sources/scala/tools/scalac/backend/GenJVMFromICode.scala b/sources/scala/tools/scalac/backend/GenJVMFromICode.scala
new file mode 100644
index 0000000000..2745c4b0ee
--- /dev/null
+++ b/sources/scala/tools/scalac/backend/GenJVMFromICode.scala
@@ -0,0 +1,753 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+import scalac.symtab._;
+import scalac.{Global => scalac_Global};
+import scalac.atree._;
+import scalac.Unit;
+import scalac.util.Debug;
+import scala.tools.scalac.icode._;
+import ch.epfl.lamp.fjbg._;
+import scala.collection.mutable.HashMap;
+
+import java.util.StringTokenizer;
+import java.io.File;
+
+package scala.tools.scalac.backend {
+
+/* This class implements the backend which create
+ * Java Virtual Machine's bytecode with
+ * The Intermediate Code of the compiler */
+class GenJVMFromICode(global: scalac_Global) {
+
+ // ##################################################
+ // Private fields - Utils
+
+ private val defs = global.definitions;
+
+ private val fjbgContext = new FJBGContext();
+
+ private val typer = new ATreeTyper(global);
+
+ // ##################################################
+ // Private fields - Data
+ private var currentSrcFileName: String = null;
+
+ private val clasz = new HashMap[Symbol, JVMClass];
+
+ private val typeMap = new HashMap[Symbol, JType];
+
+ // ##################################################
+ // Constructor code
+ initTypeMap;
+
+ // ##################################################
+ // Public methods
+
+ /* This method generates byte code for a single unit */
+ def translate(unit: Unit) = {
+ global.log("Jvm.translate() called");
+ currentSrcFileName = unit.source.toString();
+ // Generate the structure
+ val classes_it = new IterableArray(unit.repository.classes()).elements;
+ classes_it.foreach(genClass(null));
+ dumpStructure;
+ // Generate the code & Save the classes
+ var pairs_it = clasz.elements;
+ pairs_it.foreach ((p: Pair[Symbol, JVMClass]) => {
+ val sym = p._1;
+ val jvmClass = p._2;
+ val methods_it = jvmClass.methods.values;
+ global.log("Jvm.translate: translating class "+sym);
+ methods_it.foreach ((m: JVMMethod) => if(!m.aMethod.isAbstract()) genCode(m));
+ //jvmClass.jClass.writeTo("/tmp/"+javaName(sym)); // tmp
+ });
+ pairs_it = clasz.elements; // Remettre joli quand ca marche !!!
+ pairs_it.foreach ((p: Pair[Symbol, JVMClass]) => {
+ val sym = p._1;
+ val jvmClass = p._2;
+ val fileName = javaFileName(javaName(sym));
+ global.log("Jvm.translate: writing class "+sym);
+ jvmClass.jClass.writeTo(fileName);
+ });
+ global.operation("Generation of "+currentSrcFileName+" succeded.");
+
+ currentSrcFileName = null;
+ }
+
+ // ##################################################
+ // Private methods - Generate code
+
+ /* Generate a class */
+ private def genClass (parent: JVMClass)(aClass: AClass) : unit = {
+ // 1. ##### Create JClass object
+ val sym : Symbol = aClass.symbol();
+ val thisClassName : String = javaName(sym);
+ val flags : int = JAccessFlags.ACC_SUPER | // The way it has to be
+ (if (aClass.isPublic()) JAccessFlags.ACC_PUBLIC else 0) |
+ (if (aClass.isPrivate()) JAccessFlags.ACC_PRIVATE else 0) |
+ (if (aClass.isProtected()) JAccessFlags.ACC_PROTECTED else 0) |
+ (if (aClass.isFinal()) JAccessFlags.ACC_FINAL else 0) |
+ (if (aClass.isAbstract()) JAccessFlags.ACC_ABSTRACT else 0) |
+ (if (aClass.isInterface()) JAccessFlags.ACC_INTERFACE else 0);
+
+ global.log("genClass: parents(): ");
+ val prnt_it = new IterableArray(aClass.parents()).elements; // debug
+ prnt_it.foreach((t: Type) => {global.log(" "+t.toString())}); // debug
+
+ val baseTps = new IterableArray(aClass.parents()).elements;
+ assert (baseTps.hasNext, "Jvm::genClass: Invalid number of parents. "+Debug.show(sym));
+
+ var superClassName : String = null;
+
+ val firstParent : Type = aClass.parents()(0);
+ //var aParentType : Type = baseTps.next;
+ global.log("first parent: "+firstParent); // Debug
+ if (aClass.isInterface()) {
+ if (firstParent.isSameAs(defs.ANY_TYPE())) {
+ global.log("test ANY succeded for interface. l112");
+ baseTps.drop(1);
+ }
+ superClassName = JAVA_LANG_OBJECT;
+ } else {
+ superClassName = javaName(baseTps.next.symbol());
+ }
+
+ var interfaceNames_l : List[String] = Nil;
+
+ baseTps.foreach((aParentType : Type) =>
+ interfaceNames_l = javaName(aParentType.symbol())::interfaceNames_l);
+ val interfaceNames_a = new Array[String](interfaceNames_l.length);
+ interfaceNames_l.reverse.copyToArray(interfaceNames_a,0);
+
+ val jclass : JClass = fjbgContext.JClass(flags,
+ thisClassName,
+ superClassName,
+ interfaceNames_a,
+ currentSrcFileName);
+
+ // 2. ##### Modify context:: Enter class
+ //currentClass = aClass;
+ val jvmClass = new JVMClass(parent);
+ clasz += aClass.symbol() -> jvmClass;
+ jvmClass.jClass = jclass;
+ //classFields = new HashMap[Symbol, JField]();
+
+ // 3. ##### Access the inner classes
+ // !!! Acces aux champs extérieurs
+ val classes_it = new IterableArray(aClass.classes()).elements;
+ classes_it.foreach(genClass(jvmClass));
+
+ // 4. ##### Add fields of the class
+ //genFields(aClass, jClass);
+
+ val fields_it = new IterableArray(aClass.fields()).elements;
+ fields_it.foreach(genField(jvmClass));
+
+ // ICI -> Faut-il s'occuper du truc module ? (case ClassDef)
+
+ // 5. ##### Enregistre les methodes
+ val methods_it = new IterableArray(aClass.methods()).elements;
+ global.log(" number of methods: "+aClass.methods().length); // Debug
+ methods_it.foreach(genMethod(jvmClass));
+
+ // ##### Modify context:: Leave class
+ //currentClass = null;
+ //classFields = null;
+ }
+
+ /* Add a field to a class */
+ private def genField(jvmClass : JVMClass)(aField : AField) : unit = {
+ //val fields_it = new IterableArray(aClass.fields()).elements;
+
+ //fileds_it.foreach(aField: AField => {
+ //aField = fields_it.next;
+ val flags = (if (aField.isPublic()) JAccessFlags.ACC_PUBLIC else 0) |
+ (if (aField.isPrivate()) JAccessFlags.ACC_PRIVATE else 0) |
+ (if (aField.isProtected()) JAccessFlags.ACC_PROTECTED else 0) |
+ (if (aField.isStatic()) JAccessFlags.ACC_STATIC else 0) |
+ (if (aField.isFinal()) JAccessFlags.ACC_FINAL else 0) |
+ (if (aField.isVolatile()) JAccessFlags.ACC_VOLATILE else 0) |
+ (if (aField.isTransient()) JAccessFlags.ACC_TRANSIENT else 0);
+ jvmClass.fields += aField.symbol() ->
+ jvmClass.jClass.addNewField(flags,
+ aField.symbol().name.toString(),
+ typeStoJ(aField.symbol().info())); // VĂ©rifier si name n'est pas plus simple
+ }
+
+ /* Generate a method */
+ private def genMethod(jvmClass: JVMClass)(aMethod: AMethod): unit = {
+ // 1. ##### Create JMethod object
+
+ val flags = (if (aMethod.isPublic()) JAccessFlags.ACC_PUBLIC else 0) |
+ (if (aMethod.isPrivate()) JAccessFlags.ACC_PRIVATE else 0) |
+ (if (aMethod.isProtected()) JAccessFlags.ACC_PROTECTED else 0) |
+ (if (aMethod.isStatic()) JAccessFlags.ACC_STATIC else 0) |
+ (if (aMethod.isFinal()) JAccessFlags.ACC_FINAL else 0) |
+ (if (aMethod.isNative()) JAccessFlags.ACC_NATIVE else 0) |
+ (if (aMethod.isAbstract()) JAccessFlags.ACC_ABSTRACT else 0) |
+ (if (aMethod.isStrictFP()) JAccessFlags.ACC_STRICT else 0);
+
+ var argTypes_l : List[JType] = Nil;
+ var argNames_l : List[String] = Nil;
+
+ val vparams_it = new IterableArray(aMethod.vparams()).elements;
+ vparams_it.foreach((sym: Symbol) => {
+ argTypes_l = typeStoJ(sym.info())::argTypes_l;
+ argNames_l = sym.name.toString()::argNames_l;
+ });
+
+ val argTypes_a = new Array[JType](argTypes_l.length);
+ val argNames_a = new Array[String](argNames_l.length);
+ argTypes_l.reverse.copyToArray(argTypes_a,0);
+ argNames_l.reverse.copyToArray(argNames_a,0);
+ val jMethod : JMethod = jvmClass.jClass.addNewMethod(flags,
+ aMethod.symbol().name.toString(),
+ typeStoJ(aMethod.result()),
+ argTypes_a,
+ argNames_a);
+
+
+ // 2. ##### Modify context:: Enter method
+ //currentMethod = aMethod;
+ //methodLocals = new HashMap[Symbol, JLocalVariable];
+ //methodArgs = new HashMap[Symbol, int];
+ val jvmMethod = new JVMMethod(aMethod, jvmClass);
+ jvmClass.methods += aMethod.symbol() -> jvmMethod;
+ jvmMethod.jMethod = jMethod;
+
+ var index : int = 1;
+ vparams_it.foreach((sym: Symbol) => {
+ jvmMethod.args += sym -> index;
+ index = index + 1;
+ });
+
+ if (! jvmMethod.aMethod.isAbstract()) {
+ jvmMethod.jCode = jMethod.getCode().asInstanceOf[JExtendedCode];
+
+
+
+ // 3. ##### Generate labels
+
+ jvmMethod.aMethod.icode.asInstanceOf[ICode].icTraverse((bb : IBasicBlock) => {
+ val blockLabel : JCode$Label = jvmMethod.jCode.newLabel();
+ jvmMethod.labels += bb -> blockLabel;
+ });
+ }
+ //if (!aMethod.isAbstract()) {
+ // genCode(aMethod.icode, jMethod.getCode());
+ //}
+
+ // 3. ##### Modify context:: Leave method
+ //currentMethod = null;
+ //methodLocals = null;
+
+ }
+
+ /* Translate code */
+ private def genCode(jvmMethod : JVMMethod) = {
+ val icode : ICode = jvmMethod.aMethod.icode.asInstanceOf[ICode];
+ var stack : ICTypeStack = new ICTypeStack();
+ val jCode = jvmMethod.jCode;
+ icode.icTraverse((bb: IBasicBlock) => {
+ val blockLabel = jvmMethod.labels.apply(bb);
+ blockLabel.anchorToNext();
+ bb.bbTraverse((ic : ICInstruction) => stack = emitICInstruction(jvmMethod, stack)(ic));
+ });
+ }
+
+ /* Translate an ICInstruction to a JVM instruction */
+ private def emitICInstruction(jvmMethod: JVMMethod, stack: ICTypeStack)(instruction: ICInstruction) : ICTypeStack = {
+ val jcode = jvmMethod.jCode;
+ instruction match {
+ case THIS(_) =>
+ jcode.emitALOAD_0();
+
+
+ case CONSTANT(AConstant$BOOLEAN(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant$BYTE(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant$SHORT(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant$CHAR(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant$INT(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant$LONG(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant$FLOAT(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant$DOUBLE(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant$STRING(v)) =>
+ jcode.emitPUSH(v);
+ case CONSTANT(AConstant.NULL) =>
+ jcode.emitACONST_NULL();
+ case CONSTANT(AConstant.UNIT) =>
+ ; // ??
+ case CONSTANT(AConstant.ZERO) =>
+ ; // ??
+
+ case LOAD_ARRAY_ITEM() => {
+ // depend the type of the elements of the array
+ val elementType = typer.getArrayElementType(stack.tail.head);
+ jcode.emitALOAD(typeStoJ(elementType));
+ }
+
+ case LOAD_LOCAL(local, false) =>
+ jcode.emitLOAD(jvmMethod.locals.apply(local));
+
+ case LOAD_LOCAL(local, true) =>
+ jcode.emitLOAD(jvmMethod.args.apply(local), typeStoJ(local.getType()));
+
+ case LOAD_FIELD(field, static) => {
+ val className = javaName(field.owner());
+ val fieldName = javaName(field);
+ if (static)
+ jcode.emitGETSTATIC(className, fieldName, typeStoJ(field.getType()));
+ else
+ jcode.emitGETFIELD(className, fieldName, typeStoJ(field.getType()));
+ }
+
+ case STORE_ARRAY_ITEM() =>
+ jcode.emitASTORE(typeStoJ(stack.head));
+
+ case STORE_LOCAL(local, false) => {
+ val jLocal : JLocalVariable =
+ if (jvmMethod.locals.contains(local))
+ jvmMethod.locals.apply(local);
+ else {
+ val newLocal = jvmMethod.jMethod.addNewLocalVariable(typeStoJ(local.getType()), javaName(local));
+ jvmMethod.locals += local -> newLocal;
+ newLocal;
+ }
+ jcode.emitSTORE(jLocal);
+ }
+
+ case STORE_FIELD(field, static) => {
+ val className = javaName(field.owner());
+ val fieldName = javaName(field);
+ if (static)
+ jcode.emitPUTSTATIC(className, fieldName, typeStoJ(field.getType()));
+ else
+ jcode.emitPUTFIELD(className, fieldName, typeStoJ(field.getType()));
+ }
+
+ case CALL_PRIMITIVE(APrimitive$Negation(ATypeKind.I4)) => jcode.emitINEG();
+ case CALL_PRIMITIVE(APrimitive$Negation(ATypeKind.I8)) => jcode.emitLNEG();
+ case CALL_PRIMITIVE(APrimitive$Negation(ATypeKind.R4)) => jcode.emitFNEG();
+ case CALL_PRIMITIVE(APrimitive$Negation(ATypeKind.R8)) => jcode.emitDNEG();
+
+ //case CALL_PRIMITIVE(APrimitive$Test(*))
+ // !! Regarder les Test
+
+ //case CALL_PRIMITIVE(AComparisonOp(*))
+ // !! Regarder les comparison
+
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.ADD, ATypeKind.I4)) => jcode.emitIADD();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.ADD, ATypeKind.I8)) => jcode.emitLADD();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.ADD, ATypeKind.R4)) => jcode.emitFADD();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.ADD, ATypeKind.R8)) => jcode.emitDADD();
+
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.SUB, ATypeKind.I4)) => jcode.emitISUB();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.SUB, ATypeKind.I8)) => jcode.emitLSUB();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.SUB, ATypeKind.R4)) => jcode.emitFSUB();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.SUB, ATypeKind.R8)) => jcode.emitDSUB();
+
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.MUL, ATypeKind.I4)) => jcode.emitIMUL();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.MUL, ATypeKind.I8)) => jcode.emitLMUL();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.MUL, ATypeKind.R4)) => jcode.emitFMUL();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.MUL, ATypeKind.R8)) => jcode.emitDMUL();
+
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.DIV, ATypeKind.I4)) => jcode.emitIDIV();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.DIV, ATypeKind.I8)) => jcode.emitLDIV();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.DIV, ATypeKind.R4)) => jcode.emitFDIV();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.DIV, ATypeKind.R8)) => jcode.emitDDIV();
+
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.REM, ATypeKind.I4)) => jcode.emitIREM();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.REM, ATypeKind.I8)) => jcode.emitLREM();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.REM, ATypeKind.R4)) => jcode.emitFREM();
+ case CALL_PRIMITIVE(APrimitive$Arithmetic(AArithmeticOp.REM, ATypeKind.R8)) => jcode.emitDREM();
+
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.AND, ATypeKind.I4)) => jcode.emitIAND();
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.AND, ATypeKind.BOOL)) => jcode.emitIAND(); // ??? is that true
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.AND, ATypeKind.I8)) => jcode.emitLAND();
+
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.OR, ATypeKind.I4)) => jcode.emitIOR();
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.OR, ATypeKind.BOOL)) => jcode.emitIOR(); // ??? is that true
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.OR, ATypeKind.I8)) => jcode.emitLOR();
+
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.XOR, ATypeKind.I4)) => jcode.emitIXOR();
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.XOR, ATypeKind.BOOL)) => jcode.emitIXOR(); // ??? is that true
+ case CALL_PRIMITIVE(APrimitive$Logical(ALogicalOp.XOR, ATypeKind.I8)) => jcode.emitLXOR();
+
+ case CALL_PRIMITIVE(APrimitive$Shift(AShiftOp.ASL, ATypeKind.I4)) => jcode.emitISHL();
+ case CALL_PRIMITIVE(APrimitive$Shift(AShiftOp.ASL, ATypeKind.I8)) => jcode.emitLSHL();
+
+ case CALL_PRIMITIVE(APrimitive$Shift(AShiftOp.ASR, ATypeKind.I4)) => jcode.emitISHR();
+ case CALL_PRIMITIVE(APrimitive$Shift(AShiftOp.ASR, ATypeKind.I8)) => jcode.emitLSHR();
+
+ case CALL_PRIMITIVE(APrimitive$Shift(AShiftOp.LSR, ATypeKind.I4)) => jcode.emitIUSHR();
+ case CALL_PRIMITIVE(APrimitive$Shift(AShiftOp.LSR, ATypeKind.I8)) => jcode.emitLUSHR();
+
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I4, ATypeKind.I8)) => jcode.emitI2L();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I4, ATypeKind.R4)) => jcode.emitI2F();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I4, ATypeKind.R8)) => jcode.emitI2D();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I8, ATypeKind.I4)) => jcode.emitL2I();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I8, ATypeKind.R4)) => jcode.emitL2F();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I8, ATypeKind.R8)) => jcode.emitL2D();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.R4, ATypeKind.I4)) => jcode.emitF2I();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.R4, ATypeKind.I8)) => jcode.emitF2L();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.R4, ATypeKind.R8)) => jcode.emitF2D();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.R8, ATypeKind.I4)) => jcode.emitD2I();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.R8, ATypeKind.I8)) => jcode.emitD2L();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.R8, ATypeKind.R4)) => jcode.emitD2F();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I4, ATypeKind.I1)) => jcode.emitI2B();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I4, ATypeKind.U2)) => jcode.emitI2C();
+ case CALL_PRIMITIVE(APrimitive$Conversion(ATypeKind.I4, ATypeKind.I2)) => jcode.emitI2S();
+
+ case CALL_PRIMITIVE(APrimitive$ArrayLength(_)) => jcode.emitARRAYLENGTH();
+
+ case CALL_PRIMITIVE(APrimitive$StringConcat(_,_)) =>
+ ; // !!!
+
+ case CALL_METHOD(method, style) => {
+ var calledMethod : JMethod = null;
+ /*
+ var owner : JVMClass = method.owner;
+ while (calledMethod == null && owner != null) do
+ if (owner.methods.contains(method))
+ calledMethod = owner.methods.apply(method);
+ else
+ owner = owner.parent;
+ */ // Joli pour optimization ?
+ val clasz_it = clasz.values;
+ var aJvmClass : JVMClass = null;
+ while (clasz_it.hasNext && calledMethod == null) {
+ aJvmClass = clasz_it.next;
+ if (aJvmClass.methods.contains(method))
+ calledMethod = aJvmClass.methods.apply(method).jMethod;
+ }
+ if (calledMethod != null)
+ jcode.emitINVOKE(calledMethod); // et le style !!!
+ else {
+ // cas normal
+ val methodName = method.name.toString();
+ val className = javaName(method.owner());
+ val methodType = typeStoJ(method.info()).asInstanceOf[JMethodType];
+ style match {
+ case AInvokeStyle.Dynamic =>
+ if (method.owner().isInterface())
+ jcode.emitINVOKEINTERFACE(className, methodName, methodType);
+ else
+ jcode.emitINVOKEVIRTUAL(className, methodName, methodType);
+ case AInvokeStyle.StaticInstance =>
+ jcode.emitINVOKESPECIAL(className, methodName, methodType);
+ case AInvokeStyle.StaticClass =>
+ jcode.emitINVOKESTATIC(className, methodName, methodType);
+ }
+ }
+ }
+
+ case NEW(clasz) =>
+ jcode.emitNEW(javaName(clasz));
+
+ case CREATE_ARRAY(element) =>
+ jcode.emitNEWARRAY(typeStoJ(element));
+
+ case IS_INSTANCE(typ) =>
+ jcode.emitINSTANCEOF(typeStoJ(typ).asInstanceOf[JReferenceType]);
+
+ case CHECK_CAST(typ) =>
+ jcode.emitCHECKCAST(typeStoJ(typ).asInstanceOf[JReferenceType]);
+
+ case SWITCH(tags,blocks) => {
+ val casesTags : List[Array[int]] = List.fromArray(tags,0,tags.length);
+ val casesLabels = blocks.take(blocks.length-1);
+ val defaultBranch = jvmMethod.labels(blocks.last);
+
+ val tagsAndLabels = casesTags.zip(casesLabels);
+ var keys_l : List[int] = Nil;
+ var branches_l : List[JCode$Label] = Nil;
+
+ tagsAndLabels.foreach ((p: Pair[Array[Int], IBasicBlock]) => {
+ val tags = p._1;
+ val label = jvmMethod.labels(p._2);
+ val tag_it = new IterableArray(tags).elements;
+ tag_it.foreach((tag: int) => {
+ keys_l = tag::keys_l;
+ branches_l = label::branches_l;
+ });
+ });
+
+ val keys_a = new Array[int](keys_l.length);
+ val branches_a = new Array[JCode$Label](branches_l.length);
+ keys_l.copyToArray(keys_a,0);
+ branches_l.copyToArray(branches_a,0);
+
+ jcode.emitSWITCH(keys_a, branches_a, defaultBranch, 15); // Min density = 15 ??? !!!
+ }
+
+ case JUMP(basicBlock) =>
+ jcode.emitGOTO(jvmMethod.labels(basicBlock));
+
+ case CJUMP(success, failure, cond) => {
+ val condTag : int = condAtoJ(cond);
+ val typ = typeStoJ(stack.head);
+ if (typ.getTag() == JType.T_REFERENCE)
+ jcode.emitIF_ACMP(condTag, jvmMethod.labels(success));
+ else if (typ.getTag() == JType.T_INT)
+ jcode.emitIF_ICMP(condTag, jvmMethod.labels(success));
+ // Tres tres bizarre !!! Et les autres cas ???
+ jcode.emitGOTO(jvmMethod.labels.apply(failure)); // HA ha ha !
+ }
+
+ case CZJUMP(success, failure, cond) => {
+ val condTag = condAtoJ(cond);
+ jcode.emitIF(condTag, jvmMethod.labels.apply(success));
+ jcode.emitGOTO(jvmMethod.labels.apply(failure)); // !!! Ha ha ha
+ }
+
+ case RETURN() => {
+ if (stack.isEmpty)
+ //jcode.emitRETURN(); malheureusement ca ne marche pas
+ jcode.emitRETURN(JType.VOID); // mais ca oui
+ else
+ jcode.emitRETURN(typeStoJ(stack.head));
+ }
+
+ case THROW() => jcode.emitATHROW;
+
+ case DROP(typ) => { // A voir mieux
+ // ??? On pourrait aussi regarder sur la pile
+ val jtyp = typeStoJ(typ);
+ val jtypTag : int = jtyp.getTag();
+ if (jtyp.isObjectType() ||
+ jtyp.isReferenceType() ||
+ jtyp.isArrayType())
+ jcode.emitPOP();
+ else
+ jtypTag match { // cf. VM spec 3.11.1
+ case JType.T_BOOLEAN => jcode.emitPOP();
+ case JType.T_CHAR => jcode.emitPOP();
+ case JType.T_BYTE => jcode.emitPOP();
+ case JType.T_SHORT => jcode.emitPOP();
+ case JType.T_INT => jcode.emitPOP();
+ case JType.T_FLOAT => jcode.emitPOP();
+ case JType.T_REFERENCE => jcode.emitPOP();
+ case JType.T_ADDRESS => jcode.emitPOP();
+ case JType.T_LONG => jcode.emitPOP2();
+ case JType.T_DOUBLE => jcode.emitPOP2();
+ }
+ }
+
+ case DUP(typ) => {
+ val jtyp = typeStoJ(typ);
+ val jtypTag : int = jtyp.getTag();
+ if (jtyp.isObjectType() ||
+ jtyp.isReferenceType() ||
+ jtyp.isArrayType())
+ jcode.emitDUP();
+ else
+ jtypTag match { // cf. VM spec 3.11.1
+ case JType.T_BOOLEAN => jcode.emitDUP();
+ case JType.T_CHAR => jcode.emitDUP();
+ case JType.T_BYTE => jcode.emitDUP();
+ case JType.T_SHORT => jcode.emitDUP();
+ case JType.T_INT => jcode.emitDUP();
+ case JType.T_FLOAT => jcode.emitDUP();
+ case JType.T_REFERENCE => jcode.emitDUP();
+ case JType.T_ADDRESS => jcode.emitDUP();
+ case JType.T_LONG => jcode.emitDUP2();
+ case JType.T_DOUBLE => jcode.emitDUP2();
+ }
+ }
+
+ case MONITOR_ENTER() => jcode.emitMONITORENTER();
+
+ case MONITOR_EXIT() => jcode.emitMONITOREXIT();
+
+ }
+ return stack.eval(instruction);
+ }
+
+ /* Translate an ATree Test operation to the FJBG type */
+ private def condAtoJ(cond : ATestOp) : int = cond match {
+ case ATestOp.EQ => JExtendedCode.COND_EQ;
+ case ATestOp.NE => JExtendedCode.COND_NE;
+ case ATestOp.GE => JExtendedCode.COND_GE;
+ case ATestOp.LT => JExtendedCode.COND_LT;
+ case ATestOp.LE => JExtendedCode.COND_LE;
+ case ATestOp.GT => JExtendedCode.COND_GT;
+ }
+
+ // ##################################################
+ // Private methods - Debugging
+
+ private def dumpStructure = {
+ global.log("### Dumping structure ###");
+ val sym_it = clasz.keys;
+ sym_it.foreach((sym: Symbol) => {
+ val jvmClass = clasz.apply(sym);
+ global.log ("Classfile: "+javaName(sym));
+ global.log ("/fileds:");
+ val fields_it = jvmClass.fields.keys;
+ fields_it.foreach((f: Symbol) => {
+ global.log(" "+javaName(f));
+ });
+ global.log ("/methods:");
+ val methods_it = jvmClass.methods.keys;
+ methods_it.foreach((m: Symbol) => {
+ global.log(" "+javaName(m));
+ });
+ });
+ global.log("#########################");
+ }
+
+ //##################################################
+ // Private methods & fields
+ // translated from GenJVM - M. Schinz
+
+ private val JAVA_LANG_OBJECT = "java.lang.Object";
+
+ private def initTypeMap = {
+ typeMap += defs.ANY_CLASS -> JObjectType.JAVA_LANG_OBJECT;
+ typeMap += defs.ANYREF_CLASS -> JObjectType.JAVA_LANG_OBJECT;
+ }
+
+ /**
+ * Return a Java-compatible version of the name of the given
+ * symbol. The returned name is mangled and includes the names of
+ * the owners.
+ */
+ private def javaName(theSym: Symbol) = {
+ var sym = theSym;
+ sym match {
+ case defs.ANY_CLASS => JAVA_LANG_OBJECT;
+ case defs.ANYREF_CLASS => JAVA_LANG_OBJECT;
+ case _ => {
+ val buf = new StringBuffer(sym.name.toString());
+ if ((sym.isModule() || sym.isModuleClass()) && !sym.isJava())
+ buf.append('$');
+ sym = sym.owner();
+ while (!sym.isPackage()) {
+ buf.insert(0,'$');
+ buf.insert(0,sym.name);
+ sym = sym.owner();
+ }
+ if (!sym.isRoot()) {
+ buf.insert(0, '.');
+ buf.insert(0, sym.fullName());
+ }
+ buf.toString();
+ }
+ }
+ }
+
+ /**
+ * Return the name of the file in which to store the given class.
+ */
+ private def javaFileName(className : String) = {
+ val tokens = new StringTokenizer(className, " ");
+ var file = new File(global.outpath);
+ while (tokens.hasMoreElements()) {
+ file = new File(file, tokens.nextToken());
+ }
+ file.getPath()+".class";
+ }
+
+ /**
+ * Return the Java type corresponding to the given Scala type.
+ */
+ private def typeStoJ(tp: Type) : JType = tp match {
+ case Type$UnboxedType(TypeTags.BYTE) => JType.BYTE;
+ case Type$UnboxedType(TypeTags.CHAR) => JType.CHAR;
+ case Type$UnboxedType(TypeTags.SHORT) => JType.SHORT;
+ case Type$UnboxedType(TypeTags.INT) => JType.INT;
+ case Type$UnboxedType(TypeTags.LONG) => JType.LONG;
+ case Type$UnboxedType(TypeTags.FLOAT) => JType.FLOAT;
+ case Type$UnboxedType(TypeTags.DOUBLE) => JType.DOUBLE;
+ case Type$UnboxedType(TypeTags.BOOLEAN) => JType.BOOLEAN;
+ case Type$UnboxedType(TypeTags.UNIT) => JType.VOID;
+ case Type$UnboxedType(TypeTags.STRING) => JObjectType.JAVA_LANG_STRING;
+ case Type$UnboxedArrayType(elementType) => new JArrayType(typeStoJ(elementType));
+
+ case Type$MethodType(vparams: Array[Symbol], result: Type) => {
+ val argTypes_a = new Array[JType](vparams.length);
+ val vparams_it = new IterableArray(vparams).elements;
+ //val argTypes_it = vparams_it.map((s: Symbol) => typeStoJ(s.info()));
+ var argTypes_l : List[JType] = Nil;
+ vparams_it.foreach((s: Symbol) => argTypes_l = typeStoJ(s.info())::argTypes_l);
+ argTypes_l.reverse.copyToArray(argTypes_a,0);
+ new JMethodType(typeStoJ(result), argTypes_a);
+ }
+
+ case _ => {
+ val sym = tp.symbol();
+ if (sym == Symbol.NONE)
+ throw global.fail("invalid type ",tp);
+ else if (typeMap.contains(sym))
+ typeMap.apply(sym).asInstanceOf[JType];
+ else {
+ val jTp = new JObjectType(javaName(sym));
+ typeMap += sym -> jTp;
+ jTp;
+ }
+ }
+ }
+}
+
+
+//##################################################
+// Data structures
+
+ /* This class represents a Class Context */
+class JVMClass(theParent: JVMClass) {
+
+ /* Methods of the class */
+ val methods = new HashMap[Symbol, JVMMethod];
+
+ /* Fields of the class */
+ val fields = new HashMap[Symbol, JField];
+
+ /* The JClass object corresponding of this class */
+ var jClass : JClass = null;
+
+ /* The inner classes of the class */
+ var innerClasses : HashMap[Symbol, JVMClass] = null;
+
+ /* The parent class of the class */
+ val parent : JVMClass = theParent
+}
+
+ /* This class represents a Method context */
+class JVMMethod(theAMethod : AMethod, theOwner : JVMClass){
+
+ /* The ATree object representing this method */
+ val aMethod : AMethod = theAMethod;
+
+ /* The FJBG's object representing this method */
+ var jMethod : JMethod = null;
+
+ /* The locals variables of the method */
+ val locals = new HashMap[Symbol, JLocalVariable];
+
+ /* The arguments of the method */
+ val args = new HashMap[Symbol, int];
+
+ /* The JVM code of the method */
+ var jCode : JExtendedCode = null;
+
+ /* The owner class of the method */
+ val owner : JVMClass = theOwner;
+
+ /* The labels of the IBasicBlock's composing the ICode */
+ val labels = new HashMap[IBasicBlock, JCode$Label];
+}
+ }
diff --git a/sources/scala/tools/scalac/backend/GenJVMFromICodePhase.scala b/sources/scala/tools/scalac/backend/GenJVMFromICodePhase.scala
new file mode 100644
index 0000000000..d469c21f33
--- /dev/null
+++ b/sources/scala/tools/scalac/backend/GenJVMFromICodePhase.scala
@@ -0,0 +1,33 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+import scalac.{Global => scalac_Global}
+import scalac.{Unit => scalac_Unit}
+import scalac.PhaseDescriptor;
+import scalac.Phase;
+
+package scala.tools.scalac.backend {
+
+/* This class represents the JVMFromICode backend production
+ * Phase. It uses the ICode to create class files using
+ * the JVM's bytecode */
+class GenJVMFromICodePhase(global: scalac_Global, descriptor: PhaseDescriptor) extends Phase(global, descriptor) {
+
+ // ##################################################
+ // Public method
+
+ /* Apply this phase to all units */
+ def apply(units: Array[scalac_Unit]) = {
+ val generator = new GenJVMFromICode(global); // !!! super global
+ val units_it = new IterableArray(units).elements;
+
+ units_it.foreach(generator.translate);
+ }
+
+}
+}
diff --git a/sources/scala/tools/scalac/icode/IBasicBlock.scala b/sources/scala/tools/scalac/icode/IBasicBlock.scala
new file mode 100644
index 0000000000..588dad3709
--- /dev/null
+++ b/sources/scala/tools/scalac/icode/IBasicBlock.scala
@@ -0,0 +1,111 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+import scalac.symtab.Symbol;
+import scalac.symtab.Type;
+
+import scalac.atree._;
+
+package scala.tools.scalac.icode {
+
+/** This class represents a basic block */
+class IBasicBlock (theLabel: int) {
+
+ //##################################################
+ // Public fields
+
+ /* The type stack at the begining of the block */
+ var initialStack : ICTypeStack = null;
+
+ /* The label of the block */
+ val label = theLabel;
+
+ /* The substitute variables of the block
+ * in the case of a recursive method */
+ var substituteVars : List[Symbol] = null;
+
+ /* The stack at the end of the block */
+ var endStack : ICTypeStack = null;
+
+ /* The successors of this block */
+ var successors : List[IBasicBlock] = Nil;
+
+ /* Is the block closed*/
+ var isClosedBlock : boolean = false;
+
+ //##################################################
+ // Private fields
+
+ /* ICode instructions */
+ private var instructions : List[ICInstruction] = Nil;
+
+ //##################################################
+ // Public methods
+
+ /* Compute an hashCode for the block */
+ override def hashCode() = label;
+
+ /* Apply a function to all the instructions of the block*/
+ def bbTraverse(f: ICInstruction => unit) = instructions.reverse.foreach(f);
+
+ /* Initialize the stack of the block, must be done before evaluing
+ * the type stack */
+ def initStack(stack : ICTypeStack) = {
+ if (initialStack == null) {
+ initialStack = stack;
+ endStack = stack;
+ }
+ }
+
+ /* Add a new instruction at the end of the block */
+ def emit(instr: ICInstruction) = {
+ assert (!isClosedBlock, "IBasicBlock closed.");
+ instructions = instr::instructions;
+ }
+
+ /* Compute the type stack of the block */
+ def typeBlock = {
+ assert(initialStack != null, "Stack not initialized");
+ bbTraverse((ic : ICInstruction) => endStack = endStack.eval(ic));
+ }
+
+ /* Add a successor to the block */
+ def addSuccessor(s: IBasicBlock) =
+ if (!successors.contains(s))
+ successors = s::successors;
+
+ /* Add a list of successors to the block */
+ def addSuccessors(ss: List[IBasicBlock]) =
+ ss.foreach(addSuccessor);
+
+ /* Close the block */
+ def close = isClosedBlock = true;;
+
+ //##################################################
+ // Public methods - printing (used for debbuging)
+ // Instead of it, rather use a printer
+ def print() : unit = print(System.out);
+
+ def print(out: java.io.PrintStream) : unit = {
+ out.println("block #"+label+" :");
+ instructions.reverse.foreach(
+ (i: ICInstruction) => out.println(" "+i));
+ out.print("Successors: ");
+ successors.foreach((x: IBasicBlock) => out.print(" "+x.label.toString()));
+ out.println();
+ }
+
+ // ##################################################
+ // Private methods
+
+ // none.
+
+}
+
+}
+
diff --git a/sources/scala/tools/scalac/icode/ICInstruction.scala b/sources/scala/tools/scalac/icode/ICInstruction.scala
new file mode 100644
index 0000000000..fc83269ead
--- /dev/null
+++ b/sources/scala/tools/scalac/icode/ICInstruction.scala
@@ -0,0 +1,355 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+
+import scalac.symtab.Symbol;
+import scalac.symtab.Type;
+
+import scalac.atree._;
+
+package scala.tools.scalac.icode {
+
+/** This class represents an instruction of intermediate code */
+abstract class ICInstruction {
+
+ /** This abstract method returns the number of used elements on the stack */
+ def consumed : int = 0; // !!!
+
+ /** This abstract method returns the number of produced elements on the stack */
+ def produced : int = 0; // !!!
+
+ /** This method returns the difference of size of the stack when the instruction is used */
+ def difference = produced-consumed;
+}
+
+//##################################################
+// Instruction cases
+
+/** This class represents a THIS instruction
+ * Stack: ...
+ * ->: ...:ref
+ */
+case class THIS(clasz: Symbol) extends ICInstruction {
+ /** Returns a string representation of this constant */
+ override def toString(): String = "THIS";
+
+ override def consumed = 0;
+ override def produced = 1;
+}
+
+/** This class retpresents a CONSTANT instruction
+ * Stack: ...
+ * ->: ...:constant
+ */
+case class CONSTANT(constant: AConstant) extends ICInstruction{
+ /** Returns a string representation of this constant */
+ override def toString(): String = "CONSTANT ("+constant.toString()+")";
+
+ override def consumed = 0;
+ override def produced = 1;
+}
+
+/** This class represents a LOAD_ARRAY_ITEM instruction
+ * Stack: ...:array[a](Ref):index(Int)
+ * ->: ...:element(a)
+ */
+case class LOAD_ARRAY_ITEM extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String = "LOAD_ARRAY_ITEM";
+
+ override def consumed = 2;
+ override def produced = 1;
+}
+
+/** This class represents a LOAD_LOCAL instruction
+ * Stack: ...
+ * ->: ...:value
+ */
+case class LOAD_LOCAL(local: Symbol, isArgument: boolean) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String = "LOAD_LOCAL "+local.toString(); //+isArgument?" (argument)":"";
+
+ override def consumed = 0;
+ override def produced = 1;
+}
+
+/** This class represents a LOAD_FIELD instruction
+ * Stack: ...:ref
+ * ->: ...:value
+ */
+case class LOAD_FIELD(field: Symbol, isStatic: boolean) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String = "LOAD_FIELD "+field.toString(); //+isStatic?" (static)":"";
+
+ override def consumed = 1;
+ override def produced = 1;
+}
+
+/** This class represents a STORE_ARRAY_ITEM instruction
+ * Stack: ...:array[a](Ref):index(Int):value(a)
+ * ->: ...
+ */
+case class STORE_ARRAY_ITEM extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String = "STORE_ARRAY_ITEM";
+
+ override def consumed = 3;
+ override def produced = 0;
+}
+
+/** This class represents a STORE_LOCAL instruction
+ * Stack: ...:value
+ * ->: ...
+ */
+case class STORE_LOCAL(local: Symbol, isArgument: boolean) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String = "STORE_LOCAL "+local.toString(); //+isArgument?" (argument)":"";
+
+ override def consumed = 1;
+ override def produced = 0;
+}
+
+/** This class represents a STORE_FIELD instruction
+ * Stack: ...:ref:value
+ * ->: ...
+ */
+case class STORE_FIELD(field: Symbol, isStatic: boolean) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String = "STORE_FIELD "+field.toString(); //+isStatic?" (static)":"";
+
+ override def consumed = 2;
+ override def produced = 0;
+}
+
+/** This class represents a CALL_PRIMITIVE instruction
+ * Stack: ...:arg1:arg2:...:argn
+ * ->: ...:result
+ */
+case class CALL_PRIMITIVE(primitive: APrimitive) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="CALL "+primitive.toString();
+
+ override def consumed = primitive match {
+ case (APrimitive$Negation(_)) => 1;
+ case (APrimitive$Test(_,_,true)) => 1;
+ case (APrimitive$Test(_,_,false)) => 2;
+ case (APrimitive$Comparison(_,_)) => 2;
+ case (APrimitive$Arithmetic(_,_)) => 2;
+ case (APrimitive$Logical(_,_)) => 2;
+ case (APrimitive$Shift(_,_)) => 2;
+ case (APrimitive$Conversion(_,_)) => 1;
+ case (APrimitive$ArrayLength(_)) => 1;
+ case (APrimitive$StringConcat(_,_)) => 2;
+ }
+ override def produced = 1;
+}
+
+/** This class represents a CALL_METHOD instruction
+ * STYLE: dynamic / static(StaticInstance)
+ * Stack: ...:ref:arg1:arg2:...:argn
+ * ->: ...:result
+ *
+ * STYLE: new - unused by jvm
+ * Stack: ...:arg1:arg2:...:argn
+ * ->: ...:ref
+ *
+ * STYLE: static(StaticClass)
+ * Stack: ...:arg1:arg2:...:argn
+ * ->: ...:result
+ *
+ */
+case class CALL_METHOD(method: Symbol, style: AInvokeStyle) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="CALL_METHOD "+method.toString()+" ("+style.toString()+")";
+
+ override def consumed = {
+ var result = method.getType().valueParams().length;
+ result = result + (style match
+ {case(AInvokeStyle.Dynamic) => 1
+ case(AInvokeStyle.StaticInstance) => 1
+ case(_) => 0 });
+ result;
+ }
+ override def produced = 1;
+}
+
+/** This class represents a NEW instruction
+ * Stack: ...:
+ * ->: ...:ref
+ */
+ case class NEW(clasz: Symbol) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String = "NEW "+clasz.toString();
+
+ override def consumed = 0;
+ override def produced = 1;
+ }
+
+
+ /** This class represents a CREATE_ARRAY instruction
+ * Stack: ...:size(int)
+ * ->: ...:arrayref
+ */
+case class CREATE_ARRAY(element: Type) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="CREATE_ARRAY "+element.toString();
+
+ override def consumed = 1;
+ override def produced = 1;
+}
+
+ /** This class represents a IS_INSTANCE instruction
+ * Stack: ...:ref
+ * ->: ...:result(boolean)
+ */
+case class IS_INSTANCE(typ: Type) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="IS_INSTANCE "+typ.toString();
+
+ override def consumed = 1;
+ override def produced = 1;
+}
+
+/** This class represents a CHECK_CAST instruction
+ * Stack: ...:ref(oldtype)
+ * ->: ...:ref(typ <=: oldtype)
+ */
+case class CHECK_CAST(typ: Type) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="CHECK_CAST "+typ.toString();
+
+ override def consumed = 1;
+ override def produced = 1;
+}
+
+/** This class represents a SWITCH instruction
+ * Stack: ...:index(int)
+ * ->: ...:
+ */
+case class SWITCH(tags: Array[Array[int]], labels: List[IBasicBlock]) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="SWITCH ...";
+
+ override def consumed = 1;
+ override def produced = 0;
+}
+
+/** This class represents a JUMP instruction
+ * Stack: ...
+ * ->: ...
+ */
+case class JUMP(where: IBasicBlock) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="JUMP "+where.label;
+
+ override def consumed = 0;
+ override def produced = 0;
+}
+
+/** This class represents a CJUMP instruction
+ * It compares the two values on the stack with the 'cond' test operator
+ * Stack: ...:value1:value2
+ * ->: ...
+ */
+case class CJUMP(successBlock: IBasicBlock, failureBlock: IBasicBlock, cond: ATestOp) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="CJUMP "+cond.toString()+" ? "+successBlock.label+" : "+failureBlock.label;
+
+ override def consumed = 2;
+ override def produced = 0;
+}
+
+/** This class represents a CZJUMP instruction
+ * It compares the one value on the stack and zero with the 'cond' test operator
+ * Stack: ...:value:
+ * ->: ...
+ */
+case class CZJUMP(successBlock: IBasicBlock, failureBlock: IBasicBlock, cond: ATestOp) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="CZJUMP "+cond.toString()+" ? "+successBlock.label+" : "+failureBlock.label;
+
+ override def consumed = 1;
+ override def produced = 0;
+}
+
+
+/** This class represents a RETURN instruction
+ * Stack: ...
+ * ->: ...
+ */
+case class RETURN extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="RETURN";
+
+ override def consumed = 0;
+ override def produced = 0;
+}
+
+/** This class represents a THROW instruction
+ * Stack: ...:Throwable(Ref)
+ * ->: ...:
+ */
+case class THROW extends ICInstruction {
+/** Returns a string representation of this instruction */
+ override def toString(): String ="THROW";
+
+ override def consumed = 1;
+ override def produced = 0;
+}
+
+/** This class represents a DROP instruction
+ * Stack: ...:something
+ * ->: ...
+ */
+case class DROP (typ: Type) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="DROP "+typ.toString();
+
+ override def consumed = 1;
+ override def produced = 0;
+}
+
+ /** This class represents a DUP instruction
+ * Stack: ...:something
+ * ->: ...:something:something
+ */
+ case class DUP (typ: Type) extends ICInstruction {
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="DUP";
+
+ override def consumed = 1;
+ override def produced = 2;
+ }
+
+ /** This class represents a MONITOR_ENTER instruction
+ * Stack: ...:object(ref)
+ * ->: ...:
+ */
+ case class MONITOR_ENTER extends ICInstruction {
+
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="MONITOR_ENTER";
+
+ override def consumed = 1;
+ override def produced = 0;
+ }
+
+ /** This class represents a MONITOR_EXIT instruction
+ * Stack: ...:object(ref)
+ * ->: ...:
+ */
+ case class MONITOR_EXIT extends ICInstruction {
+
+ /** Returns a string representation of this instruction */
+ override def toString(): String ="MONITOR_EXIT";
+
+ override def consumed = 1;
+ override def produced = 0;
+ }
+
+}
diff --git a/sources/scala/tools/scalac/icode/ICTypeStack.scala b/sources/scala/tools/scalac/icode/ICTypeStack.scala
new file mode 100644
index 0000000000..9914fdf270
--- /dev/null
+++ b/sources/scala/tools/scalac/icode/ICTypeStack.scala
@@ -0,0 +1,145 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+import scalac.atree._;
+import scalac.symtab._;
+import scalac.Global;
+
+package scala.tools.scalac.icode {
+
+/* This class simulates the type of the opperand
+ * stack of the ICode. */
+class ICTypeStack() {
+
+ // ##################################################
+ // Private fields
+ private var stack : List[Type] = Nil;
+
+ private val global = Global.instance;
+
+ private val typer = new ATreeTyper(global); // !!! Using atree typer !
+
+ private val definitions = global.definitions;
+
+ // ##################################################
+ // Private constructor
+
+ private def this(stack : List[Type]) = {
+ this();
+ this.stack = stack;
+ }
+
+ // ##################################################
+ // Public method
+
+ /* This methods simulate the effect of an ICInstruction
+ * on the stack. It returns the new stack */
+ def eval(instr: ICInstruction) : ICTypeStack = {
+ global.log(instr.toString());
+ if (stack.length < instr.consumed) {
+ global.log("Invalid instruction :"+instr+" for stack "+toString());
+ this;
+ } else {
+ val result = new ICTypeStack(erase(production(instr)):::stack.drop(instr.consumed)); /// !!! Opt
+ global.log("\t-> "+result.toString());
+ result;
+ }
+ }
+
+ // ##################################################
+ // Public methods - Operation on the stack
+
+ /* Push a new type */
+ def push(t: Type) = stack = t::stack;
+
+ /* Returns the topmost type of the stack */
+ def head = stack.head;
+
+ /* Returns the stack without the topmost element */
+ def tail = stack.tail;
+
+ /* Is the stack empty ? */
+ def isEmpty = stack.isEmpty;
+
+ // ##################################################
+ // Private methods
+
+ /* Compute what type(s) the instruction produce on the stack */
+ private def production(instr: ICInstruction) : List[Type] = instr match {
+ case THIS(clasz) => clasz.thisType()::Nil;
+
+ case CONSTANT(aConstant) => typer.computeType(aConstant)::Nil;
+
+ case LOAD_ARRAY_ITEM() => typer.getArrayElementType(stack.tail.head)::Nil;
+
+ case LOAD_LOCAL(local, _) => local.getType()::Nil;
+
+ case LOAD_FIELD(field, _) => stack.head.memberStabilizedType(field)::Nil; // ??
+
+ case STORE_ARRAY_ITEM() => Nil;
+
+ case STORE_LOCAL(_,_) => Nil;
+
+ case STORE_FIELD(_,_) => Nil;
+
+ case CALL_PRIMITIVE(p) => typer.computeType(p)::Nil;
+
+ case CALL_METHOD(method, style) => style match {
+ //case AInvokeStyle.Dynamic => stack.head.memberStabilizedType(method)::Nil; // ???
+ //case AInvokeStyle.Dynamic => stack.drop(method.getType().valueParams().length).head.resultType()::Nil;
+ case AInvokeStyle.New => method.owner().thisType()::Nil;
+
+ case _ => method.resultType()::Nil; // Valable pour Dynamic
+ //case _ => method.owner().thisType().memberStabilizedType(method)::Nil; // ???
+ }
+ case NEW(clasz) => clasz.getType()::Nil;
+
+ case CREATE_ARRAY(element) => definitions.ARRAY_TYPE(element)::Nil;
+
+ case IS_INSTANCE(_) => definitions.BOOLEAN_TYPE()::Nil;
+
+ case CHECK_CAST(typ) => typ::Nil;
+
+ case SWITCH(_,_) => Nil;
+
+ case JUMP(_) => Nil;
+
+ case CJUMP(_,_,_) => Nil;
+
+ case CZJUMP(_,_,_) => Nil;
+
+ case RETURN() => Nil;
+
+ case THROW() => Nil;
+
+ case DROP(_) => Nil;
+
+ case DUP(_) => stack.head::stack.head::Nil;
+
+ case MONITOR_ENTER() => Nil;
+
+ case MONITOR_EXIT() => Nil;
+ }
+
+ /* This method kill all the produced *Unit* elements */
+ // !!! Hack
+ private def erase(production : List[Type]) = production.filter((t: Type) => t match {
+ case Type$UnboxedType(TypeTags.UNIT) => false;
+ case _ => true
+ });
+
+ /* This method returns a String representation of the stack */
+ // !!! POUAH SALE !
+ override def toString() = {
+ var ret : String = "";
+ stack.foreach((t: Type) => ret=(t.toString()+"::")+ret);
+ ret;
+
+ }
+}
+}
diff --git a/sources/scala/tools/scalac/icode/ICode.scala b/sources/scala/tools/scalac/icode/ICode.scala
new file mode 100644
index 0000000000..0fecf66109
--- /dev/null
+++ b/sources/scala/tools/scalac/icode/ICode.scala
@@ -0,0 +1,486 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+import scalac.{Global => scalac_Global}
+
+import scala.collection.mutable.HashMap;
+import scala.collection.mutable.HashSet;
+
+import scalac.symtab._;
+import scalac.atree._;
+import scalac.util.Debug;
+
+package scala.tools.scalac.icode {
+
+/** This class represents the intermediate code of a method*/
+class ICode(label: String, global: scalac_Global) {
+
+ //##################################################
+ // Public fields
+
+ /* The set of all blocks */
+ val blocks: HashSet[IBasicBlock] = new HashSet;
+
+ /* The start block of the method */
+ var startBlock : IBasicBlock = null;
+
+ /* The stack produced by this method */
+ var producedStack : ICTypeStack = null;
+
+ //##################################################
+ // Private fields
+ private var currentLabel : int = 0;
+
+ private var aTreeLabels : HashMap[Symbol, IBasicBlock] = new HashMap;
+
+ //##################################################
+ // Constructor code
+
+ startBlock = newBlock;
+ startBlock.initStack(new ICTypeStack);
+
+ //##################################################
+ // Public methods
+
+ /** This method produce the intermediate code for
+ * the given ATree */
+ def generate(acode : ACode) = {
+ val ctx = gen(acode, new GenContext(startBlock, null));
+
+ ctx.emit(RETURN()); // ??? RETURN instruction rather come from ATree
+ genTypeStack;
+
+ producedStack = ctx.currentBlock.endStack;
+ }
+
+ /* This method applies the given function to all the block */
+ def icTraverse(f: IBasicBlock => unit) = {
+ // ?? Define order (actually preorder)
+ val visited : HashMap[IBasicBlock, boolean] = new HashMap;
+ visited.incl(blocks.elements.map((x: IBasicBlock) => Pair(x, false)));
+
+ var blockToVisit : List[IBasicBlock] = startBlock::Nil;
+
+ while (blockToVisit != Nil) {
+ blockToVisit match {
+ case b::xs => {
+ if (!visited(b)) {
+ f(b);
+ blockToVisit = b.successors:::xs;
+ visited += b -> true;
+ } else
+ blockToVisit = xs;
+ }
+ }
+ }
+ }
+
+
+ /** This methods returns a string representation of the ICode */
+ override def toString() : String = "ICode '"+label+"'"; //
+
+ //##################################################
+ // Public method - printing (for debug use)
+
+ /** This method print the code */
+ def print() : unit = print(System.out);
+
+ def print(out: java.io.PrintStream) : unit = {
+ icTraverse((bb: IBasicBlock) => {
+ out.println("Block #"+bb.label);
+ out.println("Substituable variables : ");
+ if (bb.substituteVars != null)
+ bb.substituteVars.foreach(out.print);
+ else
+ out.println(" {Empty} ");
+ out.println("Instructions:");
+ bb.bbTraverse((ici: ICInstruction) =>
+ out.println(" "+ici.toString()));
+ out.print ("Successors: ");
+ bb.successors.foreach((bb: IBasicBlock) => out.print(bb.label+", "));
+ out.println (""); // ?? Del
+ out.println ();
+ });
+ }
+
+
+ def logType = {
+ global.log ("// Typing "+toString());
+ this.icTraverse((bb: IBasicBlock) => {
+ global.log ("Typing block #"+bb.label);
+ var typer = new ICTypeStack;
+ bb.bbTraverse((ic: ICInstruction) => {
+ typer = typer.eval(ic);
+ global.log(ic.toString()+" -> "+typer.toString());
+ });
+
+ });
+ }
+
+ //##################################################
+ // Private methods
+
+ /* Compute a unique new label */
+ private def nextLabel = {
+ currentLabel = currentLabel + 1;
+ currentLabel;
+ }
+
+ /* This method :
+ * 1/ create a new block
+ * 2/ add the new block to the set
+ * 3/ return the new block
+ */
+ private def newBlock : IBasicBlock = {
+ val block = new IBasicBlock(nextLabel);
+ blocks += block;
+ block;
+ }
+
+ /* Generate the code from a given ATree */
+ private def gen(aCode: ACode, ctx: GenContext) : GenContext =
+ aCode match {
+ case ACode.Void => {
+ global.log ("ICodeGenerator::emit: Void node found");
+ ctx;
+ }
+
+ case ACode$This(clasz) =>
+ ctx.emit(THIS(clasz));
+
+ case ACode$Constant(c) =>
+ ctx.emit(CONSTANT(c));
+
+ case ACode$Load(ALocation$Module(_)) => {
+ global.log ("ICodeGenerator::emit: Load(Module) node found");
+ ctx;
+ }
+
+ case ACode$Load(ALocation$Field(obj, field ,isStatic)) => {
+ var ctx1 = gen(obj, ctx);
+ ctx.emit(LOAD_FIELD(field, isStatic));
+ }
+
+ case ACode$Load(ALocation$Local(local,isArgument)) =>
+ ctx.emit(LOAD_LOCAL(local, isArgument));
+
+ case ACode$Load(ALocation$ArrayItem(array, index)) => {
+ var ctx1 = gen(array, ctx);
+ ctx1 = gen(index, ctx1);
+ ctx1.emit(LOAD_ARRAY_ITEM());
+ }
+
+ case ACode$Store(ALocation$Module(_),_) => {
+ global.log ("ICodeGenerator::emit: Store(Module(_)) node found");
+ ctx;
+ }
+
+ case ACode$Store(ALocation$Field(obj, field, isStatic), value) => {
+ var ctx1 = gen(obj, ctx);
+ ctx1 = gen(value, ctx1);
+ ctx1.emit(STORE_FIELD(field, isStatic));
+ }
+
+ case ACode$Store(ALocation$Local(local, isArgument), value) => {
+ val ctx1 = gen(value, ctx);
+ ctx1.emit(STORE_LOCAL(local, isArgument));
+ }
+
+ case ACode$Store(ALocation$ArrayItem(array, index), value) => {
+ var ctx1 = gen(array, ctx);
+ ctx1 = gen(index, ctx1);
+ ctx1 = gen(value, ctx1);
+ ctx1.emit(STORE_ARRAY_ITEM());
+ }
+
+ case ACode$Apply(AFunction$Method(_,sym,AInvokeStyle.New),_,vargs) => {
+ val vargs_it = new IterableArray(vargs).elements;
+ // !!! Depend the backend in use
+ ctx.emit(NEW(sym.owner()));
+ ctx.emit(DUP(sym.owner().getType()));
+ var ctx1 = ctx;
+ vargs_it.foreach((varg: ACode) => ctx1 = gen(varg, ctx1));
+ ctx1.emit(CALL_METHOD(sym,AInvokeStyle.StaticInstance));
+ }
+
+ case ACode$Apply(AFunction$Method(obj,sym,style),_,vargs) => {
+ val vargs_it = new IterableArray(vargs).elements;
+ var ctx1 = ctx;
+ style match {
+ case AInvokeStyle.StaticClass =>
+ ; // NOP
+ case _ =>
+ ctx1 = gen(obj, ctx1);
+ }
+ vargs_it.foreach((varg: ACode) => ctx1 = gen(varg, ctx1));
+ ctx1.emit(CALL_METHOD(sym,style));
+ }
+
+ case ACode$Apply(AFunction$Primitive(p),_,vargs) => {
+ val vargs_it = new IterableArray(vargs).elements;
+ var ctx1 = ctx;
+
+ vargs_it.foreach((varg: ACode) => ctx1 = gen(varg, ctx1));
+ ctx1.emit(CALL_PRIMITIVE(p));
+ }
+
+ case ACode$Apply(AFunction$NewArray(element),_,vargs) => {
+ var ctx1 = gen(vargs(0), ctx); // The size is given as first argument
+ ctx1.emit(CREATE_ARRAY(element));
+ }
+
+ case ACode$IsAs(value,typ,false) => {
+ var ctx1 = gen(value, ctx);
+ ctx1.emit(IS_INSTANCE(typ));
+ }
+
+ case ACode$IsAs(value,typ,true) => {
+ var ctx1 = gen(value, ctx);
+ ctx1.emit(CHECK_CAST(typ));
+ }
+
+ case ACode$If(test, success, failure) => {
+ genAlt(test, success, failure, ctx, newBlock);
+ }
+
+ case ACode$Switch(test,tags,bodies) => {
+
+ val switchBodies = List.fromArray(bodies, 0, bodies.length);
+ var switchBlocks: List[IBasicBlock] = Nil;
+ for (val i : ACode <- switchBodies) switchBlocks = newBlock::switchBlocks;
+ val switchPairs = switchBodies.zip(switchBlocks);
+
+ val nextBlock = newBlock;
+
+ var ctx1 = gen(test, ctx);
+ ctx1.emit(SWITCH(tags, switchBlocks));
+ ctx1.currentBlock.addSuccessors(switchBlocks);
+
+ switchPairs.foreach((p: Pair[ACode, IBasicBlock]) => {
+ val code = p._1;
+ val block = p._2;
+
+ val ctx2 = gen(code, new GenContext(block, nextBlock));
+ ctx2.closeBlock;
+ });
+
+ ctx1.changeBlock(nextBlock);
+ }
+
+ case ACode$Synchronized(lock, value) => {
+ var ctx1 = gen(lock, ctx);
+ ctx1.emit(MONITOR_ENTER());
+ ctx1 = gen(value,ctx);
+ ctx1 = gen(lock, ctx);
+ ctx1.emit(MONITOR_EXIT());
+ }
+
+ case ACode$Block(_,statements,value) => {
+ val statements_it = new IterableArray(statements).elements;
+ var ctx1 = ctx;
+ statements_it.foreach((st: ACode) => ctx1 = gen(st, ctx1));
+ ctx1 = gen(value, ctx1);
+ ctx1;
+ }
+
+ case ACode$Label(label, locals, value) => {
+
+ val loopBlock = newBlock;
+ var ctx1 = ctx.changeBlock(loopBlock);
+ ctx.nextBlock = loopBlock;
+ ctx.closeBlock;
+
+ aTreeLabels += label -> loopBlock;
+
+ loopBlock.substituteVars = List.fromIterator((new IterableArray(locals)).elements);
+ gen(value, ctx1);
+ }
+
+ case ACode$Goto(label,vargs) => {
+
+ val vargs_it = new IterableArray(vargs).elements;
+ global.log("Current label mapping: "+aTreeLabels.keys.foreach((s: Symbol) => global.log(s.toString())));
+ global.log("Looking for sym: "+label);
+ val gotoBlock = aTreeLabels(label);
+ var ctx1 = ctx;
+
+ // Stack-> :
+ vargs_it.foreach((varg: ACode) => ctx1 = gen(varg, ctx1));
+
+ // Stack-> :varg0:varg1:...:vargn
+ // We should have the same number of varg that substitute vars
+
+ gotoBlock.substituteVars.reverse.foreach(
+ (varg: Symbol) => ctx1.emit(STORE_LOCAL(varg, false)) // ?? false
+ );
+ ctx1.nextBlock = gotoBlock;
+ ctx1.closeBlock;
+
+ ctx1;
+ }
+
+ case ACode$Return(_,value) => {
+ var ctx1 = gen(value, ctx);
+ ctx1.emit(RETURN());
+ }
+ case ACode$Throw(value) => {
+ var ctx1 = gen(value, ctx);
+ ctx1.emit(THROW());
+ }
+
+ case ACode$Drop(value, typ) => {
+ var ctx1 = gen(value, ctx);
+ //global.log("Type de Drop: "+typ+" = unboxed:"+typ.unbox() );
+ if (! typ.isSameAs(global.definitions.UNIT_TYPE()))
+ typ.unbox() match { // !!! Hack
+ case Type$UnboxedType(TypeTags.UNIT) =>
+ global.log("it matches UNIT !"); // debug ; // NOP
+ case _ =>
+ ctx1.emit(DROP(typ));
+ }
+ else
+ global.log("it matches SCALAC_UNIT :-(");
+ ctx1;
+ }
+ }
+
+ /* This method genrates an alternative. In the case of an if instruction
+ * It looks at the kind of alternatives and creates new basic blocks
+ *
+ * @param nextBlock : represents the block where alternatives meet again*/
+ private def genAlt (cond : ACode, success: ACode, failure: ACode, ctx: GenContext, nextBlock: IBasicBlock) : GenContext = {
+ val successBlock = success match {
+ case ACode.Void => nextBlock;
+
+ case ACode$If(test, innerSuccess, innerFailure) => {
+ val ctx1 = new GenContext(newBlock, null);
+ val ctx2 = genAlt(test, innerSuccess, innerFailure, ctx1, nextBlock);
+ //ctx2.closeBlock; // or close when CJUMP is emitted
+ ctx1.currentBlock;
+ }
+
+ case _ => {
+ val ctx1 = new GenContext(newBlock, nextBlock);
+ val ctx2 = gen(success, ctx1);
+ ctx2.closeBlock;
+ ctx1.currentBlock;
+ }
+ }
+
+ val failureBlock = failure match {
+ case ACode.Void => nextBlock;
+
+ case ACode$If(test, innerSuccess, innerFailure) => {
+ val ctx1 = new GenContext(newBlock, null);
+ val ctx2 = genAlt(test, innerSuccess, innerFailure, ctx1, nextBlock);
+ //ctx2.closeBlock; // or close when CJUMP is emitted
+ ctx1.currentBlock;
+ }
+
+ case _ => {
+ val ctx1 = new GenContext(newBlock, nextBlock);
+ val ctx2 = gen(failure, ctx1);
+ ctx2.closeBlock;
+ ctx1.currentBlock;
+ }
+ }
+
+ var ctx1 = genCond(cond, successBlock, failureBlock, ctx);
+ ctx1.changeBlock(nextBlock);
+ }
+
+ /* This methods generate the test and the jump instruction */
+ private def genCond(cond: ACode, successBlock: IBasicBlock, failureBlock: IBasicBlock, ctx: GenContext) : GenContext= {
+ var ctx1 = ctx;
+ cond match {
+ case ACode$Apply(AFunction$Primitive(APrimitive$Test(op,_,zero)),_, vargs) => {
+ ctx1 = gen(vargs(0),ctx1);
+ if (zero)
+ ctx1.emit(CZJUMP(successBlock, failureBlock, op));
+ else {
+ ctx1 = gen(vargs(1), ctx1);
+ ctx1.emit(CJUMP(successBlock, failureBlock, op));
+ }
+ ctx1.currentBlock.addSuccessors(successBlock::failureBlock::Nil);
+ }
+
+ case ACode$Apply(AFunction$Primitive(APrimitive$Negation(_)),_,vargs) =>
+ ctx1 = genCond(vargs(0), failureBlock, successBlock, ctx1);
+ // ??? Test with TestOp opposite ?
+ case _ => {
+ ctx1 = gen(cond, ctx1);
+ ctx1.emit(CONSTANT(AConstant.INT(1)));
+ ctx1.emit(CJUMP(successBlock, failureBlock, ATestOp.EQ));
+ ctx1.currentBlock.addSuccessors(successBlock::failureBlock::Nil);
+ }
+ }
+ ctx1;
+ }
+
+ /* This method generate the type stacks of all the blocks
+ * of this method.*/
+ private def genTypeStack = {
+ icTraverse((bb: IBasicBlock) => {
+ global.log("// Typing block #"+bb.label);
+ global.log("\t-> "+bb.endStack);
+ bb.typeBlock;
+ // !!! Here we must test if all the meeting blocks have the
+ // !!! same stack.
+ bb.successors.foreach((suc: IBasicBlock) => suc.initStack(bb.endStack));
+ });
+ }
+
+}
+
+ /* This class represents the context of generating icode */
+ class GenContext(current: IBasicBlock, next: IBasicBlock) {
+
+ // ##################################################
+ // Public fields
+
+ /* The block in which we add instructions */
+ val currentBlock = current;
+
+ /* The block were we jump at the end of the current block
+ * It can be the *null* value */
+ var nextBlock = next;
+
+ // ##################################################
+ // Constructor code
+
+ assert(current != null, "No current block");
+
+ // ##################################################
+ // Public methods
+
+ /* append an instruction at the end of the current block */
+ def emit(instr: ICInstruction) : GenContext = {
+ currentBlock.emit(instr);
+ this;
+ }
+
+ /* Split the current block. The next block is still the same */
+ def changeBlock(bb: IBasicBlock) = {
+ new GenContext(bb, next);
+ }
+
+ /* Close the current block. If there's a known next block
+ * It append a jump instruction to the block.
+ * This method do something only the first time it's called */
+ def closeBlock = {
+ if (!currentBlock.isClosedBlock) {
+ if (nextBlock != null) {
+ emit(JUMP(nextBlock));
+ currentBlock.addSuccessor(nextBlock);
+ }
+ currentBlock.close;
+ }
+ }
+ }
+
+} // package
diff --git a/sources/scala/tools/scalac/icode/ICodePhase.scala b/sources/scala/tools/scalac/icode/ICodePhase.scala
new file mode 100644
index 0000000000..ab55131066
--- /dev/null
+++ b/sources/scala/tools/scalac/icode/ICodePhase.scala
@@ -0,0 +1,65 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+import scalac.transformer.{ICodePhase => scalac_ICodePhase}
+import scalac.{Global => scalac_Global}
+import scalac.{Unit => scalac_Unit}
+import scalac.PhaseDescriptor;
+import scalac.symtab.Symbol;
+import scalac.symtab.Type;
+import scalac.Phase;
+import scalac.atree._;
+
+import ch.epfl.lamp.util.CodePrinter;
+
+package scala.tools.scalac.icode {
+
+/** This class represents the ICode phase. This phase use the ATrees
+ * that represents the code with some primitives backends-like
+ * and convert them in a inline form: The ICode (for intermediate
+ * code). The ICode will be produced in the icode variable
+ * of all AMethod objects. */
+class ICodePhase(global: scalac_Global, descriptor: PhaseDescriptor) extends scalac_ICodePhase (global, descriptor) {
+
+ // ##################################################
+ // Public methods
+
+ /* Apply the icode phase to the given units */
+ override def apply(units: Array[scalac_Unit]) = {
+ val units_it = new IterableArray(units).elements;
+
+ units_it.foreach(translate);
+ }
+
+ /* Return a CodePrinter for the ICode */
+ override def getPrinter(cp: CodePrinter) = new ICodePrinter(cp);
+
+ // ##################################################
+ // Private methods
+
+ /** This method translate a single unit, it traverses all methods and
+ * generate ICode for each of them */
+ private def translate(u: scalac_Unit) : unit = {
+ val classes_it = new IterableArray(u.repository.classes()).elements;
+ classes_it.foreach((c: AClass) => {
+ val methods_it = new IterableArray(c.methods()).elements;
+ methods_it.foreach((m: AMethod) => {
+ val label : String = m.symbol().name.toString();
+
+ val ic : ICode = new ICode(label, global);
+ ic.generate(m.code());
+
+ // save the produced ICode
+ m.icode = ic;
+
+ });
+ });
+ }
+
+}
+}
diff --git a/sources/scala/tools/scalac/icode/ICodePrinter.scala b/sources/scala/tools/scalac/icode/ICodePrinter.scala
new file mode 100644
index 0000000000..7021f54566
--- /dev/null
+++ b/sources/scala/tools/scalac/icode/ICodePrinter.scala
@@ -0,0 +1,72 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+import ch.epfl.lamp.util.CodePrinter;
+
+import scalac.Unit;
+import scalac.{Global => scalac_Global}
+import scalac.atree._;
+
+import scalac.symtab.{Symbol => scalac_Symbol}
+
+package scala.tools.scalac.icode {
+
+/* This class implements a Printer for the ICode */
+class ICodePrinter (printer: CodePrinter) extends ATreePrinter (printer: CodePrinter) {
+
+ // ##################################################
+ // Public methods
+
+ /* This method print all ICode produced after the ICode phase */
+ override def printGlobal(global: scalac_Global) : ATreePrinter = { // !!! Extends ATree !!!
+ val phase = global.currentPhase;
+
+ printer.println("[[ICode at "+phase+" (after "+phase.prev+")]]");
+ val units_it = new IterableArray(global.units).elements;
+ units_it.foreach(printAnUnit);
+
+ this;
+ }
+
+ /* This method print a single unit. */
+ def printAnUnit(unit: Unit) = { // ??? Private
+ printer.println ("// Scala source: "+unit.source);
+ val classes_it = new IterableArray(unit.repository.classes()).elements;
+ classes_it.foreach((c: AClass) => {
+ printer.println ("");
+ printer.println ("// ICode for class <"+c.symbol().name+">");
+ val methods_it = new IterableArray(c.methods()).elements;
+ methods_it.foreach((m: AMethod) => {
+ val icode : ICode = m.icode.asInstanceOf[ICode];
+ printer.println ("// ::"+m.symbol().name);
+ icode.icTraverse((bb: IBasicBlock) => {
+ printer.println("Block #"+bb.label);
+ printer.println("Initial stack -> "+bb.initialStack);
+ printer.println("Substituable variables : ");
+ if (bb.substituteVars != null)
+ bb.substituteVars.foreach((s: scalac_Symbol) => printer.print(s.name.toString()));
+ else
+ printer.println(" {Empty} ");
+ printer.println("Instructions:");
+ printer.indent();
+ bb.bbTraverse((ici: ICInstruction) =>
+ printer.println(ici.toString()));
+ printer.undent();
+ printer.println("End stack -> "+bb.endStack);
+ printer.print ("Successors: ");
+ bb.successors.foreach((bb: IBasicBlock) => printer.print(bb.label+", "));
+ printer.println (""); // ?? Del
+ printer.println ();
+ });
+ });
+ });
+
+
+ }
+}
+}
diff --git a/sources/scalac/CompilerPhases.java b/sources/scalac/CompilerPhases.java
index dae13e6c91..adac32a95e 100644
--- a/sources/scalac/CompilerPhases.java
+++ b/sources/scalac/CompilerPhases.java
@@ -37,8 +37,10 @@ public class CompilerPhases {
public final PhaseDescriptor EXPANDMIXIN;
public final PhaseDescriptor MAKEBOXINGEXPLICIT;
public final PhaseDescriptor ERASURE;
+ public final PhaseDescriptor ICODE;
public final PhaseDescriptor GENMSIL;
public final PhaseDescriptor GENJVM;
+ public final PhaseDescriptor GENJVMFROMICODE;
public final PhaseDescriptor TERMINAL;
//########################################################################
@@ -62,8 +64,10 @@ public class CompilerPhases {
protected Class ADDINTERFACES_PHASE() { return scalac.transformer.AddInterfacesPhase.class; }
protected Class EXPANDMIXIN_PHASE() { return scalac.transformer.ExpandMixinsPhase.class; }
protected Class ERASURE_PHASE() { return scalac.transformer.ErasurePhase.class; }
+ protected Class ICODE_PHASE() { return scalac.util.EmptyPhase.class; } // No java version
protected Class GENMSIL_PHASE() { return scalac.backend.msil.GenMSILPhase.class; }
protected Class GENJVM_PHASE() { return scalac.backend.jvm.GenJVMPhase.class; }
+ protected Class GENJVMFROMICODE_PHASE() { return scalac.util.EmptyPhase.class; } // No java version
//########################################################################
// Public Constructors
@@ -152,6 +156,11 @@ public class CompilerPhases {
"type eraser",
"erased types",
ERASURE_PHASE()),
+ this.ICODE = new PhaseDescriptor(
+ "icode",
+ "generate icode",
+ "generated icode",
+ ICODE_PHASE()),
this.GENMSIL = new PhaseDescriptor(
"genmsil",
"generate MSIL code",
@@ -162,7 +171,12 @@ public class CompilerPhases {
"generate JVM bytecodes",
"generated JVM code",
GENJVM_PHASE()),
- this.TERMINAL = new PhaseDescriptor(
+ this.GENJVMFROMICODE = new PhaseDescriptor(
+ "genjvmfromicode",
+ "generate JVM bytecodes using ICode",
+ "generated JVM code using ICode",
+ GENJVMFROMICODE_PHASE()),
+ this.TERMINAL = new PhaseDescriptor(
"terminal",
"compilation terminated",
"compilation terminated",
diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java
index bd411f7439..37e2ed95d9 100644
--- a/sources/scalac/Global.java
+++ b/sources/scalac/Global.java
@@ -136,11 +136,13 @@ public class Global {
public static final String TARGET_INT;
public static final String TARGET_JVM;
public static final String TARGET_MSIL;
+ public static final String TARGET_JVMFROMICODE;
public static final String[] TARGETS = new String[] {
- TARGET_INT = "int",
- TARGET_JVM = "jvm",
- TARGET_MSIL = "msil",
+ TARGET_INT = "int",
+ TARGET_JVM = "jvm",
+ TARGET_MSIL = "msil",
+ TARGET_JVMFROMICODE = "jvmfromicode"
};
/** tree printers
@@ -225,6 +227,12 @@ public class Global {
// TODO: Enable TailCall for other backends when they handle LabelDefs
if (target != TARGET_MSIL) args.phases.GENMSIL.addSkipFlag();
if (target != TARGET_JVM) args.phases.GENJVM.addSkipFlag();
+ if (target != TARGET_JVMFROMICODE) {
+ args.phases.ICODE.addSkipFlag();
+ args.phases.GENJVMFROMICODE.addSkipFlag();
+ } else {
+ ;//args.phases.ERASURE.addSkipFlag();
+ }
PHASE.freeze();
PhaseDescriptor[] descriptors = PHASE.phases();
this.firstPhase = descriptors[0].create(this);
@@ -334,6 +342,15 @@ public class Global {
printer.printGlobal(this);
if (next) currentPhase = currentPhase.prev;
if (html) writer.println("</pre>");
+ } else if (currentPhase.id == PHASE.ICODE.id()) {
+ boolean html = args.printer.value.equals(PRINTER_HTML);
+ if (html) writer.println("<pre>");
+ ATreePrinter printer = ((scalac.transformer.ICodePhase)currentPhase).getPrinter(new CodePrinter(writer)); // Oh !!
+ boolean next = currentPhase.next != null;
+ if (next) currentPhase = currentPhase.next;
+ printer.printGlobal(this);
+ if (next) currentPhase = currentPhase.prev;
+ if (html) writer.println("</pre>");
} else {
// go to next phase to print symbols with their new type
boolean next = currentPhase.next != null;
diff --git a/sources/scalac/atree/AMethod.java b/sources/scalac/atree/AMethod.java
index 332f2284d4..f904fa6b92 100644
--- a/sources/scalac/atree/AMethod.java
+++ b/sources/scalac/atree/AMethod.java
@@ -13,6 +13,11 @@ import scalac.symtab.Type;
/** This class represents an attributed method. */
public class AMethod extends AMember {
+ //########################################################################
+ // Public Fields
+
+ /** Contains the Intermediate code of this Method */
+ public Object icode = null;
//########################################################################
// Public Constructors
diff --git a/sources/scalac/atree/AShiftOp.java b/sources/scalac/atree/AShiftOp.java
index 102f7963bd..fbed80fcde 100644
--- a/sources/scalac/atree/AShiftOp.java
+++ b/sources/scalac/atree/AShiftOp.java
@@ -16,24 +16,24 @@ public class AShiftOp {
//########################################################################
// Public Cases
- /** A logical shift to the left */
- public case LSL;
-
- /** A logical shift to the right */
- public case LSR;
+ /** An arithmetic shift to the left */
+ public case ASL;
/** An arithmetic shift to the right */
public case ASR;
+ /** A logical shift to the right */
+ public case LSR;
+
//########################################################################
// Public Methods
/** Returns a string representation of this operation. */
public String toString() {
switch (this) {
- case LSL: return "LSL";
- case LSR: return "LSR";
+ case ASL: return "ASL";
case ASR: return "ASR";
+ case LSR: return "LSR";
default: throw Debug.abort("unknown case", this);
}
}
diff --git a/sources/scalac/atree/ATreeTyper.java b/sources/scalac/atree/ATreeTyper.java
index 3a1a1df5c7..dead4e7c40 100644
--- a/sources/scalac/atree/ATreeTyper.java
+++ b/sources/scalac/atree/ATreeTyper.java
@@ -217,6 +217,36 @@ public class ATreeTyper {
}
//########################################################################
+ // Public Methods - aliases of type() for scala
+ public Type[] computeType(ACode[] codes) {
+ return type(codes);
+ }
+
+ public Type computeType(ACode code) {
+ return type(code);
+ }
+
+ public Type computeType(ALocation location) {
+ return type(location);
+ }
+
+ public Type computeType(AFunction function) {
+ return type(function);
+ }
+
+ public Type computeType(APrimitive primitive) {
+ return type(primitive);
+ }
+
+ public Type computeType(AConstant constant) {
+ return type(constant);
+ }
+
+ public Type computeType(ATypeKind kind) {
+ return type(kind);
+ }
+
+ //########################################################################
// Private Methods
/** Returns the application of given arguments to given type. */
@@ -231,7 +261,7 @@ public class ATreeTyper {
}
/** Returns the element type of the given array type. */
- private Type getArrayElementType(Type type) {
+ public Type getArrayElementType(Type type) { // !!! public / private
switch (type) {
case TypeRef(_, Symbol symbol, Type[] args):
assert symbol == definitions.ARRAY_CLASS && args.length == 1: type;
diff --git a/sources/scalac/transformer/ICodePhase.java b/sources/scalac/transformer/ICodePhase.java
new file mode 100644
index 0000000000..5ed3212da1
--- /dev/null
+++ b/sources/scalac/transformer/ICodePhase.java
@@ -0,0 +1,59 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id:
+
+package scalac.transformer;
+
+import scalac.Global;
+import scalac.Phase;
+import scalac.PhaseDescriptor;
+import scalac.Unit;
+import scalac.checkers.TreeChecker;
+import scalac.symtab.Definitions;
+
+import ch.epfl.lamp.util.CodePrinter;
+import scalac.atree.ATreePrinter;
+
+
+/**
+ * This class represents the ICode phase for the java version
+ * of the compiler. It doesn't do anything but permit to make
+ * a bridge between the java implementation of Socos et the
+ * scala one. See scala.tools.scalac.icode.ICodePhase for
+ * implementation
+ */
+public class ICodePhase extends Phase {
+
+ //########################################################################
+ // Private Fields
+
+ private final Definitions definitions;
+
+ //########################################################################
+ // Public Constructors
+
+ /** Initializes this instance. */
+ public ICodePhase(Global global, PhaseDescriptor descriptor) {
+ super(global, descriptor);
+ this.definitions = global.definitions;
+ }
+
+ //########################################################################
+ // Public Methods
+
+ /** Applies this phase to the given compilation units. */
+ public void apply(Unit[] units) {
+ // This java version doesn't make anything
+ }
+
+ public ATreePrinter getPrinter(CodePrinter cp) {
+ return new ATreePrinter(cp);
+ // !! Useless
+ }
+
+}
+