summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Garcia <miguelalfredo.garcia@epfl.ch>2012-07-26 20:35:21 +0200
committerMiguel Garcia <miguelalfredo.garcia@epfl.ch>2012-07-26 20:35:21 +0200
commitf2c1736b94c96a6e6950801ee053b30e872985a4 (patch)
tree50129acd31031f811f4eb662f4809b05a82d95a8
parentad08f24448729009fc8d5ff0acf307a43b4cfe0a (diff)
downloadscala-f2c1736b94c96a6e6950801ee053b30e872985a4.tar.gz
scala-f2c1736b94c96a6e6950801ee053b30e872985a4.tar.bz2
scala-f2c1736b94c96a6e6950801ee053b30e872985a4.zip
SI-6142: warn @inline-methods ending up not inlined (rightfully or not)
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala11
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala25
-rw-r--r--test/files/neg/t3234.check2
-rw-r--r--test/files/neg/t3234.flags (renamed from test/files/pos/t3234.flags)0
-rw-r--r--test/files/neg/t3234.scala (renamed from test/files/pos/t3234.scala)0
5 files changed, 33 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
index 7a5615ac26..962c47f443 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
@@ -470,6 +470,8 @@ abstract class TypeFlowAnalysis {
val isOnWatchlist = mutable.Set.empty[Instruction]
+ val warnIfInlineFails = mutable.Set.empty[opcodes.CALL_METHOD] // cache for a given IMethod (ie cleared on Inliner.analyzeMethod).
+
/* Each time CallerCalleeInfo.isSafeToInline determines a concrete callee is unsafe to inline in the current caller,
the fact is recorded in this TFA instance for the purpose of avoiding devoting processing to that callsite next time.
The condition of "being unsafe to inline in the current caller" sticks across inlinings and TFA re-inits
@@ -510,6 +512,7 @@ abstract class TypeFlowAnalysis {
// initially populate the watchlist with all callsites standing a chance of being inlined
isOnWatchlist.clear()
relevantBBs.clear()
+ warnIfInlineFails.clear()
/* TODO Do we want to perform inlining in non-finally exception handlers?
* Seems counterproductive (the larger the method the less likely it will be JITed.
* It's not that putting on radar only `linearizer linearizeAt (m, m.startBlock)` makes for much shorter inlining times (a minor speedup nonetheless)
@@ -533,11 +536,11 @@ abstract class TypeFlowAnalysis {
private def putOnRadar(blocks: Traversable[BasicBlock]) {
for(bb <- blocks) {
- val preCands = bb.toList collect {
- case cm : opcodes.CALL_METHOD
- if isPreCandidate(cm) /* && !isReceiverKnown(cm) */
- => cm
+ val calls = bb.toList collect { case cm : opcodes.CALL_METHOD => cm }
+ for(c <- calls; if(inliner.hasInline(c.method))) {
+ warnIfInlineFails += c
}
+ val preCands = calls filter isPreCandidate
isOnWatchlist ++= preCands
}
relevantBBs ++= blocks
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index 44acfed411..cce18d436f 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -129,11 +129,15 @@ abstract class Inliners extends SubComponent {
override def apply(c: IClass) { queue += c }
override def run() {
+ knownLacksInline.clear()
+ knownHasInline.clear()
try {
super.run()
for(c <- queue) { inliner analyzeClass c }
} finally {
inliner.clearCaches()
+ knownLacksInline.clear()
+ knownHasInline.clear()
}
}
}
@@ -157,7 +161,21 @@ abstract class Inliners extends SubComponent {
}
}
- def hasInline(sym: Symbol) = sym hasAnnotation ScalaInlineClass
+ val knownLacksInline = mutable.Set.empty[Symbol] // cache to avoid multiple inliner.hasInline() calls.
+ val knownHasInline = mutable.Set.empty[Symbol] // as above. Motivated by the need to warn on "inliner failures".
+
+ def hasInline(sym: Symbol) = {
+ if (knownLacksInline(sym)) false
+ else if(knownHasInline(sym)) true
+ else {
+ val b = (sym hasAnnotation ScalaInlineClass)
+ if(b) { knownHasInline += sym }
+ else { knownLacksInline += sym }
+
+ b
+ }
+ }
+
def hasNoInline(sym: Symbol) = sym hasAnnotation ScalaNoInlineClass
/**
@@ -536,6 +554,10 @@ abstract class Inliners extends SubComponent {
}
while (retry && count < MAX_INLINE_RETRY)
+ for(inlFail <- tfa.warnIfInlineFails) {
+ warn(inlFail.pos, "At the end of the day, could not inline @inline-marked method " + inlFail.method.originalName.decode)
+ }
+
m.normalize
if (sizeBeforeInlining > 0) {
val instrAfterInlining = m.code.instructionCount
@@ -731,6 +753,7 @@ abstract class Inliners extends SubComponent {
tfa.remainingCALLs.remove(instr) // this bookkpeeping is done here and not in MTFAGrowable.reinit due to (1st) convenience and (2nd) necessity.
tfa.isOnWatchlist.remove(instr) // ditto
+ tfa.warnIfInlineFails.remove(instr)
val targetPos = instr.pos
log("Inlining " + inc.m + " in " + caller.m + " at pos: " + posToStr(targetPos))
diff --git a/test/files/neg/t3234.check b/test/files/neg/t3234.check
new file mode 100644
index 0000000000..477b021e5e
--- /dev/null
+++ b/test/files/neg/t3234.check
@@ -0,0 +1,2 @@
+error: there were 1 inliner warnings; re-run with -Yinline-warnings for details
+one error found
diff --git a/test/files/pos/t3234.flags b/test/files/neg/t3234.flags
index c9cefdc4b9..c9cefdc4b9 100644
--- a/test/files/pos/t3234.flags
+++ b/test/files/neg/t3234.flags
diff --git a/test/files/pos/t3234.scala b/test/files/neg/t3234.scala
index 443d0467f0..443d0467f0 100644
--- a/test/files/pos/t3234.scala
+++ b/test/files/neg/t3234.scala