summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorGilles Dubochet <gilles.dubochet@epfl.ch>2007-11-29 15:50:14 +0000
committerGilles Dubochet <gilles.dubochet@epfl.ch>2007-11-29 15:50:14 +0000
commit5e175852a78b2ca4b8b42e1d0cc79c2bd5b72a0f (patch)
tree2a68d2cc7ff6efd999f059b33097e6f9e96ea8c5 /src/compiler
parent8f305d4959487780e20d3fc5ff1071ec92b112d0 (diff)
downloadscala-5e175852a78b2ca4b8b42e1d0cc79c2bd5b72a0f.tar.gz
scala-5e175852a78b2ca4b8b42e1d0cc79c2bd5b72a0f.tar.bz2
scala-5e175852a78b2ca4b8b42e1d0cc79c2bd5b72a0f.zip
Structural calls should be faster thanks to met...
Structural calls should be faster thanks to method caching. Fixed issue #192.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala310
6 files changed, 275 insertions, 63 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 36264dfa84..29b47abbc9 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -43,9 +43,7 @@ abstract class GenICode extends SubComponent {
val SCALA_ALLREF = REFERENCE(definitions.AllRefClass)
val THROWABLE = REFERENCE(definitions.ThrowableClass)
- val BoxedCharacterClass = if (forMSIL) null else definitions.getClass("java.lang.Character")
- val Comparator_equals = definitions.getMember(definitions.getModule("scala.runtime.Comparator"),
- nme.equals_)
+ val BoxesRunTime_equals = definitions.getMember(definitions.BoxesRunTimeClass, nme.equals_)
override def run: Unit = {
scalaPrimitives.init
@@ -1450,7 +1448,7 @@ abstract class GenICode extends SubComponent {
(sym isNonBottomSubClass definitions.LongClass)
}
else ((sym isNonBottomSubClass definitions.BoxedNumberClass) ||
- (!forMSIL && (sym isNonBottomSubClass BoxedCharacterClass)))
+ (!forMSIL && (sym isNonBottomSubClass definitions.BoxedCharacterClass)))
val lsym = l.tpe.typeSymbol
val rsym = r.tpe.typeSymbol
@@ -1463,7 +1461,7 @@ abstract class GenICode extends SubComponent {
val ctx1 = genLoad(l, ctx, ANY_REF_CLASS)
val ctx2 = genLoad(r, ctx1, ANY_REF_CLASS)
- ctx2.bb.emit(CALL_METHOD(Comparator_equals, Static(false)))
+ ctx2.bb.emit(CALL_METHOD(BoxesRunTime_equals, Static(false)))
ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
ctx2.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 39d6226ff4..5088c602d4 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -60,7 +60,7 @@ abstract class GenJVM extends SubComponent {
class BytecodeGenerator {
val MIN_SWITCH_DENSITY = 0.7
val StringBufferClass = if (settings.target.value == "jvm-1.5") "java.lang.StringBuilder" else "java.lang.StringBuffer"
- val BoxesUtility = "scala.runtime.BoxesUtility"
+ val BoxesRunTime = "scala.runtime.BoxesRunTime"
val stringBufferType = new JObjectType(StringBufferClass)
val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY)
@@ -815,11 +815,11 @@ abstract class GenJVM extends SubComponent {
case BOX(kind) =>
val boxedType = definitions.boxedClass(kind.toType.typeSymbol)
val mtype = new JMethodType(javaType(boxedType), Array(javaType(kind)))
- jcode.emitINVOKESTATIC(BoxesUtility, "boxTo" + boxedType.nameString, mtype)
+ jcode.emitINVOKESTATIC(BoxesRunTime, "boxTo" + boxedType.nameString, mtype)
case UNBOX(kind) =>
val mtype = new JMethodType(javaType(kind), Array(JObjectType.JAVA_LANG_OBJECT))
- jcode.emitINVOKESTATIC(BoxesUtility, "unboxTo" + kind.toType.typeSymbol.nameString, mtype)
+ jcode.emitINVOKESTATIC(BoxesRunTime, "unboxTo" + kind.toType.typeSymbol.nameString, 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 42a3336137..92b4afce17 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -307,12 +307,14 @@ trait Definitions {
var PatternWildcard: Symbol = _
// boxed classes
- lazy val BoxesUtilityClass = getModule("scala.runtime.BoxesUtility")
+ lazy val BoxesRunTimeClass = getModule("scala.runtime.BoxesRunTime")
lazy val BoxedArrayClass = getClass("scala.runtime.BoxedArray")
lazy val BoxedAnyArrayClass = getClass("scala.runtime.BoxedAnyArray")
lazy val BoxedObjectArrayClass = getClass("scala.runtime.BoxedObjectArray")
lazy val BoxedUnitClass = getClass("scala.runtime.BoxedUnit")
lazy val BoxedNumberClass = getClass(sn.BoxedNumber)
+ lazy val BoxedCharacterClass = getClass(sn.BoxedCharacter)
+ lazy val BoxedBooleanClass = getClass(sn.BoxedBoolean)
lazy val BoxedUnitModule = getModule("scala.runtime.BoxedUnit")
def BoxedUnit_UNIT = getMember(BoxedUnitModule, "UNIT")
lazy val ObjectRefClass = getClass("scala.runtime.ObjectRef")
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index 4b9b9292cf..de4fa90b7e 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -116,6 +116,8 @@ abstract class SymbolTable extends Names
val IOOBException: Name // IndexOutOfBoundsException
val Code : Name
val BoxedNumber : Name
+ val BoxedCharacter : Name
+ val BoxedBoolean : Name
import scala.collection.mutable.HashMap
val Boxed = new HashMap[Name, Name]
@@ -132,6 +134,8 @@ abstract class SymbolTable extends Names
final val Delegate = nme.NOSYMBOL
final val IOOBException = newTermName("java.lang.IndexOutOfBoundsException")
final val BoxedNumber = newTermName("java.lang.Number")
+ final val BoxedCharacter = newTermName("java.lang.Character")
+ final val BoxedBoolean = newTermName("java.lang.Boolean")
Boxed += nme.Boolean -> newTermName("java.lang.Boolean")
Boxed += nme.Byte -> newTermName("java.lang.Byte")
@@ -157,6 +161,8 @@ abstract class SymbolTable extends Names
final val IOOBException = newTermName("System.IndexOutOfRangeException")
final val Code = nme.NOSYMBOL
final val BoxedNumber = newTermName("System.IConvertible")
+ final val BoxedCharacter = newTermName("System.IConvertible")
+ final val BoxedBoolean = newTermName("System.IConvertible")
Boxed += nme.Boolean -> newTermName("System.Boolean")
Boxed += nme.Byte -> newTermName("System.Byte")
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 9dce5031ea..8cb95aae74 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -630,10 +630,10 @@ abstract class ICodeReader extends ClassfileParser {
/** TODO: move in Definitions and remove obsolete isBox/isUnbox found there. */
def isBox(m: Symbol): Boolean =
- (m.owner == definitions.BoxesUtilityClass.moduleClass
+ (m.owner == definitions.BoxesRunTimeClass.moduleClass
&& m.name.startsWith("boxTo"))
def isUnbox(m: Symbol): Boolean =
- (m.owner == definitions.BoxesUtilityClass.moduleClass
+ (m.owner == definitions.BoxesRunTimeClass.moduleClass
&& m.name.startsWith("unboxTo"))
/** Return the icode class that should include members with the given flags.
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 14739b5e31..b0140dae73 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -47,10 +47,7 @@ abstract class CleanUp extends Transform {
}
}
- private var localTyper: analyzer.Typer = null;
-
- private def freshClassConstantMethName() = unit.fresh.newName("class$Method")
- private def freshClassConstantVarName() = unit.fresh.newName("class$Cache")
+ private var localTyper: analyzer.Typer = null
private def classConstantMethod(pos: Position, sig: String): Symbol = classConstantMeth.get(sig) match {
case Some(meth) =>
@@ -59,7 +56,7 @@ abstract class CleanUp extends Transform {
val forName = getMember(ClassClass.linkedModuleOfClass, nme.forName)
val owner = currentOwner.enclClass
- val cvar = owner.newVariable(pos, freshClassConstantVarName())
+ val cvar = owner.newVariable(pos, unit.fresh.newName("class$Cache"))
.setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC).setInfo(ClassClass.tpe)
owner.info.decls.enter(cvar)
val cdef =
@@ -69,7 +66,7 @@ abstract class CleanUp extends Transform {
}
}
- val meth = owner.newMethod(pos, freshClassConstantMethName())
+ val meth = owner.newMethod(pos, unit.fresh.newName("class$Method"))
.setFlag(PRIVATE | STATIC | SYNTHETIC).setInfo(MethodType(List(), ClassClass.tpe))
owner.info.decls.enter(meth)
val mdef =
@@ -88,6 +85,90 @@ abstract class CleanUp extends Transform {
meth
}
+ private val existingReflectiveMethodCache = new HashMap[(String, List[Type]), Symbol]
+
+ /* Transforms a list of types into a list of trees representing these types
+ * as java.lang.Class instances. */
+ private def paramTypeClasses(paramTypes: List[Type]): List[Tree] =
+ paramTypes map { pt => Literal(Constant(pt)) }
+
+ private def reflectiveMethodCache(pos: Position, method: String, paramTypes: List[Type]): Symbol =
+ existingReflectiveMethodCache.get((method, paramTypes)) match {
+ case Some(cache) => cache
+ case None =>
+ val owner = currentOwner.enclClass
+
+ val rmvar = owner.newVariable(pos, unit.fresh.newName("reflMethod$Cache"))
+ .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC)
+ .setInfo(MethodClass.tpe)
+ owner.info.decls.enter(rmvar)
+ val rmdef =
+ localTyper.typed {
+ atPos(pos) {
+ ValDef(rmvar, Literal(Constant(null)))
+ }
+ }
+
+ val rmcvar = owner.newVariable(pos, unit.fresh.newName("reflClass$Cache"))
+ .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC)
+ .setInfo(ClassClass.tpe)
+ owner.info.decls.enter(rmcvar)
+ val rmcdef =
+ localTyper.typed {
+ atPos(pos) {
+ ValDef(rmcvar, Literal(Constant(null)))
+ }
+ }
+
+ val rmmeth = owner.newMethod(pos, unit.fresh.newName("reflMethod$Method"))
+ .setFlag(PRIVATE | STATIC | SYNTHETIC)
+ .setInfo(MethodType(List(ClassClass.tpe), MethodClass.tpe))
+ owner.info.decls.enter(rmmeth)
+ val rmmdef =
+ localTyper.typed {
+ atPos(pos) {
+ DefDef(rmmeth, { vparamss =>
+ val callClass = vparamss(0)(0)
+ Block(
+ List(
+ If(
+ gen.mkOr(
+ Apply(Select(Select(This(owner), rmvar), nme.eq), List(Literal(Constant(null)))),
+ Apply(Select(Select(This(owner), rmcvar), nme.ne), List(gen.mkAttributedRef(callClass)))
+ ),
+ Block(
+ List(
+ Assign(
+ Select(This(owner), rmvar),
+ Apply(
+ Select(
+ gen.mkAttributedRef(callClass),
+ ClassClass.tpe.member(nme.getMethod_)
+ ),
+ List(
+ Literal(Constant(method)),
+ ArrayValue(TypeTree(ClassClass.tpe), paramTypeClasses(paramTypes))
+ )
+ )
+ ),
+ Assign(Select(This(owner), rmcvar), gen.mkAttributedRef(callClass))
+ ),
+ Literal(Constant(()))
+ ),
+ EmptyTree
+ )
+ ),
+ Select(This(owner), rmvar)
+ )
+ })
+ }
+ }
+
+ newDefs.append(transform(rmdef), transform(rmcdef), transform(rmmdef));
+ existingReflectiveMethodCache.update((method, paramTypes), rmmeth)
+ rmmeth
+ }
+
override def transformUnit(unit: CompilationUnit) =
unit.body = transform(unit.body)
@@ -131,7 +212,104 @@ abstract class CleanUp extends Transform {
* type variable. */
case ad@ApplyDynamic(qual, params) =>
assert(ad.symbol.isPublic)
- val thisTyper = typer.atOwner(tree, currentOwner)
+
+ val testForNumber: Tree =
+ gen.mkOr(
+ Apply(
+ TypeApply(
+ gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf),
+ List(TypeTree(BoxedNumberClass.tpe.normalize))
+ ),
+ List()
+ ),
+ Apply(
+ TypeApply(
+ gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf),
+ List(TypeTree(BoxedCharacterClass.tpe.normalize))
+ ),
+ List()
+ )
+ )
+
+ val testForBoolean: Tree =
+ Apply(
+ TypeApply(
+ gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf),
+ List(TypeTree(BoxedBooleanClass.tpe.normalize))
+ ),
+ List()
+ )
+
+ val testForNumberOrBoolean: Tree = gen.mkOr(testForNumber, testForBoolean)
+
+ def getPrimitiveReplacementForStructuralCall: PartialFunction[Name, (Symbol, Tree)] = {
+ /* Unary arithmetic */
+ case nme.UNARY_+ =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("positive")), testForNumber)
+ case nme.UNARY_- =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("negate")), testForNumber)
+ /* Unary logic */
+ case nme.UNARY_~ =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("complement")), testForNumber)
+ case nme.UNARY_! =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeNot")), testForBoolean)
+ /* Binary arithmetic */
+ case nme.ADD =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("add")), testForNumber)
+ case nme.SUB =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("substract")), testForNumber)
+ case nme.MUL =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("multiply")), testForNumber)
+ case nme.DIV =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("divide")), testForNumber)
+ case nme.MOD =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeModulo")), testForNumber)
+ /* Binary logic */
+ case nme.OR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeOr")), testForNumberOrBoolean)
+ case nme.XOR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeXor")), testForNumberOrBoolean)
+ case nme.AND =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeAnd")), testForNumberOrBoolean)
+ case nme.ZOR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeConditionalOr")), testForBoolean)
+ case nme.ZAND =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("takeConditionalAnd")), testForBoolean)
+ /* Shifting */
+ case nme.LSL =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftSignedLeft")), testForNumber)
+ case nme.LSR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftSignedRight")), testForNumber)
+ case nme.ASR =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftLogicalRight")), testForNumber)
+ case nme.EQ =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testEqual")), testForNumberOrBoolean)
+ case nme.NE =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testNotEqual")), testForNumberOrBoolean)
+ case nme.LT =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testLessThan")), testForNumber)
+ case nme.LE =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testLessOrEqualThan")), testForNumber)
+ case nme.GE =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testGreaterOrEqualThan")), testForNumber)
+ case nme.GT =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("testGreaterThan")), testForNumber)
+ /* Conversions */
+ case nme.toByte =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toByte")), testForNumber)
+ case nme.toShort =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toShort")), testForNumber)
+ case nme.toChar =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toCharacter")), testForNumber)
+ case nme.toInt =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toInteger")), testForNumber)
+ case nme.toLong =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toLong")), testForNumber)
+ case nme.toFloat =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toFloat")), testForNumber)
+ case nme.toDouble =>
+ (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("toDouble")), testForNumber)
+ }
/* Transforms the result of a reflective call (always an AnyRef) to
* the actual result value (an AnyRef too). The transformation
@@ -144,32 +322,33 @@ abstract class CleanUp extends Transform {
* is enough even for value (int et al.) values as the result of
* a dynamic call will box them as a side-effect. */
def fixResult(resType: Type)(tree: Tree): Tree =
- thisTyper.typed {
+ localTyper.typed {
if (resType.typeSymbol == UnitClass)
Block (
List(tree),
gen.mkAttributedRef(BoxedUnit_UNIT)
)
- else {
+ else if (resType.typeSymbol == ArrayClass) {
val sym = currentOwner.newValue(tree.pos, newTermName(unit.fresh.newName)) setInfo ObjectClass.tpe
Block(
List(ValDef(sym, tree)),
If(
Apply(Select(Literal(Constant(null)), Any_==), List(gen.mkAttributedRef(sym))),
Literal(Constant(null)),
- if (resType.typeSymbol == ArrayClass)
- Apply(
- Select(
- gen.mkAttributedRef(ScalaRunTimeModule),
- ScalaRunTimeModule.tpe.member(nme.boxArray)
- ),
- List(gen.mkAttributedRef(sym))
- )
- else
- gen.mkAttributedCast(gen.mkAttributedRef(sym), resType)
+ Apply(
+ Select(
+ gen.mkAttributedRef(ScalaRunTimeModule),
+ ScalaRunTimeModule.tpe.member(nme.boxArray)
+ ),
+ List(gen.mkAttributedRef(sym))
+ )
)
)
}
+ else if (resType.typeSymbol == ObjectClass) // TODO: remove the cast always when unnecessary.
+ tree
+ else
+ gen.mkAttributedCast(tree, resType)
}
/* Transforms the parameters of a dynamic apply (always AnyRefs) to
@@ -180,7 +359,7 @@ abstract class CleanUp extends Transform {
* unboxed array, it is left alone. */
def fixParams(params: List[Tree], paramTypes: List[Type]): List[Tree] =
(params zip paramTypes) map { case (param, paramType) =>
- thisTyper.typed {
+ localTyper.typed {
if (paramType.typeSymbol == ArrayClass) {
val sym = currentOwner.newValue(tree.pos, newTermName(unit.fresh.newName)) setInfo ObjectClass.tpe
val arrayType = {
@@ -214,15 +393,59 @@ abstract class CleanUp extends Transform {
}
}
- /* Transforms a list of types into a list of trees representing these types
- * as java.lang.Class instances. */
- def paramTypeClasses(paramTypes: List[Type]): List[Tree] =
- paramTypes map { pt => Literal(Constant(pt)) }
+ def callAsOperator(paramTypes: List[Type], resType: Type): Tree = localTyper.typed {
+ if (getPrimitiveReplacementForStructuralCall isDefinedAt ad.symbol.name) {
+ val (operator, test) = getPrimitiveReplacementForStructuralCall(ad.symbol.name)
+ If(
+ test,
+ Apply(
+ gen.mkAttributedRef(operator),
+ qual :: fixParams(params, paramTypes)
+ ),
+ callAsMethod(paramTypes, resType)
+ )
+ }
+ else callAsMethod(paramTypes, resType)
+ }
+
+ def callAsMethod(paramTypes: List[Type], resType: Type): Tree = localTyper.typed {
+ Apply(
+ Select(
+ Apply(
+ gen.mkAttributedRef(reflectiveMethodCache(tree.pos, ad.symbol.name.toString, paramTypes)),
+ List(Apply(Select(qual, ObjectClass.tpe.member(nme.getClass_)), Nil))
+ ),
+ MethodClass.tpe.member(nme.invoke_)
+ ),
+ List(
+ qual,
+ ArrayValue(TypeTree(ObjectClass.tpe), fixParams(params, paramTypes))
+ )
+ )
+ }
+
+ def mayRequirePrimitiveReplacement: Boolean = {
+
+ def isBoxed(sym: Symbol): Boolean =
+ if (forCLDC) {
+ (sym isNonBottomSubClass ByteClass) ||
+ (sym isNonBottomSubClass ShortClass) ||
+ (sym isNonBottomSubClass CharClass) ||
+ (sym isNonBottomSubClass IntClass) ||
+ (sym isNonBottomSubClass LongClass)
+ }
+ else ((sym isNonBottomSubClass BoxedNumberClass) ||
+ (!forMSIL && (sym isNonBottomSubClass BoxedCharacterClass)))
+
+ val sym = qual.tpe.typeSymbol
+ (sym == definitions.ObjectClass) || isBoxed(sym)
+
+ }
/* This creates the tree that does the reflective call (see general comment
* on the apply-dynamic tree for its format). This tree is simply composed
* of three succesive calls, first to getClass on the callee, then to
- * getMethod on the class, then to invoke on the method.
+ * getMethod on the classs, then to invoke on the method.
* - getMethod needs an array of classes for choosing one amongst many
* overloaded versions of the method. This is provided by paramTypeClasses
* and must be done on the static type as Scala's dispatching is static on
@@ -243,27 +466,12 @@ abstract class CleanUp extends Transform {
val t: Tree = ad.symbol.tpe match {
case MethodType(paramTypes, resType) =>
assert(params.length == paramTypes.length)
- atPos(tree.pos)(thisTyper.typed {
+ atPos(tree.pos)(localTyper.typed {
fixResult(if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType) {
- Apply(
- Select(
- Apply(
- Select(
- Apply(Select(qual, ObjectClass.tpe.member(nme.getClass_)), Nil),
- ClassClass.tpe.member(nme.getMethod_)
- ),
- List(
- Literal(Constant(ad.symbol.name.toString)),
- ArrayValue(TypeTree(ClassClass.tpe), paramTypeClasses(paramTypes))
- )
- ),
- MethodClass.tpe.member(nme.invoke_)
- ),
- List(
- transform(qual),
- ArrayValue(TypeTree(ObjectClass.tpe), fixParams(params, paramTypes))
- )
- )
+ if (mayRequirePrimitiveReplacement)
+ callAsOperator(paramTypes, resType)
+ else
+ callAsMethod(paramTypes, resType)
}
})
}
@@ -298,12 +506,10 @@ abstract class CleanUp extends Transform {
case Template(parents, self, body) if !forMSIL =>
localTyper = typer.atOwner(tree, currentOwner)
- if (settings.target.value != "jvm-1.5" && !forMSIL) {
- classConstantMeth.clear
- newDefs.clear
- val body1 = transformTrees(body)
- copy.Template(tree, parents, self, newDefs.toList ::: body1)
- } else super.transform(tree)
+ classConstantMeth.clear
+ newDefs.clear
+ val body1 = transformTrees(body)
+ copy.Template(tree, parents, self, newDefs.toList ::: body1)
case Literal(c) if (c.tag == ClassTag) && !forMSIL=>
val tpe = c.typeValue
@@ -311,7 +517,7 @@ abstract class CleanUp extends Transform {
localTyper.typed {
if (isValueClass(tpe.typeSymbol) && !forCLDC)
Select(gen.mkAttributedRef(javaBoxClassModule(tpe.typeSymbol)), "TYPE")
- else if (settings.target.value != "jvm-1.5")
+ else if (settings.target.value != "jvm-1.5" && !forMSIL)
Apply(
gen.mkAttributedRef(classConstantMethod(tree.pos, signature(tpe))),
List())