summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-11-21 23:55:06 +0000
committerPaul Phillips <paulp@improving.org>2009-11-21 23:55:06 +0000
commit442766475e500840284167b09b148fe00e00ef34 (patch)
tree7831ed0cb2f0e337b0c90c5af28c99f2334a1848
parent40dabcbb6a3f4fb3e129172361592097156eaa31 (diff)
downloadscala-442766475e500840284167b09b148fe00e00ef34.tar.gz
scala-442766475e500840284167b09b148fe00e00ef34.tar.bz2
scala-442766475e500840284167b09b148fe00e00ef34.zip
Cleanup of Cleanup.
duplicated boxing code in the right location.
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala22
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala21
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala194
4 files changed, 108 insertions, 133 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 569b0f7b37..5d0b69e0da 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -199,6 +199,10 @@ trait TreeDSL {
if (guards.isEmpty) EmptyTree
else guards reduceLeft gen.mkAnd
+ def OR(guards: Tree*) =
+ if (guards.isEmpty) EmptyTree
+ else guards reduceLeft gen.mkOr
+
def IF(tree: Tree) = new IfStart(tree, EmptyTree)
def TRY(tree: Tree) = new TryStart(tree, Nil, EmptyTree)
def BLOCK(xs: Tree*) = Block(xs.init.toList, xs.last)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 4d6757dd80..22934a78a7 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -28,7 +28,8 @@ abstract class GenICode extends SubComponent {
import icodes.opcodes._
import definitions.{
ArrayClass, ObjectClass, ThrowableClass,
- Object_equals, Object_isInstanceOf, Object_asInstanceOf
+ Object_equals, Object_isInstanceOf, Object_asInstanceOf,
+ isMaybeBoxed
}
import scalaPrimitives.{
isArrayOp, isComparisonOp, isLogicalOp,
@@ -1332,23 +1333,8 @@ abstract class GenICode extends SubComponent {
* comparison might have a run-time type subtype of java.lang.Number or java.lang.Character.
* When it is statically known that both sides are equal and subtypes of Number of Character,
* not using the rich equality is possible (their own equals method will do ok.)*/
- def mustUseAnyComparator: Boolean = {
- import definitions._
-
- /** The various ways a boxed primitive might materialize at runtime. */
- def isJavaBoxed(sym: Symbol) =
- (sym == ObjectClass) ||
- (sym == SerializableClass) ||
- (sym == ComparableClass) ||
- (sym isNonBottomSubClass BoxedNumberClass) ||
- (sym isNonBottomSubClass BoxedCharacterClass)
-
- def isBoxed(sym: Symbol): Boolean =
- if (forMSIL) (sym isNonBottomSubClass BoxedNumberClass)
- else isJavaBoxed(sym)
-
- isBoxed(l.tpe.typeSymbol) && isBoxed(r.tpe.typeSymbol)
- }
+ def mustUseAnyComparator: Boolean =
+ isMaybeBoxed(l.tpe.typeSymbol) && isMaybeBoxed(r.tpe.typeSymbol)
if (mustUseAnyComparator) {
// when -optimise is on we call the @inline-version of equals, found in ScalaRunTime
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index c65e206a0c..aa4234fbfb 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -95,6 +95,11 @@ trait Definitions {
def Boolean_and = getMember(BooleanClass, nme.ZAND)
def Boolean_or = getMember(BooleanClass, nme.ZOR)
+ def ScalaValueClasses = List(
+ UnitClass, ByteClass, ShortClass, IntClass, LongClass,
+ CharClass, FloatClass, DoubleClass, BooleanClass
+ )
+
// exceptions and other throwables
lazy val ThrowableClass = getClass(sn.Throwable)
lazy val NullPointerExceptionClass = getClass(sn.NPException)
@@ -125,10 +130,10 @@ trait Definitions {
// fundamental reference classes
lazy val ScalaObjectClass = getClass("scala.ScalaObject")
lazy val PartialFunctionClass = getClass("scala.PartialFunction")
+ lazy val SymbolClass = getClass("scala.Symbol")
lazy val StringClass = getClass(sn.String)
lazy val ClassClass = getClass(sn.Class)
def Class_getMethod = getMember(ClassClass, nme.getMethod_)
- lazy val SymbolClass = getClass("scala.Symbol")
// fundamental modules
lazy val PredefModule: Symbol = getModule("scala.Predef")
@@ -142,7 +147,7 @@ trait Definitions {
def Predef_conforms = getMember(PredefModule, nme.conforms)
lazy val ConsoleModule: Symbol = getModule("scala.Console")
lazy val ScalaRunTimeModule: Symbol = getModule("scala.runtime.ScalaRunTime")
- lazy val SymbolModule: Symbol = getModule("scala.Symbol")
+ lazy val SymbolModule: Symbol = getModule("scala.Symbol")
def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq)
def checkDefinedMethod = getMember(ScalaRunTimeModule, "checkDefined")
def isArrayMethod = getMember(ScalaRunTimeModule, "isArray")
@@ -408,6 +413,18 @@ trait Definitions {
lazy val BoxedFloatClass = getClass("java.lang.Float")
lazy val BoxedDoubleClass = getClass("java.lang.Double")
+ /** The various ways a boxed primitive might materialize at runtime. */
+ def isMaybeBoxed(sym: Symbol) =
+ if (forMSIL)
+ sym isNonBottomSubClass BoxedNumberClass
+ else {
+ (sym == ObjectClass) ||
+ (sym == SerializableClass) ||
+ (sym == ComparableClass) ||
+ (sym isNonBottomSubClass BoxedNumberClass) ||
+ (sym isNonBottomSubClass BoxedCharacterClass)
+ }
+
lazy val BoxedUnitClass = getClass("scala.runtime.BoxedUnit")
lazy val BoxedUnitModule = getModule("scala.runtime.BoxedUnit")
def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT")
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 1806035596..9bd8337106 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -53,7 +53,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
localTyper typed { atPos(pos)(tree) }
private def classConstantMethod(pos: Position, sig: String): Symbol =
- (classConstantMeth get sig) getOrElse {
+ classConstantMeth.getOrElseUpdate(sig, {
val forName = getMember(ClassClass.linkedModuleOfClass, nme.forName)
val owner = currentOwner.enclClass
@@ -70,9 +70,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
)
newDefs.append(cdef, mdef)
- classConstantMeth.update(sig, meth)
meth
- }
+ })
override def transformUnit(unit: CompilationUnit) =
unit.body = transform(unit.body)
@@ -80,7 +79,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
/** A value class is defined to be only Java-compatible values: unit is
* not part of it, as opposed to isValueClass in definitions. scala.Int is
* a value class, java.lang.Integer is not. */
- def isValueClass(sym: Symbol) = boxedClass contains sym
+ def isJavaValueClass(sym: Symbol) = boxedClass contains sym
override def transform(tree: Tree): Tree = tree match {
@@ -350,13 +349,16 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
}
val qualSym = qual.tpe.typeSymbol
val methSym = ad.symbol
+ def args = qual :: params
+
+ /** Normal non-Array call */
def defaultCall = {
// reflective method call machinery
- val invokeName = MethodClass.tpe member nme.invoke_ // reflect.Method.invoke(...)
- def cache = REF(reflectiveMethodCache(ad.symbol.name.toString, paramTypes)) // cache Symbol
- def lookup = Apply(cache, List(qual GETCLASS)) // get Method object from cache
- def args = ArrayValue(TypeTree(ObjectClass.tpe), params) // args for invocation
- def invocation = (lookup DOT invokeName)(qual, args) // .invoke(qual, ...)
+ val invokeName = MethodClass.tpe member nme.invoke_ // reflect.Method.invoke(...)
+ def cache = REF(reflectiveMethodCache(ad.symbol.name.toString, paramTypes)) // cache Symbol
+ def lookup = Apply(cache, List(qual GETCLASS)) // get Method object from cache
+ def invokeArgs = ArrayValue(TypeTree(ObjectClass.tpe), params) // args for invocation
+ def invocation = (lookup DOT invokeName)(qual, invokeArgs) // .invoke(qual, ...)
// exception catching machinery
val invokeExc = currentOwner.newValue(ad.pos, mkTerm()) setInfo InvocationTargetExceptionClass.tpe
@@ -364,53 +366,43 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
def catchBody = Throw(Apply(Select(Ident(invokeExc), nme.getCause), Nil))
// try { method.invoke } catch { case e: InvocationTargetExceptionClass => throw e.getCause() }
- TRY (invocation) CATCH { CASE (catchVar) ==> catchBody } ENDTRY
+ fixResult( TRY (invocation) CATCH { CASE (catchVar) ==> catchBody } ENDTRY )
}
- def useValueOperator = {
- def isBoxed(qualSym: Symbol): Boolean =
- (qualSym isNonBottomSubClass BoxedNumberClass) ||
- (!forMSIL && (qualSym isNonBottomSubClass BoxedCharacterClass))
- ((qualSym == definitions.ObjectClass) || isBoxed(qualSym)) && // may be a boxed value class
+
+ def useValueOperator =
+ isMaybeBoxed(qualSym) && // may be a boxed value class
(getPrimitiveReplacementForStructuralCall isDefinedAt methSym.name) &&
- ((resType :: paramTypes) forall (x => isValueClass(x.typeSymbol))) // issue #1110
- }
- def useArrayOperator =
- ((qualSym == definitions.ObjectClass) || (qualSym == definitions.ArrayClass)) && (
- (methSym.name == nme.length && params.isEmpty) ||
- (methSym.name == nme.update && (structResType.typeSymbol eq UnitClass)) ||
- (methSym.name == nme.apply && params.size == 1)
- )
- val callCode = if (useValueOperator) {
- val (operator, test) = getPrimitiveReplacementForStructuralCall(methSym.name)
- def args = qual :: params
- fixResult((IF (test) THEN (REF(operator) APPLY args) ELSE defaultCall))
+ ((resType :: paramTypes) forall (x => isJavaValueClass(x.typeSymbol))) // issue #1110
+
+ def isArrayMethodSignature =
+ (methSym.name == nme.length && params.isEmpty) ||
+ (methSym.name == nme.update && (structResType.typeSymbol eq UnitClass)) ||
+ (methSym.name == nme.apply && params.size == 1)
+
+ def isDefinitelyArray = isArrayMethodSignature && (qualSym == ArrayClass)
+ def isMaybeArray = isArrayMethodSignature && (qualSym == ObjectClass) // precondition: !isDefinitelyArray
+
+ def genArrayCall = methSym.name match {
+ case nme.length => REF(boxMethod(IntClass)) APPLY (REF(arrayLengthMethod) APPLY args)
+ case nme.update => REF(arrayUpdateMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)), args(2))
+ case nme.apply => REF(arrayApplyMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)))
}
- else if (useArrayOperator) {
- val args = qual :: params
- val operatorCall = // what follows is incredibly ugly. this dirty fix should be deal with at the next cleanup of cleanup.
- if (methSym.name == nme.length)
- (REF(boxMethod(IntClass)) APPLY (REF(arrayLengthMethod) APPLY args))
- else if (methSym.name == nme.update)
- (REF(arrayUpdateMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1)), args(2)))
- else
- (REF(arrayApplyMethod) APPLY List(args(0), (REF(unboxMethod(IntClass)) APPLY args(1))))
- (IF (qual IS_OBJ arrayType(ObjectClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(ByteClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(ShortClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(IntClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(LongClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(FloatClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(DoubleClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(CharClass.tpe)) THEN operatorCall
- ELSE (IF (qual IS_OBJ arrayType(BooleanClass.tpe)) THEN operatorCall
- ELSE fixResult(defaultCall)
- )))))))))
+ def genArrayTest = {
+ def oneTest(s: Symbol) = qual IS_OBJ arrayType(s.tpe)
+ OR((ObjectClass :: ScalaValueClasses filterNot (_ eq UnitClass)) map oneTest: _*)
}
- else fixResult(defaultCall)
- localTyper.typed(callCode)
- }
- def getClass(q: Tree): Tree = (q DOT nme.getClass_)()
+ val callCode =
+ if (useValueOperator) {
+ val (operator, test) = getPrimitiveReplacementForStructuralCall(methSym.name)
+ IF (test) THEN fixResult(REF(operator) APPLY args) ELSE defaultCall
+ }
+ else if (isDefinitelyArray) genArrayCall
+ else if (isMaybeArray) IF (genArrayTest) THEN genArrayCall ELSE defaultCall
+ else defaultCall
+
+ localTyper typed callCode
+ }
if (settings.refinementMethodDispatch.value == "invoke-dynamic") {
/* val guardCallSite: Tree = {
@@ -456,7 +448,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val sym = currentOwner.newValue(ad.pos, mkTerm("qual")) setInfo qual0.tpe
qual = REF(sym)
- def structResType = if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType
+ def structResType = if (isJavaValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType
BLOCK(
VAL(sym) === qual0,
callAsReflective(mparams map (_.tpe), resType, structResType)
@@ -531,7 +523,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
case Literal(c) if (c.tag == ClassTag) && !forMSIL=>
val tpe = c.typeValue
typedWithPos(tree.pos) {
- if (isValueClass(tpe.typeSymbol) || tpe.typeSymbol == definitions.UnitClass) {
+ if (isValueClass(tpe.typeSymbol)) {
if (tpe.typeSymbol == UnitClass)
Select(REF(BoxedUnit_TYPE), BoxedUnit_TYPE)
else
@@ -603,10 +595,10 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
* have little in common.
*/
case symapp @ Apply(Select(Select(a @ Ident(nme.scala_), b @ nme.Symbol), nme.apply),
- List(Literal(Constant(symname)))) =>
+ List(Literal(Constant(symname: String)))) =>
// add the symbol name to a map if it's not there already
- val rhs = treeGen.mkCast(Apply(treeGen.scalaDot(nme.Symbol), List(Literal(Constant(symname)))), symbolType)
- val (staticFieldSym, sfdef, sfinit) = getSymbolStaticField(symapp.pos, symname.asInstanceOf[String], rhs, symapp)
+ val rhs = gen.mkCast(Apply(gen.scalaDot(nme.Symbol), List(Literal(Constant(symname)))), symbolType)
+ val (staticFieldSym, sfdef, sfinit) = getSymbolStaticField(symapp.pos, symname, rhs, symapp)
// create a reference to a static field
val ntree = typedWithPos(symapp.pos)(REF(staticFieldSym))
@@ -616,18 +608,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
super.transform(tree)
}
- /* serves as a tree generator */
- object treeGen extends scala.tools.nsc.ast.TreeGen {
- val global: CleanUp.this.global.type = CleanUp.this.global
- }
-
/* Returns the symbol and the tree for the symbol field interning a reference to a symbol 'synmname'.
* If it doesn't exist, i.e. the symbol is encountered the first time,
* it creates a new static field definition and initalization and returns it.
*/
- private def getSymbolStaticField(pos: Position, symname: String, rhs: Tree, tree: Tree): (Symbol, Tree, Tree) = {
- if (symbolStaticFields.contains(symname)) symbolStaticFields(symname)
- else {
+ private def getSymbolStaticField(pos: Position, symname: String, rhs: Tree, tree: Tree): (Symbol, Tree, Tree) =
+ symbolStaticFields.getOrElseUpdate(symname, {
val freshname = unit.fresh.newName(pos, "symbol$")
val theTyper = typer.atOwner(tree, currentClass)
@@ -639,36 +625,27 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
// create field definition and initialization
val stfieldDef = theTyper.typed { atPos(pos)(VAL(stfieldSym) === rhs) }
- val stfieldInit = theTyper.typed { atPos(pos)(REF(stfieldSym) === rhs) }
-
- // add field definition to new defs
- newDefs append stfieldDef
+ val stfieldInit = theTyper.typed { atPos(pos)(REF(stfieldSym) === rhs) }
- symbolStaticFields.put(symname, (stfieldSym, stfieldDef, stfieldInit))
+ // add field definition to new defs
+ newDefs append stfieldDef
- symbolStaticFields(symname)
- }
- }
+ (stfieldSym, stfieldDef, stfieldInit)
+ })
/* returns a list of all trees for symbol static fields, and clear the list */
private def flushSymbolFieldsInitializations: List[Tree] = {
- var fieldlst: List[Tree] = Nil
-
- for ((symbolname, (symbol, deftree, inittree)) <- symbolStaticFields) {
- fieldlst ::= inittree
- }
+ val fields = (symbolStaticFields.valuesIterator map (_._3)).toList
symbolStaticFields.clear
-
- fieldlst
+ fields
}
/* finds the static ctor DefDef tree within the template if it exists. */
- def findStaticCtor(template: Template): Option[Tree] = {
- template.body.find(_ match {
- case defdef @ DefDef(mods, name, tparam, vparam, tp, rhs) => name == nme.CONSTRUCTOR && defdef.symbol.hasFlag(STATIC)
- case _ => false
- })
- }
+ def findStaticCtor(template: Template): Option[Tree] =
+ template.body find {
+ case defdef @ DefDef(mods, nme.CONSTRUCTOR, tparam, vparam, tp, rhs) => defdef.symbol hasFlag STATIC
+ case _ => false
+ }
/* changes the template for the class so that it contains a static constructor with symbol fields inits,
* augments an existing static ctor if one already existed.
@@ -679,40 +656,31 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
else {
val theTyper = typer.atOwner(template, currentClass)
val newCtor = findStaticCtor(template) match {
- // in case there already were static ctors - augment existing ones
- // currently, however, static ctors aren't being generated anywhere else
- case Some(ctorTree) =>
- val ctor = ctorTree.asInstanceOf[DefDef]
- // modify existing static ctor
- val newBlock = ctor.rhs match {
- case block @ Block(stats, expr) =>
- // need to add inits to existing block
- treeCopy.Block(block, symbolInitTrees ::: stats, expr)
- case term @ _ if term.isInstanceOf[TermTree] =>
- // need to create a new block with inits and the old term
- treeCopy.Block(term, symbolInitTrees, term)
- }
- treeCopy.DefDef(ctor, ctor.mods, ctor.name, ctor.tparams, ctor.vparamss, ctor.tpt, newBlock)
- case None =>
+ // in case there already were static ctors - augment existing ones
+ // currently, however, static ctors aren't being generated anywhere else
+ case Some(ctor @ DefDef(mods, name, tparams, vparamss, tpt, rhs)) =>
+ // modify existing static ctor
+ val newBlock = rhs match {
+ case block @ Block(stats, expr) =>
+ // need to add inits to existing block
+ treeCopy.Block(block, symbolInitTrees ::: stats, expr)
+ case term: TermTree =>
+ // need to create a new block with inits and the old term
+ treeCopy.Block(term, symbolInitTrees, term)
+ }
+ treeCopy.DefDef(ctor, mods, name, tparams, vparamss, tpt, newBlock)
+ case None =>
// create new static ctor
- val staticCtorSym = currentClass.newConstructor(template.pos)
- .setFlag(STATIC)
- .setInfo(UnitClass.tpe)
+ val staticCtorSym = currentClass.newConstructor(template.pos)
+ .setFlag(STATIC)
+ .setInfo(UnitClass.tpe)
val rhs = Block(symbolInitTrees, Literal(()))
val staticCtorTree = DefDef(staticCtorSym, rhs)
- theTyper.typed{ atPos(template.pos)(staticCtorTree) }
+ theTyper.typed { atPos(template.pos)(staticCtorTree) }
}
- val newTemplate = treeCopy.Template(template, template.parents, template.self, newCtor :: template.body)
- //println(newTemplate)
- newTemplate
+ treeCopy.Template(template, template.parents, template.self, newCtor :: template.body)
}
}
-
} // CleanUpTransformer
}
-
-
-
-
-