diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2015-08-17 14:35:22 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2015-08-17 14:35:22 +0200 |
commit | 0ed745364891e4e5f78e51ac9f3aad111b5c7bb3 (patch) | |
tree | 9468e4f25bd016956ecbe74e1574897a47f17096 /src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala | |
parent | 5217b00082d1a7bce2cd44666cb93dab7cb93f0a (diff) | |
download | scala-0ed745364891e4e5f78e51ac9f3aad111b5c7bb3.tar.gz scala-0ed745364891e4e5f78e51ac9f3aad111b5c7bb3.tar.bz2 scala-0ed745364891e4e5f78e51ac9f3aad111b5c7bb3.zip |
Group call graph by method
Change the hash maps in the call graph to index callsites and
closure instantiations by the containing method. This is beneficial
for implementing inliner heuristics and the closure optimizer.
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 | 68 |
1 files changed, 30 insertions, 38 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 8477f5461a..c5d2d212f4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala @@ -27,8 +27,8 @@ class Inliner[BT <: BTypes](val btypes: BT) { def eliminateUnreachableCodeAndUpdateCallGraph(methodNode: MethodNode, definingClass: InternalName): Unit = { localOpt.minimalRemoveUnreachableCode(methodNode, definingClass) foreach { - case invocation: MethodInsnNode => callGraph.callsites.remove(invocation) - case indy: InvokeDynamicInsnNode => callGraph.closureInstantiations.remove(indy) + case invocation: MethodInsnNode => callGraph.removeCallsite(invocation, methodNode) + case indy: InvokeDynamicInsnNode => callGraph.removeClosureInstantiation(indy, methodNode) case _ => } } @@ -48,7 +48,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { // DCE above removes unreachable callsites from the call graph. If the inlining request denotes // such an eliminated callsite, do nothing. - if (callGraph.callsites contains request.callsiteInstruction) { + if (callGraph.callsites(request.callsiteMethod).contains(request.callsiteInstruction)) { val r = inline(request.callsiteInstruction, request.callsiteStackHeight, request.callsiteMethod, request.callsiteClass, callee.callee, callee.calleeDeclarationClass, request.receiverKnownNotNull, keepLineNumbers = false) @@ -90,7 +90,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { * requests is allowed to have cycles, and the callsites can appear in any order. */ def selectCallsitesForInlining: List[Callsite] = { - callsites.valuesIterator.filter({ + callsites.valuesIterator.flatMap(_.valuesIterator.filter({ case callsite @ Callsite(_, _, _, Right(Callee(callee, calleeDeclClass, safeToInline, _, annotatedInline, _, warning)), _, _, _, pos) => val res = doInlineCallsite(callsite) @@ -118,7 +118,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { if (warning.emitWarning(compilerSettings)) backendReporting.inlinerWarning(pos, s"failed to determine if ${ins.name} should be inlined:\n$warning") false - }).toList + })).toList } /** @@ -136,7 +136,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { // Rewriting final trait method callsites to the implementation class enables inlining. // We cannot just iterate over the values of the `callsites` map because the rewrite changes the // map. Therefore we first copy the values to a list. - callsites.values.toList.foreach(rewriteFinalTraitMethodInvocation) + callsites.valuesIterator.flatMap(_.valuesIterator).toList.foreach(rewriteFinalTraitMethodInvocation) } /** @@ -202,7 +202,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { callsite.callsiteMethod.instructions.insert(callsite.callsiteInstruction, newCallsiteInstruction) callsite.callsiteMethod.instructions.remove(callsite.callsiteInstruction) - callGraph.callsites.remove(callsite.callsiteInstruction) + callGraph.removeCallsite(callsite.callsiteInstruction, callsite.callsiteMethod) val staticCallsite = Callsite( callsiteInstruction = newCallsiteInstruction, callsiteMethod = callsite.callsiteMethod, @@ -220,13 +220,13 @@ class Inliner[BT <: BTypes](val btypes: BT) { receiverKnownNotNull = callsite.receiverKnownNotNull, callsitePosition = callsite.callsitePosition ) - callGraph.callsites(newCallsiteInstruction) = staticCallsite + callGraph.addCallsite(staticCallsite) } for (warning <- res.left) { val Right(callee) = callsite.callee val newCallee = callee.copy(calleeInfoWarning = Some(RewriteTraitCallToStaticImplMethodFailed(calleeDeclarationClass.internalName, callee.callee.name, callee.callee.desc, warning))) - callGraph.callsites(callsite.callsiteInstruction) = callsite.copy(callee = Right(newCallee)) + callGraph.addCallsite(callsite.copy(callee = Right(newCallee))) } } } @@ -435,38 +435,30 @@ class Inliner[BT <: BTypes](val btypes: BT) { callsiteMethod.tryCatchBlocks.addAll(cloneTryCatchBlockNodes(callee, labelsMap).asJava) // Add all invocation instructions and closure instantiations that were inlined to the call graph - callee.instructions.iterator().asScala foreach { - case originalCallsiteIns: MethodInsnNode => - callGraph.callsites.get(originalCallsiteIns) match { - case Some(originalCallsite) => - val newCallsiteIns = instructionMap(originalCallsiteIns).asInstanceOf[MethodInsnNode] - callGraph.callsites(newCallsiteIns) = Callsite( - callsiteInstruction = newCallsiteIns, - callsiteMethod = callsiteMethod, - callsiteClass = callsiteClass, - callee = originalCallsite.callee, - argInfos = Nil, // TODO: re-compute argInfos for new destination (once we actually compute them) - callsiteStackHeight = callsiteStackHeight + originalCallsite.callsiteStackHeight, - receiverKnownNotNull = originalCallsite.receiverKnownNotNull, - callsitePosition = originalCallsite.callsitePosition - ) - - case None => - } - - case indy: InvokeDynamicInsnNode => - callGraph.closureInstantiations.get(indy) match { - case Some(closureInit) => - val newIndy = instructionMap(indy).asInstanceOf[InvokeDynamicInsnNode] - callGraph.closureInstantiations(newIndy) = ClosureInstantiation(closureInit.lambdaMetaFactoryCall.copy(indy = newIndy), callsiteMethod, callsiteClass) - - case None => - } + callGraph.callsites(callee).valuesIterator foreach { originalCallsite => + val newCallsiteIns = instructionMap(originalCallsite.callsiteInstruction).asInstanceOf[MethodInsnNode] + callGraph.addCallsite(Callsite( + callsiteInstruction = newCallsiteIns, + callsiteMethod = callsiteMethod, + callsiteClass = callsiteClass, + callee = originalCallsite.callee, + argInfos = Nil, // TODO: re-compute argInfos for new destination (once we actually compute them) + callsiteStackHeight = callsiteStackHeight + originalCallsite.callsiteStackHeight, + receiverKnownNotNull = originalCallsite.receiverKnownNotNull, + callsitePosition = originalCallsite.callsitePosition + ) + ) + } - case _ => + callGraph.closureInstantiations(callee).valuesIterator foreach { originalClosureInit => + val newIndy = instructionMap(originalClosureInit.lambdaMetaFactoryCall.indy).asInstanceOf[InvokeDynamicInsnNode] + callGraph.addClosureInstantiation( + ClosureInstantiation(originalClosureInit.lambdaMetaFactoryCall.copy(indy = newIndy), callsiteMethod, callsiteClass) + ) } + // Remove the elided invocation from the call graph - callGraph.callsites.remove(callsiteInstruction) + callGraph.removeCallsite(callsiteInstruction, callsiteMethod) // Inlining a method body can render some code unreachable, see example above (in runInliner). unreachableCodeEliminated -= callsiteMethod |