summaryrefslogtreecommitdiff
path: root/sources/scalac
diff options
context:
space:
mode:
Diffstat (limited to 'sources/scalac')
-rw-r--r--sources/scalac/backend/msil/GenMSIL.java1943
-rw-r--r--sources/scalac/backend/msil/GenMSILPhase.java45
-rw-r--r--sources/scalac/backend/msil/TypeCreator.java743
3 files changed, 2731 insertions, 0 deletions
diff --git a/sources/scalac/backend/msil/GenMSIL.java b/sources/scalac/backend/msil/GenMSIL.java
new file mode 100644
index 0000000000..e126b72216
--- /dev/null
+++ b/sources/scalac/backend/msil/GenMSIL.java
@@ -0,0 +1,1943 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+
+package scalac.backend.msil;
+
+import scalac.Global;
+import scalac.Unit;
+import scalac.Phase;
+import scalac.PhaseDescriptor;
+import scalac.ApplicationError;
+
+import scalac.util.Debug;
+
+import scalac.util.Name;
+import scalac.util.Names;
+import scalac.util.Position;
+import scalac.util.Debug;
+import scalac.ast.Tree;
+import Tree.*;
+import scalac.symtab.Symbol;
+import scalac.symtab.Scope;
+import scalac.symtab.Kinds;
+import scalac.symtab.TypeTags;
+import scalac.symtab.Modifiers;
+import scalac.symtab.Definitions;
+import Scope.SymbolIterator;
+
+import scalac.backend.Primitives;
+
+import ch.epfl.lamp.compiler.msil.*;
+import ch.epfl.lamp.compiler.msil.emit.*;
+
+import Item.*;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.io.IOException;
+
+/**
+ * Generates MS IL code via the Reflection.Emit API
+ * (ch.epfl.lamp.compiler.msil.emit package)
+ *
+ * @author Nikolay Mihaylov
+ */
+
+public class GenMSIL extends Phase /*implements Modifiers */ {
+
+ final Map assemblies;
+
+ // tells which symbols are functions arguments or locals
+ Map params, locals;
+
+ AssemblyBuilder defaultAssembly, currAssembly;
+ ModuleBuilder currModule, scalaModule;
+
+ ILGenerator code;
+
+ final TypeCreator tc;
+ final Definitions defs;
+ final Primitives primitives;
+ final ItemFactory items;
+
+ Symbol currentPackage;
+
+ static final HashMap opMap = new HashMap();
+ static final HashMap cmpMap = new HashMap();
+ {
+ opMap.put(Names.ADD, OpCodes.Add);
+ opMap.put(Names.SUB, OpCodes.Sub );
+ opMap.put(Names.MUL, OpCodes.Mul);
+ opMap.put(Names.DIV, OpCodes.Div);
+ opMap.put(Names.MOD, OpCodes.Rem);
+ opMap.put(Names.AND, OpCodes.And);
+ opMap.put(Names.OR, OpCodes.Or);
+ opMap.put(Names.XOR, OpCodes.Xor);
+ opMap.put(Names.LSL, OpCodes.Shl);
+ opMap.put(Names.ASR, OpCodes.Shr);
+ opMap.put(Names.LSR, OpCodes.Shr_Un);
+
+ cmpMap.put(Names.EQ, new Integer(Test.EQ));
+ cmpMap.put(Names.NE, new Integer(Test.NE));
+ cmpMap.put(Names.LT, new Integer(Test.LT_IS));
+ cmpMap.put(Names.GT, new Integer(Test.GT_IS));
+ cmpMap.put(Names.LE, new Integer(Test.LE_IS));
+ cmpMap.put(Names.GE, new Integer(Test.GE_IS));
+ }
+
+ static final Item TRUE_ITEM = Item.CondItem(Test.True, null, null);
+ static final Item FALSE_ITEM = Item.CondItem(Test.False, null, null);
+
+
+ final Symbol STRING_CONCAT;
+ static final Type SCALA_UNIT = TypeCreator.getJavaType("scala.Unit");
+ static final FieldInfo RUNTIME_UNIT_VAL =
+ TypeCreator.getJavaType("scala.runtime.RunTime").GetField("UNIT_VAL");
+
+ /**
+ */
+ public GenMSIL(Global global, GenMSILPhase phase) {
+ super(global, phase);
+ defs = global.definitions;
+ primitives = global.primitives;
+ assemblies = phase.assemblies;
+
+ tc = new TypeCreator(this);
+ items = new ItemFactory(this);
+
+ currentPackage = defs.ROOT_CLASS; /// ???
+ scalaModule = getPackage("scala", false);
+
+ STRING_CONCAT = defs.STRING_CLASS.members().
+ lookup(Name.fromString("concat"));
+
+ }
+
+
+ /** Generate .NET assembly
+ */
+ public ModuleBuilder getPackage(String name, boolean isRealAssembly) {
+ AssemblyBuilder assem = (AssemblyBuilder) assemblies.get(name);
+ if (assem == null) {
+ AssemblyName an = new AssemblyName();
+ an.Name = name;
+ assem = EmitUtils.DefineDynamicAssembly(an);
+ if (isRealAssembly)
+ assemblies.put(name, assem);
+ }
+ ModuleBuilder module = (ModuleBuilder) assem.GetModule(name);
+ if (module == null) {
+ module = assem.DefineDynamicModule(name, name + ".dll");
+ }
+ return module;
+ }
+
+
+ /**
+ */
+ public void apply() {
+ if (global.target == global.TARGET_MSIL) {
+ currModule = getPackage("prog", true);
+ main = (MethodBuilder) currModule.GetMethod("Main", Type.EmptyTypes);
+ if (main == null) {
+ main = currModule.DefineGlobalMethod
+ ("Main", MethodAttributes.Static,
+ Type.GetType("System.Void"),
+ new Type[] {Type.GetType("System.String[]")} );
+ main.DefineParameter(0, 0L, "args");
+ }
+
+ // create mappings from Symbols to MSIL Types
+ tc.traverse(global.units);
+
+ try {
+ super.apply(); // this invokes apply(Unit) for each Unit
+ } catch (Throwable e) {
+ //log("params: " + params);
+ //log("locals: " + locals);
+ if (code != null) {
+ MethodBase method = code.owner;
+ log("Processing method " + method.DeclaringType +
+ "::" +method.Name);
+ }
+ e.printStackTrace();
+ throw (Error) e;
+ }
+ tc.createTypes();
+ main.GetILGenerator().Emit(OpCodes.Ret);
+ ((AssemblyBuilder)currModule.Assembly).SetEntryPoint(main);
+ try {
+ Iterator iter = assemblies.values().iterator();
+ while (iter.hasNext()) {
+ AssemblyBuilder assem = (AssemblyBuilder) iter.next();
+ assem.Save(assem.FullName + ".il");
+ }
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ static String dumpSym(Symbol sym) {
+ if (sym == null) return "<null>";
+ if (sym == Symbol.NONE) return "NoSymbol";
+ return "symbol = " + Debug.show(sym) +
+ "; owner = " + Debug.show(sym.owner()) +
+ //"; info = " + Debug.show(sym.info()) +
+ "; kind = " + sym.kind +
+ "; flags = " + Integer.toHexString(sym.flags);
+ }
+
+
+ MethodBuilder main;
+
+ static final Type STRING_ARRAY = Type.GetType("System.String[]");
+
+ final HashMap mains = new HashMap();
+
+ void checkMain(MethodBase method) {
+ //log("checking method: " + method);
+ if ( ! currentClass.isModuleClass() )
+ return;
+
+ if (method.IsConstructor || method.IsAbstract ||
+ !method.Name.equals("main"))
+ return;
+ ParameterInfo[] params = method.GetParameters();
+ if (params.length != 1)
+ return;
+ if (params[0].ParameterType != STRING_ARRAY)
+ return;
+
+ //log("'main' method found: " + method);
+ mains.put(currentClass, method);
+ ILGenerator code = main.GetILGenerator();
+ code.Emit(OpCodes.Ldsfld, tc.getModuleField(currentClass));
+ code.Emit(OpCodes.Ldarg_0);
+ code.Emit(OpCodes.Callvirt, (MethodInfo)method);
+ if (!returnsVoid(main))
+ code.Emit(OpCodes.Pop);
+ }
+
+
+ Unit currUnit;
+
+ /**
+ */
+ public void apply(Unit unit) {
+ currUnit = unit;
+ for (int i = 0; i < unit.body.length; i++) {
+ Tree tree = unit.body[i];
+ Symbol sym = tree.symbol();
+ switch (tree) {
+ case Empty: break;
+ case ClassDef(_, _, _, _, _, Template(_, Tree[] body)):
+ genClass(sym, body);
+ break;
+ case PackageDef(Tree packaged, Template impl):
+ //String packageName = packaged.symbol().fullNameString();
+ //log("Package: " + dumpSym(packaged.symbol()));// +
+ //"; symbol.fullName() = " + packaged.symbol().fullName());
+ //currModule = getPackage(packageName);
+ genPackage(currAssembly, impl.body);
+ break;
+ case ValDef(_, _, _, _):
+ //log("ValDef: " + dumpSym(tree.symbol()));
+ break;
+ default:
+ throw new ApplicationError
+ ("Illegal top-level definition: " + Debug.show(tree));
+ }
+ }
+ }
+
+
+ /** Generate the code for Package definition
+ */
+ public void genPackage(AssemblyBuilder assembly, Tree[] body) {
+ for (int i = 0; i < body.length; i++) {
+ Symbol sym = body[i].symbol();
+ //log("genPackage: " + dumpSym(body[i].symbol()));
+ switch (body[i]) {
+ case Empty:
+ break;
+
+ case ClassDef(_, _, _, _, _, Template(_, Tree[] classBody)):
+ genClass(sym, classBody);
+ break;
+
+ case ValDef(_, _, Tree tpe, Tree rhs):
+ if (sym.isModule()) {
+ } else
+ throw new ApplicationError();
+ //log("ValDef: " + dumpSym(tree.symbol()));
+ break;
+
+ case PackageDef(Tree packaged, Template(_ , Tree[] body2)):
+ //log("genPackage: nested package: " + dumpSym(sym));
+ genPackage(currAssembly, body2);
+ break;
+
+ default:
+ log("genPackage: Only class definitions expected in a package!: Found instead: " +
+ dumpSym(sym));
+ }
+ }
+ }
+
+ public Symbol currentClass;
+
+ public MethodBase currentMethod;
+
+ /** Generate the code for a class
+ */
+ public void genClass(Symbol clazz, Tree[] body) {
+ //log("genClass: " + dumpSym(clazz));
+ //log("\tfullName = " + clazz.fullName());
+ //log("\tqualifier = " + Debug.show(clazz.qualifier()));
+ //log("class members: " + clazz.members());
+ Symbol outerClass = currentClass;
+ currentClass = clazz;
+ if ( clazz.isModule() || clazz.isModuleClass() ) {
+ //log("genClass: initializing module field for module " + dumpSym(clazz));
+ tc.getModuleField(clazz);
+ }
+ for (int i = 0; i < body.length; i++) {
+ Symbol sym = body[i].symbol();
+ switch (body[i]) {
+ case Empty:
+ break;
+
+ case ValDef(_, _, _, _):
+ // just to generate the field declaration
+ // the rhs should've been moved to the constructor body
+ tc.getField(sym);
+ break;
+
+ case ClassDef(_, _, _, _, _, Template impl):
+ genClass(sym, impl.body);
+ break;
+
+ case DefDef(_, _, _, ValDef[][] vparams, Tree tpe, Tree rhs):
+ //log("genClass.DefDef: " + dumpSym(sym));
+ //log("DefDef: type = " + Debug.show(tpe.type));
+ currentMethod = tc.getMethod(sym);
+ if (!currentMethod.IsAbstract) {
+ checkMain(currentMethod);
+ genDef(sym, vparams[0], rhs, type2MSILType(tpe.type));
+ }
+ break;
+
+ default:
+ assert false : "Illegal class body definition: " + body[i];
+ }
+ }
+ currentClass = outerClass;
+ } //genClass()
+
+
+ boolean lastStatement;
+ static final boolean enableTailCalls = true;
+
+
+ /** Generate the code for Methods
+ */
+ public void genDef(Symbol sym, ValDef[] parameters, Tree rhs, MSILType toType) {
+ MethodBase method = tc.getMethod(sym);
+ //log("genDef: " + method.getSignature());
+ assert params == null && locals == null : "No nested function definitions";
+
+ params = new HashMap();
+ locals = new HashMap();
+ int argOffset = method.IsStatic ? 0 : 1;
+ for (int i = 0; i < parameters.length; i++) {
+ params.put(parameters[i].symbol(), new Integer(i + argOffset));
+ }
+
+ if (method.IsConstructor) {
+ ConstructorInfo ctor = (ConstructorInfo) method;
+ code = ((ConstructorBuilder)ctor).GetILGenerator();
+ FieldInfo moduleField = tc.getModuleField(currentClass);
+ if (moduleField != null) {
+ //log("genDef: initializing " + MODULE_S + " for class " + method.DeclaringType);
+
+ // emit the call to the superconstructor
+ switch (rhs) {
+ case Block(Tree[] stats):
+ // this is the call to the super constructor
+ drop(gen(stats[0], MSILType.VOID));
+ break;
+ default:
+ drop(gen(rhs, MSILType.VOID));
+ }
+
+ ConstructorBuilder cctor = ((TypeBuilder)(method.DeclaringType)).
+ DefineConstructor(MethodAttributes.Static |
+ MethodAttributes.Public,
+ CallingConventions.Standard,
+ Type.EmptyTypes);
+ currentMethod = cctor;
+ ILGenerator ctorCode = code;
+ code = cctor.GetILGenerator();
+ // initialize the static module reference
+ code.Emit(OpCodes.Newobj, ctor);
+ code.Emit(OpCodes.Stsfld, moduleField);
+ switch (rhs) {
+ case Block(Tree[] stats):
+ int n = stats.length;
+ assert n > 0;
+ for (int i = 1; i < n; i++)
+ drop(gen(stats[i], MSILType.VOID));
+ break;
+ }
+ code.Emit(OpCodes.Ret);
+ code = ctorCode;
+ } else
+ drop(gen(rhs, MSILType.VOID));
+ }
+ else {
+ lastStatement = true;
+ code = ((MethodBuilder)method).GetILGenerator();
+ Item item = gen(rhs, toType);
+ if (returnsVoid(method))
+ drop(item);
+ else
+ coerce(load(item), toType); // coerce???
+ }
+ code.Emit(OpCodes.Ret);
+
+ lastStatement = false;
+ params = null;
+ locals = null;
+ code = null;
+ }
+
+
+ /** check if the result type of a method is void
+ */
+ public boolean returnsVoid(MethodBase method) {
+ return method.IsConstructor ||
+ (((MethodInfo)method).ReturnType == TypeCreator.VOID);
+ }
+
+
+ /** emit the code for this'
+ */
+ void emitThis() {
+ if (currentMethod.IsStatic) {
+ if (currentMethod.IsConstructor) {
+ code.Emit(OpCodes.Ldsfld, tc.getModuleField(currentClass));
+ } else
+ throw new ApplicationError
+ ("Static methods don't have 'this' pointer");
+ } else
+ code.Emit(OpCodes.Ldarg_0);
+ }
+
+
+ /** Generate code for array of trees
+ */
+ public Item gen(Tree[] trees) {
+ int n = trees.length;
+ if (n == 0)
+ return items.VoidItem();
+ boolean tmpLastStatement = lastStatement; lastStatement = false;
+ for (int i = 0; i < n-1; i++) {
+ drop(gen(trees[i], MSILType.VOID));
+ }
+ lastStatement = tmpLastStatement;
+ return gen(trees[n-1], type2MSILType(trees[n-1].type));
+ }
+
+
+ public Item gen(Tree tree) {
+ return gen(tree, type2MSILType(tree.type));
+ }
+
+
+ Item check(Item i) {
+ assert i != null;
+ return i;
+ }
+
+ int pos;
+ /** The main generator function. It keeps track of
+ * the current position in the tree for better error messages
+ */
+ Item gen(Tree tree, MSILType toType) {
+ int tmpPos = pos;
+ pos = tree.pos;
+ Item i = null;
+ //i = gen2(tree, toType);
+ try { i = gen2(tree, toType); }
+ catch (Throwable e) {
+ logErr(tree.pos, "gen(): Exception");
+ e.printStackTrace();
+ System.exit(1);
+ throw (Error) e;
+ }
+ pos = tmpPos;
+ return i;
+ }
+
+ /** Generate the code corresponding to a tree node
+ */
+ Item gen2(Tree tree, MSILType toType) {
+ Symbol sym = tree.hasSymbol() ? tree.symbol() : null;
+ switch (tree) {
+ case Empty:
+ return items.VoidItem();;
+
+ case Block(Tree[] stats):
+ return gen(stats);
+
+ case ValDef(_, Name name, Tree tpe, Tree rhs):
+ LocalBuilder local = code.DeclareLocal(tc.getType(sym));
+ local.SetLocalSymInfo(name.toString());
+ locals.put(sym, local);
+ if (rhs == Tree.Empty)
+ return items.VoidItem();
+ MSILType type = type2MSILType(tpe.type);
+ load(coerce(gen(rhs, type), type));
+ return check(store(items.LocalItem(type, local)));
+
+ case Ident(Name name):
+ //log("Ident: " + dumpSym(sym));
+ if (sym == defs.NULL)
+ return items.LiteralItem(NULL_TAG, null);
+ MSILType type = type2MSILType(sym.type());
+ if ( sym.isModule() ) // ???
+ return load(items.StaticItem
+ (type2MSILType(tree.type), tc.getModuleField(sym)));
+ else {
+ Integer slot = (Integer) params.get(sym);
+ if (slot != null) {
+ return items.ArgItem(type, slot.intValue());
+ } else {
+ LocalBuilder local = (LocalBuilder) locals.get(sym);
+ if (local != null)
+ return items.LocalItem(type, local);
+ }
+ return items.SelectItem(type,
+ items.SelfItem(tc.getType(currentClass)),
+ tc.getField(sym));
+ }
+// switch (sym.kind) {
+// case Kinds.VAL:
+// case Kinds.VAR:
+// Integer slot = (Integer) params.get(sym);
+// if (slot != null) {
+// return items.ArgItem(type, slot.intValue());
+// } else {
+// LocalBuilder local = (LocalBuilder) locals.get(sym);
+// if (local != null)
+// return items.LocalItem(type, local);
+// }
+// return items.SelectItem(type,
+// items.SelfItem(tc.getType(currentClass)),
+// tc.getField(sym));
+// case Kinds.MODULE:
+// return load(items.StaticItem(type2MSILType(tree.type),
+// tc.getModuleField(sym)));
+// default:
+// log("gen.Ident: Dunno what to do with: " + dumpSym(sym));
+// }
+// break;
+
+ case Select(Tree qualifier, Name selector):
+ if (sym == defs.TRUE())
+ return TRUE_ITEM;
+ if (sym == defs.FALSE())
+ return FALSE_ITEM;
+ if (sym.isModule()) {
+ //log("gen: Select from a module: " + sym);
+ if (sym.isJava())
+ logErr("gen.Select: Cannot treat Java class '" +
+ sym.fullNameString() + "' as value:\n\t" + dumpSym(sym));
+ else { // scala module
+ Type module = tc.getType(sym);
+ return items.StaticItem(MSILType.REF(module),
+ tc.getModuleField(sym));
+ }
+ }
+ if (!qualifier.hasSymbol()) {
+ return items.SelectItem(type2MSILType(tree.type),
+ gen(qualifier), tc.getField(sym));
+ }
+//??? if ((qualifier.symbol().flags & NOVAL) == NOVAL) {
+// log("gen.Select: owner NOVAL");
+// return items.StaticItem(type2MSILType(tree.type), tc.getField(sym));
+// }
+ // check if the tree corresponds to a static Java field
+ if (qualifier.symbol().isModule() && sym.isJava()) {
+ //log("gen.Select: static Java field");
+ return items.StaticItem(type2MSILType(tree.type), tc.getField(sym));
+ }
+ if ( qualifier.symbol().isModule() ) { // ?????
+ //log("gen: Select from a non-Java module: " + qualifier.symbol() + "::" + selector);
+ return items.SelectItem(type2MSILType(tree.type), gen(qualifier), tc.getField(sym));
+ }
+
+ if ( sym.isValue() || sym.isVariable() ) {
+ return items.SelectItem
+ (type2MSILType(sym.type()),
+ gen(qualifier, type2MSILType(qualifier.type)),
+ tc.getField(sym));
+ }
+
+ log("gen.Select: Dunno what to do with: " + dumpSym(sym));
+ break;
+
+// switch (sym.kind) {
+// case Kinds.VAL:
+// case Kinds.VAR:
+// //log("gen.Select: qualifier " + dumpSym(qualifier.symbol()) + ";;; " + dumpSym(sym));
+// //log("MSILType = " + type2MSILType(sym.type()));
+// return items.SelectItem(type2MSILType(sym.type()),
+// gen(qualifier, type2MSILType(qualifier.type)),
+// tc.getField(sym));
+// default:
+// log("gen.Select: Dunno what to do with: " + dumpSym(sym));
+// }
+// break;
+
+ case Apply(Tree fun, Tree[] args):
+ return check(genApply(fun, args, type2MSILType(tree.type)));
+
+ case Assign(Tree lhs, Tree rhs):
+ boolean tmpLastStatement = lastStatement; lastStatement = false;
+ MSILType type = type2MSILType(lhs.type);
+ Item var = gen(lhs, type);
+ load(gen(rhs, type));
+ lastStatement = tmpLastStatement;
+ return check(store(var));
+
+ case Typed(Literal(Object value), Tree tpe):
+ int kind = 0;// ?????
+ int newKind = kind;
+ switch (tpe.type()) {
+ case UnboxedType(int _kind):
+ newKind = _kind;
+ break;
+ default:
+ if (kind != TypeTags.STRING)
+ throw new ApplicationError("Bad type: " +
+ Debug.show(tpe.type()));
+ }
+ return items.LiteralItem(newKind, value);
+
+ case Typed(Tree expr, Tree tpe):
+ //log("gen.Typed: processing node: " + Debug.show(tree));
+ return gen(expr, type2MSILType(tpe.type));
+
+ case New(Template(Tree[] baseClasses, Tree[] body)):
+ assert body.length == 0 : "Template should not have a body!";
+ switch (baseClasses[0]) {
+ case Apply(Tree fun, Tree[] args):
+ ConstructorInfo ctor = (ConstructorInfo) tc.getMethod(fun.symbol());
+ loadArgs(args, ctor.GetParameters());
+ code.Emit(OpCodes.Newobj, ctor);
+ return items.StackItem(MSILType.REF(ctor.DeclaringType));
+ default:
+ throw new ApplicationError("Dunno what to do!");
+ }
+
+ case This(_):
+ return items.SelfItem(tc.getType(currentClass));
+
+ case Super(Tree tpe):
+ //logErr("Super not implemented yet");
+ return items.VoidItem();
+
+ case Literal(Object value):
+ return items.LiteralItem(0/*kind*/, value); // ?????????
+
+ case If(Tree cond, Tree thenp, Tree elsep):
+ //log("gen.If: cond = " + Debug.show(cond));
+ //log(" then = " + Debug.show(thenp));
+ //log(" else = " + Debug.show(elsep));
+ Item item = genIf(cond, thenp, elsep, toType);
+ return check(item);
+
+ default:
+ throw new ApplicationError("Dunno what to do: " + tree);
+ }
+ throw new ApplicationError
+ ("Dunno what to do with tree node: " + Debug.show(tree));
+
+ } //gen()
+
+
+ Item genIf(Tree condp, Tree thenp, Tree elsep, MSILType toType) {
+ Item iThen = null;
+ //log("genIf: coerce to type: " + toType);
+ //log(" thenTree = " + Debug.show(thenp));
+ //log(" elseTree = " + Debug.show(elsep));
+ if (elsep == Tree.Empty && toType == MSILType.VOID) {
+ boolean tmpLastStatement = lastStatement; lastStatement = false;
+ Item condi = gen(condp, type2MSILType(condp.type));
+ Item.CondItem cond = mkCond(condi); //gen(cond, type2MSILType(cond.type)));
+ lastStatement = tmpLastStatement;
+ if (cond.success == null) {
+ Chain success = new Chain(code.DefineLabel(), null);
+ branch(cond.test, success);
+ iThen = coerce(load(gen(thenp, toType)), toType);
+ resolve(success);
+ resolve(cond.failure);
+ } else {
+ Chain fail = (cond.failure != null) ?
+ cond.failure : new Chain(code.DefineLabel(), null);
+ branch(cond.test, fail);
+ resolve(cond.success);
+ iThen = coerce(load(gen(thenp, toType)), toType);
+ resolve(fail);
+ }
+ } else {
+ boolean tmpLastStatement = lastStatement; lastStatement = false;
+ Item condi = gen(condp, type2MSILType(condp.type));
+ Item.CondItem cond = mkCond(condi); //gen(cond, type2MSILType(cond.type)));
+ lastStatement = tmpLastStatement;
+
+ Chain fail = cond.failure != null ?
+ cond.failure : new Chain(code.DefineLabel(), null);
+ branch(cond.test, fail);
+ resolve(cond.success);
+ Item thenItem = gen(thenp, toType);
+ iThen = load(coerce(thenItem, toType));
+ Label exit = null;
+ if (lastStatement)
+ code.Emit(OpCodes.Ret);
+ else {
+ if (lastStatement)
+ code.Emit(OpCodes.Ret);
+ else {
+ exit = code.DefineLabel();
+ code.Emit(OpCodes.Br, exit);
+ }
+ }
+ resolve(fail);
+ Item iElse= null;
+ if (elsep == Tree.Empty) {
+ iElse = items.StaticItem(MSILType.REF(SCALA_UNIT), RUNTIME_UNIT_VAL);
+ iElse = coerce(iElse, toType);
+ } else
+ iElse = load(coerce(gen(elsep, toType), toType));
+ resolve(exit);
+ //log("\tgenIf: 'then' item = " + iThen + "; 'else' item" + iElse);
+ }
+ return iThen;
+ } //genIf
+
+
+ Item coerce(Item item, MSILType toType) {
+ if (toType == MSILType.VOID)
+ return drop(item);
+ switch (item) {
+ case VoidItem():
+ case SelfItem():
+ return item;
+ case StackItem():
+ if (item.type == MSILType.BOOL && toType == MSILType.I4 )
+ return items.StackItem(toType);
+ if (item.type != toType) {
+ emitConvert(toType);
+ return items.StackItem(toType);
+ }
+ return item;
+ case LiteralItem(int kind, Object value):
+ int newKind = kind;
+ switch (toType) {
+ case I1: newKind = TypeTags.BYTE; break;
+ case I2: newKind = TypeTags.SHORT; break;
+ case I4: newKind = TypeTags.INT; break;
+ case I8: newKind = TypeTags.LONG; break;
+ case R4: newKind = TypeTags.FLOAT; break;
+ case R8: newKind = TypeTags.DOUBLE; break;
+ }
+ if (newKind == kind)
+ return item;
+ else
+ return items.LiteralItem(newKind, value);
+
+ default:
+ return coerce(load(item), toType);
+ }
+ }
+
+ void emitConvert(MSILType toType) {
+ switch (toType) {
+ case I1: code.Emit(OpCodes.Conv_I1); break;
+ case I2: code.Emit(OpCodes.Conv_I2); break;
+ case I4: code.Emit(OpCodes.Conv_I4); break;
+ case I8: code.Emit(OpCodes.Conv_I8); break;
+ case R4: code.Emit(OpCodes.Conv_R4); break;
+ case R8: code.Emit(OpCodes.Conv_R8); break;
+ case REF(_): break;
+ case ARRAY(_): break;
+ default:
+ logErr("emitConvert: " + toType);
+ }
+ }
+
+
+ /*static final HashMap conv = new HashMap();
+ {
+ conv.put(Name.fromString("asDouble"), OpCodes.Conv_R8);
+ conv.put(Name.fromString("asFloat"), OpCodes.Conv_R4);
+ conv.put(Name.fromString("asLong"), OpCodes.Conv_I8);
+ conv.put(Name.fromString("asInt"), OpCodes.Conv_I4);
+ conv.put(Name.fromString("asShort"), OpCodes.Conv_I2);
+ conv.put(Name.fromString("asByte"), OpCodes.Conv_I1);
+ }
+ */
+
+ /** Generate the code for an Apply node
+ */
+ Item genApply(Tree fun, Tree[] args, MSILType resType) {
+ boolean tmpLastStatement = lastStatement; lastStatement = false;
+ Symbol sym = fun.symbol();
+ switch (fun) {
+ case Ident(_):
+ emitThis();
+ lastStatement = tmpLastStatement;
+ return check(invokeMethod(sym, args, resType));
+
+ case Select(Tree qualifier, Name selector):
+ if (sym == global.primitives.AS_UVALUE) {
+ return coerce(gen(qualifier, MSILType.VOID), MSILType.VOID);
+ }
+ if (sym == global.primitives.BOX_UVALUE) {
+ return items.StaticItem(MSILType.REF(SCALA_UNIT), RUNTIME_UNIT_VAL);
+ }
+ if (selector == Names.PLUS) {
+ //if (sym == defs.STRING_PLUS_ANY) {
+ assert args.length == 1;
+ if (type2MSILType(qualifier.type).
+ isType(TypeCreator.SYSTEM_STRING) ||
+ type2MSILType(args[0].type).
+ isType(TypeCreator.SYSTEM_STRING) )
+ {
+ //log("genApply: + -> " + dumpSym(sym));
+ Item i1 = load(gen(qualifier));
+ Item i2 = load(gen(args[0]));
+ code.Emit(OpCodes.Call, TypeCreator.CONCAT_OBJECT_OBJECT);
+ return items.StackItem(MSILType.REF(TypeCreator.SYSTEM_STRING));
+ }
+ }
+ switch (qualifier.type) {
+ case TypeRef(_, _, _):
+ //log("genApply: qualifier " + dumpSym(qualifier.symbol()) + "; selector = " + selector);
+ switch (qualifier) {
+ case Apply(Select(Tree qual, Name sel), Tree[] boxArgs):
+ if (sel == Name.fromString("box")) {
+ if (args.length == 0) {
+ if (selector == Names.MINUS) {
+ Item item = load(gen(boxArgs[0]));
+ code.Emit(OpCodes.Neg);
+ return check(item);
+ }
+ if (selector == Names.TILDE) {
+ Item item = load(gen(boxArgs[0]));
+ code.Emit(OpCodes.Not);
+ return check(item);
+ }
+ if (selector == Names.BANG) {
+ Item.CondItem cond = mkCond(gen(boxArgs[0]));
+ //return items.CondItem(cond.test, cond.failure, cond.success);
+ return items.CondItem(negate(cond.test),
+ cond.success, cond.failure);
+ }
+ } else if (args.length == 1) {
+ assert sym.name == selector;
+ return binaryOp(boxArgs[0], sym, args[0], resType);
+ }
+ }
+ break;
+ }
+ if (sym == defs.EQEQ) {
+ load(gen(qualifier));
+ load(gen(args[0]));
+ code.Emit(OpCodes.Callvirt, TypeCreator.OBJECT_EQUALS);
+ return items.StackItem(MSILType.BOOL);
+ }
+ if (sym == defs.BANGEQ) {
+ log("genApply: != : " + dumpSym(sym));
+ Item i1 = load(gen(qualifier));
+ Item i2 = load(gen(args[0]));
+ return items.CondItem(Test.Binary(Test.NE, i2.type),
+ null, null);
+ }
+ if (selector == Names.BANG) {
+ Item.CondItem cond = mkCond(gen(qualifier));
+ // swap the failure and success chains
+ return items.CondItem(cond.test, cond.failure, cond.success);
+ }
+ if (sym == defs.THROW) {
+ load(gen(qualifier));
+ code.Emit(OpCodes.Throw);
+ code.Emit(OpCode.Ldnull);
+ return items.StackItem(MSILType.NULL_REF);
+ }
+ if (sym == defs.STRING_PLUS_ANY || sym == STRING_CONCAT) {
+ load(gen(qualifier));
+ load(gen(args[0]));
+ code.Emit(OpCodes.Call, TypeCreator.CONCAT_OBJECT_OBJECT);
+ return items.StackItem(resType);
+ }
+ MethodBase method = tc.getMethod(sym);
+ if (!method.IsStatic || becomesStatic(sym)) {
+ load(gen(qualifier));
+ }
+ lastStatement = tmpLastStatement;
+ if (primitives.isPrimitive(sym)) {
+ log("genApply: TypeRef" + primitives.getPrimitiveIndex(sym));
+ log("\t" + dumpSym(sym));
+ }
+ return check(invokeMethod(sym, args, resType));
+
+ case UnboxedArrayType(_):
+ if (primitives.isPrimitive(sym)) {
+ log("genApply: " + primitives.getPrimitive(sym));
+ } else {
+ log("genApply: Array stuff is not primitive!");
+ }
+ // handle array.length
+ if (selector == Names.length) {
+ assert args.length == 0;
+ load(gen(qualifier));
+ code.Emit(OpCodes.Ldlen);
+ return items.StackItem(MSILType.I4);
+ }
+ // handle array indexing
+ else if (selector == Names.apply) {
+ assert args.length == 1;
+ Item i = load(gen(qualifier));
+ MSILType elemtype = ((MSILType.ARRAY) i.type).t;
+ load(gen(args[0]));
+ switch (elemtype) {
+ case I1: code.Emit(OpCodes.Ldelem_I1); break;
+ case I2: code.Emit(OpCodes.Ldelem_I2); break;
+ case I4: code.Emit(OpCodes.Ldelem_I4); break;
+ case I8: code.Emit(OpCodes.Ldelem_I8); break;
+ case R4: code.Emit(OpCodes.Ldelem_R4); break;
+ case R8: code.Emit(OpCodes.Ldelem_R8); break;
+ case BOOL: code.Emit(OpCodes.Ldelem_I1); break;
+ case REF(_): code.Emit(OpCodes.Ldelem_Ref); break;
+ case ARRAY(_): code.Emit(OpCodes.Ldelem_Ref); break;
+ default:
+ throw new ApplicationError();
+ }
+ return items.StackItem(elemtype);
+ }
+ // hande array update
+ else if (selector == Names.update) {
+ assert args.length == 2;
+ Item i = load(gen(qualifier));
+ MSILType elemtype = ((MSILType.ARRAY) i.type).t;
+ load(gen(args[0]));
+ load(gen(args[1]));
+ switch (elemtype) {
+ case I1: code.Emit(OpCodes.Stelem_I1); break;
+ case I2: code.Emit(OpCodes.Stelem_I2); break;
+ case I4: code.Emit(OpCodes.Stelem_I4); break;
+ case I8: code.Emit(OpCodes.Stelem_I8); break;
+ case R4: code.Emit(OpCodes.Stelem_R4); break;
+ case R8: code.Emit(OpCodes.Stelem_R8); break;
+ case BOOL: code.Emit(OpCodes.Stelem_I1); break;
+ case REF(_): code.Emit(OpCodes.Stelem_Ref); break;
+ case ARRAY(_): code.Emit(OpCodes.Stelem_Ref); break;
+ default:
+ throw new ApplicationError();
+ }
+ return items.VoidItem();
+ }
+ throw new ApplicationError("Applying selector '" + selector +
+ "' to qualifier " +
+ dumpSym(qualifier.symbol()));
+
+ default:
+ throw new ApplicationError();
+ }
+
+ case TypeApply(Select(Tree qualifier,_), Tree[] targs):
+// case TypeApply(Tree fun, Tree[] targs):
+ //final Symbol sym = fun.symbol();
+ final Type type = tc.getType(targs[0].symbol());
+ log("genApply.TypeApply: " + dumpSym(sym));
+ Item i = load(gen(qualifier));
+ if (sym == defs.IS) {
+ code.Emit(OpCodes.Isinst, type);
+ return mkCond(items.StackItem(MSILType.REF(type)));
+ }
+ if (sym == defs.AS) {
+ if (type != TypeCreator.SYSTEM_OBJECT) {
+ log("genApply: casting item: " + i + " to type: " + type);
+ code.Emit(OpCodes.Castclass, type);
+ }
+ return items.StackItem(MSILType.REF(type));
+ }
+ throw new ApplicationError
+ ("genApply: Dunno how to process TypeApply");
+
+ default: throw new ApplicationError
+ ("genApply: Unknown function node: " + fun);
+ }
+ } //genApply()
+
+
+ MSILType arithmCoercion(MSILType t1, MSILType t2) {
+ if (t1 == t2) return t1;
+ int i, j, n = MSILType.ARITHM_PRECISION.length;
+ for (i = 0; i < n; i++)
+ if (t1 == MSILType.ARITHM_PRECISION[i])
+ break;
+ for (j = 0; j < n; j++)
+ if (t2 == MSILType.ARITHM_PRECISION[j])
+ break;
+ if (i >= n || j >= n)
+ log("arithmCoercion: cannot find coercion for (" + t1 + ", " + t2 + ")");
+ else
+ return MSILType.ARITHM_PRECISION[Math.max(i, j)];
+ return null;
+ }
+
+
+ /** generate code for binary operators
+ */
+ public Item binaryOp(Tree left, Symbol opSym, Tree right, MSILType resType) {
+ Name op = opSym.name;
+ Item iLeft = null;
+// if (global.primitives.isPrimitive(opSym)) {
+// log("binaryOP: prmitive -> " + dumpSym(opSym));
+// log("\tleft = " + Debug.show(left));
+// log("\tright = " + Debug.show(right));
+// }
+ switch (left) {
+ case Apply(Select(Tree qualifier, Name selector), Tree[] args):
+ if (selector == Name.fromString("box")) {
+ log("binaryOp(): qualifier = " + dumpSym(qualifier.symbol()));
+ assert args.length == 1;
+ iLeft = gen(args[0]);
+ }
+ else iLeft = gen(left, resType);
+ break;
+ default:
+ iLeft = gen(left, resType);
+ }
+ OpCode opcode = (OpCode) opMap.get(op);
+ if (opcode != null) {
+ //log("binaryOp: arithm" + type2MSILType(left.type) + " " + op + " " + type2MSILType(right.type) + " -> " + resType);
+ load(coerce(iLeft, resType));
+ load(coerce(gen(right, resType), resType));
+ code.Emit(opcode);
+ return items.StackItem(resType);
+ }
+ Integer test = (Integer) cmpMap.get(op);
+ if (test != null) {
+ resType = arithmCoercion(type2MSILType(left.type),
+ type2MSILType(right.type));
+ //log("binaryOp: test: " + type2MSILType(left.type) + " " + op + " " + type2MSILType(right.type) + " -> " + resType);
+
+ load(coerce(iLeft, resType));
+ load(coerce(gen(right, resType), resType));
+ return items.CondItem(Test.Binary(test.intValue(), resType), null, null);
+ }
+ if (opSym == defs.BARBAR()) {
+ Item.CondItem lcond = mkCond(iLeft), rcond = null;
+ Chain success = lcond.success, failure = lcond.failure;
+ switch (lcond.test) {
+ case True:
+ return lcond;
+ case False:
+ return mkCond(gen(right, MSILType.BOOL));
+ case And(Test t):
+ success = (success != null) ?
+ success : new Chain(code.DefineLabel(), null);
+ branch(negate(lcond.test), success);
+ resolve(failure);
+ failure = null;
+ break;
+ default:
+ success = (success != null) ?
+ success : new Chain(code.DefineLabel(), null);
+ branch(negate(lcond.test), success);
+ }
+ rcond = mkCond((gen(right, MSILType.BOOL)));
+ rcond = items.CondItem(Test.Or(rcond.test),
+ merge(success, rcond.success),
+ merge(failure, rcond.failure));
+ return rcond;
+ }
+ if (opSym == defs.AMPAMP()) {
+ Item.CondItem lcond = mkCond(iLeft), rcond = null;
+ Chain success = lcond.success, failure = lcond.failure;
+ switch (lcond.test) {
+ case False:
+ return lcond;
+ case True:
+ return mkCond(gen(right, MSILType.BOOL));
+ case Or(Test t):
+ failure = (failure != null) ?
+ failure : new Chain(code.DefineLabel(), null);
+ branch(lcond.test, failure);
+ resolve(success);
+ success = null;
+ break;
+ default:
+ failure = (failure != null) ?
+ failure : new Chain(code.DefineLabel(), null);
+ branch(lcond.test, failure);
+ }
+ rcond = mkCond(gen(right, MSILType.BOOL));
+ rcond = items.CondItem(Test.And(rcond.test),
+ merge(success, rcond.success),
+ merge(failure, rcond.failure));
+ return rcond;
+ }
+ throw new ApplicationError("Unknown binary op: " + op);
+ } // binaryOp()
+
+
+ void loadArgs(Tree[] args, ParameterInfo[] params) {
+ boolean tmpLastStatement = lastStatement;
+ lastStatement = false;
+ for (int i = 0; i < args.length; i++) {
+ MSILType toType = type2MSILType(params[i].ParameterType); //type2MSILType(args[i].type);
+ load(coerce(gen(args[i], toType), toType));
+ }
+ lastStatement = tmpLastStatement;
+ }
+
+ private boolean becomesStatic(Symbol sym) {
+ MethodBase method = tc.getMethod(sym);
+ return method.IsStatic && method.DeclaringType == TypeCreator.MONITOR;
+ }
+
+ /** Generate code for method invocation
+ */
+ Item invokeMethod(Symbol fun, Tree[] args, MSILType resType) {
+ //log("invokeMethod: " + dumpSym(fun));
+ MethodBase method = tc.getMethod(fun);
+ assert method != null : "Coudn't resolve method: " + dumpSym(fun);
+ Item res = null;
+ if (method.IsStatic) {
+ ParameterInfo[] params = method.GetParameters();
+ if (becomesStatic(fun)) {
+ assert params.length == args.length + 1;
+ ParameterInfo[] newParams = new ParameterInfo[params.length - 1];
+ for (int i = 0; i < newParams.length; i++)
+ newParams[i] = params[i + 1];
+ params = newParams;
+ }
+ loadArgs(args, params);
+ code.Emit(OpCodes.Call, (MethodInfo)method);
+ res = returnsVoid(method) ? items.VoidItem() :
+ items.StackItem(resType);
+ } else if (method.IsConstructor) {
+ // used only for calls to super constructor
+ emitThis();
+ loadArgs(args, method.GetParameters());
+ code.Emit(OpCodes.Call, (ConstructorInfo)method);
+ res = items.VoidItem();
+ } else {
+ loadArgs(args, method.GetParameters());
+ if (enableTailCalls && lastStatement && method == currentMethod)
+ code.Emit(OpCodes.Tailcall);
+ code.Emit(OpCodes.Callvirt, (MethodInfo)method);
+ res = returnsVoid(method) ? items.VoidItem() : items.StackItem(resType);
+ }
+ return check(res);
+ }
+
+ public MSILType type2MSILType(scalac.symtab.Type type) {
+ switch (type) {
+ case UnboxedType(int kind):
+ return MSILType.fromKind(kind);
+ case TypeRef(_, Symbol s, _):
+ //log("TypeRef: " + dumpSym(s));
+ return MSILType.REF(tc.getType(s));
+ case UnboxedArrayType(scalac.symtab.Type t):
+ return MSILType.ARRAY(type2MSILType(t));
+ default:
+ return MSILType.NULL_REF;
+ //logErr("type2MSILType: " + Debug.show(type));
+ //throw new ApplicationError();
+ }
+ }
+
+ public MSILType type2MSILType(Type type) {
+ if (type == TypeCreator.BYTE) return MSILType.I1;
+ if (type == TypeCreator.SHORT) return MSILType.I2;
+ if (type == TypeCreator.INT) return MSILType.I4;
+ if (type == TypeCreator.LONG) return MSILType.I8;
+ if (type == TypeCreator.FLOAT) return MSILType.R4;
+ if (type == TypeCreator.DOUBLE) return MSILType.R8;
+ //log("type2MSILType: Dont know how to convert " + type);
+ return MSILType.REF(type);
+ }
+
+// static final Type SCALA_RUNTIME;
+// static final FieldInfo RUNTIME_UNIT_VAL;
+// static final MethodInfo BOX_UNIT = SCALA_RUNTIME.GetMethod("box", Type.EmptyTypes);
+// static final MethodInfo BOX_BYTE = SCALA_RUNTIME.GetMethod("box", new Type[]{BYTE});
+// static final MethodInfo BOX_INT = SCALA_RUNTIME.GetMethod("box", new Type[]{INT});
+// static final MethodInfo BOX_SHORT = SCALA_RUNTIME.GetMethod("box", new Type[]{SHORT});
+// static final MethodInfo BOX_CHAR = SCALA_RUNTIME.GetMethod("box", new Type[]{CHAR});
+// static final MethodInfo BOX_LONG = SCALA_RUNTIME.GetMethod("box", new Type[]{LONG});
+// static final MethodInfo BOX_FLOAT = SCALA_RUNTIME.GetMethod("box", new Type[]{FLOAT});
+// static final MethodInfo BOX_DOUBLE = SCALA_RUNTIME.GetMethod("box", new Type[]{DOUBLE});
+// static final MethodInfo BOX_BOOLEAN = SCALA_RUNTIME.GetMethod("box", new Type[]{BOOLEAN});
+
+// public void box(Item that) {
+// MethodInfo box = null;
+// switch (that.type) {
+// case I1: box = BOX_BYTE; break;
+// case I2: box = BOX_SHORT; break;
+// case I4: box = BOX_INT; break;
+// case I8: box = BOX_LONG; break;
+// case R4: box = BOX_FLOAT; break;
+// case R8: box = BOX_DOUBLE; break;
+// case BOOL: box = BOX_BOOLEAN; break;
+// case CHAR: box = BOX_CHAR; break;
+// case VOID:
+// log("box: boxing Unit");
+// drop(that);
+// box = BOX_UNIT;
+// break;
+// case REF(_):
+// case ARRAY(_):
+// return;
+// default:
+// logErr("box(Item) -> Dunno how to box item: " + that);
+// }
+// code.Emit(OpCodes.Call, box);
+// }
+
+
+ /** load an item onto the stack
+ */
+ public Item load(Item that) {
+ switch (that) {
+ case VoidItem():
+ return that;
+
+ case StackItem():
+ return (StackItem) that;
+
+ case LiteralItem(int kind, Object value):
+ return loadLiteral(kind, value);
+
+ case SelfItem():
+ emitThis();
+ return items.StackItem(that.type);
+
+ case ArgItem(int slot):
+ if (slot > 255)
+ code.Emit(OpCodes.Ldarg, slot);
+ else if(slot > 3)
+ code.Emit(OpCodes.Ldarg_S, slot);
+ else switch (slot) {
+ case 0: code.Emit(OpCodes.Ldarg_0); break;
+ case 1: code.Emit(OpCodes.Ldarg_1); break;
+ case 2: code.Emit(OpCodes.Ldarg_2); break;
+ case 3: code.Emit(OpCodes.Ldarg_3); break;
+ }
+ return items.StackItem(that.type);
+
+ case LocalItem(LocalBuilder local):
+ code.Emit(OpCodes.Ldloc, local);
+ return items.StackItem(that.type);
+
+ case StaticItem(FieldInfo field):
+ code.Emit(OpCodes.Ldsfld, field);
+ return items.StackItem(that.type);
+
+ case SelectItem(Item qual, FieldInfo field):
+ Item i = load(qual);
+// switch (i.type) {
+// case REF(Type t):
+// if (t.IsInterface) {
+// Symbol s = tc.getSymbol(t);
+// s = (Symbol) global.PHASE.ADDINTERFACES.interfaceToClass.get(s);
+// Type classType = tc.getType(s);
+// log("load.SelectItem: warning: inserting class cast from " + t + " to " + classType);
+// code.Emit(OpCodes.Castclass, classType);
+// }
+// break;
+// default:
+// }
+ code.Emit(OpCodes.Ldfld, field);
+ //log("load(Item): SelectItem; type = " + that.type);
+ return items.StackItem(that.type);
+
+ case CondItem(Test test, Chain success, Chain failure):
+ load(test);
+ switch (test) {
+ case Or(_):
+ case And(_):
+ //log("Loading " + that);
+ Label exit = null;
+ if (lastStatement)
+ code.Emit(OpCodes.Ret);
+ else {
+ exit = code.DefineLabel();
+ code.Emit(OpCodes.Br, exit);
+ }
+ if (failure != null) {
+ resolve(failure);
+ load(FALSE_ITEM);
+ if (success != null) {
+ if (lastStatement)
+ code.Emit(OpCodes.Ret);
+ else
+ code.Emit(OpCodes.Br, exit);
+ }
+ }
+ if (success != null) {
+ resolve(success);
+ load(TRUE_ITEM);
+ }
+ resolve(exit);
+ //log("Loading " + that);
+ break;
+ }
+ return items.StackItem(MSILType.BOOL);
+
+ default:
+ throw new ApplicationError("load item: " + that);
+ }
+ }
+
+
+ /**
+ */
+ void load(Test test) {
+ switch (test) {
+ case False:
+ code.Emit(OpCodes.Ldc_I4_0);
+ break;
+ case True:
+ code.Emit(OpCodes.Ldc_I4_1);
+ break;
+ case Bool(boolean value):
+ if (value) negate_load();
+ break;
+ case Binary(int opcode, MSILType type):
+ code.Emit(load(opcode));
+ if (negate_load(opcode)) negate_load();
+ break;
+ case And(Test t):
+ load(t);
+ break;
+ case Or(Test t):
+ load(t);
+ break;
+ default:
+ throw new ApplicationError(test.getClass().getName());
+ }
+ }
+
+ static final int NULL_TAG = TypeTags.LastUnboxedTag + 42;
+
+ /**
+ * Generate the code for a literal
+ */
+ protected Item.StackItem loadLiteral(int kind, Object obj) {
+ switch (kind) {
+ case TypeTags.STRING:
+ code.Emit(OpCodes.Ldstr, obj.toString());
+ break;
+ case TypeTags.BYTE:
+ case TypeTags.SHORT:
+ case TypeTags.INT:
+ case TypeTags.CHAR:
+ int i = ((Number)obj).intValue();
+ switch (i) {
+ case -1:code.Emit(OpCodes.Ldc_I4_M1); break;
+ case 0: code.Emit(OpCodes.Ldc_I4_0); break;
+ case 1: code.Emit(OpCodes.Ldc_I4_1); break;
+ case 2: code.Emit(OpCodes.Ldc_I4_2); break;
+ case 3: code.Emit(OpCodes.Ldc_I4_3); break;
+ case 4: code.Emit(OpCodes.Ldc_I4_4); break;
+ case 5: code.Emit(OpCodes.Ldc_I4_5); break;
+ case 6: code.Emit(OpCodes.Ldc_I4_6); break;
+ case 7: code.Emit(OpCodes.Ldc_I4_7); break;
+ case 8: code.Emit(OpCodes.Ldc_I4_8); break;
+ default:
+ if (i >= -128 && i <= 127)
+ code.Emit(OpCodes.Ldc_I4_S, i);
+ else
+ code.Emit(OpCodes.Ldc_I4, i);
+ }
+ break;
+ case TypeTags.LONG:
+ code.Emit(OpCodes.Ldc_I8, ((Number)obj).longValue());
+ break;
+ case TypeTags.FLOAT:
+ code.Emit(OpCodes.Ldc_R4, ((Number)obj).floatValue());
+ break;
+ case TypeTags.DOUBLE:
+ code.Emit(OpCodes.Ldc_R8, ((Number)obj).doubleValue());
+ break;
+ case TypeTags.BOOLEAN:
+ if (((Boolean)obj).booleanValue())
+ code.Emit(OpCodes.Ldc_I4_1);
+ else
+ code.Emit(OpCodes.Ldc_I4_0);
+ break;
+ case TypeTags.UNIT:
+ code.Emit(OpCodes.Ldsfld, RUNTIME_UNIT_VAL);
+ break;
+ case NULL_TAG:
+ code.Emit(OpCodes.Ldnull);
+ break;
+ default:
+ throw new ApplicationError("loadLiteral(): Unknown literal kind: "+
+ kind);
+ }
+ return items.StackItem(MSILType.fromKind(kind));
+ } // genLiteral()
+
+
+ /**
+ */
+ public Item store(Item that) {
+ switch (that) {
+ case ArgItem(int slot):
+ code.Emit(OpCodes.Starg, slot);
+ break;
+
+ case LocalItem(LocalBuilder local):
+ code.Emit(OpCodes.Stloc, local);
+ break;
+
+ case StaticItem(FieldInfo field):
+ code.Emit(OpCodes.Stsfld, field);
+ break;
+
+ case SelectItem(Item qual, FieldInfo field):
+ load(qual);
+ code.Emit(OpCodes.Stfld, field);
+ break;
+
+ default:
+ throw new ApplicationError("Cannot store item: " + that);
+ }
+ return items.VoidItem();
+ }
+
+ /**
+ */
+ Item drop(Item that) {
+ switch (that) {
+ case VoidItem():
+ case SelfItem():
+ case LiteralItem(_, _):
+ case ArgItem(_):
+ case LocalItem(_):
+ case StaticItem(_):
+ break;
+ case StackItem():
+ code.Emit(OpCodes.Pop);
+ break;
+ case SelectItem(Item qual, _):
+ drop(qual);
+ break;
+ case CondItem(Test test, _, _):
+ switch (test) {
+ case False:
+ case True:
+ break;
+ case Bool(_):
+ code.Emit(OpCodes.Pop);
+ break;
+ case And(_):
+ case Or(_):
+ drop(load(that));
+ break;
+ case Binary(_, _):
+ code.Emit(OpCodes.Pop);
+ code.Emit(OpCodes.Pop);
+ break;
+ default :
+ throw new ApplicationError(that.getClass().getName());
+ }
+ break;
+ default:
+ drop(load(that));
+ }
+ return Item.VoidItem();
+ }
+
+ public Item.CondItem mkCond(Item that) {
+ switch (that) {
+ case CondItem(_, _, _): return (Item.CondItem) that;
+ default:
+ load(that);
+ return items.CondItem(Test.Bool(false), null, null);
+ }
+ }
+
+ void negate_load() {
+ code.Emit(OpCodes.Ldc_I4_1);
+ code.Emit(OpCodes.Xor);
+ }
+
+
+ public Test negate(Test that) {
+ switch (that) {
+
+ case False:
+ return Test.True;
+
+ case True:
+ return Test.False;
+
+ case Bool(boolean value):
+ return Test.Bool(!value);
+
+ case And(Test test):
+ return Test.Or(negate(test));
+
+ case Or(Test test):
+ return Test.And(negate(test));
+
+ case Binary(int opcode, MSILType type):
+ return Test.Binary(negate(opcode), type);
+
+ default:
+ throw new ApplicationError(that.getClass().getName());
+ }
+ }
+
+
+ Label branch(Test test, Chain chain) {
+ assert chain != null;
+ Label label = chain.label;
+ switch (test) {
+ case False:
+ code.Emit(OpCodes.Br, label);
+ return label;
+ case True:
+ return null;
+ case Bool(boolean value):
+ code.Emit(value ? OpCodes.Brtrue : OpCodes.Brfalse, label);
+ return label;
+ case And(Test t):
+ return branch(t, chain);
+ case Or(Test t):
+ return branch(t, chain);
+ case Binary(int opcode, MSILType type):
+ code.Emit(branch(negate(opcode)), label);
+ return label;
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+
+ static Chain merge(Chain c1, Chain c2) {
+ if (c1 == null) return c2;
+ if (c2 == null) return c1;
+ Chain c = c1;
+ for(; c.next != null; c = c.next) ;
+ c.next = c2;
+ return c1;
+ }
+
+ void resolve(Chain c) {
+ for (; c != null; c = c.next)
+ code.MarkLabel(c.label);
+ }
+
+ void resolve(Label l) {
+ if (l != null)
+ code.MarkLabel(l);
+ }
+
+ public static boolean negate_load(int opcode) {
+ switch (opcode) {
+ case Test.LT_IS: return false;
+ case Test.LE_IS: return true;
+ case Test.GT_IS: return false;
+ case Test.GE_IS: return true;
+ case Test.LT_IU: return false;
+ case Test.LE_IU: return true;
+ case Test.GT_IU: return false;
+ case Test.GE_IU: return true;
+ case Test.LT_RO: return false;
+ case Test.LE_RO: return true;
+ case Test.GT_RO: return false;
+ case Test.GE_RO: return true;
+ case Test.LT_RU: return false;
+ case Test.LE_RU: return true;
+ case Test.GT_RU: return false;
+ case Test.GE_RU: return true;
+ case Test.EQ : return false;
+ case Test.NE : return true;
+ default : throw new ApplicationError("" + opcode);
+ }
+ }
+
+ public static OpCode load(int opcode) {
+ switch (opcode) {
+ case Test.LT_IS: return OpCodes.Clt;
+ case Test.LE_IS: return OpCodes.Cgt; // negate
+ case Test.GT_IS: return OpCodes.Cgt;
+ case Test.GE_IS: return OpCodes.Clt; // negate
+ case Test.LT_IU: return OpCodes.Clt_Un;
+ case Test.LE_IU: return OpCodes.Cgt_Un; // negate
+ case Test.GT_IU: return OpCodes.Cgt_Un;
+ case Test.GE_IU: return OpCodes.Clt_Un; // negate
+ case Test.LT_RO: return OpCodes.Clt;
+ case Test.LE_RO: return OpCodes.Cgt_Un; // negate
+ case Test.GT_RO: return OpCodes.Cgt;
+ case Test.GE_RO: return OpCodes.Clt_Un; // negate
+ case Test.LT_RU: return OpCodes.Clt_Un;
+ case Test.LE_RU: return OpCodes.Cgt; // negate
+ case Test.GT_RU: return OpCodes.Cgt_Un;
+ case Test.GE_RU: return OpCodes.Clt; // negate
+ case Test.EQ : return OpCodes.Ceq;
+ case Test.NE : return OpCodes.Ceq; // negate
+ default : throw new ApplicationError("" + opcode);
+ }
+ }
+
+ public static int negate(int opcode) {
+ switch (opcode) {
+ case Test.LT_IS: return Test.GE_IS;
+ case Test.LE_IS: return Test.GT_IS;
+ case Test.GT_IS: return Test.LE_IS;
+ case Test.GE_IS: return Test.LT_IS;
+ case Test.LT_IU: return Test.GE_IU;
+ case Test.LE_IU: return Test.GT_IU;
+ case Test.GT_IU: return Test.LE_IU;
+ case Test.GE_IU: return Test.LT_IU;
+ case Test.LT_RO: return Test.GE_RU;
+ case Test.LE_RO: return Test.GT_RU;
+ case Test.GT_RO: return Test.LE_RU;
+ case Test.GE_RO: return Test.LT_RU;
+ case Test.LT_RU: return Test.GE_RO;
+ case Test.LE_RU: return Test.GT_RO;
+ case Test.GT_RU: return Test.LE_RO;
+ case Test.GE_RU: return Test.LT_RO;
+ case Test.EQ : return Test.NE;
+ case Test.NE : return Test.EQ;
+ default : throw new ApplicationError("" + opcode);
+ }
+ }
+
+ public static OpCode branch(int opcode) {
+ switch (opcode) {
+ case Test.LT_IS:
+ case Test.LT_RO: return OpCodes.Blt;
+ case Test.LE_IS:
+ case Test.LE_RO: return OpCodes.Ble;
+ case Test.GT_IS:
+ case Test.GT_RO: return OpCodes.Bgt;
+ case Test.GE_IS:
+ case Test.GE_RO: return OpCodes.Bge;
+ case Test.LT_IU:
+ case Test.LT_RU: return OpCodes.Blt_Un;
+ case Test.LE_IU:
+ case Test.LE_RU: return OpCodes.Ble_Un;
+ case Test.GT_IU:
+ case Test.GT_RU: return OpCodes.Bgt_Un;
+ case Test.GE_IU:
+ case Test.GE_RU: return OpCodes.Bge_Un;
+ case Test.EQ : return OpCodes.Beq;
+ case Test.NE : return OpCodes.Bne_Un;
+ default : throw new ApplicationError("" + opcode);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ */
+ void log(String message) {
+ System.err.println(message);
+ //log(1, message);
+ }
+
+ void logErr(int pos, String message) {
+ log(currUnit.source.getMessage(pos, message));
+ }
+
+ void logErr(String message) {
+ if (code != null) {
+ MethodBase method = code.owner;
+ System.err.print("Processing " + method.DeclaringType.FullName +
+ "::" + method.Name + " -> ");
+ }
+ System.err.println(message);
+ throw new ApplicationError();
+ //log(1, message);
+ }
+
+ private static final int DEBUG_LEVEL = 2;
+
+ private void log(int level, String message) {
+ if (level < DEBUG_LEVEL)
+ global.log(message);
+ }
+
+
+ void emitComment(String str) {
+ code.Emit(OpCodes.Ldstr, str);
+ code.Emit(OpCodes.Pop);
+ }
+
+} // class GenMSIL
+
+
+public class MSILType {
+ public case BOOL;
+ public case CHAR;
+ public case I1;
+ public case I2;
+ public case U2;
+ public case I4;
+ public case I8;
+ public case R4;
+ public case R8;
+ public case REF(Type t);
+ public case ARRAY(MSILType t);
+ public case VOID;
+
+ public static final MSILType NULL_REF = REF(null);
+ public static final MSILType [] ARITHM_PRECISION =
+ new MSILType[] {I1, I2, I4, I8, R4, R8};
+
+ public static MSILType fromKind(int kind) {
+ switch (kind) {
+ case TypeTags.BYTE: return I1;
+ case TypeTags.CHAR: return CHAR;
+ case TypeTags.SHORT: return I2;
+ case TypeTags.INT: return I4;
+ case TypeTags.LONG: return I8;
+ case TypeTags.FLOAT: return R4;
+ case TypeTags.DOUBLE: return R8;
+ case TypeTags.BOOLEAN: return BOOL;
+ case TypeTags.UNIT: return VOID;
+ case GenMSIL.NULL_TAG: return NULL_REF;
+ case TypeTags.STRING: return REF(TypeCreator.SYSTEM_STRING);
+ default:
+ throw new ApplicationError("Unknown kind: " + kind);
+
+ }
+ }
+
+
+ public boolean isType(Type type) {
+ switch (this) {
+ case REF(Type t): return (type == t);
+ default:
+ return false;
+ }
+ }
+
+ public String toString() {
+ switch (this) {
+ case I1: return "I1";
+ case I2: return "I2";
+ case U2: return "U2";
+ case I4: return "I4";
+ case I8: return "I8";
+ case R4: return "R4";
+ case R8: return "R8";
+ case BOOL: return "BOOL";
+ case CHAR: return "CHAR";
+ case REF(Type t): return "REF(" + t + ")";
+ case ARRAY(MSILType t): return "ARRAY(" + t + ")";
+ case VOID: return "VOID";
+ default: return getClass().getName();
+ }
+ }
+}
+
+
+/** class representing the items
+ */
+class Item {
+ public MSILType type;
+
+ public case VoidItem();
+ public case StackItem();
+ public case SelfItem();
+ public case LiteralItem(int kind, Object value);
+ public case ArgItem(int slot);
+ public case LocalItem(LocalBuilder local);
+ public case StaticItem(FieldInfo field);
+ public case SelectItem(Item qual, FieldInfo field);
+ public case CondItem(Test test, Chain success, Chain failure);
+
+ public String toString() {
+ switch (this) {
+ case VoidItem(): return "VoidItem";
+ case StackItem(): return "StackItem : " + type ;
+ case SelfItem(): return "";
+ case LiteralItem(_, Object value): return "LiteralItem(" + value + ")";;
+ case ArgItem( int slot): return "ArgItem(" + slot + ")";
+ case LocalItem( LocalBuilder local): return "LocalItem(" + local + ")";
+ case StaticItem( FieldInfo field): return "StaticItem(" + field + ")";
+ case SelectItem(_, FieldInfo field): return "SelectItem(" + field + ")";
+ case CondItem(Test test, Chain success, Chain failure):
+ return "CondItem(" + test + ", " + success + ", " + failure + ")";
+ }
+ return "??Item??";
+ }
+}
+
+
+/** class implementing a chain (list) of labels
+ */
+class Chain {
+ Label label;
+ Chain next;
+ Chain(Label l, Chain n) { label = l; next = n; }
+}
+
+
+class ItemFactory {
+ GenMSIL coder;
+ private static final Item.VoidItem VOID = Item.VoidItem();
+ static { VOID.type = MSILType.VOID; }
+
+ public ItemFactory(GenMSIL _coder) {
+ coder = _coder;
+ }
+ public Item.VoidItem VoidItem() {
+ return VOID;
+ }
+ public Item.StackItem StackItem(MSILType type) {
+ Item.StackItem item = Item.StackItem();
+ item.type = type;
+ return item;
+ }
+ public Item.SelfItem SelfItem(Type t) {
+ Item.SelfItem item = Item.SelfItem();
+ item.type = MSILType.REF(t);
+ return item;
+ }
+ public Item.LiteralItem LiteralItem(int kind, Object value) {
+ Item.LiteralItem item = Item.LiteralItem(kind, value);
+ item.type = MSILType.fromKind(kind);
+ return item;
+ }
+ public Item.ArgItem ArgItem(MSILType type, int slot) {
+ Item.ArgItem item = Item.ArgItem(slot);
+ item.type = type;
+ return item;
+ }
+ public Item.LocalItem LocalItem(MSILType type, LocalBuilder local) {
+ Item.LocalItem item = Item.LocalItem(local);
+ item.type = type;
+ return item;
+ }
+ public Item.StaticItem StaticItem(MSILType type, FieldInfo field) {
+ assert field.IsStatic;
+ Item.StaticItem item = Item.StaticItem(field);
+ item.type = type;
+ return item;
+ }
+ public Item.SelectItem SelectItem(MSILType type, Item qualifier, FieldInfo field) {
+ assert !field.IsStatic;
+ Item.SelectItem item = Item.SelectItem(coder.load(qualifier), field);
+ item.type = type;
+ return item;
+ }
+ public Item.CondItem CondItem(Test test, Chain success, Chain failure) {
+ Item.CondItem item = Item.CondItem(test, success, failure);
+ item.type = MSILType.BOOL;
+ return item;
+ }
+}
+
+/** class representing the possible tests in conditional item
+ */
+public class Test {
+
+ public case False;
+ public case True;
+ public case Bool(boolean value);
+ public case Or(Test test);
+ public case And(Test test);
+ public case Binary(int opcode, MSILType type);
+
+ public static final int LT_IS = 0x00;
+ public static final int LE_IS = 0x01;
+ public static final int GT_IS = 0x02;
+ public static final int GE_IS = 0x03;
+
+ public static final int LT_IU = 0x04;
+ public static final int LE_IU = 0x05;
+ public static final int GT_IU = 0x06;
+ public static final int GE_IU = 0x07;
+
+ public static final int LT_RO = 0x08;
+ public static final int LE_RO = 0x09;
+ public static final int GT_RO = 0x0A;
+ public static final int GE_RO = 0x0B;
+
+ public static final int LT_RU = 0x0C;
+ public static final int LE_RU = 0x0D;
+ public static final int GT_RU = 0x0E;
+ public static final int GE_RU = 0x0F;
+
+ public static final int EQ = 0x10;
+ public static final int NE = 0x11;
+
+ public static String toString(int opcode) {
+ switch (opcode) {
+ case LT_IS: return "GE_IS";
+ case LE_IS: return "GT_IS";
+ case GT_IS: return "LE_IS";
+ case GE_IS: return "LT_IS";
+ case LT_IU: return "GE_IU";
+ case LE_IU: return "GT_IU";
+ case GT_IU: return "LE_IU";
+ case GE_IU: return "LT_IU";
+ case LT_RO: return "GE_RU";
+ case LE_RO: return "GT_RU";
+ case GT_RO: return "LE_RU";
+ case GE_RO: return "LT_RU";
+ case LT_RU: return "GE_RO";
+ case LE_RU: return "GT_RO";
+ case GT_RU: return "LE_RO";
+ case GE_RU: return "LT_RO";
+ case EQ : return "NE";
+ case NE : return "EQ";
+ default : throw new InternalError("" + opcode);
+ }
+ }
+
+ public String toString() {
+ switch (this) {
+
+ case False:
+ return "False";
+ case True:
+ return "True";
+ case Bool(boolean value):
+ return "Test(" + value + ")";
+ case Or(Test test):
+ return "Or(" + test + ")";
+ case And(Test test):
+ return "And(" + test + ")";
+ case Binary(int opcode, MSILType type):
+ return "Binary(" + toString(opcode) +"," + type + ")";
+
+ default:
+ throw new ApplicationError(getClass().getName());
+ }
+ }
+} // class Test
diff --git a/sources/scalac/backend/msil/GenMSILPhase.java b/sources/scalac/backend/msil/GenMSILPhase.java
new file mode 100644
index 0000000000..9239fdf625
--- /dev/null
+++ b/sources/scalac/backend/msil/GenMSILPhase.java
@@ -0,0 +1,45 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+\* */
+
+// $Id$
+
+package scalac.backend.msil;
+
+import scalac.Global;
+import scalac.Unit;
+import scalac.Phase;
+import scalac.PhaseDescriptor;
+
+import java.util.HashMap;
+
+public class GenMSILPhase extends PhaseDescriptor {
+
+ final HashMap assemblies = new HashMap();
+
+ final HashMap types2symbols = new HashMap();
+ final HashMap symbols2types = new HashMap();
+ final HashMap symbols2fields = new HashMap();
+ final HashMap symbols2methods = new HashMap();
+ final HashMap symbols2moduleFields = new HashMap();
+
+ public String name () {
+ return "genmsil";
+ }
+
+ public String description () {
+ return "generate MSIL code";
+ }
+
+ public String taskDescription() {
+ return "generated MSIL code";
+ }
+
+ public Phase createPhase(Global global) {
+ return new GenMSIL(global, this);
+ }
+
+}
diff --git a/sources/scalac/backend/msil/TypeCreator.java b/sources/scalac/backend/msil/TypeCreator.java
new file mode 100644
index 0000000000..aff49c99fc
--- /dev/null
+++ b/sources/scalac/backend/msil/TypeCreator.java
@@ -0,0 +1,743 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.backend.msil;
+
+import scalac.Global;
+import scalac.Unit;
+import scalac.ApplicationError;
+import scalac.ast.Tree;
+import scalac.util.Debug;
+import scalac.util.Name;
+import scalac.util.Names;
+import scalac.util.Position;
+import scalac.symtab.Kinds;
+import scalac.symtab.TypeTags;
+import scalac.symtab.Symbol;
+import scalac.symtab.Scope;
+import scalac.symtab.Modifiers;
+import scalac.symtab.Definitions;
+
+import Tree.*;
+
+import ch.epfl.lamp.compiler.msil.*;
+import ch.epfl.lamp.compiler.msil.emit.*;
+
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public final class TypeCreator
+ extends scalac.ast.Traverser
+{
+
+ final private GenMSIL gen;
+ final private Global global;
+ final private Definitions defs;
+
+ final private ArrayList typeBuilders = new ArrayList();
+
+ final private Map types2symbols;
+ final private Map symbols2types;
+ final private Map symbols2fields;
+ final private Map symbols2methods;
+ final private Map symbols2moduleFields;
+
+ Unit unit;
+
+ int pos = Position.NOPOS;
+
+ static final String MODULE_S = "$MODULE";
+
+ static final Type BYTE = Type.GetType("System.SByte");
+ static final Type CHAR = Type.GetType("System.Char");
+ static final Type SHORT = Type.GetType("System.Int16");
+ static final Type INT = Type.GetType("System.Int32");
+ static final Type LONG = Type.GetType("System.Int64");
+ static final Type FLOAT = Type.GetType("System.Single");
+ static final Type DOUBLE = Type.GetType("System.Double");
+ static final Type BOOLEAN = Type.GetType("System.Boolean");
+ static final Type VOID = Type.GetType("System.Void");
+
+ static final Type SYSTEM_OBJECT = Type.GetType("System.Object");
+ static final Type SYSTEM_STRING = Type.GetType("System.String");
+ static final Type MONITOR = Type.GetType("System.Threading.Monitor");
+
+ static final MethodInfo CONCAT_OBJECT =
+ SYSTEM_STRING.GetMethod("Concat", new Type[] {SYSTEM_OBJECT});
+ static final MethodInfo CONCAT_STRING_STRING =
+ SYSTEM_STRING.GetMethod("Concat", new Type[] {SYSTEM_STRING, SYSTEM_STRING});
+ static final MethodInfo CONCAT_OBJECT_OBJECT =
+ SYSTEM_STRING.GetMethod("Concat", new Type[] {SYSTEM_OBJECT, SYSTEM_OBJECT});
+
+ static final MethodInfo OBJECT_EQUALS =
+ SYSTEM_OBJECT.GetMethod("Equals", new Type[] {SYSTEM_OBJECT});
+
+ static final MethodInfo MONITOR_PULSE =
+ MONITOR.GetMethod("Pulse", new Type[] {SYSTEM_OBJECT});
+
+ static final MethodInfo MONITOR_PULSE_ALL =
+ MONITOR.GetMethod("PulseAll", new Type[] {SYSTEM_OBJECT});
+
+ static final MethodInfo MONITOR_WAIT =
+ MONITOR.GetMethod("Wait", new Type[] {SYSTEM_OBJECT});
+
+ static final MethodInfo MONITOR_WAIT_TIMEOUT =
+ MONITOR.GetMethod("Wait", new Type[] {SYSTEM_OBJECT, INT});
+
+
+ public static Type getJavaType(String name) {
+ try { return JavaType.fromString(name); }
+ catch (ClassNotFoundException e) {
+ System.err.println("Cannot find class: " + name);
+ throw Debug.abort(e); }
+ }
+
+ TypeCreator(GenMSIL _gen) {
+ gen = _gen;
+ global = gen.global;
+ defs = global.definitions;
+
+ GenMSILPhase phase = (GenMSILPhase) gen.descr;
+ types2symbols = phase.types2symbols;
+ symbols2types = phase.symbols2types;
+ symbols2fields = phase.symbols2fields;
+ symbols2methods = phase.symbols2methods;
+ symbols2moduleFields = phase.symbols2moduleFields;
+
+ map(defs.ANY_CLASS, SYSTEM_OBJECT);
+ map(defs.ANYREF_CLASS, SYSTEM_OBJECT);
+ map(defs.JAVA_OBJECT_CLASS, SYSTEM_OBJECT);
+ map(defs.JAVA_STRING_CLASS, SYSTEM_STRING);
+
+ translateMethod(defs.JAVA_OBJECT_CLASS, "equals",
+ SYSTEM_OBJECT, "Equals");
+ translateMethod(defs.JAVA_OBJECT_CLASS, "hashCode",
+ SYSTEM_OBJECT, "GetHashCode");
+ translateMethod(defs.JAVA_STRING_CLASS, "equals",
+ SYSTEM_STRING, "Equals");
+ translateMethod(defs.JAVA_STRING_CLASS, "toString",
+ SYSTEM_STRING, "ToString");
+ translateMethod(defs.JAVA_STRING_CLASS, "startsWith",
+ SYSTEM_STRING, "StartsWith");
+ translateMethod(defs.JAVA_STRING_CLASS, "length",
+ SYSTEM_STRING, "get_Length");
+ translateMethod(defs.JAVA_STRING_CLASS, "charAt",
+ SYSTEM_STRING, "get_Chars");
+ translateMethod(defs.JAVA_STRING_CLASS, "substring",
+ SYSTEM_STRING, "Substring");
+
+ //generate mappings for the methods of System.Threading.Monitor
+ //final Type MONITOR = Type.GetType("System.Threading.Monitor");
+ final Type[] OBJECT_1 = new Type[] {SYSTEM_OBJECT};
+ final scalac.symtab.Type UNBOXED_LONG =
+ new scalac.symtab.Type.UnboxedType(TypeTags.LONG);
+
+ translateMethod(defs.JAVA_OBJECT_CLASS, "wait",
+ scalac.symtab.Type.EMPTY_ARRAY,
+ MONITOR, "Wait", OBJECT_1);
+ translateMethod(defs.JAVA_OBJECT_CLASS, "wait",
+ new scalac.symtab.
+ Type[] {UNBOXED_LONG},
+ MONITOR, "Wait",
+ new Type[] {SYSTEM_OBJECT, INT});
+ translateMethod(defs.JAVA_OBJECT_CLASS, "notify",
+ scalac.symtab.Type.EMPTY_ARRAY,
+ MONITOR, "Pulse", OBJECT_1);
+ translateMethod(defs.JAVA_OBJECT_CLASS, "notifyAll",
+ scalac.symtab.Type.EMPTY_ARRAY,
+ MONITOR, "PulseAll", OBJECT_1);
+ }
+
+ // looks up a method according to the signature
+ Symbol lookupMethod(Symbol clazz, String name,
+ scalac.symtab.Type[] paramTypes)
+ {
+ Symbol[] methods = clazz.members().
+ lookup(Name.fromString(name)).alternatives();
+ search:
+ for (int i = 0; i < methods.length; i++) {
+ switch (methods[i].info()) {
+ case MethodType(Symbol[] vparams, _):
+ if (paramTypes.length != vparams.length)
+ continue;
+ for (int j = 0; j < vparams.length; j++) {
+ if (!paramTypes[j].equals(vparams[j].info()))
+ continue search;
+ }
+ return methods[i];
+ default:
+ continue;
+ }
+ }
+ return null;
+ }
+
+ // create mapping between the specified two methods only
+ void translateMethod(Symbol clazz, String name,
+ scalac.symtab.Type[] paramTypes,
+ Type newClazz, String newName, Type[] newParamTypes)
+ {
+ Symbol sym = lookupMethod(clazz, name, paramTypes);
+ assert sym != null : "Cannot find method: " + name;
+ //System.out.println("translate2staticMethod:");
+ //System.out.println("\told method: " + dumpSym(sym));
+ MethodInfo method = newClazz.GetMethod(newName, newParamTypes);
+ symbols2methods.put(sym, method);
+ //System.out.println("\tnew method: " + method);
+ }
+
+ // look up the method and then create the mapping
+ void translateMethod(Symbol clazz, String name,
+ Type newClazz, String newName)
+ {
+ Symbol sym = clazz.lookup(Name.fromString(name));
+ assert sym != null : "Cannot find method: " + name;
+ translateMethod(sym, newClazz, newName);
+ }
+
+ // create a mapping for the two methods
+ void translateMethod(Symbol sym, Type newClazz, String newName) {
+ switch (sym.info()) {
+ case MethodType(Symbol[] vparams, scalac.symtab.Type result):
+ Type[] params = new Type[vparams.length];
+ for (int i = 0; i < params.length; i++)
+ params[i] = getType(vparams[i]);
+ MethodInfo method = newClazz.GetMethod(newName, params);
+ symbols2methods.put(sym, method);
+ break;
+ case OverloadedType(Symbol[] alts, _):
+ for (int i = 0; i < alts.length; i++)
+ translateMethod(alts[i], newClazz, newName);
+ return;
+ default:
+ global.fail("" + Debug.show(sym.info()));
+ }
+ }
+
+ public void traverse(Unit[] units) {
+ for (int i = 0; i < units.length; i++) {
+ unit = units[i];
+ traverse(unit);
+ }
+ }
+
+ private Symbol currentClass;
+
+ public void traverse(Tree tree) {
+ pos = tree.pos;
+ final Symbol sym = tree.hasSymbol() ? tree.symbol() : null;
+ switch (tree) {
+ case ClassDef(_, _, _, _, _, Template(_, Tree[] body)):
+ Symbol tmpClass = currentClass;
+ currentClass = sym;
+ TypeBuilder tb = (TypeBuilder) symbols2types.get(sym);
+ if (tb != null) {
+ assert tb == null || (tb instanceof TypeBuilder);
+ //logErr("Class already defined: " + dumpSym(sym) +
+ // ";old type: " + tb);
+ } else {
+ tb = (TypeBuilder) createType(sym);
+ }
+ types2symbols.put(tb, sym);
+ traverse(body);
+ currentClass = tmpClass;
+ break;
+
+ case ValDef(_, _, _, _):
+ if (currentClass == null)
+ break;
+ FieldBuilder field = (FieldBuilder) symbols2fields.get(sym);
+ if (field != null)
+ logErr("Field already defined: " + dumpSym(sym));
+ else {
+ field = (FieldBuilder) createField(sym);
+ }
+ break;
+
+ case DefDef(_, _, _, _, _, _):
+ MethodBase method = (MethodBase) symbols2methods.get(sym);
+ if (method != null)
+ logErr("Method already defined: " + dumpSym(sym));
+ else
+ method = createMethod(sym);
+ break;
+
+ default:
+ super.traverse(tree);
+ }
+ }
+
+ public void createTypes() {
+ Iterator iter = typeBuilders.iterator();
+ while (iter.hasNext())
+ ((TypeBuilder)iter.next()).CreateType();
+ }
+
+
+ public void map(Symbol sym, Type type) {
+ symbols2types.put(sym, type);
+ if (sym.isClass())
+ types2symbols.put(type, sym);
+ }
+
+ Symbol getSymbol(Type t) {
+ return (Symbol) types2symbols.get(t);
+ }
+
+// public Type getType(Symbol sym) {
+// Type type = null;
+// try { type = getType2(sym); }
+// catch (Throwable e) {
+// log("getType: Exception cought for " + dumpSym(sym));
+// //log("-->symbol.type() = " + Debug.show(sym.type()));
+// //log("-->symbol.info()" + Debug.show(sym.info()));
+// e.printStackTrace();
+// }
+// return type;
+// }
+
+ public Type getType(Symbol sym) {
+ if (sym == null) return null;
+ Type type = (Type) symbols2types.get(sym);
+ if (type != null)
+ return type;
+ if (sym.isJava()) {
+ //log("getType: looking up Java class: " + dumpSym(sym));
+// try {
+// type = JavaType.fromString(sym.fullNameString());
+// } catch (ClassNotFoundException e) {
+// global.fail(formatMessage("Cannot find class: " +
+// sym.fullNameString()));
+// }
+ type = getJavaType(sym.fullNameString());
+ }
+ else
+ switch (sym.info()) {
+ case CompoundType(_, _):
+ String fullname = sym.type().symbol().fullNameString();
+ type = Type.GetType(fullname);
+ if (type == null)
+ type = createType(sym);
+ break;
+
+ case UnboxedArrayType(scalac.symtab.Type elemtp):
+// // force the creation of the type
+// log("UnboxedArrayType: " + elemtp + "[]");
+// getType(elemtp.symbol());
+// Type t = Type.GetType(elemtp + "[]");
+// log("Array type: " + t);
+// return t;
+ type = getTypeFromType(sym.info());
+ break;
+
+ default:
+ //log("getType: Going through the type: " + dumpSym(sym));
+ type = getTypeFromType(sym.type());
+ }
+ assert type != null : "Unable to find type: " + dumpSym(sym);
+ map(sym, type);
+ return type;
+ }
+
+
+ /** Creates a TypeBuilder object corresponding to the symbol
+ */
+ public TypeBuilder createType(Symbol sym) {
+ assert !symbols2types.containsKey(sym);
+ TypeBuilder type = null;
+ final String name = sym.fullNameString();
+ final ModuleBuilder module = gen.currModule;
+ switch (sym.info()) {
+ case CompoundType(scalac.symtab.Type[] baseTypes, _):
+ final Symbol owner = sym.owner();
+ Type superType = null;
+ Type[] interfaces = null;
+ int inum = baseTypes.length;
+ if (sym.isInterface()) {
+ interfaces = new Type[inum];
+ for (int i = 0; i < inum; i++)
+ interfaces[i] = getType(baseTypes[i].symbol());
+ } else {
+ superType = getType(baseTypes[0].symbol());
+ assert inum > 0;
+ interfaces = new Type[inum - 1];
+ for (int i = 1; i < inum; i++)
+ interfaces[i - 1] = getType(baseTypes[i].symbol());
+ }
+
+ // i.e. top level class
+ if (owner.isRoot()) {
+ type = module.DefineType(name,
+ translateTypeAttributes(sym.flags, false),
+ superType,
+ interfaces);
+ } else {
+ TypeBuilder outerType = (TypeBuilder) getType(owner);
+ type = outerType.
+ DefineNestedType(sym.nameString(),
+ translateTypeAttributes(sym.flags, true),
+ superType,
+ interfaces);
+ }
+ break;
+
+ default:
+ global.fail("Symbol does not have a CompoundType: " +
+ Debug.show(sym));
+ }
+ typeBuilders.add(type);
+ map(sym, type);
+ //log("createType: " + dumpSym(sym) + " => " + type.getSignature());
+ //log("createType: symbol type symbol = " +
+ //getTypeFromType(sym.type()).getSignature());
+ return type;
+ }
+
+ /**
+ */
+ public Type getTypeFromType(scalac.symtab.Type type) {
+ //log("getTypeFromType: " + Debug.show(type));
+ switch (type) {
+ case CompoundType(_, _):
+ return getType(type.symbol());
+
+ case UnboxedType(int kind):
+ return getTypeFromKind(kind);
+
+ case TypeRef(_, Symbol s, _):
+ return getType(s);
+
+ case UnboxedArrayType(scalac.symtab.Type elemtp):
+ // force the creation of the type
+ //log("UnboxedArrayType: " + elemtp + "[]");
+ return Type.GetType(getTypeFromType(elemtp) + "[]");
+
+ default:
+ global.fail("getTypeFromType: " + Debug.show(type));
+ }
+ return null;
+ }
+
+ public MethodBase getMethod(Symbol sym) {
+ MethodBase method = null;
+ try {
+ method = getMethod2(sym);
+ } catch (ClassCastException e) {
+ logErr("getMethod: " + dumpSym(sym));
+ e.printStackTrace();
+ }
+ return method;
+ }
+
+ /** Returns the MethodBase object corresponding to the symbol
+ */
+ public MethodBase getMethod2(Symbol sym) {
+ MethodBase method = (MethodBase) symbols2methods.get(sym);
+ if (method != null)
+ return method;
+ //log("getMethod: resolving " + dumpSym(sym));
+ //log("getMethod: sym.owner() = " + dumpSym(sym.owner()));
+ switch (sym.info()) {
+ case MethodType(Symbol[] vparams, scalac.symtab.Type result):
+ Type[] params = new Type[vparams.length];
+ for (int i = 0; i < params.length; i++)
+ params[i] = getType(vparams[i]);
+ if ( sym.isConstructor() ) {
+ // The owner of a constructor is the outer class
+ // so get the result type of the constructor
+ Type type = getTypeFromType(result);
+ method = type.GetConstructor(params);
+ } else {
+ String name = sym.name.toString();
+ if (sym.name == Names.toString) name = "ToString";
+ else if (sym.name == Names.hashCode) name = "GetHashCode";
+ else if (sym.name == Names.equals) name = "Equals";
+ //log("Resolving method " + dumpSym(sym));
+ Type type = getType(sym.owner());
+ method = type.GetMethod(name, params);
+ }
+ break;
+ default:
+ global.fail("Symbol doesn't have a method type: " + Debug.show(sym));
+ }
+ assert method != null : "Cannot find method: " + dumpSym(sym);
+ symbols2methods.put(sym, method);
+ return method;
+ }
+
+ MethodBase createMethod(Symbol sym) {
+ MethodBase method = null;
+ try {
+ method = createMethod2(sym);
+ } catch (RuntimeException e) {
+ logErr(e.getMessage());
+ e.printStackTrace();
+ System.exit(1);
+ }
+ return method;
+ }
+
+ MethodBase createMethod2(Symbol sym) {
+ final Symbol owner = sym.owner();
+ MethodBase method = null;
+ //log("createMethod: resolving " + dumpSym(sym));
+ //log("createMethod: sym.owner() = " + dumpSym(sym.owner()));
+ switch (sym.info()) {
+ case MethodType(Symbol[] vparams, scalac.symtab.Type result):
+ Type[] params = new Type[vparams.length];
+ for (int i = 0; i < params.length; i++)
+ params[i] = getType(vparams[i]);
+
+ int flags = ( owner.isJava() && owner.isModuleClass() ) ?
+ sym.flags | Modifiers.STATIC :
+ sym.flags;
+
+ if (sym.isConstructor()) {
+
+ Type type = getTypeFromType(result);
+ ConstructorBuilder constructor =
+ ((TypeBuilder)type).DefineConstructor
+ (translateMethodAttributes(flags, true),
+ CallingConventions.Standard,
+ params);
+ for (int i = 0; i < vparams.length; i++)
+ constructor.DefineParameter
+ (i, ParameterAttributes.In, vparams[i].name.toString());
+ method = constructor;
+ } else {
+ String name = sym.name.toString();
+ if (sym.name == Names.toString) name = "ToString";
+ else if (sym.name == Names.hashCode) name = "GetHashCode";
+ else if (sym.name == Names.equals) name = "Equals";
+ Type type = getType(owner);
+ //log("createMethod: Define method for " + dumpSym(sym));
+ MethodBuilder methodBuilder =
+ ((TypeBuilder)type).DefineMethod
+ (name, translateMethodAttributes(flags, false),
+ getTypeFromType(result), params);
+ for (int i = 0; i < vparams.length; i++)
+ methodBuilder.DefineParameter
+ (i, ParameterAttributes.In,
+ vparams[i].name.toString());
+ method = methodBuilder;
+ //log("createMethod: New method defined: " +
+ //method.getSignature());
+ }
+ break;
+ default:
+ assert false : "Symbol doesn't have a method type: " + dumpSym(sym);
+ }
+ symbols2methods.put(sym, method);
+ return method;
+ }
+
+ /** Returns teh FieldInfo object corresponing to the symbol
+ */
+ public FieldInfo getField(Symbol sym) {
+ FieldInfo field = (FieldInfo) symbols2fields.get(sym);
+ if (field == null) {
+ //log("getField: resolving symbol: " + dumpSym(sym));
+ //log("-->symbol.type() = " + Debug.show(sym.type()));
+ //log("-->symbol.info()" + Debug.show(sym.info()));
+ field = getType(sym.owner()).GetField(sym.name.toString());
+ symbols2fields.put(sym, field);
+ }
+ assert field != null : "Cannot find field: " + dumpSym(sym);
+ return field;
+ }
+
+ public FieldInfo createField(Symbol sym) {
+ FieldBuilder field;
+ //log("createField: resolving symbol: " + dumpSym(sym));
+ //log("-->symbol.type() = " + Debug.show(sym.type()));
+ //log("-->symbol.info()" + Debug.show(sym.info()));
+ TypeBuilder owner = (TypeBuilder) getType(sym.owner());
+ int flags = ( sym.owner().isJava() && sym.owner().isModuleClass() ) ?
+ sym.flags | Modifiers.STATIC : sym.flags;
+ field = owner.DefineField(sym.name.toString(),
+ getTypeFromType(sym.type()),
+ translateFieldAttributes(flags));
+ Object o = symbols2fields.put(sym, field);
+ assert o == null : "Cannot re-define field: " + dumpSym(sym);
+ return field;
+ }
+
+ FieldInfo getModuleField(Type type) {
+ Symbol sym = (Symbol) types2symbols.get(type);
+ assert sym != null;
+ return getModuleField(sym);
+ }
+
+ private Symbol getTypeSymbol(scalac.symtab.Type type) {
+ switch (type) {
+ case TypeRef(_, Symbol s, _):
+ return s;
+ default:
+ logErr("Strange type: " + Debug.show(type));
+ }
+ return null;
+ }
+
+ FieldInfo getModuleField(Symbol sym) {
+ FieldInfo moduleField = null;
+ if (sym.isModule() || sym.isModuleClass()) {
+ moduleField = (FieldInfo) symbols2moduleFields.get(sym);
+ if (moduleField == null) {
+ //log("TypeCreator.getModuleField - " + dumpSym(sym));
+ //log("\t-->type = " + Debug.show(sym.type()));
+ //log("\t-->info = " + Debug.show(sym.info()));
+ Symbol s = getTypeSymbol(sym.type());
+ if (sym != s) {
+ //log("getModuleField: going through: " + dumpSym(s));
+ moduleField = getModuleField(s);
+ } else {
+ TypeBuilder module = (TypeBuilder) getType(sym);
+ moduleField = module.DefineField
+ (MODULE_S, module,
+ FieldAttributes.Public |
+ FieldAttributes.InitOnly |
+ FieldAttributes.Static);
+ }
+ symbols2moduleFields.put(sym, moduleField);
+ }
+ }
+ else {
+ return null;
+ //throw new ApplicationError("getModuleField: not a module: " +
+ //dumpSym(sym));
+ }
+ return moduleField;
+ }
+
+ /**
+ * Translates Scala modifiers into TypeAttributes
+ */
+ public static long translateTypeAttributes(int mods, boolean nested) {
+ long attr = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass;
+
+ if (Modifiers.Helper.isInterface(mods))
+ attr |= TypeAttributes.Interface;
+ else
+ attr |= TypeAttributes.Class;
+
+ if (Modifiers.Helper.isAbstract(mods))
+ attr |= TypeAttributes.Abstract;
+ if (Modifiers.Helper.isFinal(mods))
+ attr |= TypeAttributes.Sealed;
+
+ if (nested) {
+ if (Modifiers.Helper.isPrivate(mods))
+ attr |= TypeAttributes.NestedPrivate;
+ else if (Modifiers.Helper.isProtected(mods))
+ attr |= TypeAttributes.NestedFamORAssem;
+ else
+ attr |= TypeAttributes.NestedPublic;
+ } else {
+ if (Modifiers.Helper.isPrivate(mods))
+ attr |= TypeAttributes.NotPublic;
+ else
+ attr |= TypeAttributes.Public;
+ }
+
+ return attr;
+ }
+
+ /**
+ * Translates Scala modifiers into FieldAttributes
+ */
+ public static long translateFieldAttributes(int mods) {
+ long attr = 0L;
+
+ if (Modifiers.Helper.isFinal(mods))
+ attr |= FieldAttributes.InitOnly;
+ if (Modifiers.Helper.isPrivate(mods))
+ attr |= FieldAttributes.Private;
+ else if (Modifiers.Helper.isProtected(mods))
+ attr |= FieldAttributes.FamORAssem;
+ else
+ attr |= FieldAttributes.Public;
+
+ if (Modifiers.Helper.isStatic(mods))
+ attr |= FieldAttributes.Static;
+
+ return attr;
+ }
+
+ /**
+ * Translates Scala modifiers into MethodAttributes
+ */
+ public static long translateMethodAttributes(int mods, boolean constructor)
+ {
+ long attr = MethodAttributes.HideBySig;
+ if (!constructor) {
+ attr |= MethodAttributes.Virtual;
+ if (Modifiers.Helper.isFinal(mods))
+ attr |= MethodAttributes.Final;
+ if (Modifiers.Helper.isAbstract(mods))
+ attr |= MethodAttributes.Abstract;
+ }
+
+ if (Modifiers.Helper.isStatic(mods)) {
+ attr |= MethodAttributes.Static;
+ attr &= ~MethodAttributes.Virtual;
+ }
+ if (Modifiers.Helper.isPrivate(mods))
+ attr |= MethodAttributes.Private;
+ //else if (Modifiers.Helper.isProtected(mods))
+ // attr |= MethodAttributes.FamORAssem;
+ else
+ attr |= MethodAttributes.Public;
+
+ return attr;
+ }
+
+ /** Retrieves the primitive datatypes given their kind
+ */
+ public static Type getTypeFromKind(int kind) {
+ switch (kind) {
+ case TypeTags.CHAR: return CHAR;
+ case TypeTags.BYTE: return BYTE;
+ case TypeTags.SHORT: return SHORT;
+ case TypeTags.INT: return INT;
+ case TypeTags.LONG: return LONG;
+ case TypeTags.FLOAT: return FLOAT;
+ case TypeTags.DOUBLE: return DOUBLE;
+ case TypeTags.BOOLEAN: return BOOLEAN;
+ case TypeTags.UNIT: return VOID;
+ case TypeTags.STRING: return SYSTEM_STRING;
+ default:
+ throw new ApplicationError("Unknown kind: " + kind);
+ }
+ }
+
+ static String dumpSym(Symbol sym) {
+ if (sym == null) return "<null>";
+ if (sym == Symbol.NONE) return "NoSymbol";
+ return "symbol = " + Debug.show(sym) +
+ "; owner = " + Debug.show(sym.owner()) +
+ //"; type = " + Debug.show(sym.type()) +
+ //"; info = " + Debug.show(sym.info()) +
+ "; kind = " + sym.kind +
+ "; flags = " + Integer.toHexString(sym.flags);
+ }
+
+ void log(String message) {
+ System.err.println(message);
+ //log(1, message);
+ }
+
+ void logErr(String message) {
+ log(formatMessage(message));
+ }
+
+ String formatMessage(String message) {
+ return unit.source.getMessage(pos, message);
+ }
+
+} // class TypeCreator