summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilles Dubochet <gilles.dubochet@epfl.ch>2007-04-30 18:14:11 +0000
committerGilles Dubochet <gilles.dubochet@epfl.ch>2007-04-30 18:14:11 +0000
commit750e57765b10d0f072eff68274047daa1c2040ae (patch)
tree8a3b19243e0ccc7ef54d6f5aaf4dd931120fd57d
parent10aa20170079d81f3e80d1cf5d0fc821336ae2d9 (diff)
downloadscala-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.).
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala172
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala57
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala175
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala89
-rw-r--r--src/library/scala/BigInt.scala13
-rw-r--r--src/library/scala/runtime/BoxedAnyArray.scala150
-rw-r--r--src/library/scala/runtime/BoxedBooleanArray.scala4
-rw-r--r--src/library/scala/runtime/BoxedByteArray.scala4
-rw-r--r--src/library/scala/runtime/BoxedCharArray.scala4
-rw-r--r--src/library/scala/runtime/BoxedDoubleArray.scala4
-rw-r--r--src/library/scala/runtime/BoxedFloatArray.scala4
-rw-r--r--src/library/scala/runtime/BoxedIntArray.scala4
-rw-r--r--src/library/scala/runtime/BoxedLongArray.scala4
-rw-r--r--src/library/scala/runtime/BoxedShortArray.scala4
-rw-r--r--src/library/scala/runtime/BoxesUtility.java167
-rw-r--r--src/library/scala/runtime/Comparator.java40
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;
+ }
+
+}