diff options
author | Iulian Dragos <jaguarul@gmail.com> | 2005-10-06 13:43:32 +0000 |
---|---|---|
committer | Iulian Dragos <jaguarul@gmail.com> | 2005-10-06 13:43:32 +0000 |
commit | 8c7d8bd610fbe29cb6ff57de7694648d502ea7f4 (patch) | |
tree | e8a231f69273ea128dcb7e7e3ffbcf700da216dd /sources | |
parent | 25a98964b5109aa55b71a8a26886c59903193548 (diff) | |
download | scala-8c7d8bd610fbe29cb6ff57de7694648d502ea7f4.tar.gz scala-8c7d8bd610fbe29cb6ff57de7694648d502ea7f4.tar.bz2 scala-8c7d8bd610fbe29cb6ff57de7694648d502ea7f4.zip |
Experimental module support.
Diffstat (limited to 'sources')
-rwxr-xr-x | sources/scala/tools/nsc/Global.scala | 16 | ||||
-rw-r--r-- | sources/scala/tools/nsc/ast/TreeBrowsers.scala | 5 | ||||
-rw-r--r-- | sources/scala/tools/nsc/backend/icode/BasicBlocks.scala | 2 | ||||
-rw-r--r-- | sources/scala/tools/nsc/backend/icode/Checkers.scala | 30 | ||||
-rw-r--r-- | sources/scala/tools/nsc/backend/icode/GenICode.scala | 81 | ||||
-rw-r--r-- | sources/scala/tools/nsc/backend/icode/Members.scala | 58 | ||||
-rw-r--r-- | sources/scala/tools/nsc/backend/icode/Opcodes.scala | 12 | ||||
-rw-r--r-- | sources/scala/tools/nsc/backend/icode/Printers.scala | 18 | ||||
-rw-r--r-- | sources/scala/tools/nsc/backend/jvm/GenJVM.scala | 227 |
9 files changed, 354 insertions, 95 deletions
diff --git a/sources/scala/tools/nsc/Global.scala b/sources/scala/tools/nsc/Global.scala index e82af18eb9..3e7b8b7fde 100755 --- a/sources/scala/tools/nsc/Global.scala +++ b/sources/scala/tools/nsc/Global.scala @@ -456,7 +456,19 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable } private def writeICode(): Unit = { - val printer = new icodePrinter.TextPrinter(new PrintWriter(System.out, true)); - icodes.classes.foreach(printer.printClass); + val printer = new icodePrinter.TextPrinter(null); + icodes.classes.foreach((cls) => { + val file = getFile(cls.symbol, ".icode"); + try { + val stream = new FileOutputStream(file); + printer.setWriter(new PrintWriter(stream, true)); + printer.printClass(cls); + informProgress("wrote " + file); + } catch { + case ex: IOException => + if (settings.debug.value) ex.printStackTrace(); + error("could not write file " + file); + } + }); } } diff --git a/sources/scala/tools/nsc/ast/TreeBrowsers.scala b/sources/scala/tools/nsc/ast/TreeBrowsers.scala index 1695bc7ac1..2c9aaaaa37 100644 --- a/sources/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/sources/scala/tools/nsc/ast/TreeBrowsers.scala @@ -526,7 +526,10 @@ abstract class TreeBrowsers { var att = ""; if (s != null) { - flagsToString(s.flags); + var str = flagsToString(s.flags); + if (s.hasFlag(STATIC) || s.hasFlag(STATICMEMBER)) + str = str + " isStatic "; + str } else ""; } diff --git a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala index 277b3de748..edf2d5021b 100644 --- a/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/sources/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -130,6 +130,8 @@ trait BasicBlocks: ICodes { /** Close the block */ def close = { + assert(instructionList.length > 0, + "Empty block."); closed = true; instrs = toInstructionArray(instructionList.reverse); } diff --git a/sources/scala/tools/nsc/backend/icode/Checkers.scala b/sources/scala/tools/nsc/backend/icode/Checkers.scala index 527cf64919..2a1c802b23 100644 --- a/sources/scala/tools/nsc/backend/icode/Checkers.scala +++ b/sources/scala/tools/nsc/backend/icode/Checkers.scala @@ -54,6 +54,7 @@ abstract class Checkers { val emptyStack = new TypeStack(); val STRING = REFERENCE(definitions.StringClass); + val SCALA_ALL = REFERENCE(definitions.AllClass); def checkICodes: Unit = classes foreach check; @@ -66,7 +67,8 @@ abstract class Checkers { def check(m: IMethod): Unit = { log("Checking method " + m); method = m; - check(m.code); + if (!m.isDeferred) + check(m.code); } def check(c: Code): Unit = { @@ -136,8 +138,8 @@ abstract class Checkers { else (); - def checkLocal(local: Symbol) = - method.lookupLocal(local.name) match { + def checkLocal(local: Local) = + method.lookupLocal(local.sym.name) match { case None => error(" " + local + " is not defined in method " + method); case _ => () } @@ -228,7 +230,7 @@ abstract class Checkers { case LOAD_LOCAL(local, isArg) => checkLocal(local); - stack.push(toTypeKind(local.info)); + stack.push(local.kind); case LOAD_FIELD(field, isStatic) => if (isStatic) { @@ -261,10 +263,10 @@ abstract class Checkers { case STORE_LOCAL(local, isArg) => checkLocal(local); checkStack(1); - val localType = toTypeKind(local.info); + val actualType = stack.pop; - if (!(actualType <:< localType)) - typeError(localType, actualType); + if (!(actualType <:< local.kind)) + typeError(local.kind, actualType); case STORE_FIELD(field, isStatic) => if (isStatic) { @@ -376,12 +378,13 @@ abstract class Checkers { } - case NEW(ctor) => - checkBool(ctor.isConstructor, - "'new' call to non-constructor method"); - checkMethodArgs(ctor); - checkMethod(REFERENCE(ctor.owner), ctor); - stack.push(REFERENCE(ctor.owner)); + case NEW(kind) => + kind match { + case REFERENCE(cls) => + stack.push(kind); + + case _ => error("NEW call to non-reference type: " + kind); + } case CREATE_ARRAY(elem) => checkStack(1); @@ -435,6 +438,7 @@ abstract class Checkers { val thrown = stack.pop; checkBool(thrown.toType <:< definitions.ThrowableClass.tpe, "Element on top of stack should implement 'Throwable': " + thrown); + stack.push(SCALA_ALL); case DROP(kind) => checkType(stack.pop, kind); diff --git a/sources/scala/tools/nsc/backend/icode/GenICode.scala b/sources/scala/tools/nsc/backend/icode/GenICode.scala index c9f0566a8d..68ac59d21b 100644 --- a/sources/scala/tools/nsc/backend/icode/GenICode.scala +++ b/sources/scala/tools/nsc/backend/icode/GenICode.scala @@ -102,10 +102,20 @@ abstract class GenICode extends SubComponent { val resTpe = if (tree.symbol.isConstructor) UNIT else toTypeKind(ctx1.method.symbol.info.resultType); - ctx1 = genLoad(rhs, ctx1, resTpe); + if (!m.isDeferred) { + ctx1 = genLoad(rhs, ctx1, resTpe); - ctx1.bb.emit(RETURN(resTpe)); - ctx1.bb.close; + // reverse the order of the local variables, to match the source-order + m.locals = m.locals.reverse; + + rhs match { + case Block(_, Return(_)) => (); + case Return(_) => (); + case _ => ctx1.bb.emit(RETURN(resTpe)); + } + ctx1.bb.close; + } else + ctx1.method.setCode(null); ctx1; case Template(parents, body) => @@ -170,7 +180,8 @@ abstract class GenICode extends SubComponent { // assert(ctx.method.locals.contains(lhs.symbol) | ctx.clazz.fields.contains(lhs.symbol), // "Assignment to inexistent local or field: " + lhs.symbol); val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info)); - ctx1.bb.emit(STORE_LOCAL(lhs.symbol, lhs.symbol.isValueParameter)); + val Some(l) = ctx.method.lookupLocal(lhs.symbol); + ctx1.bb.emit(STORE_LOCAL(l, lhs.symbol.isValueParameter)); ctx1 case _ => @@ -337,7 +348,7 @@ abstract class GenICode extends SubComponent { // genLoad val resCtx: Context = tree match { case LabelDef(name, params, rhs) => - ctx.method.addLocals(params map (.symbol)); + ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info)))); val ctx1 = ctx.newBlock; ctx1.labels.get(tree.symbol) match { case Some(label) => label.anchor(ctx1.bb); @@ -354,10 +365,11 @@ abstract class GenICode extends SubComponent { if (rhs == EmptyTree) log("Uninitialized variable " + tree + " at: " + unit.position(tree.pos)); val sym = tree.symbol; - ctx.method.addLocal(sym); - val ctx1 = genLoad(rhs, ctx, toTypeKind(sym.info)); + val local = new Local(sym, toTypeKind(sym.info)); + ctx.method.addLocal(local); + val ctx1 = genLoad(rhs, ctx, local.kind); if (rhs != EmptyTree) - ctx1.bb.emit(STORE_LOCAL(sym, false)); + ctx1.bb.emit(STORE_LOCAL(local, false)); generatedType = UNIT; ctx1 @@ -434,17 +446,27 @@ abstract class GenICode extends SubComponent { // 'new' constructor call case Apply(fun @ Select(New(tpt), nme.CONSTRUCTOR), args) => val ctor = fun.symbol; - assert(fun != null && ctor.isClassConstructor, + assert(ctor.isClassConstructor, "'new' call to non-constructor: " + tree); - var ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx); + generatedType = toTypeKind(tpt.tpe); + assert(generatedType.isReferenceType || generatedType.isArrayType, "Non reference type cannot be instantiated: " + generatedType); + + var ctx1 = ctx; + generatedType match { case ARRAY(elem) => + ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx); ctx1.bb.emit(CREATE_ARRAY(elem)); + case REFERENCE(cls) => - ctx1.bb.emit(NEW(ctor)); assert(ctor.owner == cls, "Symbol " + ctor.owner.fullNameString + "is different than " + tpt); + ctx.bb.emit(NEW(generatedType)); + ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx); + + ctx1.bb.emit(CALL_METHOD(ctor, Static(true))); + case _ => abort("Cannot instantiate " + tpt + "of kind: " + generatedType); } @@ -539,10 +561,11 @@ abstract class GenICode extends SubComponent { } case This(qual) => - assert(tree.symbol == ctx.clazz.symbol | tree.symbol.isModuleClass, + assert(tree.symbol == ctx.clazz.symbol || tree.symbol.isModuleClass, "Trying to access the this of another class: " + "tree.symbol = " + tree.symbol + ", ctx.clazz.symbol = " + ctx.clazz.symbol); if (tree.symbol.isModuleClass && tree.symbol != ctx.clazz.symbol) { + log("LOAD_MODULE from 'This'"); ctx.bb.emit(LOAD_MODULE(tree.symbol)); generatedType = REFERENCE(tree.symbol); } else { @@ -556,6 +579,7 @@ abstract class GenICode extends SubComponent { "Selection of non-module from empty package: " + tree.toString() + " sym: " + tree.symbol + " at: " + unit.position(tree.pos)); + log("LOAD_MODULE from Select(<emptypackage>)"); ctx.bb.emit(LOAD_MODULE(tree.symbol)); ctx @@ -564,6 +588,7 @@ abstract class GenICode extends SubComponent { val generatedType = toTypeKind(sym.info); if (sym.isModule) { + log("LOAD_MODULE from Select(qualifier, selector)"); ctx.bb.emit(LOAD_MODULE(sym)); ctx } else if (isStaticSymbol(sym)) { @@ -577,11 +602,15 @@ abstract class GenICode extends SubComponent { case Ident(name) => if (!tree.symbol.isPackage) { - if (tree.symbol.isModule) + if (tree.symbol.isModule) { + log("LOAD_MODULE from Ident(name)"); ctx.bb.emit(LOAD_MODULE(tree.symbol)); - else - ctx.bb.emit(LOAD_LOCAL(tree.symbol, tree.symbol.isValueParameter)); - generatedType = toTypeKind(tree.symbol.info); + generatedType = toTypeKind(tree.symbol.info); + } else { + val Some(l) = ctx.method.lookupLocal(tree.symbol); + ctx.bb.emit(LOAD_LOCAL(l, tree.symbol.isValueParameter)); + generatedType = l.kind; + } } ctx @@ -699,8 +728,9 @@ abstract class GenICode extends SubComponent { var param = label.params; while (arg != Nil) { - ctx1 = genLoad(arg.head, ctx1, toTypeKind(param.head.info)); - ctx1.bb.emit(STORE_LOCAL(param.head, param.head.isValueParameter)); + val Some(l) = ctx.method.lookupLocal(param.head); + ctx1 = genLoad(arg.head, ctx1, l.kind); + ctx1.bb.emit(STORE_LOCAL(l, param.head.isValueParameter)); arg = arg.tail; param = param.tail; } @@ -899,29 +929,32 @@ abstract class GenICode extends SubComponent { */ def genEqEqPrimitive(l: Tree, r: Tree, ctx: Context, thenCtx: Context, elseCtx: Context): Unit = { var eqEqTempVar: Symbol = null; + var eqEqTempLocal: Local = null; + ctx.method.lookupLocal(eqEqTemp) match { - case Some(sym) => eqEqTempVar = sym; + case Some(local) => eqEqTempVar = local.sym; case None => eqEqTempVar = ctx.method.symbol.newVariable(l.pos, eqEqTemp); eqEqTempVar.setInfo(definitions.AnyRefClass.typeConstructor); - ctx.method.addLocal(eqEqTempVar); + eqEqTempLocal = new Local(eqEqTempVar, REFERENCE(definitions.AnyRefClass)); + ctx.method.addLocal(eqEqTempLocal); } var ctx1 = genLoad(l, ctx, ANY_REF_CLASS); ctx1 = genLoad(r, ctx1, ANY_REF_CLASS); val tmpNullCtx = ctx1.newBlock; val tmpNonNullCtx = ctx1.newBlock; - ctx1.bb.emit(STORE_LOCAL(eqEqTempVar, false)); + ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal, false)); ctx1.bb.emit(DUP(ANY_REF_CLASS)); ctx1.bb.emit(CZJUMP(tmpNullCtx.bb, tmpNonNullCtx.bb, EQ, ANY_REF_CLASS)); ctx1.bb.close; tmpNullCtx.bb.emit(DROP(ANY_REF_CLASS)); // type of AnyRef - tmpNullCtx.bb.emit(LOAD_LOCAL(eqEqTempVar, false)); + tmpNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal, false)); tmpNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)); tmpNullCtx.bb.close; - tmpNonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempVar, false)); + tmpNonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal, false)); tmpNonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)); tmpNonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)); tmpNonNullCtx.bb.close; @@ -950,7 +983,7 @@ abstract class GenICode extends SubComponent { case vparams :: Nil => for (val p <- vparams) - ctx.method.addParam(p.symbol); + ctx.method.addParam(new Local(p.symbol, toTypeKind(p.symbol.info))); ctx.method.params = ctx.method.params.reverse; case _ => diff --git a/sources/scala/tools/nsc/backend/icode/Members.scala b/sources/scala/tools/nsc/backend/icode/Members.scala index 3fe21b1856..3d8798d0f9 100644 --- a/sources/scala/tools/nsc/backend/icode/Members.scala +++ b/sources/scala/tools/nsc/backend/icode/Members.scala @@ -11,6 +11,8 @@ import scala.collection.mutable.HashMap; import scala.collection.mutable.HashSet; import scala.{Symbol => scala_Symbol}; +import scala.tools.nsc.symtab.Flags; + trait Members: ICodes { import global._; @@ -141,45 +143,73 @@ trait Members: ICodes { class IField(val symbol: Symbol) { } - /** Represent a method in ICode */ + /** + * Represents a method in ICode. Local variables contain + * both locals and parameters, similar to the way the JVM + * 'sees' them. + * + * Locals and parameters are added in reverse order, as they + * are kept in cons-lists. The 'builder' is responsible for + * reversing them and putting them back, when the generation is + * finished (GenICode does that). + */ class IMethod(val symbol: Symbol) { var code: Code = null; var exh: List[ExceptionHandler] = _; /** local variables and method parameters */ - var locals: List[Symbol] = Nil; + var locals: List[Local] = Nil; /** method parameters */ - var params: List[Symbol] = Nil; + var params: List[Local] = Nil; def setCode(code: Code): IMethod = { this.code = code; this } - def addLocal(sym: Symbol): Unit = - if (!(locals contains sym)) - locals = sym :: locals; + def addLocal(l: Local): Unit = + if (!(locals contains l)) + locals = l :: locals; - def addLocals(ls: List[Symbol]): Unit = + def addLocals(ls: List[Local]): Unit = ls foreach addLocal; - def addParam(sym: Symbol): Unit = - if (!(params contains sym)) { - params = sym :: params; - locals = sym :: locals; + def addParam(p: Local): Unit = + if (!(params contains p)) { + params = p :: params; + locals = p :: locals; } - def addParams(as: List[Symbol]): Unit = + def addParams(as: List[Local]): Unit = as foreach addParam; - def lookupLocal(n: Name): Option[Symbol] = - locals find ((sym) => sym.name == n); + def lookupLocal(n: Name): Option[Local] = + locals find ((l) => l.sym.name == n); + + def lookupLocal(sym: Symbol): Option[Local] = + locals find ((l) => l.sym == sym); def addHandler(e: ExceptionHandler): Unit = exh = e :: exh; + /** Is this method deferred ('abstract' in Java sense) */ + def isDeferred = + symbol.hasFlag(Flags.DEFERRED) || + symbol.owner.hasFlag(Flags.INTERFACE); override def toString() = symbol.fullNameString; } + + /** Represent local variables and parameters */ + class Local(val sym: Symbol, val kind: TypeKind) { + var index: Int = -1; + + override def equals(other: Any): Boolean = + other.isInstanceOf[Local] && + other.asInstanceOf[Local].sym == this.sym; + + override def toString(): String = sym.toString(); + } + } diff --git a/sources/scala/tools/nsc/backend/icode/Opcodes.scala b/sources/scala/tools/nsc/backend/icode/Opcodes.scala index 2c5e3e73a6..f0fbf05959 100644 --- a/sources/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/sources/scala/tools/nsc/backend/icode/Opcodes.scala @@ -24,7 +24,7 @@ import scala.tools.nsc.ast._; case STORE_FIELD(field, isStatic) => case CALL_PRIMITIVE(primitive) => case CALL_METHOD(method, style) => - case NEW(clasz) => + case NEW(kind) => case CREATE_ARRAY(elem) => case IS_INSTANCE(tpe) => case CHECK_CAST(tpe) => @@ -108,7 +108,7 @@ import scala.tools.nsc.ast._; * Stack: ... * ->: ...:value */ - case class LOAD_LOCAL(local: Symbol, isArgument: boolean) extends Instruction { + case class LOAD_LOCAL(local: Local, isArgument: boolean) extends Instruction { /** Returns a string representation of this instruction */ override def toString(): String = "LOAD_LOCAL "+local.toString(); //+isArgument?" (argument)":""; @@ -157,7 +157,7 @@ import scala.tools.nsc.ast._; * Stack: ...:value * ->: ... */ - case class STORE_LOCAL(local: Symbol, isArgument: boolean) extends Instruction { + case class STORE_LOCAL(local: Local, isArgument: boolean) extends Instruction { /** Returns a string representation of this instruction */ override def toString(): String = "STORE_LOCAL "+local.toString(); //+isArgument?" (argument)":""; @@ -232,9 +232,9 @@ import scala.tools.nsc.ast._; * Stack: ...:arg1:arg2:...:argn * ->: ...:ref */ - case class NEW(ctor: Symbol) extends Instruction { + case class NEW(kind: TypeKind) extends Instruction { /** Returns a string representation of this instruction */ - override def toString(): String = "NEW "+ctor.fullNameString; + override def toString(): String = "NEW "+ kind; override def consumed = 0; override def produced = 1; @@ -334,7 +334,7 @@ import scala.tools.nsc.ast._; cond: TestOp, kind: TypeKind) extends Instruction { /** Returns a string representation of this instruction */ - override def toString(): String ="CZJUMP )" + kind + ")" + + override def toString(): String ="CZJUMP (" + kind + ")" + cond.toString()+" ? "+successBlock.label+" : "+failureBlock.label; override def consumed = 1; diff --git a/sources/scala/tools/nsc/backend/icode/Printers.scala b/sources/scala/tools/nsc/backend/icode/Printers.scala index 717af7ef73..22362756c6 100644 --- a/sources/scala/tools/nsc/backend/icode/Printers.scala +++ b/sources/scala/tools/nsc/backend/icode/Printers.scala @@ -9,6 +9,8 @@ package scala.tools.nsc.backend.icode; import java.io.PrintWriter; +import scala.tools.nsc.symtab.Flags; + abstract class Printers { val global: Global; import global._; @@ -78,13 +80,19 @@ abstract class Printers { def printMethod(m: IMethod): Unit = { print("def "); print(m.symbol.name); print("("); printList(printParam)(m.params.reverse, ", "); print(")"); - print(": "); print(m.symbol.info.resultType); println(" {"); - printCode(m.code); - println("}"); + print(": "); print(m.symbol.info.resultType); + + if (!m.isDeferred) { + println(" {"); + printCode(m.code); + println("}"); + } else + println; } - def printParam(p: Symbol): Unit = { - print(p.name); print(": "); print(p.info); + def printParam(p: Local): Unit = { + print(p.sym.name); print(": "); print(p.sym.info); + print(" ("); print(p.kind); print(")"); } def printCode(code: Code): Unit = { diff --git a/sources/scala/tools/nsc/backend/jvm/GenJVM.scala b/sources/scala/tools/nsc/backend/jvm/GenJVM.scala index 1f3ce47e89..ffb0b7a2a8 100644 --- a/sources/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/sources/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -7,6 +7,8 @@ package scala.tools.nsc.backend.jvm; +import java.io.File; + import scala.collection.mutable.{Map, HashMap}; import scala.tools.nsc.symtab._; @@ -24,7 +26,8 @@ abstract class BytecodeGenerators extends SubComponent { /** Create a new phase */ override def newPhase(p: Phase) = new JvmPhase(p); - /** JVM code generation phase */ + /** JVM code generation phase + */ class JvmPhase(prev: Phase) extends GlobalPhase(prev) { def name = phaseName; override def newFlags = phaseNewFlags; @@ -39,10 +42,15 @@ abstract class BytecodeGenerators extends SubComponent { } /** - * Java bytecode generator + * Java bytecode generator. + * + * TODO: take care of different size in local variables (LOAD/STORE_LOCAL) */ class GenJVM { val MIN_SWITCH_DENSITY = 0.7; + val MODULE_INSTANCE_NAME = "MODULE$"; + val JAVA_LANG_STRINGBUFFER = "java.lang.StringBuffer"; + val stringBufferType = new JObjectType(JAVA_LANG_STRINGBUFFER); var clasz: IClass = _; var method: IMethod = _; @@ -53,11 +61,13 @@ abstract class BytecodeGenerators extends SubComponent { val fjbgContext = new FJBGContext(); + def genClass(c: IClass): Unit = { - log("Generating class " + c); + log("Generating class " + c.symbol + " flags: " + Flags.flagsToString(c.symbol.flags)); clasz = c; var parents = c.symbol.info.parents; var ifaces = JClass.NO_INTERFACES; + val name = javaName(c.symbol); // + (if (c.symbol.isModuleClass) "$" else ""); if (parents.isEmpty) parents = definitions.ObjectClass.tpe :: parents; @@ -69,7 +79,7 @@ abstract class BytecodeGenerators extends SubComponent { } jclass = fjbgContext.JClass(javaFlags(c.symbol), - javaName(c.symbol), + name, javaName(parents(0).symbol), ifaces, c.cunit.source.toString()); @@ -77,7 +87,19 @@ abstract class BytecodeGenerators extends SubComponent { clasz.fields foreach genField; clasz.methods foreach genMethod; - jclass.writeTo(getFile(c.symbol, ".class")); + if (isTopLevelModule(c.symbol)) { + addModuleInstanceField; + dumpMirrorClass; + } + + jclass.writeTo(getFile(jclass, ".class")); + } + + def isTopLevelModule(sym: Symbol): Boolean = { + log("Symbol: " + sym + " isNestedClass? " + atPhase(currentRun.erasurePhase)(sym.isNestedClass) + + " hasFlag LIFTED? " + sym.hasFlag(Flags.LIFTED)); + + sym.isModuleClass && !sym.isImplClass && !sym.hasFlag(Flags.LIFTED) /* && !atPhase(currentRun.erasurePhase)(sym.isNestedClass) */ } def genField(f: IField): Unit = { @@ -88,8 +110,10 @@ abstract class BytecodeGenerators extends SubComponent { } def genMethod(m: IMethod): Unit = { - log("Adding method " + m.symbol.fullNameString + " ctor: " + m.symbol.isClassConstructor); + log("Adding method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) + + " owner: " + m.symbol.owner); method = m; + computeLocalVarsIndex(m); var resTpe = javaType(toTypeKind(m.symbol.tpe.resultType)); if (m.symbol.isClassConstructor) @@ -98,15 +122,83 @@ abstract class BytecodeGenerators extends SubComponent { jmethod = jclass.addNewMethod(javaFlags(m.symbol), javaName(m.symbol), resTpe, - javaTypes(m.params map (p => toTypeKind(p.tpe))), - javaNames(m.params)); + javaTypes(m.params map (.kind)), + javaNames(m.params map (.sym))); if (!jmethod.isAbstract()) { + for (val local <- m.locals; !local.sym.isValueParameter) + jmethod.addNewLocalVariable(javaType(local.kind), javaName(local.sym)); + jcode = jmethod.getCode().asInstanceOf[JExtendedCode]; genCode(m.code); } } + def addModuleInstanceField: Unit = { + import JAccessFlags._; + jclass.addNewField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, + MODULE_INSTANCE_NAME, + jclass.getType()); + } + + def addStaticInit(cls: JClass): Unit = { + import JAccessFlags._; + val clinitMethod = cls.addNewMethod(ACC_PUBLIC | ACC_STATIC, + "<clinit>", + JType.VOID, + JType.EMPTY_ARRAY, + new Array[String](0)); + val clinit = clinitMethod.getCode(); + clinit.emitNEW(cls.getName()); + clinit.emitDUP(); + clinit.emitINVOKESPECIAL(cls.getName(), + JMethod.INSTANCE_CONSTRUCTOR_NAME, + JMethodType.ARGLESS_VOID_FUNCTION); + clinit.emitPUTSTATIC(cls.getName(), + MODULE_INSTANCE_NAME, + jclass.getType()); + clinit.emitRETURN(); + } + + def dumpMirrorClass: Unit = { + import JAccessFlags._; + assert(clasz.symbol.isModuleClass); + + log("Dumping mirror class for object: " + clasz); + val moduleName = javaName(clasz.symbol); // + "$"; + val mirrorName = moduleName.substring(0, moduleName.length() - 1); + val mirrorClass = fjbgContext.JClass(ACC_SUPER | ACC_PUBLIC | ACC_FINAL, + mirrorName, + "java.lang.Object", + JClass.NO_INTERFACES, + clasz.cunit.source.toString()); + for (val m <- clasz.methods; !(m.symbol.hasFlag(Flags.PRIVATE)) && !m.symbol.isClassConstructor && !isStaticSymbol(m.symbol) ) { + val mirrorMethod = mirrorClass.addNewMethod(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, + javaName(m.symbol), + javaType(toTypeKind(m.symbol.tpe.resultType)), + javaTypes(m.params map (.kind)), + javaNames(m.params map (.sym))); + val mirrorCode = mirrorMethod.getCode().asInstanceOf[JExtendedCode]; + mirrorCode.emitGETSTATIC(moduleName, + MODULE_INSTANCE_NAME, + new JObjectType(moduleName)); + var i = 0; + var index = 0; + var argTypes = mirrorMethod.getArgumentTypes(); + while (i < argTypes.length) { + mirrorCode.emitLOAD(index, argTypes(i)); + index = index + argTypes(i).getSize(); + i = i + 1; + } + + mirrorCode.emitINVOKEVIRTUAL(moduleName, mirrorMethod.getName(), mirrorMethod.getType().asInstanceOf[JMethodType]); + mirrorCode.emitRETURN(mirrorMethod.getReturnType()); + } + + addStaticInit(jclass); // should be the current module class + mirrorClass.writeTo(getFile(mirrorClass, ".class")); + } + val linearizer = new NormalLinearizer(); @@ -145,39 +237,49 @@ abstract class BytecodeGenerators extends SubComponent { case LOAD_LOCAL(local, isArg) => if (isArg) - jcode.emitLOAD(1 + method.params.indexOf(local), javaType(local)); + jcode.emitLOAD(indexOf(local), javaType(local.kind)); else - jcode.emitLOAD(1 + method.locals.indexOf(local), javaType(local)); + jcode.emitLOAD(indexOf(local), javaType(local.kind)); case LOAD_FIELD(field, isStatic) => + var owner = javaName(field.owner); +// if (field.owner.hasFlag(Flags.MODULE)) owner = owner + "$"; + + log("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags)); if (isStatic) - jcode.emitGETSTATIC(javaName(field.owner), + jcode.emitGETSTATIC(owner, javaName(field), javaType(field)); else - jcode.emitGETFIELD(javaName(field.owner), + jcode.emitGETFIELD(owner, javaName(field), javaType(field)); case LOAD_MODULE(module) => - (); + assert(module.isModule); + log("genearting LOAD_MODULE for: " + module + " flags: " + + Flags.flagsToString(module.flags)); + jcode.emitGETSTATIC(javaName(module) /* + "$" */ , + MODULE_INSTANCE_NAME, + javaType(module)); case STORE_ARRAY_ITEM(kind) => jcode.emitASTORE(javaType(kind)); case STORE_LOCAL(local, isArg) => if (isArg) - jcode.emitSTORE(1 + method.params.indexOf(local), javaType(local)); + jcode.emitSTORE(indexOf(local), javaType(local.kind)); else - jcode.emitSTORE(1 + method.locals.indexOf(local), javaType(local)); + jcode.emitSTORE(indexOf(local), javaType(local.kind)); case STORE_FIELD(field, isStatic) => + val owner = javaName(field.owner); // + (if (field.owner.hasFlag(Flags.MODULE)) "$" else ""); if (isStatic) - jcode.emitPUTSTATIC(javaName(field.owner), + jcode.emitPUTSTATIC(owner, javaName(field), javaType(field)); else - jcode.emitPUTFIELD(javaName(field.owner), + jcode.emitPUTFIELD(owner, javaName(field), javaType(field)); @@ -187,40 +289,42 @@ abstract class BytecodeGenerators extends SubComponent { // TODO: reference the type of the receiver instead of the // method owner. case CALL_METHOD(method, style) => + val owner = javaName(method.owner); // + (if (method.owner.isModuleClass) "$" else ""); + style match { case Dynamic => if (method.owner.hasFlag(Flags.INTERFACE)) - jcode.emitINVOKEINTERFACE(javaName(method.owner), + jcode.emitINVOKEINTERFACE(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]) else - jcode.emitINVOKEVIRTUAL(javaName(method.owner), + jcode.emitINVOKEVIRTUAL(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]); case Static(instance) => if (instance) { - jcode.emitINVOKESPECIAL(javaName(method.owner), + jcode.emitINVOKESPECIAL(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]); } else - jcode.emitINVOKESTATIC(javaName(method.owner), + jcode.emitINVOKESTATIC(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]); case SuperCall(_) => - jcode.emitINVOKESPECIAL(javaName(method.owner), + jcode.emitINVOKESPECIAL(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]); } - case NEW(ctor) => - val className = javaName(ctor.owner); + case NEW(REFERENCE(cls)) => + val className = javaName(cls); jcode.emitNEW(className); jcode.emitDUP(); - jcode.emitINVOKESPECIAL(className, - JMethod.INSTANCE_CONSTRUCTOR_NAME, - javaType(ctor).asInstanceOf[JMethodType]); +// jcode.emitINVOKESPECIAL(className, +// JMethod.INSTANCE_CONSTRUCTOR_NAME, +// javaType(ctor).asInstanceOf[JMethodType]); case CREATE_ARRAY(elem) => jcode.emitNEWARRAY(javaType(elem)); @@ -396,6 +500,18 @@ abstract class BytecodeGenerators extends SubComponent { case Conversion(src, dst) => jcode.emitT2T(javaType(src), javaType(dst)); + case StringConcat(lf, rg) => +// jcode.emitNEW(JAVA_LANG_STRINGBUFFER); +// jcode.emitDUP(); +// jcode.emitINVOKESPECIAL(JAVA_LANG_STRINGBUFFER, +// JMethod.INSTANCE_CONSTRUCTOR_NAME, +// JMethodType.ARGLESS_VOID_FUNCTION); +// jcode.emitINVOKEVIRTUAL(JAVA_LANG_STRINGBUFFER, +// "append", +// new JMethodType(stringBufferType, +// javaType(lf))); + + case _ => log("Unimplemented primitive " + primitive); } } @@ -415,13 +531,58 @@ abstract class BytecodeGenerators extends SubComponent { bs foreach (bb => labels += bb -> jcode.newLabel() ); } + + ////////////////////// local vars /////////////////////// + + def sizeOf(sym: Symbol): Int = sizeOf(toTypeKind(sym.tpe)); + + + def sizeOf(k: TypeKind): Int = k match { + case DOUBLE | LONG => 2; + case _ => 1; + } + + def indexOf(m: IMethod, sym: Symbol): Int = { + val Some(local) = m.lookupLocal(sym); + assert (local.index >= 0, + "Invalid index for: " + local); + local.index + } + + def indexOf(local: Local): Int = { + assert (local.index >= 0, + "Invalid index for: " + local); + local.index + } + + /** + * Compute the indexes of each local variable of the given + * method. + */ + def computeLocalVarsIndex(m: IMethod): Unit = { + var idx = 1; + if (isStaticSymbol(m.symbol)) + idx = 0; + + for (val l <- m.locals) { + log("Index value for " + l + ": " + idx); + l.index = idx; + idx = idx + sizeOf(l.kind); + } + } + ////////////////////// Utilities //////////////////////// - def javaName(sym: Symbol) = - if (sym.isClass) + def javaName(sym: Symbol) = { + val suffix = if (sym.hasFlag(Flags.MODULE) && !sym.isMethod && + !sym.isImplClass && + !sym.hasFlag(Flags.JAVA)) "$" else ""; + + (if (sym.isClass || (sym.isModule && !sym.isMethod)) sym.fullNameString('/') else - sym.simpleName.toString(); + sym.simpleName.toString()) + suffix; + } def javaNames(syms: List[Symbol]): Array[String] = { val res = new Array[String](syms.length); @@ -497,6 +658,12 @@ abstract class BytecodeGenerators extends SubComponent { // syms foreach ( s => { res(i) = javaType(toTypeKind(s.tpe)); i = i + 1; } ); // res // } + + def getFile(cls: JClass, suffix: String): String = { + val path = cls.getName().replace('.', File.separatorChar); + settings.outdir.value + File.separatorChar + path + suffix + } + } } |