Changed annotation handling in the backend to use symbols instead of types.

Added support for @inline and @noinline.
Improved boxing/unboxing optimization.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@12365 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
dragos 2007-07-19 15:53:28 +00:00
parent 39722d1493
commit 00ee246af3
6 changed files with 88 additions and 84 deletions

View File

@ -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)) =>

View File

@ -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;
}

View File

@ -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)
}
/**
@ -57,6 +55,9 @@ abstract class Inliners extends SubComponent {
fresh(s) = 1
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
}
/** 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 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: " + 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 (isClosureClass(callee.symbol.owner))
score = score + 2
score > 0
}
} /* class Inliner */
/** 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.==
}
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
/** 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
if (settings.debug.value)
log("shouldInline: score decreased to " + score + " because small " + caller + " would become large")
}
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
}
} /* class Inliners */

View File

@ -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
}

View File

@ -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] &&

View File

@ -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"))))))