diff options
Diffstat (limited to 'src')
5 files changed, 577 insertions, 559 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 2bcfb9d4a9..ec6c631bd1 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -350,6 +350,7 @@ trait Opcodes { self: ICodes => } case class BOX(boxType: TypeKind) extends Instruction { + assert(boxType.isValueType && (boxType ne UNIT)) // documentation override def toString(): String = "BOX " + boxType override def consumed = 1 override def consumedTypes = boxType :: Nil @@ -357,6 +358,7 @@ trait Opcodes { self: ICodes => } case class UNBOX(boxType: TypeKind) extends Instruction { + assert(boxType.isValueType && (boxType ne UNIT)) // documentation override def toString(): String = "UNBOX " + boxType override def consumed = 1 override def consumedTypes = ObjectReference :: Nil diff --git a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala index 37fff0e1e8..f99ac28e9d 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala @@ -120,47 +120,50 @@ trait Primitives { self: ICodes => /** This class represents a test operation. */ - class TestOp { + sealed abstract class TestOp { /** Returns the negation of this operation. */ - def negate(): TestOp = this match { - case EQ => NE - case NE => EQ - case LT => GE - case GE => LT - case LE => GT - case GT => LE - case _ => throw new RuntimeException("TestOp unknown case") - } + def negate(): TestOp /** Returns a string representation of this operation. */ - override def toString(): String = this match { - case EQ => "EQ" - case NE => "NE" - case LT => "LT" - case GE => "GE" - case LE => "LE" - case GT => "GT" - case _ => throw new RuntimeException("TestOp unknown case") - } + override def toString(): String } + /** An equality test */ - case object EQ extends TestOp + case object EQ extends TestOp { + def negate() = NE + override def toString() = "EQ" + } /** A non-equality test */ - case object NE extends TestOp + case object NE extends TestOp { + def negate() = EQ + override def toString() = "NE" + } /** A less-than test */ - case object LT extends TestOp + case object LT extends TestOp { + def negate() = GE + override def toString() = "LT" + } /** A greater-than-or-equal test */ - case object GE extends TestOp + case object GE extends TestOp { + def negate() = LT + override def toString() = "GE" + } /** A less-than-or-equal test */ - case object LE extends TestOp + case object LE extends TestOp { + def negate() = GT + override def toString() = "LE" + } /** A greater-than test */ - case object GT extends TestOp + case object GT extends TestOp { + def negate() = LE + override def toString() = "GT" + } /** This class represents an arithmetic operation. */ class ArithmeticOp { diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 5eef02f2cb..2ff0c1926c 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -74,22 +74,19 @@ trait TypeKinds { self: ICodes => case _ => false } - /** On the JVM, these types are like Ints for the - * purposes of calculating the lub. + /** On the JVM, + * BOOL, BYTE, CHAR, SHORT, and INT + * are like Ints for the purposes of calculating the lub. */ - def isIntSizedType: Boolean = this match { - case BOOL | CHAR | BYTE | SHORT | INT => true - case _ => false - } - def isIntegralType: Boolean = this match { - case BYTE | SHORT | INT | LONG | CHAR => true - case _ => false - } - def isRealType: Boolean = this match { - case FLOAT | DOUBLE => true - case _ => false - } - def isNumericType: Boolean = isIntegralType | isRealType + def isIntSizedType: Boolean = false + + /** On the JVM, similar to isIntSizedType except that BOOL isn't integral while LONG is. */ + def isIntegralType: Boolean = false + + /** On the JVM, FLOAT and DOUBLE. */ + def isRealType: Boolean = false + + final def isNumericType: Boolean = isIntegralType | isRealType /** Simple subtyping check */ def <:<(other: TypeKind): Boolean = (this eq other) || (this match { @@ -97,11 +94,8 @@ trait TypeKinds { self: ICodes => case _ => this eq other }) - /** Is this type a category 2 type in JVM terms? */ - def isWideType: Boolean = this match { - case DOUBLE | LONG => true - case _ => false - } + /** Is this type a category 2 type in JVM terms? (ie, is it LONG or DOUBLE?) */ + def isWideType: Boolean = false /** The number of dimensions for array types. */ def dimensions: Int = 0 @@ -182,6 +176,7 @@ trait TypeKinds { self: ICodes => /** A boolean value */ case object BOOL extends ValueTypeKind { + override def isIntSizedType = true def maxType(other: TypeKind) = other match { case BOOL | REFERENCE(NothingClass) => BOOL case _ => uncomparable(other) @@ -195,6 +190,8 @@ trait TypeKinds { self: ICodes => /** A 1-byte signed integer */ case object BYTE extends ValueTypeKind { + override def isIntSizedType = true + override def isIntegralType = true def maxType(other: TypeKind) = { if (other == BYTE || other.isNothingType) BYTE else if (other == CHAR) INT @@ -205,6 +202,8 @@ trait TypeKinds { self: ICodes => /** A 2-byte signed integer */ case object SHORT extends ValueTypeKind { + override def isIntSizedType = true + override def isIntegralType = true override def maxType(other: TypeKind) = other match { case BYTE | SHORT | REFERENCE(NothingClass) => SHORT case CHAR => INT @@ -215,6 +214,8 @@ trait TypeKinds { self: ICodes => /** A 2-byte UNSIGNED integer */ case object CHAR extends ValueTypeKind { + override def isIntSizedType = true + override def isIntegralType = true override def maxType(other: TypeKind) = other match { case CHAR | REFERENCE(NothingClass) => CHAR case BYTE | SHORT => INT @@ -225,6 +226,8 @@ trait TypeKinds { self: ICodes => /** A 4-byte signed integer */ case object INT extends ValueTypeKind { + override def isIntSizedType = true + override def isIntegralType = true override def maxType(other: TypeKind) = other match { case BYTE | SHORT | CHAR | INT | REFERENCE(NothingClass) => INT case LONG | FLOAT | DOUBLE => other @@ -234,6 +237,8 @@ trait TypeKinds { self: ICodes => /** An 8-byte signed integer */ case object LONG extends ValueTypeKind { + override def isIntegralType = true + override def isWideType = true override def maxType(other: TypeKind): TypeKind = if (other.isIntegralType || other.isNothingType) LONG else if (other.isRealType) DOUBLE @@ -242,6 +247,7 @@ trait TypeKinds { self: ICodes => /** A 4-byte floating point number */ case object FLOAT extends ValueTypeKind { + override def isRealType = true override def maxType(other: TypeKind): TypeKind = if (other == DOUBLE) DOUBLE else if (other.isNumericType || other.isNothingType) FLOAT @@ -250,6 +256,8 @@ trait TypeKinds { self: ICodes => /** An 8-byte floating point number */ case object DOUBLE extends ValueTypeKind { + override def isRealType = true + override def isWideType = true override def maxType(other: TypeKind): TypeKind = if (other.isNumericType || other.isNothingType) DOUBLE else uncomparable(other) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 387b7fb3d7..c5b49ceca1 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -40,16 +40,16 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with private def outputDirectory(sym: Symbol): AbstractFile = settings.outputDirs outputDirFor beforeFlatten(sym.sourceFile) - private def getFile(base: AbstractFile, cls: JClass, suffix: String): AbstractFile = { + private def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { var dir = base - val pathParts = cls.getName().split("[./]").toList + val pathParts = clsName.split("[./]").toList for (part <- pathParts.init) { dir = dir.subdirectoryNamed(part) } dir.fileNamed(pathParts.last + suffix) } - private def getFile(sym: Symbol, cls: JClass, suffix: String): AbstractFile = - getFile(outputDirectory(sym), cls, suffix) + private def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = + getFile(outputDirectory(sym), clsName, suffix) /** JVM code generation phase */ @@ -231,11 +231,47 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with vp } + private def helperBoxTo(kind: ValueTypeKind): Tuple2[String, JMethodType] = { + val boxedType = definitions.boxedClass(kind.toType.typeSymbol) + val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind))) + + Pair("boxTo" + boxedType.decodedName, mtype) + } + + private val jBoxTo: Map[TypeKind, Tuple2[String, JMethodType]] = Map( + BOOL -> helperBoxTo(BOOL) , + BYTE -> helperBoxTo(BYTE) , + CHAR -> helperBoxTo(CHAR) , + SHORT -> helperBoxTo(SHORT) , + INT -> helperBoxTo(INT) , + LONG -> helperBoxTo(LONG) , + FLOAT -> helperBoxTo(FLOAT) , + DOUBLE -> helperBoxTo(DOUBLE) + ) + + private def helperUnboxTo(kind: ValueTypeKind): Tuple2[String, JMethodType] = { + val mtype = new JMethodType(javaType(kind), Array(JAVA_LANG_OBJECT)) + val mname = "unboxTo" + kind.toType.typeSymbol.decodedName + + Pair(mname, mtype) + } + + private val jUnboxTo: Map[TypeKind, Tuple2[String, JMethodType]] = Map( + BOOL -> helperUnboxTo(BOOL) , + BYTE -> helperUnboxTo(BYTE) , + CHAR -> helperUnboxTo(CHAR) , + SHORT -> helperUnboxTo(SHORT) , + INT -> helperUnboxTo(INT) , + LONG -> helperUnboxTo(LONG) , + FLOAT -> helperUnboxTo(FLOAT) , + DOUBLE -> helperUnboxTo(DOUBLE) + ) + var clasz: IClass = _ var method: IMethod = _ var jclass: JClass = _ var jmethod: JMethod = _ -// var jcode: JExtendedCode = _ + // var jcode: JExtendedCode = _ def isParcelableClass = isAndroidParcelableClass(clasz.symbol) def isRemoteClass = clasz.symbol hasAnnotation RemoteAttr @@ -263,7 +299,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with private def innerClassSymbolFor(s: Symbol): Symbol = if (s.isClass) s else if (s.isModule) s.moduleClass else NoSymbol - override def javaName(sym: Symbol): String = { + override def javaName(sym: Symbol): String = { // TODO Miguel says: check whether a single pass over `icodes.classes` can populate `innerClassBuffer` faster. /** * Checks if given symbol corresponds to inner class/object and add it to innerClassBuffer * @@ -274,10 +310,13 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // TODO: some beforeFlatten { ... } which accounts for // being nested in parameterized classes (if we're going to selectively flatten.) val x = innerClassSymbolFor(s) - val isInner = x.isClass && !x.rawowner.isPackageClass - if (isInner) { - innerClassBuffer += x - collectInnerClass(x.rawowner) + if(x ne NoSymbol) { + assert(x.isClass, "not an inner-class symbol") + val isInner = !x.rawowner.isPackageClass + if (isInner) { + innerClassBuffer += x + collectInnerClass(x.rawowner) + } } } collectInnerClass(sym) @@ -1126,8 +1165,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with linearization = linearizer.linearize(m) val labels = makeLabels(linearization) - /** local variables whose scope appears in this block. */ - val varsInBlock: mutable.Set[Local] = new mutable.HashSet var nextBlock: BasicBlock = linearization.head @@ -1137,302 +1174,298 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with case x :: y :: ys => nextBlock = y; genBlock(x); genBlocks(y :: ys) } - /** Generate exception handlers for the current method. */ - def genExceptionHandlers() { + /** Generate exception handlers for the current method. */ + def genExceptionHandlers() { - /** Return a list of pairs of intervals where the handler is active. - * The intervals in the list have to be inclusive in the beginning and - * exclusive in the end: [start, end). - */ - def ranges(e: ExceptionHandler): List[(Int, Int)] = { - var covered = e.covered - var ranges: List[(Int, Int)] = Nil - var start = -1 - var end = -1 - - linearization foreach { b => - if (! (covered contains b) ) { - if (start >= 0) { // we're inside a handler range - end = labels(b).getAnchor() - ranges ::= ((start, end)) - start = -1 + /** Return a list of pairs of intervals where the handler is active. + * The intervals in the list have to be inclusive in the beginning and + * exclusive in the end: [start, end). + */ + def ranges(e: ExceptionHandler): List[(Int, Int)] = { + var covered = e.covered + var ranges: List[(Int, Int)] = Nil + var start = -1 + var end = -1 + + linearization foreach { b => + if (! (covered contains b) ) { + if (start >= 0) { // we're inside a handler range + end = labels(b).getAnchor() + ranges ::= ((start, end)) + start = -1 + } + } else { + if (start < 0) // we're not inside a handler range + start = labels(b).getAnchor() + + end = endPC(b) + covered -= b } - } else { - if (start < 0) // we're not inside a handler range - start = labels(b).getAnchor() + } - end = endPC(b) - covered -= b + /* Add the last interval. Note that since the intervals are + * open-ended to the right, we have to give a number past the actual + * code! + */ + if (start >= 0) { + ranges ::= ((start, jcode.getPC())) } - } - /* Add the last interval. Note that since the intervals are - * open-ended to the right, we have to give a number past the actual - * code! - */ - if (start >= 0) { - ranges ::= ((start, jcode.getPC())) + if (!covered.isEmpty) + debuglog("Some covered blocks were not found in method: " + method + + " covered: " + covered + " not in " + linearization) + ranges } - if (!covered.isEmpty) - debuglog("Some covered blocks were not found in method: " + method + - " covered: " + covered + " not in " + linearization) - ranges + for (e <- this.method.exh ; p <- ranges(e).sortBy(_._1)) { + if (p._1 < p._2) { + debuglog("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method + + " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls); + val cls = if (e.cls == NoSymbol || e.cls == ThrowableClass) null + else javaName(e.cls) + jcode.addExceptionHandler(p._1, p._2, + labels(e.startBlock).getAnchor(), + cls) + } else + log("Empty exception range: " + p) + } } - for (e <- this.method.exh ; p <- ranges(e).sortBy(_._1)) { - if (p._1 < p._2) { - debuglog("Adding exception handler " + e + "at block: " + e.startBlock + " for " + method + - " from: " + p._1 + " to: " + p._2 + " catching: " + e.cls); - val cls = if (e.cls == NoSymbol || e.cls == ThrowableClass) null - else javaName(e.cls) - jcode.addExceptionHandler(p._1, p._2, - labels(e.startBlock).getAnchor(), - cls) - } else - log("Empty exception range: " + p) + def isAccessibleFrom(target: Symbol, site: Symbol): Boolean = { + target.isPublic || target.isProtected && { + (site.enclClass isSubClass target.enclClass) || + (site.enclosingPackage == target.privateWithin) + } } - } - def isAccessibleFrom(target: Symbol, site: Symbol): Boolean = { - target.isPublic || target.isProtected && { - (site.enclClass isSubClass target.enclClass) || - (site.enclosingPackage == target.privateWithin) - } - } + def genCallMethod(call: CALL_METHOD) { + val CALL_METHOD(method, style) = call + val siteSymbol = clasz.symbol + val hostSymbol = call.hostClass + val methodOwner = method.owner + // info calls so that types are up to date; erasure may add lateINTERFACE to traits + hostSymbol.info ; methodOwner.info + + def isInterfaceCall(sym: Symbol) = ( + sym.isInterface && methodOwner != ObjectClass + || sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass) + ) + // whether to reference the type of the receiver or + // the type of the method owner (if not an interface!) + val useMethodOwner = ( + style != Dynamic + || !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol) + || hostSymbol.isBottomClass + ) + val receiver = if (useMethodOwner) methodOwner else hostSymbol + val jowner = javaName(receiver) + val jname = javaName(method) + val jtype = javaType(method).asInstanceOf[JMethodType] - def genCallMethod(call: CALL_METHOD) { - val CALL_METHOD(method, style) = call - val siteSymbol = clasz.symbol - val hostSymbol = call.hostClass - val methodOwner = method.owner - // info calls so that types are up to date; erasure may add lateINTERFACE to traits - hostSymbol.info ; methodOwner.info - - def isInterfaceCall(sym: Symbol) = ( - sym.isInterface && methodOwner != ObjectClass - || sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass) - ) - // whether to reference the type of the receiver or - // the type of the method owner (if not an interface!) - val useMethodOwner = ( - style != Dynamic - || !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol) - || hostSymbol.isBottomClass - ) - val receiver = if (useMethodOwner) methodOwner else hostSymbol - val jowner = javaName(receiver) - val jname = javaName(method) - val jtype = javaType(method).asInstanceOf[JMethodType] - - def emit(invoke: String) { - debuglog("%s %s %s.%s:%s".format(invoke, receiver.accessString, jowner, jname, jtype)) - invoke match { - case "invokeinterface" => jcode.emitINVOKEINTERFACE(jowner, jname, jtype) - case "invokevirtual" => jcode.emitINVOKEVIRTUAL(jowner, jname, jtype) - case "invokespecial" => jcode.emitINVOKESPECIAL(jowner, jname, jtype) - case "invokestatic" => jcode.emitINVOKESTATIC(jowner, jname, jtype) + def debugMsg(invoke: String) { + debuglog("%s %s %s.%s:%s".format(invoke, receiver.accessString, jowner, jname, jtype)) } - } - def initModule() { - // we initialize the MODULE$ field immediately after the super ctor - if (isStaticModule(siteSymbol) && !isModuleInitialized && - jmethod.getName() == JMethod.INSTANCE_CONSTRUCTOR_NAME && - jname == JMethod.INSTANCE_CONSTRUCTOR_NAME) { - isModuleInitialized = true - jcode.emitALOAD_0() - jcode.emitPUTSTATIC(jclass.getName(), - nme.MODULE_INSTANCE_FIELD.toString, - jclass.getType()) + + def initModule() { + // we initialize the MODULE$ field immediately after the super ctor + if (isStaticModule(siteSymbol) && !isModuleInitialized && + jmethod.getName() == JMethod.INSTANCE_CONSTRUCTOR_NAME && + jname == JMethod.INSTANCE_CONSTRUCTOR_NAME) { + isModuleInitialized = true + jcode.emitALOAD_0() + jcode.emitPUTSTATIC(jclass.getName(), + nme.MODULE_INSTANCE_FIELD.toString, + jclass.getType()) + } } - } - style match { - case Static(true) => emit("invokespecial") - case Static(false) => emit("invokestatic") - case Dynamic if isInterfaceCall(receiver) => emit("invokeinterface") - case Dynamic => emit("invokevirtual") - case SuperCall(_) => emit("invokespecial") ; initModule() + style match { + case Static(true) => jcode.emitINVOKESPECIAL (jowner, jname, jtype) ; debugMsg("invokespecial") + case Static(false) => jcode.emitINVOKESTATIC (jowner, jname, jtype) ; debugMsg("invokestatic") + case Dynamic if isInterfaceCall(receiver) => jcode.emitINVOKEINTERFACE(jowner, jname, jtype) ; debugMsg("invokinterface") + case Dynamic => jcode.emitINVOKEVIRTUAL (jowner, jname, jtype) ; debugMsg("invokevirtual") + case SuperCall(_) => + jcode.emitINVOKESPECIAL(jowner, jname, jtype) + initModule() + debugMsg("invokespecial") + } } - } - def genBlock(b: BasicBlock) { - labels(b).anchorToNext() + def genBlock(b: BasicBlock) { + labels(b).anchorToNext() - debuglog("Generating code for block: " + b + " at pc: " + labels(b).getAnchor()) - var lastMappedPC = 0 - var lastLineNr = 0 - var crtPC = 0 - varsInBlock.clear() + debuglog("Generating code for block: " + b + " at pc: " + labels(b).getAnchor()) + var lastMappedPC = 0 + var lastLineNr = 0 + var crtPC = 0 - for (instr <- b) { + /** local variables whose scope appears in this block. */ + val varsInBlock: mutable.Set[Local] = new mutable.HashSet + val lastInstr = b.lastInstruction - instr match { - case THIS(clasz) => - jcode.emitALOAD_0() + for (instr <- b) { - case CONSTANT(const) => - genConstant(jcode, const) + instr match { + case THIS(clasz) => jcode.emitALOAD_0() - case LOAD_ARRAY_ITEM(kind) => - jcode.emitALOAD(javaType(kind)) + case CONSTANT(const) => genConstant(jcode, const) - case LOAD_LOCAL(local) => - jcode.emitLOAD(indexOf(local), javaType(local.kind)) + case LOAD_ARRAY_ITEM(kind) => + if(kind.isRefOrArrayType) { jcode.emitAALOAD() } + else { + (kind: @unchecked) match { + case UNIT => throw new IllegalArgumentException("invalid type for aload " + kind) + case BOOL | BYTE => jcode.emitBALOAD() + case SHORT => jcode.emitSALOAD() + case CHAR => jcode.emitCALOAD() + case INT => jcode.emitIALOAD() + case LONG => jcode.emitLALOAD() + case FLOAT => jcode.emitFALOAD() + case DOUBLE => jcode.emitDALOAD() + } + } - case lf @ LOAD_FIELD(field, isStatic) => - var owner = javaName(lf.hostClass) - debuglog("LOAD_FIELD with owner: " + owner + - " flags: " + Flags.flagsToString(field.owner.flags)) - if (isStatic) - jcode.emitGETSTATIC(owner, - javaName(field), - javaType(field)) - else - jcode.emitGETFIELD(owner, - javaName(field), - javaType(field)) - - case LOAD_MODULE(module) => -// assert(module.isModule, "Expected module: " + module) - debuglog("generating LOAD_MODULE for: " + module + " flags: " + - Flags.flagsToString(module.flags)); - if (clasz.symbol == module.moduleClass && jmethod.getName() != nme.readResolve.toString) - jcode.emitALOAD_0() - else - jcode.emitGETSTATIC(javaName(module) /* + "$" */ , - nme.MODULE_INSTANCE_FIELD.toString, - javaType(module)) - - case STORE_ARRAY_ITEM(kind) => - jcode emitASTORE javaType(kind) - - case STORE_LOCAL(local) => - jcode.emitSTORE(indexOf(local), javaType(local.kind)) - - case STORE_THIS(_) => - // this only works for impl classes because the self parameter comes first - // in the method signature. If that changes, this code has to be revisited. - jcode.emitASTORE_0() - - case STORE_FIELD(field, isStatic) => - val owner = javaName(field.owner) - if (isStatic) - jcode.emitPUTSTATIC(owner, - javaName(field), - javaType(field)) - else - jcode.emitPUTFIELD(owner, - javaName(field), - javaType(field)) - - case CALL_PRIMITIVE(primitive) => - genPrimitive(primitive, instr.pos) - - /** Special handling to access native Array.clone() */ - case call @ CALL_METHOD(definitions.Array_clone, Dynamic) => - val target: String = javaType(call.targetTypeKind).getSignature() - jcode.emitINVOKEVIRTUAL(target, "clone", arrayCloneType) - - case call @ CALL_METHOD(method, style) => - genCallMethod(call) - - case BOX(kind) => - val boxedType = definitions.boxedClass(kind.toType.typeSymbol) - val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind))) - jcode.emitINVOKESTATIC(BoxesRunTime, "boxTo" + boxedType.decodedName, mtype) - - case UNBOX(kind) => - val mtype = new JMethodType(javaType(kind), Array(JAVA_LANG_OBJECT)) - jcode.emitINVOKESTATIC(BoxesRunTime, "unboxTo" + kind.toType.typeSymbol.decodedName, mtype) - - case NEW(REFERENCE(cls)) => - val className = javaName(cls) - jcode emitNEW className - - case CREATE_ARRAY(elem, 1) => elem match { - case REFERENCE(_) | ARRAY(_) => - jcode emitANEWARRAY javaType(elem).asInstanceOf[JReferenceType] - case _ => - jcode emitNEWARRAY javaType(elem) - } + case LOAD_LOCAL(local) => jcode.emitLOAD(indexOf(local), javaType(local.kind)) + + case lf @ LOAD_FIELD(field, isStatic) => + var owner = javaName(lf.hostClass) + debuglog("LOAD_FIELD with owner: " + owner + + " flags: " + Flags.flagsToString(field.owner.flags)) + val fieldJName = javaName(field) + val fieldJType = javaType(field) + if (isStatic) jcode.emitGETSTATIC(owner, fieldJName, fieldJType) + else jcode.emitGETFIELD( owner, fieldJName, fieldJType) + + case LOAD_MODULE(module) => + // assert(module.isModule, "Expected module: " + module) + debuglog("generating LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags)); + if (clasz.symbol == module.moduleClass && jmethod.getName() != nme.readResolve.toString) + jcode.emitALOAD_0() + else + jcode.emitGETSTATIC(javaName(module) /* + "$" */ , + nme.MODULE_INSTANCE_FIELD.toString, + javaType(module)) + + case STORE_ARRAY_ITEM(kind) => + if(kind.isRefOrArrayType) { jcode.emitAASTORE() } + else { + (kind: @unchecked) match { + case UNIT => throw new IllegalArgumentException("invalid type for astore " + kind) + case BOOL | BYTE => jcode.emitBASTORE() + case SHORT => jcode.emitSASTORE() + case CHAR => jcode.emitCASTORE() + case INT => jcode.emitIASTORE() + case LONG => jcode.emitLASTORE() + case FLOAT => jcode.emitFASTORE() + case DOUBLE => jcode.emitDASTORE() + } + } - case CREATE_ARRAY(elem, dims) => - jcode.emitMULTIANEWARRAY(javaType(ArrayN(elem, dims)).asInstanceOf[JReferenceType], dims) + case STORE_LOCAL(local) => + jcode.emitSTORE(indexOf(local), javaType(local.kind)) - case IS_INSTANCE(tpe) => - tpe match { - case REFERENCE(cls) => - jcode emitINSTANCEOF new JObjectType(javaName(cls)) - case ARRAY(elem) => - jcode emitINSTANCEOF new JArrayType(javaType(elem)) - case _ => - abort("Unknown reference type in IS_INSTANCE: " + tpe) - } + case STORE_THIS(_) => + // this only works for impl classes because the self parameter comes first + // in the method signature. If that changes, this code has to be revisited. + jcode.emitASTORE_0() - case CHECK_CAST(tpe) => - tpe match { - case REFERENCE(cls) => - // No need to checkcast for Objects - if (cls != ObjectClass) - jcode emitCHECKCAST new JObjectType(javaName(cls)) - case ARRAY(elem) => - jcode emitCHECKCAST new JArrayType(javaType(elem)) - case _ => - abort("Unknown reference type in IS_INSTANCE: " + tpe) - } + case STORE_FIELD(field, isStatic) => + val owner = javaName(field.owner) + val fieldJName = javaName(field) + val fieldJType = javaType(field) + if (isStatic) jcode.emitPUTSTATIC(owner, fieldJName, fieldJType) + else jcode.emitPUTFIELD( owner, fieldJName, fieldJType) - case SWITCH(tags, branches) => - val tagArray = new Array[Array[Int]](tags.length) - var caze = tags - var i = 0 + case CALL_PRIMITIVE(primitive) => genPrimitive(primitive, instr.pos) - while (i < tagArray.length) { - tagArray(i) = new Array[Int](caze.head.length) - caze.head.copyToArray(tagArray(i), 0) - i += 1 - caze = caze.tail - } - val branchArray = jcode.newLabels(tagArray.length) - i = 0 - while (i < branchArray.length) { - branchArray(i) = labels(branches(i)) - i += 1 - } - debuglog("Emitting SWITCH:\ntags: " + tags + "\nbranches: " + branches) - jcode.emitSWITCH(tagArray, - branchArray, - labels(branches.last), - MIN_SWITCH_DENSITY) - () - - case JUMP(whereto) => - if (nextBlock != whereto) - jcode.emitGOTO_maybe_W(labels(whereto), false) // default to short jumps - - case CJUMP(success, failure, cond, kind) => - kind match { - case BOOL | BYTE | CHAR | SHORT | INT => + /** Special handling to access native Array.clone() */ + case call @ CALL_METHOD(definitions.Array_clone, Dynamic) => + val target: String = javaType(call.targetTypeKind).getSignature() + jcode.emitINVOKEVIRTUAL(target, "clone", arrayCloneType) + + case call @ CALL_METHOD(method, style) => genCallMethod(call) + + case BOX(kind) => + val Pair(mname, mtype) = jBoxTo(kind) + jcode.emitINVOKESTATIC(BoxesRunTime, mname, mtype) + + case UNBOX(kind) => + val Pair(mname, mtype) = jUnboxTo(kind) + jcode.emitINVOKESTATIC(BoxesRunTime, mname, mtype) + + case NEW(REFERENCE(cls)) => + val className = javaName(cls) + jcode emitNEW className + + case CREATE_ARRAY(elem, 1) => + if(elem.isRefOrArrayType) { jcode emitANEWARRAY javaType(elem).asInstanceOf[JReferenceType] } + else { jcode emitNEWARRAY javaType(elem) } + + case CREATE_ARRAY(elem, dims) => + jcode.emitMULTIANEWARRAY(javaType(ArrayN(elem, dims)).asInstanceOf[JReferenceType], dims) + + case IS_INSTANCE(tpe) => + tpe match { + case REFERENCE(cls) => jcode emitINSTANCEOF new JObjectType(javaName(cls)) + case ARRAY(elem) => jcode emitINSTANCEOF new JArrayType(javaType(elem)) + case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe) + } + + case CHECK_CAST(tpe) => + tpe match { + case REFERENCE(cls) => if (cls != ObjectClass) { jcode emitCHECKCAST new JObjectType(javaName(cls)) } // No need to checkcast for Objects + case ARRAY(elem) => jcode emitCHECKCAST new JArrayType(javaType(elem)) + case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe) + } + + case SWITCH(tags, branches) => + val tagArray = new Array[Array[Int]](tags.length) + var caze = tags + var i = 0 + + while (i < tagArray.length) { + tagArray(i) = new Array[Int](caze.head.length) + caze.head.copyToArray(tagArray(i), 0) + i += 1 + caze = caze.tail + } + val branchArray = jcode.newLabels(tagArray.length) + i = 0 + while (i < branchArray.length) { + branchArray(i) = labels(branches(i)) + i += 1 + } + debuglog("Emitting SWITCH:\ntags: " + tags + "\nbranches: " + branches) + jcode.emitSWITCH(tagArray, + branchArray, + labels(branches.last), + MIN_SWITCH_DENSITY) + () + + case JUMP(whereto) => + if (nextBlock != whereto) + jcode.emitGOTO_maybe_W(labels(whereto), false) // default to short jumps + + case CJUMP(success, failure, cond, kind) => + if(kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT if (nextBlock == success) { - jcode.emitIF_ICMP(conds(negate(cond)), labels(failure)) + jcode.emitIF_ICMP(conds(cond.negate()), labels(failure)) // .. and fall through to success label } else { jcode.emitIF_ICMP(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - - case REFERENCE(_) | ARRAY(_) => + } else if(kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_) if (nextBlock == success) { - jcode.emitIF_ACMP(conds(negate(cond)), labels(failure)) + jcode.emitIF_ACMP(conds(cond.negate()), labels(failure)) // .. and fall through to success label } else { jcode.emitIF_ACMP(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - - case _ => + } else { (kind: @unchecked) match { case LONG => jcode.emitLCMP() case FLOAT => @@ -1443,38 +1476,32 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with else jcode.emitDCMPL() } if (nextBlock == success) { - jcode.emitIF(conds(negate(cond)), labels(failure)) + jcode.emitIF(conds(cond.negate()), labels(failure)) // .. and fall through to success label } else { jcode.emitIF(conds(cond), labels(success)); if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - } + } - case CZJUMP(success, failure, cond, kind) => - kind match { - case BOOL | BYTE | CHAR | SHORT | INT => + case CZJUMP(success, failure, cond, kind) => + if(kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT if (nextBlock == success) { - jcode.emitIF(conds(negate(cond)), labels(failure)) + jcode.emitIF(conds(cond.negate()), labels(failure)) } else { jcode.emitIF(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - - case REFERENCE(_) | ARRAY(_) => + } else if(kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_) val Success = success val Failure = failure (cond, nextBlock) match { - case (EQ, Success) => - jcode emitIFNONNULL labels(failure) - case (NE, Failure) => - jcode emitIFNONNULL labels(success) - case (EQ, Failure) => - jcode emitIFNULL labels(success) - case (NE, Success) => - jcode emitIFNULL labels(failure) + case (EQ, Success) => jcode emitIFNONNULL labels(failure) + case (NE, Failure) => jcode emitIFNONNULL labels(success) + case (EQ, Failure) => jcode emitIFNULL labels(success) + case (NE, Success) => jcode emitIFNULL labels(failure) case (EQ, _) => jcode emitIFNULL labels(success) jcode.emitGOTO_maybe_W(labels(failure), false) @@ -1482,11 +1509,11 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with jcode emitIFNONNULL labels(success) jcode.emitGOTO_maybe_W(labels(failure), false) } - - case _ => + } else { (kind: @unchecked) match { case LONG => - jcode.emitLCONST_0(); jcode.emitLCMP() + jcode.emitLCONST_0() + jcode.emitLCMP() case FLOAT => jcode.emitFCONST_0() if (cond == LT || cond == LE) jcode.emitFCMPG() @@ -1497,263 +1524,254 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with else jcode.emitDCMPL() } if (nextBlock == success) { - jcode.emitIF(conds(negate(cond)), labels(failure)) + jcode.emitIF(conds(cond.negate()), labels(failure)) } else { jcode.emitIF(conds(cond), labels(success)) if (nextBlock != failure) jcode.emitGOTO_maybe_W(labels(failure), false) } - } + } - case RETURN(kind) => - jcode emitRETURN javaType(kind) + case RETURN(kind) => jcode emitRETURN javaType(kind) - case THROW(_) => - jcode.emitATHROW() + case THROW(_) => jcode.emitATHROW() - case DROP(kind) => - kind match { - case LONG | DOUBLE => jcode.emitPOP2() - case _ => jcode.emitPOP() - } + case DROP(kind) => + if(kind.isWideType) jcode.emitPOP2() + else jcode.emitPOP() - case DUP(kind) => - kind match { - case LONG | DOUBLE => jcode.emitDUP2() - case _ => jcode.emitDUP() - } + case DUP(kind) => + if(kind.isWideType) jcode.emitDUP2() + else jcode.emitDUP() - case MONITOR_ENTER() => - jcode.emitMONITORENTER() + case MONITOR_ENTER() => jcode.emitMONITORENTER() - case MONITOR_EXIT() => - jcode.emitMONITOREXIT() + case MONITOR_EXIT() => jcode.emitMONITOREXIT() - case SCOPE_ENTER(lv) => - varsInBlock += lv - lv.start = jcode.getPC() + case SCOPE_ENTER(lv) => + varsInBlock += lv + lv.start = jcode.getPC() - case SCOPE_EXIT(lv) => - if (varsInBlock(lv)) { - lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges - varsInBlock -= lv - } - else if (b.varsInScope(lv)) { - lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges - b.varsInScope -= lv - } - else dumpMethodAndAbort(method, "Illegal local var nesting") + case SCOPE_EXIT(lv) => + if (varsInBlock(lv)) { + lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges + varsInBlock -= lv + } + else if (b.varsInScope(lv)) { + lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges + b.varsInScope -= lv + } + else dumpMethodAndAbort(method, "Illegal local var nesting") - case LOAD_EXCEPTION(_) => - () - } + case LOAD_EXCEPTION(_) => + () + } - crtPC = jcode.getPC() + crtPC = jcode.getPC() -// assert(instr.pos.source.isEmpty || instr.pos.source.get == (clasz.cunit.source), "sources don't match") -// val crtLine = instr.pos.line.get(lastLineNr); + // assert(instr.pos.source.isEmpty || instr.pos.source.get == (clasz.cunit.source), "sources don't match") + // val crtLine = instr.pos.line.get(lastLineNr); - val crtLine = try { - if (instr.pos == NoPosition) lastLineNr else (instr.pos).line // check NoPosition to avoid costly exception - } catch { - case _: UnsupportedOperationException => - log("Warning: wrong position in: " + method) - lastLineNr - } + val crtLine = try { + if (instr.pos == NoPosition) lastLineNr else (instr.pos).line // check NoPosition to avoid costly exception + } catch { + case _: UnsupportedOperationException => + log("Warning: wrong position in: " + method) + lastLineNr + } - if (b.lastInstruction == instr) - endPC(b) = jcode.getPC() + if (instr eq lastInstr) { endPC(b) = jcode.getPC() } - //System.err.println("CRTLINE: " + instr.pos + " " + - // /* (if (instr.pos < clasz.cunit.source.content.length) clasz.cunit.source.content(instr.pos) else '*') + */ " " + crtLine); + //System.err.println("CRTLINE: " + instr.pos + " " + + // /* (if (instr.pos < clasz.cunit.source.content.length) clasz.cunit.source.content(instr.pos) else '*') + */ " " + crtLine); - if (crtPC > lastMappedPC) { - jcode.completeLineNumber(lastMappedPC, crtPC, crtLine) - lastMappedPC = crtPC - lastLineNr = crtLine + if (crtPC > lastMappedPC) { + jcode.completeLineNumber(lastMappedPC, crtPC, crtLine) + lastMappedPC = crtPC + lastLineNr = crtLine + } } - } - // local vars that survived this basic block - for (lv <- varsInBlock) { - lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges - } - for (lv <- b.varsInScope) { - lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges + // local vars that survived this basic block + for (lv <- varsInBlock) { + lv.ranges = (lv.start, jcode.getPC()) :: lv.ranges + } + for (lv <- b.varsInScope) { + lv.ranges = (labels(b).getAnchor(), jcode.getPC()) :: lv.ranges + } } - } - - /** - * @param primitive ... - * @param pos ... - */ - def genPrimitive(primitive: Primitive, pos: Position) { - primitive match { - case Negation(kind) => - kind match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitINEG() - case LONG => jcode.emitLNEG() - case FLOAT => jcode.emitFNEG() - case DOUBLE => jcode.emitDNEG() - case _ => abort("Impossible to negate a " + kind) - } - case Arithmetic(op, kind) => - op match { - case ADD => jcode.emitADD(javaType(kind)) - case SUB => - (kind: @unchecked) match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitISUB() - case LONG => jcode.emitLSUB() - case FLOAT => jcode.emitFSUB() - case DOUBLE => jcode.emitDSUB() + /** + * @param primitive ... + * @param pos ... + */ + def genPrimitive(primitive: Primitive, pos: Position) { + primitive match { + case Negation(kind) => + if(kind.isIntSizedType) { jcode.emitINEG() } + else { + kind match { + case LONG => jcode.emitLNEG() + case FLOAT => jcode.emitFNEG() + case DOUBLE => jcode.emitDNEG() + case _ => abort("Impossible to negate a " + kind) } + } - case MUL => - (kind: @unchecked) match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitIMUL() - case LONG => jcode.emitLMUL() - case FLOAT => jcode.emitFMUL() - case DOUBLE => jcode.emitDMUL() - } + case Arithmetic(op, kind) => + op match { + case ADD => + if(kind.isIntSizedType) { jcode.emitIADD() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLADD() + case FLOAT => jcode.emitFADD() + case DOUBLE => jcode.emitDADD() + } + } - case DIV => - (kind: @unchecked) match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitIDIV() - case LONG => jcode.emitLDIV() - case FLOAT => jcode.emitFDIV() - case DOUBLE => jcode.emitDDIV() - } + case SUB => + if(kind.isIntSizedType) { jcode.emitISUB() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLSUB() + case FLOAT => jcode.emitFSUB() + case DOUBLE => jcode.emitDSUB() + } + } - case REM => - (kind: @unchecked) match { - case BOOL | BYTE | CHAR | SHORT | INT => - jcode.emitIREM() - case LONG => jcode.emitLREM() - case FLOAT => jcode.emitFREM() - case DOUBLE => jcode.emitDREM() - } + case MUL => + if(kind.isIntSizedType) { jcode.emitIMUL() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLMUL() + case FLOAT => jcode.emitFMUL() + case DOUBLE => jcode.emitDMUL() + } + } - case NOT => - kind match { - case BOOL | BYTE | CHAR | SHORT | INT => + case DIV => + if(kind.isIntSizedType) { jcode.emitIDIV() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLDIV() + case FLOAT => jcode.emitFDIV() + case DOUBLE => jcode.emitDDIV() + } + } + + case REM => + if(kind.isIntSizedType) { jcode.emitIREM() } + else { + (kind: @unchecked) match { + case LONG => jcode.emitLREM() + case FLOAT => jcode.emitFREM() + case DOUBLE => jcode.emitDREM() + } + } + + case NOT => + if(kind.isIntSizedType) { jcode.emitPUSH(-1) jcode.emitIXOR() - case LONG => + } else if(kind == LONG) { jcode.emitPUSH(-1l) jcode.emitLXOR() - case _ => + } else { abort("Impossible to negate an " + kind) - } - - case _ => - abort("Unknown arithmetic primitive " + primitive) - } - - case Logical(op, kind) => (op, kind) match { - case (AND, LONG) => - jcode.emitLAND() - case (AND, INT) => - jcode.emitIAND() - case (AND, _) => - jcode.emitIAND() - if (kind != BOOL) - jcode.emitT2T(javaType(INT), javaType(kind)); - - case (OR, LONG) => - jcode.emitLOR() - case (OR, INT) => - jcode.emitIOR() - case (OR, _) => - jcode.emitIOR() - if (kind != BOOL) - jcode.emitT2T(javaType(INT), javaType(kind)); - - case (XOR, LONG) => - jcode.emitLXOR() - case (XOR, INT) => - jcode.emitIXOR() - case (XOR, _) => - jcode.emitIXOR() - if (kind != BOOL) - jcode.emitT2T(javaType(INT), javaType(kind)); - } - - case Shift(op, kind) => (op, kind) match { - case (LSL, LONG) => - jcode.emitLSHL() - case (LSL, INT) => - jcode.emitISHL() - case (LSL, _) => - jcode.emitISHL() - jcode.emitT2T(javaType(INT), javaType(kind)) - - case (ASR, LONG) => - jcode.emitLSHR() - case (ASR, INT) => - jcode.emitISHR() - case (ASR, _) => - jcode.emitISHR() - jcode.emitT2T(javaType(INT), javaType(kind)) - - case (LSR, LONG) => - jcode.emitLUSHR() - case (LSR, INT) => - jcode.emitIUSHR() - case (LSR, _) => - jcode.emitIUSHR() - jcode.emitT2T(javaType(INT), javaType(kind)) - } + } - case Comparison(op, kind) => ((op, kind): @unchecked) match { - case (CMP, LONG) => jcode.emitLCMP() - case (CMPL, FLOAT) => jcode.emitFCMPL() - case (CMPG, FLOAT) => jcode.emitFCMPG() - case (CMPL, DOUBLE) => jcode.emitDCMPL() - case (CMPG, DOUBLE) => jcode.emitDCMPL() - } + case _ => + abort("Unknown arithmetic primitive " + primitive) + } - case Conversion(src, dst) => - debuglog("Converting from: " + src + " to: " + dst) - if (dst == BOOL) { - println("Illegal conversion at: " + clasz + - " at: " + pos.source + ":" + pos.line) - } else - jcode.emitT2T(javaType(src), javaType(dst)) + case Logical(op, kind) => (op, kind) match { + case (AND, LONG) => jcode.emitLAND() + case (AND, INT) => jcode.emitIAND() + case (AND, _) => + jcode.emitIAND() + if (kind != BOOL) + jcode.emitT2T(javaType(INT), javaType(kind)); + + case (OR, LONG) => jcode.emitLOR() + case (OR, INT) => jcode.emitIOR() + case (OR, _) => + jcode.emitIOR() + if (kind != BOOL) + jcode.emitT2T(javaType(INT), javaType(kind)); + + case (XOR, LONG) => jcode.emitLXOR() + case (XOR, INT) => jcode.emitIXOR() + case (XOR, _) => + jcode.emitIXOR() + if (kind != BOOL) + jcode.emitT2T(javaType(INT), javaType(kind)); + } - case ArrayLength(_) => - jcode.emitARRAYLENGTH() + case Shift(op, kind) => (op, kind) match { + case (LSL, LONG) => jcode.emitLSHL() + case (LSL, INT) => jcode.emitISHL() + case (LSL, _) => + jcode.emitISHL() + jcode.emitT2T(javaType(INT), javaType(kind)) + + case (ASR, LONG) => jcode.emitLSHR() + case (ASR, INT) => jcode.emitISHR() + case (ASR, _) => + jcode.emitISHR() + jcode.emitT2T(javaType(INT), javaType(kind)) + + case (LSR, LONG) => jcode.emitLUSHR() + case (LSR, INT) => jcode.emitIUSHR() + case (LSR, _) => + jcode.emitIUSHR() + jcode.emitT2T(javaType(INT), javaType(kind)) + } - case StartConcat => - jcode emitNEW StringBuilderClassName - jcode.emitDUP() - jcode.emitINVOKESPECIAL(StringBuilderClassName, - JMethod.INSTANCE_CONSTRUCTOR_NAME, - JMethodType.ARGLESS_VOID_FUNCTION) - - case StringConcat(el) => - val jtype = el match { - case REFERENCE(_) | ARRAY(_) => JAVA_LANG_OBJECT - case _ => javaType(el) + case Comparison(op, kind) => ((op, kind): @unchecked) match { + case (CMP, LONG) => jcode.emitLCMP() + case (CMPL, FLOAT) => jcode.emitFCMPL() + case (CMPG, FLOAT) => jcode.emitFCMPG() + case (CMPL, DOUBLE) => jcode.emitDCMPL() + case (CMPG, DOUBLE) => jcode.emitDCMPL() } - jcode.emitINVOKEVIRTUAL(StringBuilderClassName, - "append", - new JMethodType(StringBuilderType, - Array(jtype))) - case EndConcat => - jcode.emitINVOKEVIRTUAL(StringBuilderClassName, - "toString", - toStringType) - case _ => - abort("Unimplemented primitive " + primitive) + case Conversion(src, dst) => + debuglog("Converting from: " + src + " to: " + dst) + if (dst == BOOL) { + println("Illegal conversion at: " + clasz + " at: " + pos.source + ":" + pos.line) + } else + jcode.emitT2T(javaType(src), javaType(dst)) + + case ArrayLength(_) => + jcode.emitARRAYLENGTH() + + case StartConcat => + jcode emitNEW StringBuilderClassName + jcode.emitDUP() + jcode.emitINVOKESPECIAL(StringBuilderClassName, + JMethod.INSTANCE_CONSTRUCTOR_NAME, + JMethodType.ARGLESS_VOID_FUNCTION) + + case StringConcat(el) => + val jtype = el match { + case REFERENCE(_) | ARRAY(_) => JAVA_LANG_OBJECT + case _ => javaType(el) + } + jcode.emitINVOKEVIRTUAL(StringBuilderClassName, + "append", + new JMethodType(StringBuilderType, + Array(jtype))) + case EndConcat => + jcode.emitINVOKEVIRTUAL(StringBuilderClassName, + "toString", + toStringType) + + case _ => + abort("Unimplemented primitive " + primitive) + } } - } // genCode starts here genBlocks(linearization) @@ -1823,10 +1841,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with def sizeOf(sym: Symbol): Int = sizeOf(toTypeKind(sym.tpe)) - def sizeOf(k: TypeKind): Int = k match { - case DOUBLE | LONG => 2 - case _ => 1 - } + def sizeOf(k: TypeKind): Int = if(k.isWideType) 2 else 1 def indexOf(m: IMethod, sym: Symbol): Int = { val Some(local) = m lookupLocal sym @@ -1843,9 +1858,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with * method. *Does not assume the parameters come first!* */ def computeLocalVarsIndex(m: IMethod) { - var idx = 1 - if (m.symbol.isStaticMember) - idx = 0; + var idx = if (m.symbol.isStaticMember) 0 else 1; for (l <- m.params) { debuglog("Index value for " + l + "{" + l.## + "}: " + idx) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala index 93d3d19ac8..8b08b4dc0d 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMUtil.scala @@ -54,14 +54,6 @@ trait GenJVMUtil { LE -> JExtendedCode.COND_LE, GE -> JExtendedCode.COND_GE ) - val negate = immutable.Map[TestOp, TestOp]( - EQ -> NE, - NE -> EQ, - LT -> GE, - GT -> LE, - LE -> GT, - GE -> LT - ) /** Specialized array conversion to prevent calling * java.lang.reflect.Array.newInstance via TraversableOnce.toArray |