diff options
author | mihaylov <mihaylov@epfl.ch> | 2006-11-05 19:11:08 +0000 |
---|---|---|
committer | mihaylov <mihaylov@epfl.ch> | 2006-11-05 19:11:08 +0000 |
commit | 8e56e0e55bfacfd23fae87ed2f07151e2240aeaa (patch) | |
tree | 10bd413fe5fb33f37eee34031fa47828f5b8dfa7 | |
parent | 1e23988361e85f275b44041207988ef9aa0099f2 (diff) | |
download | scala-8e56e0e55bfacfd23fae87ed2f07151e2240aeaa.tar.gz scala-8e56e0e55bfacfd23fae87ed2f07151e2240aeaa.tar.bz2 scala-8e56e0e55bfacfd23fae87ed2f07151e2240aeaa.zip |
Platform-independent boxing/unboxing
7 files changed, 113 insertions, 41 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 9c20e63d3c..f2b6b66da6 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -635,6 +635,22 @@ abstract class GenICode extends SubComponent { } ctx1 + case Apply(fun @ _, List(expr)) if (definitions.isBox(fun.symbol)) => + 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(boxType), expr.pos) + ctx1 + + case Apply(fun @ _, List(expr)) if (definitions.isUnbox(fun.symbol)) => + if (settings.debug.value) + log("UNBOX : " + fun.symbol.fullNameString) + val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe)) + val boxType = fun.symbol.owner.linkedClassOfClass.tpe + ctx1.bb.emit(UNBOX(boxType), expr.pos) + ctx1 + case Apply(fun, args) => val sym = fun.symbol diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 5d08f3e102..f814aaa04f 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -306,6 +306,18 @@ trait Opcodes requires ICodes { else 1 } + case class BOX(boxType: Type) extends Instruction { + override def toString(): String = "BOX " + boxType + override def consumed = 1 + override def produced = 1 + } + + case class UNBOX(boxType: Type) extends Instruction { + override def toString(): String = "UNBOX " + boxType + override def consumed = 1 + override def produced = 1 + } + /** Create a new instance of a class through the specified constructor * Stack: ...:arg1:arg2:...:argn * ->: ...:ref diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index f78a53a623..946a4a550e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -59,6 +59,7 @@ 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,6 +789,53 @@ abstract class GenJVM extends SubComponent { } + case BOX(boxType) => + val boxedClass = definitions.boxedClass(boxType.symbol) + val mtype = new JMethodType(javaType(boxedClass), Array(javaType(boxType))) + jcode.emitINVOKESTATIC(javaName(boxedClass), "box", mtype) + + case UNBOX(boxType) 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(boxType) => + // if null emit a zero of the appropriate kind + val nonNull = jcode.newLabel() + jcode.emitDUP() + jcode.emitIFNONNULL(nonNull) + jcode.emitPOP() + toTypeKind(boxType) 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 = boxType.symbol.name.toString() + val unboxMethod = clazzName.toLowerCase() + "Value" + val mtype = new JMethodType(javaType(boxType), new Array[JType](0)) + jcode.emitINVOKEVIRTUAL(BOXED_NUMBER, unboxMethod, mtype) + lexit.anchorToNext() + case NEW(REFERENCE(cls)) => val className = javaName(cls) jcode.emitNEW(className) diff --git a/src/compiler/scala/tools/nsc/doc/DocGenerator.scala b/src/compiler/scala/tools/nsc/doc/DocGenerator.scala index db2f6eb64d..d8b04c56b0 100644 --- a/src/compiler/scala/tools/nsc/doc/DocGenerator.scala +++ b/src/compiler/scala/tools/nsc/doc/DocGenerator.scala @@ -795,7 +795,7 @@ abstract class DocGenerator extends Models { def sym = definitions.getClass("scala.runtime.BoxedLong") } new PrimitiveContentFrame { - def sym = definitions.BoxedNumberClass + def sym = definitions.getClass("scala.runtime.BoxedNumber") } val rsrcdir = "scala/tools/nsc/doc/".replace('/', File.separatorChar) for (val base <- List("style.css", "script.js")) { diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index da4a1cd384..c47f7ac0e3 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -6,7 +6,7 @@ package scala.tools.nsc.symtab -import scala.collection.mutable.HashMap +import scala.collection.mutable.{HashMap, HashSet} import scala.tools.nsc.util.Position import Flags._ @@ -22,7 +22,6 @@ trait Definitions requires SymbolTable { var EmptyPackageClass: Symbol = _ var emptypackagescope: Scope = null //debug - var JavaPackage: Symbol = _ var JavaLangPackage: Symbol = _ var ScalaPackage: Symbol = _ var ScalaPackageClass: Symbol = _ @@ -236,7 +235,6 @@ trait Definitions requires SymbolTable { var BoxedArrayClass: Symbol = _ var BoxedAnyArrayClass: Symbol = _ var BoxedObjectArrayClass: Symbol = _ - var BoxedNumberClass: Symbol = _ var BoxedUnitClass: Symbol = _ var BoxedUnitModule: Symbol = _ def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT") @@ -324,17 +322,39 @@ trait Definitions requires SymbolTable { .setInfo(TypeBounds(AllClass.typeConstructor, AnyClass.typeConstructor)) val boxedClass = new HashMap[Symbol, Symbol] + val unboxMethod = new HashMap[Symbol, Symbol] // Type -> Method + val isUnbox = new HashSet[Symbol] + val boxMethod = new HashMap[Symbol, Symbol] // Type -> Method + val isBox = new HashSet[Symbol] val boxedArrayClass = new HashMap[Symbol, Symbol] + val refClass = new HashMap[Symbol, Symbol] private val abbrvTag = new HashMap[Symbol, char] private def newValueClass(name: Name, tag: char): Symbol = { + def boxedName: String = + "scala.runtime.Boxed" + name val clazz = newClass(ScalaPackageClass, name, List(AnyValClass.typeConstructor)) - boxedClass(clazz) = getClass("scala.runtime.Boxed" + name) + boxedClass(clazz) = getClass(boxedName) boxedArrayClass(clazz) = getClass("scala.runtime.Boxed" + name + "Array") refClass(clazz) = getClass("scala.runtime." + name + "Ref") abbrvTag(clazz) = tag + + val module = ScalaPackageClass.newModule(NoPos, name); + ScalaPackageClass.info.decls.enter(module); + 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 + isBox += box + val unbox = newMethod(mclass, nme.unbox, List(ObjectClass.typeConstructor), + clazz.typeConstructor) + unboxMethod(clazz) = unbox + isUnbox += unbox + clazz } @@ -506,7 +526,6 @@ trait Definitions requires SymbolTable { RootClass.info.decls.enter(EmptyPackage) RootClass.info.decls.enter(RootPackage) - JavaPackage = getModule("java") JavaLangPackage = getModule("java.lang") ScalaPackage = getModule("scala") assert(ScalaPackage != null, "Scala package is null") @@ -641,7 +660,6 @@ trait Definitions requires SymbolTable { BoxedArrayClass = getClass("scala.runtime.BoxedArray") BoxedAnyArrayClass = getClass("scala.runtime.BoxedAnyArray") BoxedObjectArrayClass = getClass("scala.runtime.BoxedObjectArray") - BoxedNumberClass = getClass("scala.runtime.BoxedNumber") BoxedUnitClass = getClass("scala.runtime.BoxedUnit") BoxedUnitModule = getModule("scala.runtime.BoxedUnit") ObjectRefClass = getClass("scala.runtime.ObjectRef") diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 90c54e3d4e..dc6f0fdb31 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -296,10 +296,10 @@ trait StdNames requires SymbolTable { val this_ = newTermName("this") val throw_ = newTermName("throw") val true_ = newTermName("true") - val update = newTermName("update") val unapply = newTermName("unapply") val unapplySeq = newTermName("unapplySeq") - + val unbox = newTermName("unbox") + val update = newTermName("update") val value = newTermName("value") val view_ = newTermName("view") val tag = newTermName("$tag") diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 7795fa67e2..8825f6b0b9 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -172,8 +172,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { else BoxedObjectArrayClass; Apply(Select(New(TypeTree(boxedClass.tpe)), nme.CONSTRUCTOR), List(tree)) } else { - val boxedModule = boxedClass(tree.tpe.symbol).linkedModuleOfClass; - Apply(Select(gen.mkAttributedRef(boxedModule), nme.box), List(tree)) + Apply(gen.mkAttributedRef(boxMethod(tree.tpe.symbol)), List(tree)). + setPos(tree.pos) setType ObjectClass.tpe } } } @@ -186,14 +186,6 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } - /** The method-name xxxValue, where Xxx is a numeric value class name */ - def unboxOp(tp: Type): Name = { - val clazzName = tp.symbol.name.toString() - newTermName( - //String.valueOf((clazzName.charAt(0) + ('a' - 'A')).asInstanceOf[char]) + - clazzName.charAt(0).toLowerCase + clazzName.substring(1) + "Value") - } - /** Unbox `tree' of boxed type to expected type `pt' */ private def unbox(tree: Tree, pt: Type): Tree = typed { @@ -201,28 +193,14 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { if (pt.symbol == UnitClass) { if (treeInfo.isPureExpr(tree)) Literal(()) else Block(List(tree), Literal(())) - } else { - if (pt.symbol == BooleanClass) { - val tree1 = adaptToType(tree, boxedClass(BooleanClass).tpe) - gen.mkRuntimeCall(nme.booleanValue, List(tree1)) - } else if (pt.symbol == ArrayClass) { - val tree1 = adaptToType(tree, BoxedArrayClass.tpe) -/* - val elemClass = pt.typeArgs.head.symbol; - val elemTag = - if (isValueClass(elemClass)) - gen.mkRuntimeCall(newTermName(elemClass.name.toString() + "Tag"), List()) - else - Literal(signature(pt.typeArgs.head)); -*/ - //Console.println("unboxing " + tree + ":" + tree.tpe + " to " + pt);//DEBUG - //gen.mkRuntimeCall(nme.arrayValue, List(tree1, elemTag)) - gen.mkRuntimeCall(nme.arrayValue, List(tree1, Literal(pt.typeArgs.head))) - } else { - assert(isNumericValueClass(pt.symbol)); - val tree1 = adaptToType(tree, BoxedNumberClass.tpe); - gen.mkRuntimeCall(unboxOp(pt), List(tree1)) - } + } + else if (pt.symbol == ArrayClass) { + val tree1 = adaptToType(tree, BoxedArrayClass.tpe) + gen.mkRuntimeCall(nme.arrayValue, List(tree1, Literal(pt.typeArgs.head))) + } + else { + Apply(gen.mkAttributedRef(unboxMethod(pt.symbol)), List(tree)). + setPos(tree.pos) setType pt } } } |