diff options
17 files changed, 583 insertions, 314 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 = diff --git a/src/library/scala/BigInt.scala b/src/library/scala/BigInt.scala index 9e98ec5a3e..bcdff55261 100644 --- a/src/library/scala/BigInt.scala +++ b/src/library/scala/BigInt.scala @@ -115,7 +115,7 @@ object BigInt { * @version 1.0, 15/07/2003 */ @serializable -class BigInt(val bigInteger: BigInteger) extends runtime.BoxedNumber { +class BigInt(val bigInteger: BigInteger) extends java.lang.Number { /** Returns the hash code for this BigInt. */ override def hashCode(): Int = this.bigInteger.hashCode() @@ -123,9 +123,10 @@ class BigInt(val bigInteger: BigInteger) extends runtime.BoxedNumber { /** Compares this BigInt with the specified value for equality. */ override def equals (that: Any): boolean = that match { - case that: runtime.BoxedDouble => this.bigInteger.doubleValue == that.doubleValue - case that: runtime.BoxedFloat => this.bigInteger.floatValue == that.floatValue - case that: runtime.BoxedNumber => this equals BigInt(that.longValue) + case that: java.lang.Double => this.bigInteger.doubleValue == that.doubleValue + case that: java.lang.Float => this.bigInteger.floatValue == that.floatValue + case that: java.lang.Number => this equals BigInt(that.longValue) + case that: java.lang.Character => this equals BigInt(that.charValue.asInstanceOf[Int]) case _ => false } @@ -300,14 +301,14 @@ class BigInt(val bigInteger: BigInteger) extends runtime.BoxedNumber { * Note that this conversion can lose information about the overall magnitude of the * BigInt value as well as return a result with the opposite sign. */ - def byteValue = intValue.toByte + override def byteValue = intValue.toByte /** Converts this BigInt to a <tt>short</tt>. * If the BigInt is too big to fit in a byte, only the low-order 16 bits are returned. * Note that this conversion can lose information about the overall magnitude of the * BigInt value as well as return a result with the opposite sign. */ - def shortValue = intValue.toShort + override def shortValue = intValue.toShort /** Converts this BigInt to a <tt>char</tt>. * If the BigInt is too big to fit in a char, only the low-order 16 bits are returned. diff --git a/src/library/scala/runtime/BoxedAnyArray.scala b/src/library/scala/runtime/BoxedAnyArray.scala index 2c8711d763..d6093fe027 100644 --- a/src/library/scala/runtime/BoxedAnyArray.scala +++ b/src/library/scala/runtime/BoxedAnyArray.scala @@ -31,21 +31,21 @@ final class BoxedAnyArray(val length: Int) extends BoxedArray { if (unboxed eq null) boxed(index); else if (elemClass eq classOf[Int]) - Int.box(unboxed.asInstanceOf[Array[Int]](index)) + BoxesUtility.boxToInteger(unboxed.asInstanceOf[Array[Int]](index)) else if (elemClass eq classOf[Double]) - Double.box(unboxed.asInstanceOf[Array[Double]](index)) + BoxesUtility.boxToDouble(unboxed.asInstanceOf[Array[Double]](index)) else if (elemClass eq classOf[Float]) - Float.box(unboxed.asInstanceOf[Array[Float]](index)) + BoxesUtility.boxToFloat(unboxed.asInstanceOf[Array[Float]](index)) else if (elemClass eq classOf[Long]) - Long.box(unboxed.asInstanceOf[Array[Long]](index)) + BoxesUtility.boxToLong(unboxed.asInstanceOf[Array[Long]](index)) else if (elemClass eq classOf[Char]) - Char.box(unboxed.asInstanceOf[Array[Char]](index)) + BoxesUtility.boxToCharacter(unboxed.asInstanceOf[Array[Char]](index)) else if (elemClass eq classOf[Byte]) - Byte.box(unboxed.asInstanceOf[Array[Byte]](index)) + BoxesUtility.boxToByte(unboxed.asInstanceOf[Array[Byte]](index)) else if (elemClass eq classOf[Short]) - Short.box(unboxed.asInstanceOf[Array[Short]](index)) + BoxesUtility.boxToShort(unboxed.asInstanceOf[Array[Short]](index)) else if (elemClass eq classOf[Boolean]) - Boolean.box(unboxed.asInstanceOf[Array[Boolean]](index)) + BoxesUtility.boxToBoolean(unboxed.asInstanceOf[Array[Boolean]](index)) else unboxed.asInstanceOf[Array[AnyRef]](index) } @@ -55,21 +55,21 @@ final class BoxedAnyArray(val length: Int) extends BoxedArray { if (unboxed eq null) boxed(index) = elem else if (elemClass eq classOf[Int]) - unboxed.asInstanceOf[Array[Int]](index) = Int.unbox(elem) + unboxed.asInstanceOf[Array[Int]](index) = BoxesUtility.unboxToInt(elem) else if (elemClass eq classOf[Double]) - unboxed.asInstanceOf[Array[Double]](index) = Double.unbox(elem) + unboxed.asInstanceOf[Array[Double]](index) = BoxesUtility.unboxToDouble(elem) else if (elemClass eq classOf[Float]) - unboxed.asInstanceOf[Array[Float]](index) = Float.unbox(elem) + unboxed.asInstanceOf[Array[Float]](index) = BoxesUtility.unboxToFloat(elem) else if (elemClass eq classOf[Long]) - unboxed.asInstanceOf[Array[Long]](index) = Long.unbox(elem) + unboxed.asInstanceOf[Array[Long]](index) = BoxesUtility.unboxToLong(elem) else if (elemClass eq classOf[Char]) - unboxed.asInstanceOf[Array[Char]](index) = Char.unbox(elem) + unboxed.asInstanceOf[Array[Char]](index) = BoxesUtility.unboxToChar(elem) else if (elemClass eq classOf[Byte]) - unboxed.asInstanceOf[Array[Byte]](index) = Byte.unbox(elem) + unboxed.asInstanceOf[Array[Byte]](index) = BoxesUtility.unboxToByte(elem) else if (elemClass eq classOf[Short]) - unboxed.asInstanceOf[Array[Short]](index) = Short.unbox(elem) + unboxed.asInstanceOf[Array[Short]](index) = BoxesUtility.unboxToShort(elem) else if (elemClass eq classOf[Boolean]) - unboxed.asInstanceOf[Array[Boolean]](index) = Boolean.unbox(elem) + unboxed.asInstanceOf[Array[Boolean]](index) = BoxesUtility.unboxToBoolean(elem) else unboxed.asInstanceOf[Array[AnyRef]](index) = elem } @@ -89,75 +89,75 @@ final class BoxedAnyArray(val length: Int) extends BoxedArray { if (unboxed eq null) { this.elemClass = elemClass; if (elemClass eq classOf[Int]) { - val newvalue = new Array[Int](length) - var i = 0 - while (i < length) { - newvalue(i) = Int.unbox(boxed(i)) - i = i + 1 - } - unboxed = newvalue + val newvalue = new Array[Int](length) + var i = 0 + while (i < length) { + newvalue(i) = BoxesUtility.unboxToInt(boxed(i)) + i = i + 1 + } + unboxed = newvalue } else if (elemClass eq classOf[Double]) { - val newvalue = new Array[Double](length) - var i = 0 - while (i < length) { - newvalue(i) = Double.unbox(boxed(i)) - i = i + 1 - } - unboxed = newvalue; + val newvalue = new Array[Double](length) + var i = 0 + while (i < length) { + newvalue(i) = BoxesUtility.unboxToDouble(boxed(i)) + i = i + 1 + } + unboxed = newvalue; } else if (elemClass eq classOf[Float]) { - val newvalue = new Array[Float](length) - var i = 0 - while (i < length) { - newvalue(i) = Float.unbox(boxed(i)) - i = i + 1 - } - unboxed = newvalue; + val newvalue = new Array[Float](length) + var i = 0 + while (i < length) { + newvalue(i) = BoxesUtility.unboxToFloat(boxed(i)) + i = i + 1 + } + unboxed = newvalue; } else if (elemClass eq classOf[Long]) { - val newvalue = new Array[Long](length) - var i = 0 - while (i < length) { - newvalue(i) = Long.unbox(boxed(i)) - i = i + 1 - } - unboxed = newvalue; + val newvalue = new Array[Long](length) + var i = 0 + while (i < length) { + newvalue(i) = BoxesUtility.unboxToLong(boxed(i)) + i = i + 1 + } + unboxed = newvalue; } else if (elemClass eq classOf[Char]) { - val newvalue = new Array[Char](length) - var i = 0 - while (i < length) { - newvalue(i) = Char.unbox(boxed(i)) - i = i + 1 - } - unboxed = newvalue + val newvalue = new Array[Char](length) + var i = 0 + while (i < length) { + newvalue(i) = BoxesUtility.unboxToChar(boxed(i)) + i = i + 1 + } + unboxed = newvalue } else if (elemClass eq classOf[Byte]) { - val newvalue = new Array[Byte](length) - var i = 0 - while (i < length) { - newvalue(i) = Byte.unbox(boxed(i)) - i = i + 1 - } - unboxed = newvalue; + val newvalue = new Array[Byte](length) + var i = 0 + while (i < length) { + newvalue(i) = BoxesUtility.unboxToByte(boxed(i)) + i = i + 1 + } + unboxed = newvalue; } else if (elemClass eq classOf[Short]) { - val newvalue = new Array[Short](length) - var i = 0 - while (i < length) { - newvalue(i) = Short.unbox(boxed(i)) - i = i + 1 - } - unboxed = newvalue; + val newvalue = new Array[Short](length) + var i = 0 + while (i < length) { + newvalue(i) = BoxesUtility.unboxToShort(boxed(i)) + i = i + 1 + } + unboxed = newvalue; } else if (elemClass eq classOf[Boolean]) { - val newvalue = new Array[Boolean](length) - var i = 0 - while (i < length) { - newvalue(i) = Boolean.unbox(boxed(i)) - i = i + 1 - } - unboxed = newvalue; + val newvalue = new Array[Boolean](length) + var i = 0 + while (i < length) { + newvalue(i) = BoxesUtility.unboxToBoolean(boxed(i)) + i = i + 1 + } + unboxed = newvalue; } else if (elemClass == boxed.getClass().getComponentType()) { // todo: replace with ScalaRunTime.AnyRef.class - unboxed = boxed + unboxed = boxed } else { - unboxed = Platform.createArray(elemClass, length); - Platform.arraycopy(boxed, 0, unboxed, 0, length); + unboxed = Platform.createArray(elemClass, length); + Platform.arraycopy(boxed, 0, unboxed, 0, length); } boxed = null } diff --git a/src/library/scala/runtime/BoxedBooleanArray.scala b/src/library/scala/runtime/BoxedBooleanArray.scala index 1f0567abad..e0ff708205 100644 --- a/src/library/scala/runtime/BoxedBooleanArray.scala +++ b/src/library/scala/runtime/BoxedBooleanArray.scala @@ -19,10 +19,10 @@ final class BoxedBooleanArray(val value: Array[Boolean]) extends BoxedArray { def length: Int = value.length - def apply(index: Int): Any = Boolean.box(value(index)) + def apply(index: Int): Any = BoxesUtility.boxToBoolean(value(index)) def update(index: Int, elem: Any): Unit = { - value(index) = Boolean.unbox(elem.asInstanceOf[AnyRef]) + value(index) = BoxesUtility.unboxToBoolean(elem.asInstanceOf[AnyRef]) } def unbox(elemTag: String): AnyRef = value diff --git a/src/library/scala/runtime/BoxedByteArray.scala b/src/library/scala/runtime/BoxedByteArray.scala index 753dbaea04..cf3d6bee6a 100644 --- a/src/library/scala/runtime/BoxedByteArray.scala +++ b/src/library/scala/runtime/BoxedByteArray.scala @@ -19,10 +19,10 @@ final class BoxedByteArray(val value: Array[Byte]) extends BoxedArray { def length: Int = value.length - def apply(index: Int): Any = Byte.box(value(index)) + def apply(index: Int): Any = BoxesUtility.boxToByte(value(index)) def update(index: Int, elem: Any): Unit = { - value(index) = Byte.unbox(elem.asInstanceOf[AnyRef]) + value(index) = BoxesUtility.unboxToByte(elem.asInstanceOf[AnyRef]) } def unbox(elemTag: String): AnyRef = value diff --git a/src/library/scala/runtime/BoxedCharArray.scala b/src/library/scala/runtime/BoxedCharArray.scala index adb14dda51..c13a31134a 100644 --- a/src/library/scala/runtime/BoxedCharArray.scala +++ b/src/library/scala/runtime/BoxedCharArray.scala @@ -19,10 +19,10 @@ final class BoxedCharArray(val value: Array[Char]) extends BoxedArray { def length: Int = value.length - def apply(index: Int): Any = Char.box(value(index)) + def apply(index: Int): Any = BoxesUtility.boxToCharacter(value(index)) def update(index: Int, elem: Any): Unit = { - value(index) = Char.unbox(elem.asInstanceOf[AnyRef]) + value(index) = BoxesUtility.unboxToChar(elem.asInstanceOf[AnyRef]) } def unbox(elemTag: String): AnyRef = value diff --git a/src/library/scala/runtime/BoxedDoubleArray.scala b/src/library/scala/runtime/BoxedDoubleArray.scala index 9a4564e439..08c3b6b843 100644 --- a/src/library/scala/runtime/BoxedDoubleArray.scala +++ b/src/library/scala/runtime/BoxedDoubleArray.scala @@ -19,10 +19,10 @@ final class BoxedDoubleArray(val value: Array[Double]) extends BoxedArray { def length: Int = value.length - def apply(index: Int): Any = Double.box(value(index)) + def apply(index: Int): Any = BoxesUtility.boxToDouble(value(index)) def update(index: Int, elem: Any): Unit = { - value(index) = Double.unbox(elem.asInstanceOf[AnyRef]) + value(index) = BoxesUtility.unboxToDouble(elem.asInstanceOf[AnyRef]) } def unbox(elemTag: String): AnyRef = value diff --git a/src/library/scala/runtime/BoxedFloatArray.scala b/src/library/scala/runtime/BoxedFloatArray.scala index 1b8ccb3797..13424f136b 100644 --- a/src/library/scala/runtime/BoxedFloatArray.scala +++ b/src/library/scala/runtime/BoxedFloatArray.scala @@ -19,10 +19,10 @@ final class BoxedFloatArray(val value: Array[Float]) extends BoxedArray { def length: Int = value.length - def apply(index: Int): Any = Float.box(value(index)) + def apply(index: Int): Any = BoxesUtility.boxToFloat(value(index)) def update(index: Int, elem: Any): Unit = { - value(index) = Float.unbox(elem.asInstanceOf[AnyRef]) + value(index) = BoxesUtility.unboxToFloat(elem.asInstanceOf[AnyRef]) } def unbox(elemTag: String): AnyRef = value diff --git a/src/library/scala/runtime/BoxedIntArray.scala b/src/library/scala/runtime/BoxedIntArray.scala index d2f5fd0371..a64f4fdb60 100644 --- a/src/library/scala/runtime/BoxedIntArray.scala +++ b/src/library/scala/runtime/BoxedIntArray.scala @@ -19,10 +19,10 @@ final class BoxedIntArray(val value: Array[Int]) extends BoxedArray { def length: Int = value.length - def apply(index: Int): Any = Int.box(value(index)) + def apply(index: Int): Any = BoxesUtility.boxToInteger(value(index)) def update(index: Int, elem: Any): Unit = { - value(index) = Int.unbox(elem.asInstanceOf[AnyRef]) + value(index) = BoxesUtility.unboxToInt(elem.asInstanceOf[AnyRef]) } def unbox(elemTag: String): AnyRef = value diff --git a/src/library/scala/runtime/BoxedLongArray.scala b/src/library/scala/runtime/BoxedLongArray.scala index 6accc84484..db4b266e1b 100644 --- a/src/library/scala/runtime/BoxedLongArray.scala +++ b/src/library/scala/runtime/BoxedLongArray.scala @@ -19,10 +19,10 @@ final class BoxedLongArray(val value: Array[Long]) extends BoxedArray { def length: Int = value.length - def apply(index: Int): Any = Long.box(value(index)) + def apply(index: Int): Any = BoxesUtility.boxToLong(value(index)) def update(index: Int, elem: Any): Unit = { - value(index) = Long.unbox(elem.asInstanceOf[AnyRef]) + value(index) = BoxesUtility.unboxToLong(elem.asInstanceOf[AnyRef]) } def unbox(elemTag: String): AnyRef = value diff --git a/src/library/scala/runtime/BoxedShortArray.scala b/src/library/scala/runtime/BoxedShortArray.scala index 161b7b921b..229ee46727 100644 --- a/src/library/scala/runtime/BoxedShortArray.scala +++ b/src/library/scala/runtime/BoxedShortArray.scala @@ -19,10 +19,10 @@ final class BoxedShortArray(val value: Array[Short]) extends BoxedArray { def length: Int = value.length - def apply(index: Int): Any = Short.box(value(index)) + def apply(index: Int): Any = BoxesUtility.boxToShort(value(index)) def update(index: Int, elem: Any): Unit = { - value(index) = Short.unbox(elem.asInstanceOf[AnyRef]) + value(index) = BoxesUtility.unboxToShort(elem.asInstanceOf[AnyRef]) } def unbox(elemTag: String): AnyRef = value diff --git a/src/library/scala/runtime/BoxesUtility.java b/src/library/scala/runtime/BoxesUtility.java new file mode 100644 index 0000000000..3edfef81f6 --- /dev/null +++ b/src/library/scala/runtime/BoxesUtility.java @@ -0,0 +1,167 @@ +package scala.runtime; + +public class BoxesUtility { + + private static int charLowBound = 0; + private static int charUpBound = 255; + private static Character[] charCache = new Character[charUpBound - charLowBound + 1]; + + private static int byteLowBound = -128; + private static int byteUpBound = 127; + private static Byte[] byteCache = new Byte[byteUpBound - byteLowBound + 1]; + + private static int shortLowBound = -128; + private static int shortUpBound = 127; + private static Short[] shortCache = new Short[shortUpBound - shortLowBound + 1]; + + private static int intLowBound = -128; + private static int intUpBound = 1024; + private static Integer[] intCache = new Integer[intUpBound - intLowBound + 1]; + + private static int longLowBound = -128; + private static int longUpBound = 1024; + private static Long[] longCache = new Long[longUpBound - longLowBound + 1]; + + static { + int idx = 0; + while (idx <= charUpBound - charLowBound) { + charCache[idx] = new Character((char)(idx + charLowBound)); + idx = idx + 1; + } + idx = 0; + while (idx <= byteUpBound - byteLowBound) { + byteCache[idx] = new Byte((byte)(idx + byteLowBound)); + idx = idx + 1; + } + idx = 0; + while (idx <= shortUpBound - shortLowBound) { + shortCache[idx] = new Short((short)(idx + shortLowBound)); + idx = idx + 1; + } + idx = 0; + while (idx <= intUpBound - intLowBound) { + intCache[idx] = new Integer((int)(idx + intLowBound)); + idx = idx + 1; + } + idx = 0; + while (idx <= longUpBound - longLowBound) { + longCache[idx] = new Long((long)(idx + longLowBound)); + idx = idx + 1; + } + } + + public static Boolean boxToBoolean(boolean b) { + return b ? Boolean.TRUE : Boolean.FALSE; + } + + public static Character boxToCharacter(char c) { + if (c >= charLowBound && c <= charUpBound) + return charCache[(int)c - charLowBound]; + else + return new Character(c); + } + + public static Byte boxToByte(byte b) { + if (b >= byteLowBound && b <= byteUpBound) + return byteCache[(int)b - byteLowBound]; + else + return new Byte(b); + } + + public static Short boxToShort(short s) { + if (s >= shortLowBound && s <= shortUpBound) + return shortCache[(int)s - shortLowBound]; + else + return new Short(s); + } + + public static Integer boxToInteger(int i) { + if (i >= intLowBound && i <= intUpBound) + return intCache[(int)i - intLowBound]; + else + return new Integer(i); + } + + public static Long boxToLong(long l) { + if (l >= longLowBound && l <= longUpBound) + return longCache[(int)l - longLowBound]; + else + return new Long(l); + } + + public static Float boxToFloat(float f) { + return new Float(f); + } + + public static Double boxToDouble(double d) { + return new Double(d); + } + + public static boolean unboxToBoolean(Object b) { + return b == null ? false : ((Boolean)b).booleanValue(); + } + + public static char unboxToChar(Object c) { + if (c == null) + return 0; + else if (c instanceof Character) + return ((Character)c).charValue(); + else + return ((char)((Number)c).intValue()); + } + + public static byte unboxToByte(Object b) { + if (b == null) + return 0; + else if (b instanceof Number) + return ((Number)b).byteValue(); + else + return ((byte)((Character)b).charValue()); + } + + public static short unboxToShort(Object s) { + if (s == null) + return 0; + else if (s instanceof Number) + return ((Number)s).shortValue(); + else + return ((short)((Character)s).charValue()); + } + + public static int unboxToInt(Object i) { + if (i == null) + return 0; + else if (i instanceof Number) + return ((Number)i).intValue(); + else + return ((int)((Character)i).charValue()); + } + + public static long unboxToLong(Object l) { + if (l == null) + return 0; + else if (l instanceof Number) + return ((Number)l).longValue(); + else + return ((long)((Character)l).charValue()); + } + + public static float unboxToFloat(Object f) { + if (f == null) + return 0.0f; + else if (f instanceof Number) + return ((Number)f).floatValue(); + else + return ((float)((Character)f).charValue()); + } + + public static double unboxToDouble(Object d) { + if (d == null) + return 0.0; + else if (d instanceof Number) + return ((Number)d).doubleValue(); + else + return ((double)((Character)d).charValue()); + } + +} diff --git a/src/library/scala/runtime/Comparator.java b/src/library/scala/runtime/Comparator.java new file mode 100644 index 0000000000..b090d5052e --- /dev/null +++ b/src/library/scala/runtime/Comparator.java @@ -0,0 +1,40 @@ +package scala.runtime; + +public class Comparator { + + /* A rich implementation of the equals method that overrides the default equals because Java's boxed primitives are + * utterly broken. This equals is inserted instead of a normal equals by the Scala compiler (in the icode phase, + * method genEqEqPrimitive) only when either side of the comparison is a subclass of AnyVal, of java.lang.Number, of + * java.lang.Character or is exactly Any or AnyRef. */ + public static boolean equals(Object a, Object b) { + if (a == null) + return b == null; + else if (a.equals(b)) + return true; + else if (a == b) + return true; + else if ((a instanceof Byte || a instanceof Short || a instanceof Integer) && b instanceof Number) + return ((Number)a).intValue() == ((Number)b).intValue(); + else if (a instanceof Number && (b instanceof Byte || b instanceof Short || b instanceof Integer)) + return ((Number)a).intValue() == ((Number)b).intValue(); + else if (a instanceof Long && b instanceof Number) + return ((Long)a).longValue() == ((Number)b).longValue(); + else if (a instanceof Number && b instanceof Long) + return ((Number)a).longValue() == ((Long)b).longValue(); + else if (a instanceof Float && b instanceof Number) + return ((Float)a).floatValue() == ((Number)b).floatValue(); + else if (a instanceof Number && b instanceof Float) + return ((Number)a).floatValue() == ((Float)b).floatValue(); + else if (a instanceof Number && b instanceof Number) + return ((Number)a).doubleValue() == ((Number)b).doubleValue(); + else if (a instanceof Number && b instanceof Character) + return ((Number)a).intValue() == ((Character)b).charValue(); + else if (a instanceof Character && b instanceof Number) + return ((Character)a).charValue() == ((Number)b).intValue(); + else if (a instanceof Character && b instanceof Character) + return ((Character)a).charValue() == ((Character)b).charValue(); + else + return false; + } + +} |