diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-05-24 22:13:20 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-05-24 22:23:00 +0200 |
commit | 1db58b52e064579e857260de93e1a706a783a7e5 (patch) | |
tree | 69933f1052954b12f44ca8f9a5b050c9cef658aa /src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala | |
parent | 207e32df30fd733e4dd1cb28fb8cb5c3153c21a6 (diff) | |
download | scala-1db58b52e064579e857260de93e1a706a783a7e5.tar.gz scala-1db58b52e064579e857260de93e1a706a783a7e5.tar.bz2 scala-1db58b52e064579e857260de93e1a706a783a7e5.zip |
Debug flag to print a summary of the inliner's work
Example output below. Note that inlining List.map fails because the
trait forwarder uses `INVOKESPECIAL` for now, will change with pr 5177.
$ cat Test.scala
class C {
def foo = Map(1 -> 'a', 2 -> 'b')
def bar(l: List[Int]) = l.map(_ + 1)
}
$ qsc -Yopt-log-inline _ -Yopt:l:classpath Test.scala
Inlining into C.foo (initially 36 instructions, ultimately 72):
- Inlined scala/Predef$ArrowAssoc$.$minus$greater$extension (8 instructions) 2 times: the callee is annotated `@inline`
Inlining into C.bar (initially 12 instructions, ultimately 12):
- Failed to inline scala/collection/immutable/List.map (the callee is a higher-order method, the argument for parameter (bf: Function1) is a function literal): The callee scala/collection/immutable/List::map(Lscala/Function1;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object; contains the instruction INVOKESPECIAL scala/collection/TraversableLike.map (Lscala/Function1;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object;
that would cause an IllegalAccessError when inlined into class C.
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala index f35eaa45e9..4b65a566d3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala @@ -25,6 +25,9 @@ class Inliner[BT <: BTypes](val btypes: BT) { import inlinerHeuristics._ import backendUtils._ + case class InlineLog(request: InlineRequest, sizeBefore: Int, sizeAfter: Int, sizeInlined: Int, warning: Option[CannotInlineWarning]) + var inlineLog: List[InlineLog] = Nil + def runInliner(): Unit = { for (request <- collectAndOrderInlineRequests) { val Right(callee) = request.callsite.callee // collectAndOrderInlineRequests returns callsites with a known callee @@ -42,6 +45,29 @@ class Inliner[BT <: BTypes](val btypes: BT) { } } } + + if (compilerSettings.YoptLogInline.isSetByUser) { + val methodPrefix = { val p = compilerSettings.YoptLogInline.value; if (p == "_") "" else p } + val byCallsiteMethod = inlineLog.groupBy(_.request.callsite.callsiteMethod).toList.sortBy(_._2.head.request.callsite.callsiteClass.internalName) + for ((m, mLogs) <- byCallsiteMethod) { + val initialSize = mLogs.minBy(_.sizeBefore).sizeBefore + val firstLog = mLogs.head + val methodName = s"${firstLog.request.callsite.callsiteClass.internalName}.${m.name}" + if (methodName.startsWith(methodPrefix)) { + println(s"Inlining into $methodName (initially $initialSize instructions, ultimately ${m.instructions.size}):") + val byCallee = mLogs.groupBy(_.request.callsite.callee.get).toList.sortBy(_._2.length).reverse + for ((c, cLogs) <- byCallee) { + val first = cLogs.head + if (first.warning.isEmpty) { + val num = if (cLogs.tail.isEmpty) "" else s" ${cLogs.length} times" + println(s" - Inlined ${c.calleeDeclarationClass.internalName}.${c.callee.name} (${first.sizeInlined} instructions)$num: ${first.request.reason}") + } else + println(s" - Failed to inline ${c.calleeDeclarationClass.internalName}.${c.callee.name} (${first.request.reason}): ${first.warning.get}") + } + println() + } + } + } } /** @@ -184,7 +210,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { def impl(post: InlineRequest, at: Callsite): List[InlineRequest] = { post.callsite.inlinedClones.find(_.clonedWhenInlining == at) match { case Some(clonedCallsite) => - List(InlineRequest(clonedCallsite.callsite, post.post)) + List(InlineRequest(clonedCallsite.callsite, post.post, post.reason)) case None => post.post.flatMap(impl(_, post.callsite)).flatMap(impl(_, at)) } @@ -199,9 +225,17 @@ class Inliner[BT <: BTypes](val btypes: BT) { * @return An inliner warning for each callsite that could not be inlined. */ def inline(request: InlineRequest): List[CannotInlineWarning] = canInlineBody(request.callsite) match { - case Some(w) => List(w) + case Some(w) => + if (compilerSettings.YoptLogInline.isSetByUser) { + val size = request.callsite.callsiteMethod.instructions.size + inlineLog ::= InlineLog(request, size, size, 0, Some(w)) + } + List(w) case None => + val sizeBefore = request.callsite.callsiteMethod.instructions.size inlineCallsite(request.callsite) + if (compilerSettings.YoptLogInline.isSetByUser) + inlineLog ::= InlineLog(request, sizeBefore, request.callsite.callsiteMethod.instructions.size, request.callsite.callee.get.callee.instructions.size, None) val postRequests = request.post.flatMap(adaptPostRequestForMainCallsite(_, request.callsite)) postRequests flatMap inline } |