summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-06-16 22:14:52 +0000
committerPaul Phillips <paulp@improving.org>2010-06-16 22:14:52 +0000
commitb9fb76d09d0a6e63bfb6f332079ab7d05f1233ca (patch)
treeb98217ca683aef4e378b1f189400984bf72bdf08 /src
parentf750b08d9e8121c32cd433ee167cbc95705429ed (diff)
downloadscala-b9fb76d09d0a6e63bfb6f332079ab7d05f1233ca.tar.gz
scala-b9fb76d09d0a6e63bfb6f332079ab7d05f1233ca.tar.bz2
scala-b9fb76d09d0a6e63bfb6f332079ab7d05f1233ca.zip
The inliner now looks harder for method impleme...
The inliner now looks harder for method implementations. In addition to the receiver, it will find those in directly mixed in traits and in superclasses. It still won't find those in traits mixed only into superclasses, as that didn't come quite so easily. Closes #3234 but I'll be opening up another ticket. Review by dragos.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala123
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala1
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala3
3 files changed, 67 insertions, 60 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index 6a5a107d2d..d528f56ff8 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -126,19 +126,19 @@ abstract class Inliners extends SubComponent {
var info: tfa.lattice.Elem = null
def analyzeInc(msym: Symbol, i: Instruction, bb: BasicBlock) = {
- val inc = new SymMethodInfo(msym)
- val receiver = (info.stack.types drop inc.paramTypes.length).head match {
+ def paramTypes = msym.info.paramTypes
+ val receiver = (info.stack.types drop paramTypes.length).head match {
case REFERENCE(s) => s
case _ => NoSymbol
}
- val concreteMethod = inc lookupImplFor receiver
+ val concreteMethod = lookupImplFor(msym, receiver)
def warnNoInline(reason: String) = {
- if (inc.inline && !caller.isBridge)
+ if (hasInline(msym) && !caller.isBridge)
warn(i.pos, "Could not inline required method %s because %s.".format(msym.originalName.decode, reason))
}
- if (shouldLoad(receiver, concreteMethod))
+ if (shouldLoadImplFor(concreteMethod, receiver))
icodes.icode(receiver, true)
def isAvailable = icodes available receiver
@@ -221,50 +221,64 @@ abstract class Inliners extends SubComponent {
m.normalize
}
- class SymMethodInfo(val sym: Symbol) {
- val name = sym.name
- def owner = sym.owner
- def paramTypes = sym.info.paramTypes
- def minimumStack = paramTypes.length + 1
+ private def isMonadicMethod(sym: Symbol) = sym.name match {
+ case nme.foreach | nme.filter | nme.map | nme.flatMap => true
+ case _ => false
+ }
+ private def isHigherOrderMethod(sym: Symbol) =
+ sym.isMethod && atPhase(currentRun.erasurePhase.prev)(sym.info.paramTypes exists isFunctionType)
- def inline = hasInline(sym)
- def noinline = hasNoInline(sym)
- def numInlined = inlinedMethodCount(sym)
+ /** Should method 'sym' being called in 'receiver' be loaded from disk? */
+ def shouldLoadImplFor(sym: Symbol, receiver: Symbol): Boolean = {
+ if (settings.debug.value)
+ log("shouldLoadImplFor: " + receiver + "." + sym)
- def lookupImplFor(clazz: Symbol): Symbol = {
- // TODO: verify that clazz.superClass is equivalent here to clazz.tpe.parents(0).typeSymbol (.tpe vs .info)
- def needsLookup = (clazz != NoSymbol) && (clazz != owner) && !isEffectivelyFinal && clazz.isFinal
+ def alwaysLoad = (receiver.enclosingPackage == RuntimePackage) || (receiver == PredefModule.moduleClass)
+ def loadCondition = sym.isEffectivelyFinal && isMonadicMethod(sym) && isHigherOrderMethod(sym)
- def lookup(clazz: Symbol): Symbol = {
- // println("\t\tlooking up " + meth + " in " + clazz.fullName + " meth.owner = " + meth.owner)
- if (owner == clazz || isBottomType(clazz)) sym
- else sym.overridingSymbol(clazz) match {
- case NoSymbol => if (owner.isTrait) sym else lookup(clazz.superClass)
- case imp => imp
- }
- }
- if (needsLookup) {
- val concreteMethod = lookup(clazz)
- if (settings.debug.value)
- log("\tlooked up method: " + concreteMethod.fullName)
+ hasInline(sym) || alwaysLoad || loadCondition
+ }
- concreteMethod
+ /** Look up implementation of method 'sym in 'clazz'.
+ */
+ def lookupImplFor(sym: Symbol, clazz: Symbol): Symbol = {
+ // TODO: verify that clazz.superClass is equivalent here to clazz.tpe.parents(0).typeSymbol (.tpe vs .info)
+ def needsLookup = (clazz != NoSymbol) && (clazz != sym.owner) && !sym.isEffectivelyFinal && clazz.isFinal
+
+ def lookup(clazz: Symbol): Symbol = {
+ // println("\t\tlooking up " + meth + " in " + clazz.fullName + " meth.owner = " + meth.owner)
+ if (sym.owner == clazz || isBottomType(clazz)) sym
+ else sym.overridingSymbol(clazz) match {
+ case NoSymbol => if (sym.owner.isTrait) sym else lookup(clazz.superClass)
+ case imp => imp
}
- else sym
}
+ if (needsLookup) {
+ val concreteMethod = lookup(clazz)
+ if (settings.debug.value)
+ log("\tlooked up method: " + concreteMethod.fullName)
- def isBridge = sym.isBridge
- def isInClosure = isClosureClass(owner)
- def isHigherOrder = sym.isMethod && atPhase(currentRun.erasurePhase.prev)(paramTypes exists isFunctionType)
- def isMonadic = name match {
- case nme.foreach | nme.filter | nme.map | nme.flatMap => true
- case _ => false
+ concreteMethod
}
- def isEffectivelyFinal = sym.isEffectivelyFinal
- def shouldBeLoaded = inline || (isEffectivelyFinal && isMonadic && isHigherOrder)
+ else sym
}
- class IMethodInfo(val m: IMethod) extends SymMethodInfo(m.symbol) {
+ class IMethodInfo(val m: IMethod) {
+ val sym = m.symbol
+ val name = sym.name
+ def owner = sym.owner
+ def paramTypes = sym.info.paramTypes
+ def minimumStack = paramTypes.length + 1
+
+ def inline = hasInline(sym)
+ def noinline = hasNoInline(sym)
+ def numInlined = inlinedMethodCount(sym)
+
+ def isBridge = sym.isBridge
+ def isInClosure = isClosureClass(owner)
+ def isHigherOrder = isHigherOrderMethod(sym)
+ def isMonadic = isMonadicMethod(sym)
+
def handlers = m.exh
def blocks = m.code.blocks
def locals = m.locals
@@ -288,6 +302,7 @@ abstract class Inliners extends SubComponent {
class CallerCalleeInfo(val caller: IMethodInfo, val inc: IMethodInfo) {
def isLargeSum = caller.length + inc.length - 1 > SMALL_METHOD_SIZE
+
/** Inline 'inc' into 'caller' at the given block and instruction.
* The instruction must be a CALL_METHOD.
*/
@@ -309,14 +324,14 @@ abstract class Inliners extends SubComponent {
val varsInScope: mutable.Set[Local] = HashSet() ++= block.varsInScope
- val instrBefore = block.toList.takeWhile {
- case i @ SCOPE_ENTER(l) => varsInScope += l
- i ne instr
- case i =>
- i ne instr
+ /** Side effects varsInScope when it sees SCOPE_ENTERs. */
+ def instrBeforeFilter(i: Instruction): Boolean = {
+ i match { case SCOPE_ENTER(l) => varsInScope += l ; case _ => () }
+ i ne instr
}
+ val instrBefore = block.toList takeWhile instrBeforeFilter
+ val instrAfter = block.toList drop (instrBefore.length + 1)
- val instrAfter = block.toList.drop(instrBefore.length + 1)
assert(!instrAfter.isEmpty, "CALL_METHOD cannot be the last instruction in block!")
// store the '$this' into the special local
@@ -438,7 +453,7 @@ abstract class Inliners extends SubComponent {
// re-emit the instructions before the call
block.open
block.clear
- instrBefore foreach (i => block.emit(i, i.pos))
+ block emit instrBefore
// store the arguments into special locals
inc.m.params.reverse foreach (p => blockEmit(STORE_LOCAL(inlinedLocals(p))))
@@ -471,7 +486,7 @@ abstract class Inliners extends SubComponent {
inlinedBlock(bb).close
}
- instrAfter foreach (i => afterBlock.emit(i, i.pos))
+ afterBlock emit instrAfter
afterBlock.close
count += 1
@@ -621,18 +636,10 @@ abstract class Inliners extends SubComponent {
})
}
- /** Should the given method be loaded from disk? */
- def shouldLoad(receiver: Symbol, method: Symbol): Boolean = {
- if (settings.debug.value)
- log("shouldLoad: " + receiver + "." + method)
-
- val caller = new SymMethodInfo(method)
- def alwaysLoad = (receiver.enclosingPackage == RuntimePackage) || (receiver == PredefModule.moduleClass)
+ def lookupIMethod(meth: Symbol, receiver: Symbol): Option[IMethod] = {
+ def tryParent(sym: Symbol) = icodes icode sym flatMap (_ lookupMethod meth)
- caller.shouldBeLoaded || alwaysLoad
+ receiver.info.baseClasses.iterator map tryParent find (_.isDefined) getOrElse None
}
-
- def lookupIMethod(meth: Symbol, receiver: Symbol): Option[IMethod] =
- icodes.icode(receiver).get lookupMethod meth
} /* class Inliner */
} /* class Inliners */
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
index 0c124c9c19..b9afcda3ec 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
@@ -14,6 +14,7 @@ abstract class CPSAnnotationChecker extends CPSUtils {
import definitions._
//override val verbose = true
+ @inline override final def vprintln(x: =>Any): Unit = if (verbose) println(x)
/**
* Checks whether @cps annotations conform
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
index 57cba6e829..d1a35df04b 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
@@ -11,8 +11,7 @@ trait CPSUtils {
var cpsEnabled = false
val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true"
- @inline final def vprintln(x: =>Any): Unit = if (verbose) println(x)
-
+ def vprintln(x: =>Any): Unit = if (verbose) println(x)
lazy val MarkerCPSSym = definitions.getClass("scala.util.continuations.cpsSym")
lazy val MarkerCPSTypes = definitions.getClass("scala.util.continuations.cpsParam")