diff options
author | Gilles Dubochet <gilles.dubochet@epfl.ch> | 2007-04-30 18:14:11 +0000 |
---|---|---|
committer | Gilles Dubochet <gilles.dubochet@epfl.ch> | 2007-04-30 18:14:11 +0000 |
commit | 750e57765b10d0f072eff68274047daa1c2040ae (patch) | |
tree | 8a3b19243e0ccc7ef54d6f5aaf4dd931120fd57d /src/compiler | |
parent | 10aa20170079d81f3e80d1cf5d0fc821336ae2d9 (diff) | |
download | scala-750e57765b10d0f072eff68274047daa1c2040ae.tar.gz scala-750e57765b10d0f072eff68274047daa1c2040ae.tar.bz2 scala-750e57765b10d0f072eff68274047daa1c2040ae.zip |
Changed Scala's value boxing scheme to be compa...
Changed Scala's value boxing scheme to be compatible with java's
wrapping classes.
- “Definitions” redefines what the boxed correspondants of value types are.
- “GenJVM” uses the new (un)boxing methods defined in “BoxesUtility” (MSIL not updated yet).
- “GenICode” special cases the “equals” method (to that of “Comparator”) in some cases to deal with Java's silly definition of equality on wrapped values.
- Various other fixes (in erasure to deal properly with boxing of labelled expressions, big integers, etc.).
Diffstat (limited to 'src/compiler')
5 files changed, 278 insertions, 217 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 5752b96240..a33a820e05 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -583,8 +583,11 @@ abstract class GenICode extends SubComponent { } else ctx1.bb.emit(CONSTANT(Constant(false))) } - else if (r.isValueType /*|| r.isArrayType */) - genBoxedConversion(l, r, ctx1, cast) + else if (r.isValueType && cast) { + assert(false) /* Erasure should have added an unboxing operation to prevent that. */ + } + else if (r.isValueType) + ctx.bb.emit(IS_INSTANCE(REFERENCE(definitions.boxedClass(r.toType.symbol)))) else genCast(l, r, ctx1, cast); @@ -653,8 +656,8 @@ abstract class GenICode extends SubComponent { if (settings.debug.value) log("BOX : " + fun.symbol.fullNameString); val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe)) - val boxType = fun.symbol.owner.linkedClassOfClass.tpe - ctx1.bb.emit(BOX(toTypeKind(boxType)), expr.pos) + val nativeKind = toTypeKind(expr.tpe) + ctx1.bb.emit(BOX(nativeKind), expr.pos) generatedType = ANY_REF_CLASS ctx1 @@ -663,8 +666,8 @@ abstract class GenICode extends SubComponent { log("UNBOX : " + fun.symbol.fullNameString) val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe)) assert(expectedType.isValueType) - generatedType = toTypeKind(fun.symbol.owner.linkedClassOfClass.tpe) - ctx1.bb.emit(UNBOX(generatedType), expr.pos) + generatedType = expectedType + ctx1.bb.emit(UNBOX(expectedType), expr.pos) ctx1 case Apply(fun, args) => @@ -999,11 +1002,6 @@ abstract class GenICode extends SubComponent { def isStaticSymbol(s: Symbol): Boolean = s.hasFlag(Flags.STATIC) || s.hasFlag(Flags.STATICMEMBER) || s.owner.isImplClass -// def isUnbox(s: Symbol): Boolean = ( -// s.name.==(nme.unbox) && s.owner.isModuleClass -// && s.owner.linkedClassOfClass.isSubClass(definitions.AnyValClass) -// ) - /** * Generate code that loads args into label parameters. */ @@ -1057,42 +1055,6 @@ abstract class GenICode extends SubComponent { } } - /** Generate a conversion from a reference type to a value type, like in - * Any -> Array[Int] or Any -> Int - * - * @param from ... - * @param to ... - * @param ctx ... - * @param cast ... - */ - def genBoxedConversion(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean): Unit = { - assert(to.isValueType || to.isArrayType, - "Expecting conversion to value type: " + to) - - val boxedCls = to match { - case ARRAY(ARRAY(_)) | ARRAY(REFERENCE(_)) => - definitions.BoxedObjectArrayClass - case ARRAY(elem) => - definitions.boxedArrayClass(elem.toType.symbol) - case _ => - if (cast) { - ctx.bb.emit(UNBOX(to)) - return - } - else - definitions.boxedClass(to.toType.symbol) - } - - if (cast) { - ctx.bb.emit(CHECK_CAST(REFERENCE(boxedCls))) - ctx.bb.emit(CONSTANT(Constant(definitions.signature(to.toType)))) - ctx.bb.emit(CALL_METHOD(definitions.getMember(boxedCls, "unbox"), - Dynamic)) - } else { - ctx.bb.emit(IS_INSTANCE(REFERENCE(boxedCls))) - } - } - def genCast(from: TypeKind, to: TypeKind, ctx: Context, cast: Boolean) = ctx.bb.emit(if (cast) CHECK_CAST(to) else IS_INSTANCE(to)) @@ -1331,8 +1293,8 @@ abstract class GenICode extends SubComponent { if (code == scalaPrimitives.ZNOT) { val Select(leftArg, _) = fun genCond(leftArg, ctx, elseCtx, thenCtx) - } else if ((code == scalaPrimitives.EQ || - code == scalaPrimitives.NE)) { + } + else if ((code == scalaPrimitives.EQ || code == scalaPrimitives.NE)) { val Select(leftArg, _) = fun; if (toTypeKind(leftArg.tpe).isReferenceType) { if (code == scalaPrimitives.EQ) @@ -1342,10 +1304,12 @@ abstract class GenICode extends SubComponent { } else genComparisonOp(leftArg, args.head, code); - } else if (scalaPrimitives.isComparisonOp(code)) { + } + else if (scalaPrimitives.isComparisonOp(code)) { val Select(leftArg, _) = fun genComparisonOp(leftArg, args.head, code) - } else { + } + else { code match { case scalaPrimitives.ZAND => val Select(leftArg, _) = fun @@ -1362,6 +1326,9 @@ abstract class GenICode extends SubComponent { genCond(args.head, ctxInterm, thenCtx, elseCtx) case _ => + // TODO (maybe): deal with the equals case here + // Current semantics: rich equals (from runtime.Comparator) only when == is used + // See genEqEqPrimitive for implementation var ctx1 = genLoad(tree, ctx, BOOL) ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL), tree.pos) ctx1.bb.close @@ -1403,51 +1370,76 @@ abstract class GenICode extends SubComponent { local } - (l, r) match { - // null == expr -> expr eq null - case (Literal(Constant(null)), expr) => - val ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) - ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) - ctx1.bb.close + def mustUseAnyComparator: Boolean = { + val lsym = l.tpe.symbol + val rsym = r.tpe.symbol + (lsym == definitions.ObjectClass) || + (rsym == definitions.ObjectClass) || + (lsym isNonBottomSubClass definitions.BoxedNumberClass)|| + (lsym isNonBottomSubClass definitions.BoxedCharacterClass) || + (rsym isNonBottomSubClass definitions.BoxedNumberClass) || + (rsym isNonBottomSubClass definitions.BoxedCharacterClass) + } - // expr == null -> if(expr eq null) true else expr.equals(null) - case (expr, Literal(Constant(null))) => - val eqEqTempLocal = getTempLocal - var ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) - ctx1.bb.emit(DUP(ANY_REF_CLASS)) - ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) - val nonNullCtx = ctx1.newBlock - ctx1.bb.emit(CZJUMP(thenCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)) - ctx1.bb.close + if (mustUseAnyComparator) { - nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) - nonNullCtx.bb.emit(CONSTANT(Constant(null)), r.pos) - nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) - nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) - nonNullCtx.bb.close + val ctx1 = genLoad(l, ctx, ANY_REF_CLASS) + val ctx2 = genLoad(r, ctx1, ANY_REF_CLASS) + ctx2.bb.emit(CALL_METHOD(definitions.Comparator_equals, Static(false))) + ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) + ctx2.bb.close - // l == r -> if (l eq null) r eq null else l.equals(r) - case _ => - val eqEqTempLocal = getTempLocal - var ctx1 = genLoad(l, ctx, ANY_REF_CLASS) - ctx1 = genLoad(r, ctx1, ANY_REF_CLASS) - val nullCtx = ctx1.newBlock - val nonNullCtx = ctx1.newBlock - ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) - ctx1.bb.emit(DUP(ANY_REF_CLASS)) - ctx1.bb.emit(CZJUMP(nullCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)) - ctx1.bb.close + } + else { - nullCtx.bb.emit(DROP(ANY_REF_CLASS), l.pos) // type of AnyRef - nullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal)) - nullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) - nullCtx.bb.close + (l, r) match { + // null == expr -> expr eq null + case (Literal(Constant(null)), expr) => + val ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) + ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) + ctx1.bb.close + + // expr == null -> if(expr eq null) true else expr.equals(null) + case (expr, Literal(Constant(null))) => + val eqEqTempLocal = getTempLocal + var ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) + ctx1.bb.emit(DUP(ANY_REF_CLASS)) + ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) + val nonNullCtx = ctx1.newBlock + ctx1.bb.emit(CZJUMP(thenCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)) + ctx1.bb.close + + nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) + nonNullCtx.bb.emit(CONSTANT(Constant(null)), r.pos) + nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) + nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) + nonNullCtx.bb.close + + // l == r -> if (l eq null) r eq null else l.equals(r) + case _ => + val eqEqTempLocal = getTempLocal + var ctx1 = genLoad(l, ctx, ANY_REF_CLASS) + ctx1 = genLoad(r, ctx1, ANY_REF_CLASS) + val nullCtx = ctx1.newBlock + val nonNullCtx = ctx1.newBlock + ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) + ctx1.bb.emit(DUP(ANY_REF_CLASS)) + ctx1.bb.emit(CZJUMP(nullCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)) + ctx1.bb.close + + nullCtx.bb.emit(DROP(ANY_REF_CLASS), l.pos) // type of AnyRef + nullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal)) + nullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) + nullCtx.bb.close + + nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) + nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) + nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) + nonNullCtx.bb.close + } - nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) - nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) - nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) - nonNullCtx.bb.close } + } /** diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 5f2613e59d..b55389216c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -57,7 +57,6 @@ abstract class GenJVM extends SubComponent { class BytecodeGenerator { val MIN_SWITCH_DENSITY = 0.7 val JAVA_LANG_STRINGBUFFER = "java.lang.StringBuffer" - val BOXED_NUMBER = "scala.runtime.BoxedNumber" val stringBufferType = new JObjectType(JAVA_LANG_STRINGBUFFER) val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY) @@ -788,51 +787,17 @@ abstract class GenJVM extends SubComponent { } 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(BOOL) /* if (boxType.symbol == definitions.BooleanClass) */ => - // if null emit false - val nonNull = jcode.newLabel() - jcode.emitDUP() - jcode.emitIFNONNULL(nonNull) - jcode.emitPOP() - jcode.emitPUSH(false) - val lexit = jcode.newLabel() - jcode.emitGOTO(lexit) - nonNull.anchorToNext() - // else unbox the reference at the top of the stack - val boxedBoolean = javaName(definitions.boxedClass(definitions.BooleanClass)) - jcode.emitCHECKCAST(new JObjectType(boxedBoolean)) - jcode.emitGETFIELD(boxedBoolean, "value", JType.BOOLEAN) - lexit.anchorToNext() - - case UNBOX(boxKind) => - // if null emit a zero of the appropriate kind - val nonNull = jcode.newLabel() - jcode.emitDUP() - jcode.emitIFNONNULL(nonNull) - jcode.emitPOP() - (boxKind: @unchecked) match { - case BYTE => jcode.emitPUSH(0: Byte) - case SHORT => jcode.emitPUSH(0: Short) - case CHAR => jcode.emitPUSH(0: Char) - case INT => jcode.emitPUSH(0: Int) - case LONG => jcode.emitPUSH(0: Long) - case FLOAT => jcode.emitPUSH(0.0f) - case DOUBLE => jcode.emitPUSH(0.0d) - } - val lexit = jcode.newLabel() - jcode.emitGOTO(lexit) - nonNull.anchorToNext() - // else unbox the reference at the top of the stack - jcode.emitCHECKCAST(new JObjectType(BOXED_NUMBER)) - val clazzName = boxKind.toType.symbol.name.toString - val unboxMethod = clazzName.toLowerCase() + "Value" - val mtype = new JMethodType(javaType(boxKind), new Array[JType](0)) - jcode.emitINVOKEVIRTUAL(BOXED_NUMBER, unboxMethod, mtype) - lexit.anchorToNext() + val kindSymbol = kind.toType.symbol + val boxMethod = definitions.boxMethod(kindSymbol) + val boxedType = definitions.boxedClass(kindSymbol) + val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind))) + jcode.emitINVOKESTATIC(javaName(definitions.BoxesUtilityModule), boxMethod.name.toString, mtype) + + case UNBOX(kind) => + val kindSymbol = kind.toType.symbol + val unboxMethod = definitions.unboxMethod(kindSymbol) + val mtype = new JMethodType(javaType(kind), Array(JObjectType.JAVA_LANG_OBJECT)) + jcode.emitINVOKESTATIC(javaName(definitions.BoxesUtilityModule), unboxMethod.name.toString, mtype) case NEW(REFERENCE(cls)) => val className = javaName(cls) diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 89c5c6e4c5..1c898082bc 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -37,6 +37,7 @@ trait Definitions { var AllClass: Symbol = _ var ClassClass: Symbol = _ + var MethodClass: Symbol = _ var StringClass: Symbol = _ var ThrowableClass: Symbol = _ var NullPointerExceptionClass: Symbol = _ @@ -105,6 +106,9 @@ trait Definitions { def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq); def checkDefinedMethod = getMember(ScalaRunTimeModule, "checkDefined") def isArrayMethod = getMember(ScalaRunTimeModule, "isArray") + var BoxesUtilityModule: Symbol = _ + var ComparatorModule: Symbol = _ + def Comparator_equals = getMember(ComparatorModule, nme.equals_) var RepeatedParamClass: Symbol = _ var ByNameParamClass: Symbol = _ //var UnsealedClass: Symbol = _ @@ -153,7 +157,7 @@ trait Definitions { def getProductArgs(tpe: Type): Option[List[Type]] = tpe.baseClasses.find { x => definitions.isExactProductType(x.tpe) } match { case Some(p) => Some(tpe.baseType(p).typeArgs) - case _ => None + case _ => None } var OptionClass: Symbol = _ @@ -197,9 +201,9 @@ trait Definitions { assert(ufn.isMethod) //Console.println("utl "+ufntpe+" "+ufntpe.symbol) ufn.name match { - case nme.unapply => unapplyTypeListFromReturnType(ufntpe) - case nme.unapplySeq => unapplyTypeListFromReturnTypeSeq(ufntpe) - case _ => throw new IllegalArgumentException("expected function symbol of extraction") + case nme.unapply => unapplyTypeListFromReturnType(ufntpe) + case nme.unapplySeq => unapplyTypeListFromReturnTypeSeq(ufntpe) + case _ => throw new IllegalArgumentException("expected function symbol of extraction") } } /** (the inverse of unapplyReturnTypeSeq) @@ -214,14 +218,14 @@ trait Definitions { val O = OptionClass val S = SomeClass tp.symbol match { // unapplySeqResultToMethodSig - case B => Nil - case O | S => - val prod = tp.typeArgs.head + case B => Nil + case O | S => + val prod = tp.typeArgs.head getProductArgs(prod) match { case Some(all @ (x1::x2::xs)) => all // n >= 2 case _ => prod::Nil // special n == 0 || n == 1 } - case _ => throw new IllegalArgumentException(tp.symbol + " in not in {boolean, option, some}") + case _ => throw new IllegalArgumentException(tp.symbol + " in not in {boolean, option, some}") } } @@ -234,13 +238,13 @@ trait Definitions { val tp = unapplyUnwrap(tp1) val O = OptionClass; val S = SomeClass; tp.symbol match { case O | S => - val ts = unapplyTypeListFromReturnType(tp1) - val last1 = ts.last.baseType(SeqClass) match { + val ts = unapplyTypeListFromReturnType(tp1) + val last1 = ts.last.baseType(SeqClass) match { case TypeRef(pre, seqClass, args) => typeRef(pre, RepeatedParamClass, args) - case _ => throw new IllegalArgumentException("last not seq") - } - ts.init ::: List(last1) - case _ => throw new IllegalArgumentException(tp.symbol + " in not in {option, some}") + case _ => throw new IllegalArgumentException("last not seq") + } + ts.init ::: List(last1) + case _ => throw new IllegalArgumentException(tp.symbol + " in not in {option, some}") } } @@ -250,11 +254,11 @@ trait Definitions { * else Some[Product[Ti]] def unapplyReturnType(elems: List[Type], useWildCards: Boolean) = if (elems.isEmpty) - BooleanClass.tpe + BooleanClass.tpe else if (elems.length == 1) - optionType(if(useWildCards) WildcardType else elems(0)) + optionType(if(useWildCards) WildcardType else elems(0)) else - productType({val es = elems; if(useWildCards) elems map { x => WildcardType} else elems}) + productType({val es = elems; if(useWildCards) elems map { x => WildcardType} else elems}) */ def unapplyReturnTypeExpected(argsLength: int) = argsLength match { @@ -305,9 +309,9 @@ trait Definitions { case _ => () } - case _ => () - } - } + case _ => () + } + } isCD } @@ -336,9 +340,9 @@ trait Definitions { var Object_synchronized: Symbol = _ var Object_isInstanceOf: Symbol = _ var Object_asInstanceOf: Symbol = _ - def Object_equals = getMember(ObjectClass, nme.equals_) - def Object_hashCode = getMember(ObjectClass, nme.hashCode_) - def Object_toString = getMember(ObjectClass, nme.toString_) + def Object_equals = getMember(ObjectClass, nme.equals_) + def Object_hashCode = getMember(ObjectClass, nme.hashCode_) + def Object_toString = getMember(ObjectClass, nme.toString_) var String_+ : Symbol = _ @@ -351,10 +355,11 @@ trait Definitions { // boxed classes var BoxedArrayClass: Symbol = _ - var BoxedNumberClass: Symbol = _ var BoxedAnyArrayClass: Symbol = _ var BoxedObjectArrayClass: Symbol = _ var BoxedUnitClass: Symbol = _ + var BoxedNumberClass: Symbol = _ + var BoxedCharacterClass: Symbol = _ var BoxedUnitModule: Symbol = _ def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT") var ObjectRefClass: Symbol = _ @@ -445,11 +450,82 @@ trait Definitions { .setInfo(mkTypeBounds(AllClass.typeConstructor, AnyClass.typeConstructor)) val boxedClass = new HashMap[Symbol, Symbol] - val unboxMethod = new HashMap[Symbol, Symbol] // Type -> Method - val boxMethod = new HashMap[Symbol, Symbol] // Type -> Method - val boxedArrayClass = new HashMap[Symbol, Symbol] - def isUnbox(m: Symbol) = m.name == nme.unbox && { + private var unboxMethodCache: collection.mutable.Map[Symbol, Symbol] = null + def unboxMethod = + if (unboxMethodCache != null) unboxMethodCache + else { + unboxMethodCache = new collection.mutable.Map[Symbol, Symbol] { + private val container = new HashMap[Symbol, Symbol] + private val classes = + List(BooleanClass, ByteClass, ShortClass, CharClass, IntClass, LongClass, FloatClass, DoubleClass) + for (val cl <- classes) + container.update(cl, getMember(BoxesUtilityModule, "unboxTo" + cl.name)) + def -= (key: Symbol): Unit = throw new Error() + def update(key: Symbol, value: Symbol): Unit = + container.update(key, value) + def size: Int = container.size + def elements = container.elements + def get(key: Symbol): Option[Symbol] = container.get(key) + } + unboxMethodCache + } + + private var boxMethodCache: collection.mutable.Map[Symbol, Symbol] = null + def boxMethod = + if (boxMethodCache != null) boxMethodCache + else { + boxMethodCache = new collection.mutable.Map[Symbol, Symbol] { + private val container = new HashMap[Symbol, Symbol] + private val BooleanClass = definitions.BooleanClass + private val ByteClass = definitions.ByteClass + private val CharClass = definitions.CharClass + private val ShortClass = definitions.ShortClass + private val IntClass = definitions.IntClass + private val LongClass = definitions.LongClass + private val FloatClass = definitions.FloatClass + private val DoubleClass = definitions.DoubleClass + private val classes = + List(BooleanClass, ByteClass, ShortClass, CharClass, IntClass, LongClass, FloatClass, DoubleClass) + for (val cl <- classes) { + val boxedName = + if (!forMSIL) cl match { + case BooleanClass => "Boolean" + case ByteClass => "Byte" + case CharClass => "Character" + case ShortClass => "Short" + case IntClass => "Integer" + case LongClass => "Long" + case FloatClass => "Float" + case DoubleClass => "Double" + } + else cl match { + case BooleanClass => "Boolean" + case ByteClass => "Byte" + case CharClass => "Char" + case ShortClass => "Int16" + case IntClass => "Int32" + case LongClass => "Int64" + case FloatClass => "Single" + case DoubleClass => "Double" + } + container.update(cl, getMember(BoxesUtilityModule, "boxTo" + boxedName)) + } + def -= (key: Symbol): Unit = throw new Error() + def update(key: Symbol, value: Symbol): Unit = { + assert(value.isMethod) + container.update(key, value) + } + def size: Int = container.size + def elements = container.elements + def get(key: Symbol): Option[Symbol] = container.get(key) + } + boxMethodCache + } + + val boxedArrayClass: collection.mutable.Map[Symbol, Symbol] = new HashMap[Symbol, Symbol] + + def isUnbox(m: Symbol) = (unboxMethod.values contains m) && { m.tpe match { case MethodType(_, restpe) => (unboxMethod get restpe.symbol) match { case Some(`m`) => true @@ -459,7 +535,8 @@ trait Definitions { } } - def isBox(m: Symbol) = m.name == nme.box && { + /** Test whether a method symbol is that of a boxing method. */ + def isBox(m: Symbol) = (boxMethod.values contains m) && { m.tpe match { case MethodType(List(argtpe), _) => (boxMethod get argtpe.symbol) match { case Some(`m`) => true @@ -473,9 +550,18 @@ trait Definitions { private val abbrvTag = new HashMap[Symbol, char] private def newValueClass(name: Name, tag: char): Symbol = { - def boxedName: String = - if (!forMSIL) "scala.runtime.Boxed" + name - else "System." + (name match { + val boxedName = + if (!forMSIL) name match { + case nme.Boolean => "Boolean" + case nme.Byte => "Byte" + case nme.Char => "Character" + case nme.Short => "Short" + case nme.Int => "Integer" + case nme.Long => "Long" + case nme.Float => "Float" + case nme.Double => "Double" + } + else name match { case nme.Boolean => "Boolean" case nme.Byte => "Byte" case nme.Char => "Char" @@ -484,11 +570,13 @@ trait Definitions { case nme.Long => "Int64" case nme.Float => "Single" case nme.Double => "Double" - }) + } + val boxedPathName = + if (!forMSIL) "java.lang." + boxedName else "System." + boxedName val clazz = newClass(ScalaPackageClass, name, List(AnyValClass.typeConstructor)) .setFlag(ABSTRACT | FINAL) - boxedClass(clazz) = getClass(boxedName) + boxedClass(clazz) = getClass(boxedPathName) boxedArrayClass(clazz) = getClass("scala.runtime.Boxed" + name + "Array") refClass(clazz) = getClass("scala.runtime." + name + "Ref") abbrvTag(clazz) = tag @@ -498,16 +586,11 @@ trait Definitions { val mclass = module.moduleClass mclass.setInfo(ClassInfoType(List(), newScope, mclass)) module.setInfo(mclass.tpe) - val box = newMethod(mclass, nme.box, List(clazz.typeConstructor), - ObjectClass.typeConstructor) - boxMethod(clazz) = box - val unbox = newMethod(mclass, nme.unbox, List(ObjectClass.typeConstructor), - clazz.typeConstructor) - unboxMethod(clazz) = unbox - clazz } + /** Sets-up symbols etc. for value classes, and their boxed versions. This + * method is called once from within the body of init. */ private def initValueClasses: Unit = { val booltype = BooleanClass.typeConstructor val boolparam = List(booltype) @@ -737,6 +820,7 @@ trait Definitions { StringClass = getClass(if (forMSIL) "System.String" else "java.lang.String") ClassClass = getClass(if (forMSIL) "System.Type" else "java.lang.Class") + MethodClass = getClass("java.lang.reflect.Method") ThrowableClass = getClass(if (forMSIL) "System.Exception" else "java.lang.Throwable") NullPointerExceptionClass = getClass(if (forMSIL) "System.NullReferenceException" else "java.lang.NullPointerException") @@ -789,6 +873,8 @@ trait Definitions { getClass(if (forMSIL) "System.IndexOutOfRangeException" else "java.lang.IndexOutOfBoundsException") ScalaRunTimeModule = getModule("scala.runtime.ScalaRunTime") + BoxesUtilityModule = getModule("scala.runtime.BoxesUtility") + ComparatorModule = getModule("scala.runtime.Comparator") RepeatedParamClass = newCovariantPolyClass( ScalaPackageClass, nme.REPEATED_PARAM_CLASS_NAME, tparam => typeRef(SeqClass.typeConstructor.prefix, SeqClass, List(tparam.typeConstructor))) @@ -852,11 +938,12 @@ trait Definitions { PatternWildcard = NoSymbol.newValue(NoPosition, "_").setInfo(AllClass.typeConstructor) - BoxedNumberClass = if (forMSIL) null else getClass("scala.runtime.BoxedNumber") + BoxedNumberClass = if (forMSIL) null else getClass("java.lang.Number") BoxedArrayClass = getClass("scala.runtime.BoxedArray") BoxedAnyArrayClass = getClass("scala.runtime.BoxedAnyArray") BoxedObjectArrayClass = getClass("scala.runtime.BoxedObjectArray") BoxedUnitClass = getClass("scala.runtime.BoxedUnit") + BoxedCharacterClass = getClass("java.lang.Character") BoxedUnitModule = getModule("scala.runtime.BoxedUnit") ObjectRefClass = getClass("scala.runtime.ObjectRef") @@ -902,8 +989,8 @@ trait Definitions { newMethod(StringClass, "toCharArray", List(), appliedType(ArrayClass.typeConstructor, List(charType))); - // Delegate_scalaCallerInfos = new HashMap() - Delegate_scalaCallerTargets = new HashMap() + // Delegate_scalaCallerInfos = new HashMap() + Delegate_scalaCallerTargets = new HashMap() } AnnotationDefaultAttr = newClass(RootClass, diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 63cddbbbc7..5afe99bed0 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -268,12 +268,14 @@ trait StdNames { val foreach = newTermName("foreach") val get = newTermName("get") val getClass_ = newTermName("getClass") + val getMethod_ = newTermName("getMethod") val hasAsInstance = newTermName("hasAsInstance") val hashCode_ = newTermName("hashCode") val hasNext = newTermName("hasNext") val head = newTermName("head") val identity = newTermName("identity") val intern = newTermName("intern") + val invoke_ = newTermName("invoke") val isInstanceOf_ = newTermName("isInstanceOf") val isInstanceOfErased = newTermName("isInstanceOf$erased") val isDefinedAt = newTermName("isDefinedAt") diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index c4cde60bb8..ddee05f16e 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -177,32 +177,42 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { class Eraser(context: Context) extends Typer(context) { /** Box `tree' of unboxed type */ - private def box(tree: Tree): Tree = - typed { - atPos(tree.pos) { - val sym = tree.tpe.symbol; - if (sym == UnitClass) { - if (treeInfo.isPureExpr(tree)) gen.mkAttributedRef(BoxedUnit_UNIT) - else Block(List(tree), gen.mkAttributedRef(BoxedUnit_UNIT)) - } else if (sym == ArrayClass) { - val elemClass = tree.tpe.typeArgs.head.symbol; - val boxedClass = if (isValueClass(elemClass)) boxedArrayClass(elemClass) - else BoxedObjectArrayClass; - Apply(Select(New(TypeTree(boxedClass.tpe)), nme.CONSTRUCTOR), List(tree)) - } else { - Apply(gen.mkAttributedRef(boxMethod(tree.tpe.symbol)), List(tree)). - setPos(tree.pos) setType ObjectClass.tpe + private def box(tree: Tree): Tree = tree match { + case LabelDef(name, params, rhs) => + val rhs1 = box(rhs) + copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe + case _ => + typed { + atPos(tree.pos) { + val sym = tree.tpe.symbol; + if (sym == UnitClass) { + if (treeInfo.isPureExpr(tree)) gen.mkAttributedRef(BoxedUnit_UNIT) + else Block(List(tree), gen.mkAttributedRef(BoxedUnit_UNIT)) + } else if (sym == ArrayClass) { + val elemClass = tree.tpe.typeArgs.head.symbol; + val boxedClass = if (isValueClass(elemClass)) boxedArrayClass(elemClass) + else BoxedObjectArrayClass; + Apply(Select(New(TypeTree(boxedClass.tpe)), nme.CONSTRUCTOR), List(tree)) + } else { + Apply(gen.mkAttributedRef(boxMethod(tree.tpe.symbol)), List(tree)). + setPos(tree.pos) setType ObjectClass.tpe + } } } - } + } /** generate ScalaRuntime.boxArray(tree) */ - private def boxArray(tree: Tree): Tree = - typed { - atPos(tree.pos) { - gen.mkRuntimeCall(nme.boxArray, List(tree)) + private def boxArray(tree: Tree): Tree = tree match { + case LabelDef(name, params, rhs) => + val rhs1 = boxArray(rhs) + copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe + case _ => + typed { + atPos(tree.pos) { + gen.mkRuntimeCall(nme.boxArray, List(tree)) + } } - } + } /** Unbox <code>tree</code> of boxed type to expected type <code>pt</code>. * @@ -210,24 +220,29 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { * @param pt the expected type. * @return the unboxed tree */ - private def unbox(tree: Tree, pt: Type): Tree = - typed { - atPos(tree.pos) { - if (pt.symbol == UnitClass) { - if (treeInfo.isPureExpr(tree)) Literal(()) - else Block(List(tree), Literal(())) - } - else if (pt.symbol == ArrayClass) { - val tree1 = adaptToType(tree, BoxedArrayClass.tpe) - gen.mkRuntimeCall(nme.arrayValue, List(tree1, Literal(pt.typeArgs.head))) - } - else { - atPos(tree.pos) { - Apply(gen.mkAttributedRef(unboxMethod(pt.symbol)), List(tree)) setType pt + private def unbox(tree: Tree, pt: Type): Tree = tree match { + case LabelDef(name, params, rhs) => + val rhs1 = unbox(rhs, pt) + copy.LabelDef(tree, name, params, rhs1) setType rhs1.tpe + case _ => + typed { + atPos(tree.pos) { + if (pt.symbol == UnitClass) { + if (treeInfo.isPureExpr(tree)) Literal(()) + else Block(List(tree), Literal(())) + } + else if (pt.symbol == ArrayClass) { + val tree1 = adaptToType(tree, BoxedArrayClass.tpe) + gen.mkRuntimeCall(nme.arrayValue, List(tree1, Literal(pt.typeArgs.head))) + } + else { + atPos(tree.pos) { + Apply(gen.mkAttributedRef(unboxMethod(pt.symbol)), List(tree)) setType pt + } } } } - } + } /** <p> * Generate a cast operation from <code>tree.tpe</code> to <code>pt</code>. @@ -762,7 +777,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } // todo: get rid of instanceOfErased // todo: also handle the case where the singleton type is buried in a compound - else if (fn.symbol == Any_isInstanceOf || fn.symbol == Any_isInstanceOfErased) + else if (fn.symbol == Any_isInstanceOf || fn.symbol == Any_isInstanceOfErased) fn match { case TypeApply(sel @ Select(qual, name), List(targ)) => def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree = |