summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-05-24 22:13:20 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2016-05-24 22:23:00 +0200
commit1db58b52e064579e857260de93e1a706a783a7e5 (patch)
tree69933f1052954b12f44ca8f9a5b050c9cef658aa /src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
parent207e32df30fd733e4dd1cb28fb8cb5c3153c21a6 (diff)
downloadscala-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.scala38
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
}