summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormihaylov <mihaylov@epfl.ch>2006-11-05 19:11:08 +0000
committermihaylov <mihaylov@epfl.ch>2006-11-05 19:11:08 +0000
commit8e56e0e55bfacfd23fae87ed2f07151e2240aeaa (patch)
tree10bd413fe5fb33f37eee34031fa47828f5b8dfa7 /src
parent1e23988361e85f275b44041207988ef9aa0099f2 (diff)
downloadscala-8e56e0e55bfacfd23fae87ed2f07151e2240aeaa.tar.gz
scala-8e56e0e55bfacfd23fae87ed2f07151e2240aeaa.tar.bz2
scala-8e56e0e55bfacfd23fae87ed2f07151e2240aeaa.zip
Platform-independent boxing/unboxing
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala16
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala12
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala48
-rw-r--r--src/compiler/scala/tools/nsc/doc/DocGenerator.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala30
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala42
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
}
}
}