summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-10-02 12:27:43 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-10-20 11:17:04 +0200
commit0a33c421767f6e4587f8adac19169f184d845548 (patch)
tree9a6de2618f81a5324e642865d6655d77f9f83c59 /src/compiler/scala/tools/nsc/backend
parent5bca4b2fca92dfe1f89785ba8d80cb9599d747f6 (diff)
downloadscala-0a33c421767f6e4587f8adac19169f184d845548.tar.gz
scala-0a33c421767f6e4587f8adac19169f184d845548.tar.bz2
scala-0a33c421767f6e4587f8adac19169f184d845548.zip
Simplify post inlining requests
Clean up inliner test
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala14
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala36
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala6
3 files changed, 34 insertions, 22 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
index a8f1e43071..801296908f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -67,6 +67,8 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
callsites(callsite.callsiteMethod) = methodCallsites + (callsite.callsiteInstruction -> callsite)
}
+ def containsCallsite(callsite: Callsite): Boolean = callsites(callsite.callsiteMethod) contains callsite.callsiteInstruction
+
def removeClosureInstantiation(indy: InvokeDynamicInsnNode, methodNode: MethodNode): Option[ClosureInstantiation] = {
val methodClosureInits = closureInstantiations(methodNode)
val newClosureInits = methodClosureInits - indy
@@ -130,8 +132,8 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
val callee: Either[OptimizerWarning, Callee] = for {
(method, declarationClass) <- byteCodeRepository.methodNode(call.owner, call.name, call.desc): Either[OptimizerWarning, (MethodNode, InternalName)]
(declarationClassNode, source) <- byteCodeRepository.classNodeAndSource(declarationClass): Either[OptimizerWarning, (ClassNode, Source)]
- declarationClassBType = classBTypeFromClassNode(declarationClassNode)
} yield {
+ val declarationClassBType = classBTypeFromClassNode(declarationClassNode)
val CallsiteInfo(safeToInline, safeToRewrite, annotatedInline, annotatedNoInline, samParamTypes, warning) = analyzeCallsite(method, declarationClassBType, call.owner, source)
Callee(
callee = method,
@@ -347,6 +349,12 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
final case class Callsite(callsiteInstruction: MethodInsnNode, callsiteMethod: MethodNode, callsiteClass: ClassBType,
callee: Either[OptimizerWarning, Callee], argInfos: IntMap[ArgInfo],
callsiteStackHeight: Int, receiverKnownNotNull: Boolean, callsitePosition: Position) {
+ /**
+ * Contains callsites that were created during inlining by cloning this callsite. Used to find
+ * corresponding callsites when inlining post-inline requests.
+ */
+ val inlinedClones = mutable.Set.empty[Callsite]
+
override def toString =
"Invocation of" +
s" ${callee.map(_.calleeDeclarationClass.internalName).getOrElse("?")}.${callsiteInstruction.name + callsiteInstruction.desc}" +
@@ -399,6 +407,10 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
* graph when re-writing a closure invocation to the body method.
*/
final case class ClosureInstantiation(lambdaMetaFactoryCall: LambdaMetaFactoryCall, ownerMethod: MethodNode, ownerClass: ClassBType, capturedArgInfos: IntMap[ArgInfo]) {
+ /**
+ * Contains closure instantiations that were created during inlining by cloning this instantiation.
+ */
+ val inlinedClones = mutable.Set.empty[ClosureInstantiation]
override def toString = s"ClosureInstantiation($lambdaMetaFactoryCall, ${ownerMethod.name + ownerMethod.desc}, $ownerClass)"
}
final case class LambdaMetaFactoryCall(indy: InvokeDynamicInsnNode, samMethodType: Type, implMethod: Handle, instantiatedMethodType: Type)
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 9a5341e131..4e1ecea217 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
@@ -272,14 +272,12 @@ class Inliner[BT <: BTypes](val btypes: BT) {
def inline(request: InlineRequest): List[CannotInlineWarning] = canInlineBody(request.callsite) match {
case Some(w) => List(w)
case None =>
- val instructionsMap = inlineCallsite(request.callsite)
+ inlineCallsite(request.callsite)
val postRequests = request.post.flatMap(post => {
- // the post-request invocation instruction might not exist anymore: it might have been
- // inlined itself, or eliminated by DCE.
- for {
- inlinedInvocationInstr <- instructionsMap.get(post.callsiteInstruction).map(_.asInstanceOf[MethodInsnNode])
- inlinedCallsite <- callGraph.callsites(request.callsite.callsiteMethod).get(inlinedInvocationInstr)
- } yield InlineRequest(inlinedCallsite, post.post)
+ post.callsite.inlinedClones.find(cs => cs.callsiteMethod == request.callsite.callsiteMethod) match {
+ case Some(inlinedPostCallsite) if callGraph.containsCallsite(inlinedPostCallsite) => Some(InlineRequest(inlinedPostCallsite, post.post))
+ case _ => None
+ }
})
postRequests flatMap inline
}
@@ -296,7 +294,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
* @return A map associating instruction nodes of the callee with the corresponding cloned
* instruction in the callsite method.
*/
- def inlineCallsite(callsite: Callsite): Map[AbstractInsnNode, AbstractInsnNode] = {
+ def inlineCallsite(callsite: Callsite): Unit = {
import callsite.{callsiteClass, callsiteMethod, callsiteInstruction, receiverKnownNotNull, callsiteStackHeight}
val Right(callsiteCallee) = callsite.callee
import callsiteCallee.{callee, calleeDeclarationClass}
@@ -451,7 +449,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
callGraph.callsites(callee).valuesIterator foreach { originalCallsite =>
val newCallsiteIns = instructionMap(originalCallsite.callsiteInstruction).asInstanceOf[MethodInsnNode]
val argInfos = originalCallsite.argInfos flatMap mapArgInfo
- callGraph.addCallsite(Callsite(
+ val newCallsite = Callsite(
callsiteInstruction = newCallsiteIns,
callsiteMethod = callsiteMethod,
callsiteClass = callsiteClass,
@@ -460,19 +458,21 @@ class Inliner[BT <: BTypes](val btypes: BT) {
callsiteStackHeight = callsiteStackHeight + originalCallsite.callsiteStackHeight,
receiverKnownNotNull = originalCallsite.receiverKnownNotNull,
callsitePosition = originalCallsite.callsitePosition
- ))
+ )
+ originalCallsite.inlinedClones += newCallsite
+ callGraph.addCallsite(newCallsite)
}
callGraph.closureInstantiations(callee).valuesIterator foreach { originalClosureInit =>
val newIndy = instructionMap(originalClosureInit.lambdaMetaFactoryCall.indy).asInstanceOf[InvokeDynamicInsnNode]
val capturedArgInfos = originalClosureInit.capturedArgInfos flatMap mapArgInfo
- callGraph.addClosureInstantiation(
- ClosureInstantiation(
- originalClosureInit.lambdaMetaFactoryCall.copy(indy = newIndy),
- callsiteMethod,
- callsiteClass,
- capturedArgInfos)
- )
+ val newClosureInit = ClosureInstantiation(
+ originalClosureInit.lambdaMetaFactoryCall.copy(indy = newIndy),
+ callsiteMethod,
+ callsiteClass,
+ capturedArgInfos)
+ originalClosureInit.inlinedClones += newClosureInit
+ callGraph.addClosureInstantiation(newClosureInit)
}
// Remove the elided invocation from the call graph
@@ -480,8 +480,6 @@ class Inliner[BT <: BTypes](val btypes: BT) {
// Inlining a method body can render some code unreachable, see example above (in runInliner).
unreachableCodeEliminated -= callsiteMethod
-
- instructionMap
}
/**
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
index d8f12ffb11..52627e77e6 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala
@@ -19,8 +19,10 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) {
import inliner._
import callGraph._
- case class InlineRequest(callsite: Callsite, post: List[PostInlineRequest])
- case class PostInlineRequest(callsiteInstruction: MethodInsnNode, post: List[PostInlineRequest])
+ case class InlineRequest(callsite: Callsite, post: List[InlineRequest]) {
+ // invariant: all post inline requests denote callsites in the callee of the main callsite
+ for (pr <- post) assert(pr.callsite.callsiteMethod == callsite.callee.get.callee, s"Callsite method mismatch: main $callsite - post ${pr.callsite}")
+ }
/**
* Select callsites from the call graph that should be inlined, grouped by the containing method.