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:
parent
39722d1493
commit
00ee246af3
|
@ -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)) =>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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] &&
|
||||
|
|
|
@ -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"))))))
|
||||
|
|
Loading…
Reference in New Issue