From e0fa88b7295431a4b0efae4cac2ad9680a11ac88 Mon Sep 17 00:00:00 2001 From: Iulian Dragos Date: Thu, 19 Jul 2007 15:53:28 +0000 Subject: Changed annotation handling in the backend to u... Changed annotation handling in the backend to use symbols instead of types. Added support for @inline and @noinline. Improved boxing/unboxing optimization. --- .../scala/tools/nsc/backend/icode/GenICode.scala | 19 +++- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 41 ++++----- .../scala/tools/nsc/backend/opt/Inliners.scala | 100 ++++++++++----------- src/compiler/scala/tools/nsc/symtab/Symbols.scala | 6 +- .../scala/tools/nsc/typechecker/Namers.scala | 2 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 2 +- 6 files changed, 87 insertions(+), 83 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 8a23bab19e..629701bfda 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -47,8 +47,6 @@ abstract class GenICode extends SubComponent { val Comparator_equals = definitions.getMember(definitions.getModule("scala.runtime.Comparator"), nme.equals_) - /////////////////////////////////////////////////////////// - override def run: Unit = { scalaPrimitives.init classes.clear @@ -106,8 +104,7 @@ abstract class GenICode extends SubComponent { var ctx1 = ctx.enterMethod(m, tree.asInstanceOf[DefDef]) addMethodParams(ctx1, vparamss) - val NativeAttr = atPhase(currentRun.typerPhase)(definitions.getClass("scala.native").tpe) - m.native = m.symbol.hasAttribute(NativeAttr) + m.native = m.symbol.hasAttribute(definitions.NativeAttr) if (!m.isDeferred && !m.native) { ctx1 = genLoad(rhs, ctx1, m.returnType); @@ -691,6 +688,20 @@ abstract class GenICode extends SubComponent { val nativeKind = toTypeKind(expr.tpe) ctx1.bb.emit(BOX(nativeKind), expr.pos) generatedType = toTypeKind(fun.symbol.tpe.resultType) + if (settings.Xdce.value) { + // we store this boxed value to a local, even if not really needed. + // boxing optimization might use it, and dead code elimination will + // take care of unnecessary stores + var loc1 = new Local(ctx.method.symbol.newVariable( + tree.pos, + unit.fresh.newName("boxed")) + .setInfo(definitions.ObjectClass.tpe) + .setFlag(Flags.SYNTHETIC), + ANY_REF_CLASS, false) + loc1 = ctx.method.addLocal(loc1) + ctx1.bb.emit(DUP(ANY_REF_CLASS)) + ctx1.bb.emit(STORE_LOCAL(loc1)) + } ctx1 case Apply(fun @ _, List(expr)) if (definitions.isUnbox(fun.symbol)) => diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index c28fcd6c72..809ff80eb3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -65,17 +65,14 @@ abstract class GenJVM extends SubComponent { val stringBufferType = new JObjectType(StringBufferClass) val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY) - def attributeType(name: String) = - atPhase(currentRun.typerPhase)(definitions.getClass(name).tpe) - // Scala attributes - val SerializableAttr = atPhase(currentRun.typerPhase)(definitions.SerializableAttr.tpe) - val SerialVersionUID = attributeType("scala.SerialVersionUID") - val CloneableAttr = attributeType("scala.cloneable") - val TransientAtt = attributeType("scala.transient") - val VolatileAttr = attributeType("scala.volatile") - val RemoteAttr = attributeType("scala.remote") - val ThrowsAttr = attributeType("scala.throws") + val SerializableAttr = definitions.SerializableAttr + val SerialVersionUID = definitions.getClass("scala.SerialVersionUID") + val CloneableAttr = definitions.getClass("scala.cloneable") + val TransientAtt = definitions.getClass("scala.transient") + val VolatileAttr = definitions.getClass("scala.volatile") + val RemoteAttr = definitions.getClass("scala.remote") + val ThrowsAttr = definitions.getClass("scala.throws") val CloneableClass = if (forCLDC) null else definitions.getClass("java.lang.Cloneable") @@ -149,13 +146,13 @@ abstract class GenJVM extends SubComponent { if (!forCLDC) for (val attr <- c.symbol.attributes) attr match { - case AnnotationInfo(SerializableAttr, _, _) => + case AnnotationInfo(tp, _, _) if tp.typeSymbol == SerializableAttr => parents = parents ::: List(definitions.SerializableClass.tpe) - case AnnotationInfo(CloneableAttr, _, _) => + case AnnotationInfo(tp, _, _) if tp.typeSymbol == CloneableAttr => parents = parents ::: List(CloneableClass.tpe) - case AnnotationInfo(SerialVersionUID, value :: _, _) => + case AnnotationInfo(tp, value :: _, _) if tp.typeSymbol == SerialVersionUID => serialVUID = Some(value.constant.get.longValue) - case AnnotationInfo(RemoteAttr, _, _) => + case AnnotationInfo(tp, _, _) if tp.typeSymbol == RemoteAttr => parents = parents ::: List(RemoteInterface.tpe) remoteClass = true case _ => () @@ -204,7 +201,7 @@ abstract class GenJVM extends SubComponent { def addExceptionsAttribute(sym: Symbol): Unit = { val (excs, others) = sym.attributes.partition((a => a match { - case AnnotationInfo(ThrowsAttr, _, _) => true + case AnnotationInfo(tp, _, _) if tp.typeSymbol == ThrowsAttr => true case _ => false })) if (excs isEmpty) return; @@ -217,7 +214,7 @@ abstract class GenJVM extends SubComponent { // put some radom value; the actual number is determined at the end buf.putShort(0xbaba.toShort) - for (val AnnotationInfo(ThrowsAttr, List(exc), _) <- excs.removeDuplicates) { + for (val AnnotationInfo(tp, List(exc), _) <- excs.removeDuplicates; tp.typeSymbol == ThrowsAttr) { buf.putShort( cpool.addClass( javaName(exc.constant.get.typeValue.typeSymbol)).shortValue) @@ -379,9 +376,9 @@ abstract class GenJVM extends SubComponent { var attributes = 0 f.symbol.attributes foreach { a => a match { - case AnnotationInfo(TransientAtt, _, _) => + case AnnotationInfo(tp, _, _) if tp.typeSymbol == TransientAtt => attributes = attributes | JAccessFlags.ACC_TRANSIENT - case AnnotationInfo(VolatileAttr, _, _) => + case AnnotationInfo(tp, _, _) if tp.typeSymbol == VolatileAttr => attributes = attributes | JAccessFlags.ACC_VOLATILE case _ => (); }} @@ -420,11 +417,9 @@ abstract class GenJVM extends SubComponent { if (m.symbol.hasFlag(Flags.BRIDGE)) jmethod.addAttribute(fjbgContext.JOtherAttribute(jclass, jmethod, "Bridge", new Array[Byte](0))) - if ((remoteClass || - (m.symbol.attributes contains AnnotationInfo(RemoteAttr, Nil, Nil))) && - jmethod.isPublic() && !forCLDC) - { - val ainfo = AnnotationInfo(ThrowsAttr, List(new AnnotationArgument(Constant(RemoteException))), List()) + if (remoteClass || + (m.symbol.hasAttribute(RemoteAttr) && jmethod.isPublic() && !forCLDC)) { + val ainfo = AnnotationInfo(ThrowsAttr.tpe, List(new AnnotationArgument(Constant(RemoteException))), List()) m.symbol.attributes = ainfo :: m.symbol.attributes; } diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 039a16a5d5..6f52db1acc 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -29,13 +29,11 @@ abstract class Inliners extends SubComponent { /** The Inlining phase. */ class InliningPhase(prev: Phase) extends ICodePhase(prev) { - def name = phaseName val inliner = new Inliner override def apply(c: IClass): Unit = inliner.analyzeClass(c) - } /** @@ -58,6 +56,9 @@ abstract class Inliners extends SubComponent { s + "0" } + lazy val ScalaInlineAttr = definitions.getClass("scala.inline") + lazy val ScalaNoInlineAttr = definitions.getClass("scala.noinline") + /** Inline the 'callee' method inside the 'caller' in the given * basic block, at the given instruction (which has to be a CALL_METHOD). */ @@ -262,12 +263,6 @@ abstract class Inliners extends SubComponent { assert(pending.isEmpty, "Pending NEW elements: " + pending) } - val InlineAttr = if (settings.inline.value) try { - global.definitions.getClass("scala.inline").tpe - } catch { - case e: FatalError => null - } else null; - def analyzeClass(cls: IClass): Unit = if (settings.inline.value) { if (settings.debug.value) log("Analyzing " + cls); @@ -316,15 +311,13 @@ abstract class Inliners extends SubComponent { if ( classes.contains(receiver) && (isClosureClass(receiver) - || concreteMethod.isFinal - || msym.attributes.exists(a => a.atp == InlineAttr))) { + || concreteMethod.isFinal)) { classes(receiver).lookupMethod(concreteMethod) match { case Some(inc) => if (inc.symbol != m.symbol && (inlinedMethods(inc.symbol) < 2) && (inc.code ne null) && shouldInline(m, inc) - && (inc.code.blocks.length <= MAX_INLINE_SIZE) && isSafeToInline(m, inc, info._2)) { retry = true; if (!isClosureClass(receiver)) // only count non-closures @@ -423,56 +416,59 @@ abstract class Inliners extends SubComponent { if (stack.length > (1 + callee.symbol.info.paramTypes.length) && callee.exh != Nil) { -// (callee.exh exists (_.covered.contains(callee.code.startBlock)))) { if (settings.debug.value) log("method " + callee.symbol + " is used on a non-empty stack with finalizer."); false } else true } - } /* class Inliner */ - - def isClosureClass(cls: Symbol): Boolean = { - val res = - cls.isFinal && - cls.tpe.parents.exists { t => - val TypeRef(_, sym, _) = t; - definitions.FunctionClass exists sym.== - } - res - } - - /** small method size (in blocks) */ - val SMALL_METHOD_SIZE = 4 + /** small method size (in blocks) */ + val SMALL_METHOD_SIZE = 4 - /** Decide whether to inline or not. Heuristics: - * - it's bad to make the caller larger (> SMALL_METHOD_SIZE) - * if it was small - * - it's good to inline higher order functions - * - it's good to inline closures functions. - * - it's bad (useless) to inline inside bridge methods - */ - def shouldInline(caller: IMethod, callee: IMethod): Boolean = { - if (caller.symbol.hasFlag(Flags.BRIDGE)) return false; - if (settings.debug.value) - log("shouldInline: " + caller + " with " + callee) - var score = 0 - if (callee.code.blocks.length <= SMALL_METHOD_SIZE) score = score + 1 - if (caller.code.blocks.length <= SMALL_METHOD_SIZE - && ((caller.code.blocks.length + callee.code.blocks.length) > SMALL_METHOD_SIZE)) { - score = score - 1 + /** Decide whether to inline or not. Heuristics: + * - it's bad to make the caller larger (> SMALL_METHOD_SIZE) + * if it was small + * - it's bad to inline large methods + * - it's good to inline higher order functions + * - it's good to inline closures functions. + * - it's bad (useless) to inline inside bridge methods + */ + def shouldInline(caller: IMethod, callee: IMethod): Boolean = { + if (caller.symbol.hasFlag(Flags.BRIDGE)) return false; + if (callee.symbol.hasAttribute(ScalaNoInlineAttr)) return false + if (callee.symbol.hasAttribute(ScalaInlineAttr)) return true if (settings.debug.value) - log("shouldInline: score decreased to " + score + " because small " + caller + " would become large") - } + log("shouldInline: " + caller + " with " + callee) + var score = 0 + if (callee.code.blocks.length <= SMALL_METHOD_SIZE) score = score + 1 + if (caller.code.blocks.length <= SMALL_METHOD_SIZE + && ((caller.code.blocks.length + callee.code.blocks.length) > SMALL_METHOD_SIZE)) { + score = score - 1 + if (settings.debug.value) + log("shouldInline: score decreased to " + score + " because small " + caller + " would become large") + } + if (callee.code.blocks.length > MAX_INLINE_SIZE) + score -= 1 - if (callee.symbol.tpe.paramTypes.exists(t => definitions.FunctionClass.contains(t.typeSymbol))) { - if (settings.debug.value) - log("increased score to: " + score) - score = score + 2 + if (callee.symbol.tpe.paramTypes.exists(t => definitions.FunctionClass.contains(t.typeSymbol))) { + if (settings.debug.value) + log("increased score to: " + score) + score = score + 2 + } + if (isClosureClass(callee.symbol.owner)) + score = score + 2 + + score > 0 } - if (isClosureClass(callee.symbol.owner)) - score = score + 2 + } /* class Inliner */ - score > 0 - } + /** Is the given class a subtype of a function trait? */ + def isClosureClass(cls: Symbol): Boolean = { + val res = cls.isFinal && + cls.tpe.parents.exists { t => + val TypeRef(_, sym, _) = t; + definitions.FunctionClass exists sym.== + } + res + } } /* class Inliners */ diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 60296a970b..dd2ac94f49 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -82,9 +82,11 @@ trait Symbols { } var attributes: List[AnnotationInfo] = List() - def hasAttribute(Tpe: Type): Boolean = + + /** Does this symbol have an attribute of the given class? */ + def hasAttribute(cls: Symbol): Boolean = attributes.exists { - case AnnotationInfo(Tpe, _, _) => true + case AnnotationInfo(tp, _, _) if tp.typeSymbol == cls => true case _ => false } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index c5c6326806..605263a2a1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -789,7 +789,7 @@ trait Namers { self: Analyzer => sym.isValueParameter && sym.owner.isClass && sym.owner.hasFlag(CASE)) context.error(sym.pos, "pass-by-name arguments not allowed for case class parameters"); if ((sym.flags & DEFERRED) != 0) { - if (sym.hasAttribute(definitions.NativeAttr.tpe)) + if (sym.hasAttribute(definitions.NativeAttr)) sym.resetFlag(DEFERRED) else if (!sym.isValueParameter && !sym.isTypeParameterOrSkolem && !context.tree.isInstanceOf[ExistentialTypeTree] && diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 30ef88a17b..174485c6cb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -727,7 +727,7 @@ abstract class RefChecks extends InfoTransform { val sym = tree.symbol var result = tree tree match { - case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAttribute(definitions.NativeAttr.tpe) => + case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAttribute(definitions.NativeAttr) => tree.symbol.resetFlag(DEFERRED) result = transform(copy.DefDef(tree, mods, name, tparams, vparams, tpt, typed(Apply(gen.mkAttributedRef(definitions.Predef_error), List(Literal("native method stub")))))) -- cgit v1.2.3