diff options
author | Gilles Dubochet <gilles.dubochet@epfl.ch> | 2007-11-29 15:50:14 +0000 |
---|---|---|
committer | Gilles Dubochet <gilles.dubochet@epfl.ch> | 2007-11-29 15:50:14 +0000 |
commit | 5e175852a78b2ca4b8b42e1d0cc79c2bd5b72a0f (patch) | |
tree | 2a68d2cc7ff6efd999f059b33097e6f9e96ea8c5 /src/compiler | |
parent | 8f305d4959487780e20d3fc5ff1071ec92b112d0 (diff) | |
download | scala-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')
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()) |