summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--test/files/pos/bug3234.flags1
-rw-r--r--test/files/pos/bug3234.scala19
5 files changed, 87 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")
diff --git a/test/files/pos/bug3234.flags b/test/files/pos/bug3234.flags
new file mode 100644
index 0000000000..c9cefdc4b9
--- /dev/null
+++ b/test/files/pos/bug3234.flags
@@ -0,0 +1 @@
+-Yinline -Xfatal-warnings \ No newline at end of file
diff --git a/test/files/pos/bug3234.scala b/test/files/pos/bug3234.scala
new file mode 100644
index 0000000000..1553f1fa05
--- /dev/null
+++ b/test/files/pos/bug3234.scala
@@ -0,0 +1,19 @@
+trait Trait1 {
+ // need more work before this one works
+ // @inline
+ def foo2(n: Int) = n*n
+}
+
+trait Trait2 {
+ @inline def foo3(n: Int) = 1
+}
+
+class Base extends Trait1 {
+ @inline def foo(n: Int) = n
+}
+
+object Test extends Base with Trait2 {
+ def main(args: Array[String]) = {
+ println(foo(42) + foo2(11) + foo3(2))
+ }
+} \ No newline at end of file