Skip to content

Commit a1d471f

Browse files
committed
[backport] Refactor the ClosureOptimizer, run ProdCons only once per method
Refactor and clean up the ClosureOptimzier. The goal of this change is to run the ProdCons analyzer only once per method, instead of once per closure instantiation. Bootstrapping scala with `-Yopt-inline-heuristics:everything` revealed that ProdCons can take a very long time on large methods, for example ``` [quick.compiler] scala/tools/nsc/backend/jvm/BCodeBodyBuilder$PlainBodyBuilder#genArithmeticOp - analysis: 1 spans, 17755ms [quick.compiler] scala/tools/nsc/typechecker/SuperAccessors$SuperAccTransformer#transform - analysis: 1 spans, 28024ms [quick.compiler] scala/tools/nsc/backend/jvm/BCodeBodyBuilder$PlainBodyBuilder#genInvokeDynamicLambda - analysis: 1 spans, 22100ms ``` With this change and enough time and space (-Xmx6000m), bootstrapping scala succeeds in this test mode.
1 parent f5e7276 commit a1d471f

File tree

3 files changed

+231
-158
lines changed

3 files changed

+231
-158
lines changed

src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ object BackendReporting {
255255
* Used in `rewriteClosureApplyInvocations` when a closure apply callsite cannot be rewritten
256256
* to the closure body method.
257257
*/
258-
trait RewriteClosureApplyToClosureBodyFailed extends OptimizerWarning {
258+
sealed trait RewriteClosureApplyToClosureBodyFailed extends OptimizerWarning {
259259
def pos: Position
260260

261261
override def emitWarning(settings: ScalaSettings): Boolean = this match {

src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzer.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,20 @@ import scala.collection.convert.decorateAsScala._
5757
* copying operations.
5858
*/
5959
class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName) {
60+
61+
/* Timers for benchmarking ProdCons
62+
import scala.reflect.internal.util.Statistics._
63+
import ProdConsAnalyzer._
64+
val analyzerTimer = newSubTimer(classInternalName + "#" + methodNode.name + " - analysis", prodConsAnalyzerTimer)
65+
val consumersTimer = newSubTimer(classInternalName + "#" + methodNode.name + " - consumers", prodConsAnalyzerTimer)
66+
*/
67+
6068
val analyzer = new Analyzer(new InitialProducerSourceInterpreter)
69+
70+
// val start = analyzerTimer.start()
6171
analyzer.analyze(classInternalName, methodNode)
72+
// analyzerTimer.stop(start)
73+
// println(analyzerTimer.line)
6274

6375
def frameAt(insn: AbstractInsnNode) = analyzer.frameAt(insn, methodNode)
6476

@@ -392,6 +404,7 @@ class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName)
392404

393405
/** For each instruction, a set of potential consumers of the produced values. */
394406
private lazy val _consumersOfOutputsFrom: Map[AbstractInsnNode, Vector[Set[AbstractInsnNode]]] = {
407+
// val start = consumersTimer.start()
395408
var res = Map.empty[AbstractInsnNode, Vector[Set[AbstractInsnNode]]]
396409
for {
397410
insn <- methodNode.instructions.iterator.asScala
@@ -404,13 +417,20 @@ class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName)
404417
val outputIndex = producedSlots.indexOf(i)
405418
res = res.updated(producer, currentConsumers.updated(outputIndex, currentConsumers(outputIndex) + insn))
406419
}
420+
// consumersTimer.stop(start)
421+
// println(consumersTimer.line)
407422
res
408423
}
409424

410425
private val _initialProducersCache: mutable.AnyRefMap[(AbstractInsnNode, Int), Set[AbstractInsnNode]] = mutable.AnyRefMap.empty
411426
private val _ultimateConsumersCache: mutable.AnyRefMap[(AbstractInsnNode, Int), Set[AbstractInsnNode]] = mutable.AnyRefMap.empty
412427
}
413428

429+
object ProdConsAnalyzer {
430+
import scala.reflect.internal.util.Statistics._
431+
val prodConsAnalyzerTimer = newTimer("Time in ProdConsAnalyzer", "jvm")
432+
}
433+
414434
/**
415435
* A class for pseudo-instructions representing the initial producers of local values that have
416436
* no producer instruction in the method:

0 commit comments

Comments
 (0)