From 258064826d62478fa6fb431ffd8f195272824e3a Mon Sep 17 00:00:00 2001 From: Iulian Dragos Date: Tue, 14 Nov 2006 10:15:34 +0000 Subject: Changed BOX/UNBOX to use TypeKind instead of Type. --- .../tools/nsc/backend/icode/BasicBlocks.scala | 13 +++++ .../scala/tools/nsc/backend/icode/Checkers.scala | 14 +++--- .../scala/tools/nsc/backend/icode/GenICode.scala | 4 +- .../scala/tools/nsc/backend/icode/Opcodes.scala | 4 +- .../scala/tools/nsc/backend/icode/TypeKinds.scala | 56 ++++++++++++++++++---- .../backend/icode/analysis/CopyPropagation.scala | 6 +++ .../backend/icode/analysis/TypeFlowAnalysis.scala | 8 ++++ .../scala/tools/nsc/backend/jvm/GenJVM.scala | 16 +++---- .../nsc/backend/opt/DeadCodeElimination.scala | 18 +++---- 9 files changed, 102 insertions(+), 37 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 00a1cc4c95..6c46e01af3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -61,6 +61,19 @@ trait BasicBlocks requires ICodes { // public: + /** Return the index of inst. Uses reference equality. + * Returns -1 if not found. + */ + def indexOf(inst: Instruction): Int = { + assert(closed) + var i = 0; + while (i < instrs.length) { + if (instrs(i) eq inst) return i + i = i + 1 + } + -1 + } + /** Compute an hashCode for the block */ override def hashCode() = label; diff --git a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala index a6a3f2c2d8..e7a456aee6 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Checkers.scala @@ -67,7 +67,7 @@ abstract class Checkers { val STRING = REFERENCE(definitions.StringClass) val SCALA_ALL = REFERENCE(definitions.AllClass) val SCALA_ALL_REF = REFERENCE(definitions.AllRefClass) - val CASE_CLASS = REFERENCE(definitions.getClass("scala.CaseClass")) +// val CASE_CLASS = REFERENCE(definitions.getClass("scala.CaseClass")) def checkICodes: Unit = { Console.println("[[consistency check at beginning of phase " + globalPhase.name + "]]") @@ -200,7 +200,7 @@ abstract class Checkers { /** Checks that tpe is a subtype of one of the allowed types */ def checkType(tpe: TypeKind, allowed: TypeKind*) = - if (isOneOf(tpe, allowed: _*) || tpe <:< CASE_CLASS) /* hack */ + if (isOneOf(tpe, allowed: _*)) () else error(tpe.toString() + " is not one of: " + allowed.toList.mkString("{", ", ", "}")); @@ -318,7 +318,7 @@ abstract class Checkers { val actualType = stack.pop; if (!(actualType <:< local.kind) && - actualType != CASE_CLASS && + //actualType != CASE_CLASS && local.kind != SCALA_ALL_REF) typeError(local.kind, actualType); @@ -327,8 +327,8 @@ abstract class Checkers { checkStack(1); val fieldType = toTypeKind(field.tpe); val actualType = stack.pop; - if (!(actualType <:< fieldType) && - actualType != CASE_CLASS) + if (!(actualType <:< fieldType)) + // && actualType != CASE_CLASS) typeError(fieldType, actualType); } else { checkStack(2); @@ -336,8 +336,8 @@ abstract class Checkers { case Pair(value, obj) => checkField(obj, field); val fieldType = toTypeKind(field.tpe); - if (fieldType != SCALA_ALL_REF && !(value <:< fieldType) - && value != CASE_CLASS) + if (fieldType != SCALA_ALL_REF && !(value <:< fieldType)) + //&& value != CASE_CLASS) typeError(fieldType, value); } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 4ecd9c7012..298fdc7ee4 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -640,7 +640,7 @@ abstract class GenICode extends SubComponent { log("BOX : " + fun.symbol.fullNameString); val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe)) val boxType = fun.symbol.owner.linkedClassOfClass.tpe - ctx1.bb.emit(BOX(boxType), expr.pos) + ctx1.bb.emit(BOX(toTypeKind(boxType)), expr.pos) ctx1 case Apply(fun @ _, List(expr)) if (definitions.isUnbox(fun.symbol)) => @@ -648,7 +648,7 @@ abstract class GenICode extends SubComponent { log("UNBOX : " + fun.symbol.fullNameString) val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe)) assert(expectedType.isValueType) - ctx1.bb.emit(UNBOX(expectedType.toType), expr.pos) + ctx1.bb.emit(UNBOX(expectedType), expr.pos) ctx1 case Apply(fun, args) => diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index f814aaa04f..d92106e52e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -306,13 +306,13 @@ trait Opcodes requires ICodes { else 1 } - case class BOX(boxType: Type) extends Instruction { + case class BOX(boxType: TypeKind) extends Instruction { override def toString(): String = "BOX " + boxType override def consumed = 1 override def produced = 1 } - case class UNBOX(boxType: Type) extends Instruction { + case class UNBOX(boxType: TypeKind) extends Instruction { override def toString(): String = "UNBOX " + boxType override def consumed = 1 override def produced = 1 diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index e06fd5e2e4..238f9319a7 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -51,15 +51,15 @@ trait TypeKinds requires ICodes { } def toType: Type = this match { - case UNIT => definitions.UnitClass.info - case BOOL => definitions.BooleanClass.info - case BYTE => definitions.ByteClass.info - case SHORT => definitions.ShortClass.info - case CHAR => definitions.CharClass.info - case INT => definitions.IntClass.info - case LONG => definitions.LongClass.info - case FLOAT => definitions.FloatClass.info - case DOUBLE => definitions.DoubleClass.info + case UNIT => definitions.UnitClass.tpe + case BOOL => definitions.BooleanClass.tpe + case BYTE => definitions.ByteClass.tpe + case SHORT => definitions.ShortClass.tpe + case CHAR => definitions.CharClass.tpe + case INT => definitions.IntClass.tpe + case LONG => definitions.LongClass.tpe + case FLOAT => definitions.FloatClass.tpe + case DOUBLE => definitions.DoubleClass.tpe case REFERENCE(cls) => typeRef(cls.typeConstructor.prefix, cls, Nil) case ARRAY(elem) => typeRef(definitions.ArrayClass.typeConstructor.prefix, definitions.ArrayClass, @@ -295,6 +295,44 @@ trait TypeKinds requires ICodes { } + /** A boxed value. */ + case class BOXED(kind: TypeKind) extends TypeKind { + override def toString(): String = + "BOXED(" + kind + ")" + + /** + * Approximate `lub'. The common type of two references is + * always AnyRef. For 'real' least upper bound wrt to subclassing + * use method 'lub'. + */ + override def maxType(other: TypeKind): TypeKind = + other match { + case REFERENCE(_) | ARRAY(_) | BOXED(_) => + REFERENCE(definitions.AnyRefClass) + case _ => + abort("Uncomparbale type kinds: ARRAY with " + other) + } + + /** Checks subtyping relationship. */ + override def <:<(other: TypeKind): Boolean = + other match { + case REFERENCE(sym) => + (sym == definitions.AnyRefClass || + sym == definitions.ObjectClass) // TODO: platform dependent! + + case BOXED(other) => + kind == other + + case _ => false + } + + override def equals(other: Any): Boolean = other match { + case BOXED(kind2) => kind == kind2 + case _ => false + } + + } + /** * Dummy TypeKind to represent the ConcatClass in a platform-independent * way. For JVM it would have been a REFERENCE to 'StringBuffer'. diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 00f1763945..3364f94e28 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -291,6 +291,12 @@ abstract class CopyPropagation { out = simulateCall(in, method, false); } + case BOX(tpe) => + out.stack = Unknown :: out.stack.drop(1) + + case UNBOX(tpe) => + out.stack = Unknown :: out.stack.drop(1) + case NEW(kind) => val v1 = kind match { diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index 79cc091f4f..45e5a8b61e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -253,6 +253,14 @@ abstract class TypeFlowAnalysis { stack.push(toTypeKind(method.info.resultType)); } + case BOX(kind) => + stack.pop + stack.push(BOXED(kind)) + + case UNBOX(kind) => + stack.pop + stack.push(kind) + case NEW(kind) => stack.push(kind); diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 979ed831c9..272d8c7d75 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -789,12 +789,12 @@ abstract class GenJVM extends SubComponent { } - case BOX(boxType) => - val boxedClass = definitions.boxedClass(boxType.symbol) - val mtype = new JMethodType(javaType(boxedClass), Array(javaType(boxType))) + case BOX(kind) => + val boxedClass = definitions.boxedClass(kind.toType.symbol) + val mtype = new JMethodType(javaType(boxedClass), Array(javaType(kind))) jcode.emitINVOKESTATIC(javaName(boxedClass), "box", mtype) - case UNBOX(boxType) if (boxType.symbol == definitions.BooleanClass) => + case UNBOX(BOOL) /* if (boxType.symbol == definitions.BooleanClass) */=> // if null emit false val nonNull = jcode.newLabel() jcode.emitDUP() @@ -810,13 +810,13 @@ abstract class GenJVM extends SubComponent { jcode.emitGETFIELD(boxedBoolean, "value", JType.BOOLEAN) lexit.anchorToNext() - case UNBOX(boxType) => + case UNBOX(boxKind) => // if null emit a zero of the appropriate kind val nonNull = jcode.newLabel() jcode.emitDUP() jcode.emitIFNONNULL(nonNull) jcode.emitPOP() - toTypeKind(boxType) match { + boxKind match { case BYTE => jcode.emitPUSH(0: Byte) case SHORT => jcode.emitPUSH(0: Short) case CHAR => jcode.emitPUSH(0: Char) @@ -830,9 +830,9 @@ abstract class GenJVM extends SubComponent { nonNull.anchorToNext() // else unbox the reference at the top of the stack jcode.emitCHECKCAST(new JObjectType(BOXED_NUMBER)) - val clazzName = boxType.symbol.name.toString() + val clazzName = boxKind.toType.symbol.name.toString() val unboxMethod = clazzName.toLowerCase() + "Value" - val mtype = new JMethodType(javaType(boxType), new Array[JType](0)) + val mtype = new JMethodType(javaType(boxKind), new Array[JType](0)) jcode.emitINVOKEVIRTUAL(BOXED_NUMBER, unboxMethod, mtype) lexit.anchorToNext() diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index 791dcd50c2..c23f7fcf07 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -62,7 +62,7 @@ abstract class DeadCodeElimination extends SubComponent { i match { case STORE_LOCAL(l) if (!live(l)) => - removeDefUse(bb, pos); + removeDefUse(bb, i); case _ => () } live = a.interpret(live, i); @@ -73,24 +73,24 @@ abstract class DeadCodeElimination extends SubComponent { * in the basic block. The `def' is the closest previous instruction which * produced the top value on the stack. */ - def removeDefUse(bb: BasicBlock, use: Int): Unit = { - bb.findDef(use) match { + def removeDefUse(bb: BasicBlock, use: Instruction): Unit = { + val usePos = bb.indexOf(use) + bb.findDef(usePos) match { case Some(defPos) => val definition = bb(defPos); if (isSafeToRemove(definition)) { - log("Removing instructions at BB " + bb + " def: " + definition + ", use: " + bb(use)); + log("Removing instructions at BB " + bb + " def: " + definition + ", use: " + use); if (definition.consumed == 0) { - bb.removeInstructionsAt(defPos, use) + bb.removeInstructionsAt(defPos, usePos) } else { bb.replaceInstruction(definition, definition.consumedTypes map DROP); - bb.removeInstructionsAt(use); + bb.removeInstructionsAt(usePos); } } case None => - val i = bb(use); - bb.replaceInstruction(i, i.consumedTypes map DROP); - log("Replaced dead " + i + " by DROP in bb " + bb); + bb.replaceInstruction(use, use.consumedTypes map DROP); + log("Replaced dead " + use + " by DROP in bb " + bb); } } -- cgit v1.2.3