From 4fccc851b8796d092a2910f6b746e4767d057fc4 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 27 Jun 2009 20:12:16 +0000 Subject: Continued development of code generation DSL. target file was the aptly named CleanUp.scala. Will continue polishing that file but checking in to keep this patch from getting out of hand. --- src/compiler/scala/tools/nsc/ast/TreeDSL.scala | 73 ++- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 12 +- .../scala/tools/nsc/transform/CleanUp.scala | 577 ++++++++------------- .../scala/tools/nsc/transform/Constructors.scala | 11 +- .../scala/tools/nsc/transform/LazyVals.scala | 11 +- 5 files changed, 291 insertions(+), 393 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala index 98a6919f27..1ef0a1bc69 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala @@ -21,16 +21,20 @@ trait TreeDSL { def LIT(x: Any) = Literal(Constant(x)) def TRUE = LIT(true) def FALSE = LIT(false) + def NULL = LIT(null) + def UNIT = LIT(()) + def ZERO = LIT(0) def WILD = Ident(nme.WILDCARD) + case class ExpectApply(target: Tree) { + def apply(args: Tree*) = Apply(target, args.toList) + } + class TreeMethods(target: Tree) { - private def binop(lhs: Tree, op: Name, rhs: Tree) = Apply(Select(lhs, op), List(rhs)) + private def binop(lhs: Tree, op: Name, rhs: Tree) = Apply(Select(lhs, op), List(rhs)) + private def binop(lhs: Tree, op: Symbol, rhs: Tree) = Apply(Select(lhs, op), List(rhs)) private def toAnyRef(x: Tree) = x setType AnyRefClass.tpe - case class ExpectApply(target: Tree) { - def apply(args: Tree*) = Apply(target, args.toList) - } - /** logical/comparison ops **/ def OR(other: Tree) = if (target == EmptyTree) other @@ -42,8 +46,13 @@ trait TreeDSL { else if (other == EmptyTree) target else gen.mkAnd(target, other) + def BIT_AND(other: Tree) = binop(target, Int_And, other) def EQREF(other: Tree) = binop(target, nme.eq, toAnyRef(other)) + def NE_REF(other: Tree) = binop(target, nme.ne, other) def EQEQ(other: Tree) = binop(target, nme.EQ, other) + def EQINT(other: Tree) = binop(target, Int_==, other) + def EQANY(other: Tree) = binop(target, Any_==, other) + def NOT_==(other: Tree) = binop(target, Object_ne, other) /** Apply, Select, Match **/ def APPLY(params: List[Tree]) = Apply(target, params) @@ -51,17 +60,45 @@ trait TreeDSL { def DOT(member: Name) = ExpectApply(Select(target, member)) def DOT(sym: Symbol) = ExpectApply(Select(target, sym)) - /** Casting */ - def AS(tpe: Type) = TypeApply(Select(target, Any_asInstanceOf), List(TypeTree(tpe))) - def TOSTRING() = Select(target, nme.toString_) + /** Assignment */ + def ===(rhs: Tree) = Assign(target, rhs) + + /** Casting & type tests -- working our way toward understanding exactly + * what differs between the different forms of IS and AS. + */ + def AS(tpe: Type) = TypeApply(Select(target, Any_asInstanceOf), List(TypeTree(tpe))) + def AS_ATTR(tpe: Type) = gen.mkAttributedCast(target, tpe) + + def IS(tpe: Type) = gen.mkIsInstanceOf(target, tpe, true) + def IS_OBJ(tpe: Type) = gen.mkIsInstanceOf(target, tpe, false) + + def TOSTRING() = Apply(Select(target, nme.toString_), Nil) + def GETCLASS() = Apply(Select(target, Object_getClass), Nil) } class CaseStart(pat: Tree, guard: Tree) { def IF(g: Tree): CaseStart = new CaseStart(pat, g) - def ==>(body: Tree): CaseDef = CaseDef(pat, guard, body) // DSL for => + def ==>(body: Tree): CaseDef = CaseDef(pat, guard, body) + } + + abstract class ValOrDefStart(sym: Symbol) { + def ===(body: Tree): ValOrDefDef + } + class DefStart(sym: Symbol) extends ValOrDefStart(sym) { + def ===(body: Tree) = DefDef(sym, body) + } + class ValStart(sym: Symbol) extends ValOrDefStart(sym) { + def ===(body: Tree) = ValDef(sym, body) + } + class IfStart(cond: Tree, thenp: Tree) { + def THEN(x: Tree) = new IfStart(cond, x) + def ELSE(elsep: Tree) = If(cond, thenp, elsep) + def ENDIF = If(cond, thenp, EmptyTree) } - class DefStart(sym: Symbol) { - def ===(body: Tree) = DefDef(sym, body) // DSL for = + class TryStart(body: Tree, catches: List[CaseDef], fin: Tree) { + def CATCH(xs: CaseDef*) = new TryStart(body, xs.toList, fin) + def FINALLY(x: Tree) = Try(body, catches, x) + def ENDTRY = Try(body, catches, fin) } def CASE(pat: Tree): CaseStart = new CaseStart(pat, EmptyTree) @@ -73,6 +110,7 @@ trait TreeDSL { class SymbolMethods(target: Symbol) { def BIND(body: Tree) = Bind(target, body) + // def DOT(member: Symbol) = new TreeMethods(Ident(target)) DOT member // name of nth indexed argument to a method (first parameter list), defaults to 1st def ARG(idx: Int = 0) = Ident(target.paramss.head(idx)) @@ -81,12 +119,23 @@ trait TreeDSL { } /** Top level accessible. */ - def THROW(sym: Symbol, msg: Tree) = Throw(New(TypeTree(sym.tpe), List(List(msg.TOSTRING)))) + def THROW(sym: Symbol, msg: Tree = null) = { + val arg = if (msg == null) Nil else List(msg.TOSTRING) + Throw(New(TypeTree(sym.tpe), List(arg))) + } + def NEW(tpe: Tree, args: Tree*) = New(tpe, List(args.toList)) + + def VAL(sym: Symbol) = new ValStart(sym) def DEF(sym: Symbol) = new DefStart(sym) def AND(guards: Tree*) = if (guards.isEmpty) EmptyTree else guards reduceLeft gen.mkAnd + def IF(tree: Tree) = new IfStart(tree, EmptyTree) + def TRY(tree: Tree) = new TryStart(tree, Nil, EmptyTree) + def REF(sym: Symbol) = gen.mkAttributedRef(sym) + def BLOCK(xs: Tree*) = Block(xs.init.toList, xs.last) + /** Implicits - some of these should probably disappear **/ implicit def mkTreeMethods(target: Tree): TreeMethods = new TreeMethods(target) implicit def mkTreeMethodsFromSymbol(target: Symbol): TreeMethods = new TreeMethods(Ident(target)) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 221d08e824..dcdb284af2 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -174,24 +174,28 @@ abstract class TreeGen { } /** Builds an instance test with given value and type. */ - def mkIsInstanceOf(value: Tree, tpe: Type): Tree = // buraq: we ignore erase, no rtt + def mkIsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree = { + val sym = if (any) Any_isInstanceOf else Object_isInstanceOf Apply( TypeApply( - mkAttributedSelect(value, Any_isInstanceOf), + mkAttributedSelect(value, sym), List(TypeTree(tpe.normalize)) ), Nil ) + } /** Builds a cast with given value and type. */ - def mkAsInstanceOf(value: Tree, tpe: Type): Tree = + def mkAsInstanceOf(value: Tree, tpe: Type, any: Boolean = true): Tree = { + val sym = if (any) Any_asInstanceOf else Object_asInstanceOf Apply( TypeApply( - mkAttributedSelect(value, Any_asInstanceOf), + mkAttributedSelect(value, sym), List(TypeTree(tpe.normalize)) ), Nil ) + } def mkClassOf(tp: Type): Tree = Literal(Constant(tp)) setType Predef_classOfType(tp) diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index c1ac9e15aa..f1c6641dd0 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -11,9 +11,10 @@ import Flags._ import scala.tools.nsc.util.Position import scala.collection.mutable.{ListBuffer, HashMap} -abstract class CleanUp extends Transform { +abstract class CleanUp extends Transform with ast.TreeDSL { import global._ import definitions._ + import CODE._ /** the following two members override abstract members in Transform */ val phaseName: String = "cleanup" @@ -22,7 +23,6 @@ abstract class CleanUp extends Transform { new CleanUpTransformer(unit) class CleanUpTransformer(unit: CompilationUnit) extends Transformer { - private val newDefs = new ListBuffer[Tree] private val newInits = new ListBuffer[Tree] @@ -46,40 +46,40 @@ abstract class CleanUp extends Transform { private var localTyper: analyzer.Typer = null - private def classConstantMethod(pos: Position, sig: String): Symbol = classConstantMeth.get(sig) match { - case Some(meth) => - meth - case None => + private object MethodDispatchType extends scala.Enumeration { + val NO_CACHE, MONO_CACHE, POLY_CACHE = Value + } + import MethodDispatchType.{ NO_CACHE, MONO_CACHE, POLY_CACHE } + private def dispatchType() = settings.refinementMethodDispatch.value match { + case "no-cache" => NO_CACHE + case "mono-cache" => MONO_CACHE + case "poly-cache" => POLY_CACHE + } + + private def typedWithPos(pos: Position)(tree: Tree) = + localTyper typed { atPos(pos)(tree) } + + private def classConstantMethod(pos: Position, sig: String): Symbol = + (classConstantMeth get sig) getOrElse { val forName = getMember(ClassClass.linkedModuleOfClass, nme.forName) val owner = currentOwner.enclClass val cvar = owner.newVariable(pos, unit.fresh.newName(pos, "class$Cache")) .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC).setInfo(ClassClass.tpe) - owner.info.decls.enter(cvar) - val cdef = - localTyper.typed { - atPos(pos) { - ValDef(cvar, Literal(Constant(null))) - } - } + owner.info.decls enter cvar + val cdef = typedWithPos(pos) { VAL(cvar) === NULL } val meth = owner.newMethod(pos, unit.fresh.newName(pos, "class$Method")) .setFlag(PRIVATE | STATIC | SYNTHETIC).setInfo(MethodType(List(), ClassClass.tpe)) - owner.info.decls.enter(meth) - val mdef = - localTyper.typed { - atPos(pos) { - DefDef(meth, gen.mkCached( - cvar, - Apply( - gen.mkAttributedRef(forName), List(Literal(sig))))) - } - } + owner.info.decls enter meth + val mdef = typedWithPos(pos)(DEF(meth) === + gen.mkCached(cvar, Apply(REF(forName), List(Literal(sig)))) + ) - newDefs.append(cdef, mdef); + newDefs.append(cdef, mdef) classConstantMeth.update(sig, meth) meth - } + } override def transformUnit(unit: CompilationUnit) = unit.body = transform(unit.body) @@ -123,61 +123,55 @@ abstract class CleanUp extends Transform { * refinement, where the refinement defines a parameter based on a * type variable. */ case ad@ApplyDynamic(qual0, params) => + def mkName(s: String = "") = + if (s == "") unit.fresh newName ad.pos + else unit.fresh.newName(ad.pos, s) + def mkTerm(s: String = "") = newTermName(mkName(s)) + val typedPos = typedWithPos(ad.pos) _ + assert(ad.symbol.isPublic) var qual: Tree = qual0 /* ### CREATING THE METHOD CACHE ### */ def addStaticVariableToClass(forName: String, forType: Type, forInit: Tree): Symbol = { - val varSym = currentClass.newVariable(ad.pos, unit.fresh.newName(ad.pos, forName)) + val varSym = currentClass.newVariable(ad.pos, mkName(forName)) .setFlag(PRIVATE | STATIC | MUTABLE | SYNTHETIC) .setInfo(forType) - currentClass.info.decls.enter(varSym) - val varDef = - localTyper.typed { - atPos(ad.pos) { - ValDef(varSym, forInit) - } - } - newDefs.append(transform(varDef)) - val varInit = - localTyper.typed { - atPos(ad.pos) { - Assign(gen.mkAttributedRef(varSym), forInit) - } - } - newInits.append(transform(varInit)) + currentClass.info.decls enter varSym + + val varDef = typedPos( VAL(varSym) === forInit ) + newDefs append transform(varDef) + + val varInit = typedPos( REF(varSym) === forInit ) + newInits append transform(varInit) + varSym } def addStaticMethodToClass(forName: String, forArgsTypes: List[Type], forResultType: Type) (forBody: Pair[Symbol, List[Symbol]] => Tree): Symbol = { - val methSym = currentClass.newMethod(ad.pos, unit.fresh.newName(ad.pos, forName)) + val methSym = currentClass.newMethod(ad.pos, mkName(forName)) .setFlag(STATIC | SYNTHETIC) + methSym.setInfo(MethodType(methSym.newSyntheticValueParams(forArgsTypes), forResultType)) - currentClass.info.decls.enter(methSym) - val methDef = - localTyper.typed { - atPos(ad.pos) { - DefDef(methSym, { forBody(Pair(methSym, methSym.paramss(0))) }) - } - } - newDefs.append(transform(methDef)) + currentClass.info.decls enter methSym + + val methDef = typedPos( DefDef(methSym, { forBody(Pair(methSym, methSym.paramss(0))) }) ) + newDefs append transform(methDef) + methSym } def fromTypesToClassArrayLiteral(paramTypes: List[Type]): Tree = - ArrayValue(TypeTree(ClassClass.tpe), paramTypes map { pt => Literal(Constant(pt)) }) + ArrayValue(TypeTree(ClassClass.tpe), paramTypes map LIT) def theTypeClassArray = TypeRef(ArrayClass.tpe.prefix, ArrayClass, List(ClassClass.tpe)) /* ... */ - def reflectiveMethodCache(method: String, paramTypes: List[Type]): Symbol = { - - settings.refinementMethodDispatch.value match { - - case "no-cache" => + def reflectiveMethodCache(method: String, paramTypes: List[Type]): Symbol = dispatchType match { + case NO_CACHE => /* Implementation of the cache is as follows for method "def xyz(a: A, b: B)": @@ -191,21 +185,12 @@ abstract class CleanUp extends Transform { val reflParamsCacheSym: Symbol = addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes)) - val reflMethodSym: Symbol = - addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) - { case Pair(reflMethodSym, List(forReceiverSym)) => - Apply( - Select(gen.mkAttributedRef(forReceiverSym), Class_getMethod), - List( - Literal(Constant(method)), - gen.mkAttributedRef(reflParamsCacheSym) - ) - ) - } - - reflMethodSym + addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) { + case Pair(reflMethodSym, List(forReceiverSym)) => + (REF(forReceiverSym) DOT Class_getMethod)(LIT(method), REF(reflParamsCacheSym)) + } - case "mono-cache" => + case MONO_CACHE => /* Implementation of the cache is as follows for method "def xyz(a: A, b: B)": @@ -229,47 +214,26 @@ abstract class CleanUp extends Transform { addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes)) val reflMethodCacheSym: Symbol = - addStaticVariableToClass("reflMethod$Cache", MethodClass.tpe, Literal(Constant(null))) + addStaticVariableToClass("reflMethod$Cache", MethodClass.tpe, NULL) val reflClassCacheSym: Symbol = - addStaticVariableToClass("reflClass$Cache", ClassClass.tpe, Literal(Constant(null))) - - - val reflMethodSym: Symbol = - addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) - { case Pair(reflMethodSym, List(forReceiverSym)) => - Block( - List( - If(Apply(Select(gen.mkAttributedRef(reflClassCacheSym), nme.ne), List(gen.mkAttributedRef(forReceiverSym))), - Block( - List( - Assign( - gen.mkAttributedRef(reflMethodCacheSym), - Apply( - Select( - gen.mkAttributedRef(forReceiverSym), - ClassClass.tpe.member(nme.getMethod_) - ), - List( - Literal(Constant(method)), - gen.mkAttributedRef(reflParamsCacheSym) - ) - ) - ), - Assign(gen.mkAttributedRef(reflClassCacheSym), gen.mkAttributedRef(forReceiverSym)) - ), - Literal(Constant(())) - ), - EmptyTree - ) - ), - gen.mkAttributedRef(reflMethodCacheSym) - ) - } - - reflMethodSym + addStaticVariableToClass("reflClass$Cache", ClassClass.tpe, NULL) + + def getMethodSym = ClassClass.tpe member nme.getMethod_ + + addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) { + case Pair(reflMethodSym, List(forReceiverSym)) => + BLOCK( + IF (REF(reflClassCacheSym) NE_REF REF(forReceiverSym)) THEN BLOCK( + REF(reflMethodCacheSym) === ((REF(forReceiverSym) DOT getMethodSym)(LIT(method), REF(reflParamsCacheSym))) , + REF(reflClassCacheSym) === REF(forReceiverSym), + UNIT + ) ENDIF, + REF(reflMethodCacheSym) + ) + } - case "poly-cache" => + case POLY_CACHE => /* Implementation of the cache is as follows for method "def xyz(a: A, b: B)": @@ -294,53 +258,31 @@ abstract class CleanUp extends Transform { addStaticVariableToClass("reflParams$Cache", theTypeClassArray, fromTypesToClassArrayLiteral(paramTypes)) val reflPolyCacheSym: Symbol = - addStaticVariableToClass("reflPoly$Cache", MethodCacheClass.tpe, New(TypeTree(EmptyMethodCacheClass.tpe), List(Nil))) + addStaticVariableToClass("reflPoly$Cache", MethodCacheClass.tpe, NEW(TypeTree(EmptyMethodCacheClass.tpe))) val reflMethodSym: Symbol = addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => - val methodSym = reflMethodSym.newVariable(ad.pos, newTermName(unit.fresh.newName(ad.pos, "method"))) setInfo MethodClass.tpe - Block( - List( - ValDef( - methodSym, - Apply( - Select(gen.mkAttributedRef(reflPolyCacheSym), methodCache_find), - List(gen.mkAttributedRef(forReceiverSym)) - ) + val methodSym = reflMethodSym.newVariable(ad.pos, mkTerm("method")) setInfo MethodClass.tpe + + BLOCK( + VAL(methodSym) === ((REF(reflPolyCacheSym) DOT methodCache_find)(REF(forReceiverSym))) , + IF (REF(methodSym) NOT_== NULL) . + THEN (Return(REF(methodSym))) + ELSE { + def methodSymRHS = ((REF(forReceiverSym) DOT Class_getMethod)(LIT(method), REF(reflParamsCacheSym))) + def cacheRHS = ((REF(reflPolyCacheSym) DOT methodCache_add)(REF(forReceiverSym), REF(methodSym))) + BLOCK( + REF(methodSym) === methodSymRHS, + REF(reflPolyCacheSym) === cacheRHS, + Return(REF(methodSym)) ) - ), - If( - Apply(Select(gen.mkAttributedRef(methodSym), Object_ne), List(Literal(Constant(null)))), - Return(gen.mkAttributedRef(methodSym)), - Block( - List( - Assign(gen.mkAttributedRef(methodSym), - Apply( - Select(gen.mkAttributedRef(forReceiverSym), Class_getMethod), - List( - Literal(Constant(method)), - gen.mkAttributedRef(reflParamsCacheSym) - ) - ) - ), - Assign( - gen.mkAttributedRef(reflPolyCacheSym), - Apply( - Select(gen.mkAttributedRef(reflPolyCacheSym), methodCache_add), - List(gen.mkAttributedRef(forReceiverSym), gen.mkAttributedRef(methodSym)) - ) - ) - ), - Return(gen.mkAttributedRef(methodSym)) - ) - ) + } ) } reflMethodSym - } } /* ### HANDLING METHODS NORMALLY COMPILED TO OPERATORS ### */ @@ -356,102 +298,55 @@ abstract class CleanUp extends Transform { } - 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 testForNumber: Tree = (qual IS_OBJ BoxedNumberClass.tpe) OR (qual IS_OBJ BoxedCharacterClass.tpe) + val testForBoolean: Tree = (qual IS_OBJ BoxedBooleanClass.tpe) + val testForNumberOrBoolean = testForNumber OR testForBoolean + + val getPrimitiveReplacementForStructuralCall: PartialFunction[Name, (Symbol, Tree)] = { + val testsForNumber = Map() ++ List( + nme.UNARY_+ -> "positive", + nme.UNARY_- -> "negate", + nme.UNARY_~ -> "complement", + nme.ADD -> "add", + nme.SUB -> "subtract", + nme.MUL -> "multiply", + nme.DIV -> "divide", + nme.MOD -> "takeModulo", + nme.LSL -> "shiftSignedLeft", + nme.LSR -> "shiftLogicalRight", + nme.ASR -> "shiftSignedRight", + nme.LT -> "testLessThan", + nme.LE -> "testLessOrEqualThan", + nme.GE -> "testGreaterOrEqualThan", + nme.GT -> "testGreaterThan", + nme.toByte -> "toByte", + nme.toShort -> "toShort", + nme.toChar -> "toCharacter", + nme.toInt -> "toInteger", + nme.toLong -> "toLong", + nme.toFloat -> "toFloat", + nme.toDouble-> "toDouble" ) - - val testForBoolean: Tree = - Apply( - TypeApply( - gen.mkAttributedSelect(qual, definitions.Object_isInstanceOf), - List(TypeTree(BoxedBooleanClass.tpe.normalize)) - ), - List() + val testsForBoolean = Map() ++ List( + nme.UNARY_! -> "takeNot", + nme.ZOR -> "takeConditionalOr", + nme.ZAND -> "takeConditionalAnd" + ) + val testsForNumberOrBoolean = Map() ++ List( + nme.OR -> "takeOr", + nme.XOR -> "takeXor", + nme.AND -> "takeAnd", + nme.EQ -> "testEqual", + nme.NE -> "testNotEqual" ) + def get(name: String) = getMember(BoxesRunTimeClass, name) - 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("subtract")), 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("shiftLogicalRight")), testForNumber) - case nme.ASR => - (definitions.getMember(definitions.BoxesRunTimeClass, newTermName("shiftSignedRight")), 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) + /** Begin partial function. */ + { + case x if testsForNumber contains x => (get(testsForNumber(x)), testForNumber) + case x if testsForBoolean contains x => (get(testsForBoolean(x)), testForBoolean) + case x if testsForNumberOrBoolean contains x => (get(testsForNumberOrBoolean(x)), testForNumberOrBoolean) + } } /* ### BOXING PARAMS & UNBOXING RESULTS ### */ @@ -466,35 +361,21 @@ abstract class CleanUp extends Transform { * - otherwise, the value is simply casted to the expected type. This * 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 = - localTyper.typed { - if (resType.typeSymbol == UnitClass) - Block ( - List(tree), - gen.mkAttributedRef(BoxedUnit_UNIT) - ) - else if (resType.typeSymbol == ArrayClass) { - val sym = currentOwner.newValue(ad.pos, newTermName(unit.fresh.newName(ad.pos))) setInfo ObjectClass.tpe - Block( - List(ValDef(sym, tree)), - If( - Apply(Select(Literal(Constant(null)), Any_==), List(gen.mkAttributedRef(sym))), - Literal(Constant(null)), - 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) + def fixResult(resType: Type)(tree: Tree): Tree = localTyper typed { + def boxArray = { + val sym = currentOwner.newValue(ad.pos, mkTerm()) setInfo ObjectClass.tpe + BLOCK( + VAL(sym) === tree, + IF (NULL EQANY REF(sym)) THEN NULL ELSE gen.mkRuntimeCall(nme.boxArray, List(REF(sym))) + ) } + resType.typeSymbol match { + case UnitClass => BLOCK(tree, REF(BoxedUnit_UNIT)) + case ArrayClass => boxArray + case ObjectClass => tree + case _ => tree AS_ATTR resType + } + } /* Transforms the parameters of a dynamic apply (always AnyRefs) to * something compatible with reclective calls. The transformation depends @@ -503,33 +384,23 @@ abstract class CleanUp extends Transform { * type. If it is a boxed array, the array is unboxed. If it is an * unboxed array, it is left alone. */ def fixParams(params: List[Tree], paramTypes: List[Type]): List[Tree] = - (params zip paramTypes) map { case (param, paramType) => - localTyper.typed { + for ((param, paramType) <- params zip paramTypes) yield { + localTyper typed { if (paramType.typeSymbol == ArrayClass) { - val sym = currentOwner.newValue(ad.pos, newTermName(unit.fresh.newName(ad.pos))) setInfo ObjectClass.tpe - val arrayType = { - assert(paramType.typeArgs.length == 1) - paramType.typeArgs(0).normalize - } - Block( - List(ValDef(sym, param)), - If( - Apply(Select(Literal(Constant(null)), Any_==), List(gen.mkAttributedRef(sym))), - Literal(Constant(null)), - If( - Apply( - TypeApply( - gen.mkAttributedSelect(gen.mkAttributedRef(sym), definitions.Object_isInstanceOf), - List(TypeTree(BoxedArrayClass.tpe.normalize)) - ), - List() - ), - Apply( - Select(gen.mkAttributedCast(gen.mkAttributedRef(sym), BoxedArrayClass.tpe), getMember(BoxedArrayClass, nme.unbox)), - List(Literal(Constant(arrayType))) - ), - gen.mkAttributedRef(sym) - ) + val sym = currentOwner.newValue(ad.pos, mkTerm()) setInfo ObjectClass.tpe + assert(paramType.typeArgs.length == 1) + val arrayType = paramType.typeArgs(0).normalize + lazy val unboxMethod = getMember(BoxedArrayClass, nme.unbox) + + BLOCK( + VAL(sym) === param, + IF (NULL EQANY REF(sym)) . + THEN (NULL) . + ELSE ( + IF (REF(sym) IS_OBJ BoxedArrayClass.tpe) . + THEN (((REF(sym) AS_ATTR BoxedArrayClass.tpe) DOT unboxMethod)(LIT(arrayType))) + ELSE + REF(sym) ) ) } @@ -539,50 +410,35 @@ abstract class CleanUp extends Transform { } /* ### CALLING THE APPLY -> one for operators (see above), one for normal methods ### */ - - def callAsOperator(paramTypes: List[Type], resType: Type): Tree = localTyper.typed { + def callAsOperator(paramTypes: List[Type], resType: Type): Tree = localTyper typed { + def default = callAsMethod(paramTypes, resType) 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) - ) + val (operator, test) = getPrimitiveReplacementForStructuralCall(ad.symbol.name) + def args = qual :: fixParams(params, paramTypes) + + IF (test) THEN (REF(operator) APPLY args) ELSE default } - else callAsMethod(paramTypes, resType) + else default } def callAsMethod(paramTypes: List[Type], resType: Type): Tree = localTyper.typed { - val invokeExc = - currentOwner.newValue(ad.pos, newTermName(unit.fresh.newName(ad.pos))) setInfo InvocationTargetExceptionClass.tpe - Try( - Apply( - Select( - Apply( - gen.mkAttributedRef(reflectiveMethodCache(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)) - ) - ), - List(CaseDef( - Bind(invokeExc, Typed(Ident(nme.WILDCARD), TypeTree(InvocationTargetExceptionClass.tpe))), - EmptyTree, - Throw(Apply(Select(Ident(invokeExc), nme.getCause), Nil)) - )), - EmptyTree - ) + // 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), fixParams(params, paramTypes)) // args for invocation + def invocation = (lookup DOT invokeName)(qual, args) // .invoke(qual, ...) + + // exception catching machinery + val invokeExc = currentOwner.newValue(ad.pos, mkTerm()) setInfo InvocationTargetExceptionClass.tpe + def catchVar = Bind(invokeExc, Typed(Ident(nme.WILDCARD), TypeTree(InvocationTargetExceptionClass.tpe))) + 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 } - def getClass(q: Tree): Tree = - Apply(Select(q, nme.getClass_), List()) + def getClass(q: Tree): Tree = (q DOT nme.getClass_)() if (settings.refinementMethodDispatch.value == "invoke-dynamic") { /* val guardCallSite: Tree = { @@ -626,42 +482,39 @@ abstract class CleanUp extends Transform { val t: Tree = ad.symbol.tpe match { case MethodType(mparams, resType) => assert(params.length == mparams.length) - atPos(ad.pos)(localTyper.typed { - val t1 = newTermName(unit.fresh.newName(ad.pos, "qual")) - val sym = currentOwner.newValue(ad.pos, t1) setInfo qual0.tpe - qual = gen.mkAttributedRef(sym) - Block( - List(ValDef(sym, qual0)), - fixResult(if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType) { - if (mayRequirePrimitiveReplacement) - callAsOperator(mparams map (_.tpe), resType) - else - callAsMethod(mparams map (_.tpe), resType) - } + typedPos { + val sym = currentOwner.newValue(ad.pos, mkTerm("qual")) setInfo qual0.tpe + qual = REF(sym) + + def resTypeForFix = if (isValueClass(resType.typeSymbol)) boxedClass(resType.typeSymbol).tpe else resType + def call = if (mayRequirePrimitiveReplacement) (callAsOperator _) else (callAsMethod _) + BLOCK( + VAL(sym) === qual0, + fixResult(resTypeForFix)(call(mparams map (_.tpe), resType)) ) - }) + } } /* For testing purposes, the dynamic application's condition * can be printed-out in great detail. Remove? */ if (settings.debug.value) { - Console.println( - "Dynamically applying '" + qual + "." + ad.symbol.name + - "(" + params.map(_.toString).mkString(", ") + ")' with" - ) - ad.symbol.tpe match { + def paramsToString(xs: Any*) = xs map (_.toString) mkString ", " + val mstr = ad.symbol.tpe match { case MethodType(mparams, resType) => - Console.println( - " - declared parameters' types: " + - (mparams.map(_.toString)).mkString("'",", ","'")) - Console.println( - " - passed arguments' types: " + - (params.map(_.toString)).mkString("'",", ","'")) - Console.println( - " - result type: '" + - resType.toString + "'") + """| with + | - declared parameter types: '%s' + | - passed argument types: '%s' + | - result type: '%s'""" . + stripMargin.format( + paramsToString(mparams), + paramsToString(params), + resType.toString + ) + case _ => "" } - Console.println(" - resulting code: '" + t + "'") + Console.printf("""Dynamically application '%s.%s(%s)' %s - resulting code: '%s'""", + List(qual, ad.symbol.name, paramsToString(params), mstr, t) map (_.toString) : _* + ) } /* We return the dynamic call tree, after making sure no other @@ -707,12 +560,10 @@ abstract class CleanUp extends Transform { case Literal(c) if (c.tag == ClassTag) && !forMSIL=> val tpe = c.typeValue - atPos(tree.pos) { - localTyper.typed { - if (isValueClass(tpe.typeSymbol) || tpe.typeSymbol == definitions.UnitClass) - Select(gen.mkAttributedRef(javaBoxClassModule(tpe.typeSymbol)), "TYPE") - else tree - } + typedWithPos(tree.pos) { + if (isValueClass(tpe.typeSymbol) || tpe.typeSymbol == definitions.UnitClass) + Select(REF(javaBoxClassModule(tpe.typeSymbol)), "TYPE") + else tree } /* MSIL requires that the stack is empty at the end of a try-block. diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index d5ace3c4f6..2d3edf3a0e 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -13,7 +13,7 @@ import util.TreeSet /** This phase converts classes with parameters into Java-like classes with * fields, which are assigned to from constructors. */ -abstract class Constructors extends Transform { +abstract class Constructors extends Transform with ast.TreeDSL { import global._ import definitions._ @@ -130,19 +130,16 @@ abstract class Constructors extends Transform { // Create code to copy parameter to parameter accessor field. // If parameter is $outer, check that it is not null. def copyParam(to: Symbol, from: Symbol): Tree = { + import CODE._ var result = mkAssign(to, Ident(from)) if (from.name == nme.OUTER) result = atPos(to.pos) { localTyper.typed { - If( - Apply( - Select(Ident(from), nme.eq), - List(Literal(Constant(null)))), - Throw(New(TypeTree(NullPointerExceptionClass.tpe), List(List()))), - result) + IF (from EQREF NULL) THEN THROW(NullPointerExceptionClass) ELSE result } } + result } diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index ce5329e532..9707baf392 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -3,7 +3,7 @@ package scala.tools.nsc.transform; import scala.tools.nsc._ import scala.collection.mutable.HashMap -abstract class LazyVals extends Transform { +abstract class LazyVals extends Transform with ast.TreeDSL { // inherits abstract value `global' and class `Phase' from Transform import global._ // the global environment @@ -146,13 +146,10 @@ abstract class LazyVals extends Transform { (Block(List(rhs, mkSetFlag(bitmapSym, mask)), Literal(Constant(()))), Literal(())) } + import CODE._ + val result = atPos(tree.pos) { - If(Apply( - Select( - Apply(Select(Ident(bitmapSym), Int_And), - List(mask)), - Int_==), - List(Literal(Constant(0)))), block, EmptyTree) + IF ((Ident(bitmapSym) BIT_AND mask) EQINT ZERO) THEN block ENDIF } typed(Block(List(result), res)) } -- cgit v1.2.3