From f2c1736b94c96a6e6950801ee053b30e872985a4 Mon Sep 17 00:00:00 2001 From: Miguel Garcia Date: Thu, 26 Jul 2012 20:35:21 +0200 Subject: SI-6142: warn @inline-methods ending up not inlined (rightfully or not) --- .../backend/icode/analysis/TypeFlowAnalysis.scala | 11 ++++++---- .../scala/tools/nsc/backend/opt/Inliners.scala | 25 +++++++++++++++++++++- test/files/neg/t3234.check | 2 ++ test/files/neg/t3234.flags | 1 + test/files/neg/t3234.scala | 19 ++++++++++++++++ test/files/pos/t3234.flags | 1 - test/files/pos/t3234.scala | 19 ---------------- 7 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 test/files/neg/t3234.check create mode 100644 test/files/neg/t3234.flags create mode 100644 test/files/neg/t3234.scala delete mode 100644 test/files/pos/t3234.flags delete mode 100644 test/files/pos/t3234.scala 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/neg/t3234.flags b/test/files/neg/t3234.flags new file mode 100644 index 0000000000..c9cefdc4b9 --- /dev/null +++ b/test/files/neg/t3234.flags @@ -0,0 +1 @@ +-Yinline -Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/t3234.scala b/test/files/neg/t3234.scala new file mode 100644 index 0000000000..443d0467f0 --- /dev/null +++ b/test/files/neg/t3234.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 diff --git a/test/files/pos/t3234.flags b/test/files/pos/t3234.flags deleted file mode 100644 index c9cefdc4b9..0000000000 --- a/test/files/pos/t3234.flags +++ /dev/null @@ -1 +0,0 @@ --Yinline -Xfatal-warnings \ No newline at end of file diff --git a/test/files/pos/t3234.scala b/test/files/pos/t3234.scala deleted file mode 100644 index 443d0467f0..0000000000 --- a/test/files/pos/t3234.scala +++ /dev/null @@ -1,19 +0,0 @@ -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 -- cgit v1.2.3