diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2015-09-09 20:11:27 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2015-09-17 22:05:05 +0200 |
commit | 7b52a12b0a4b5c7e7dcc439714baf167cf2f6e84 (patch) | |
tree | 5d5e8aa3a57be980a711cf93bf999ee5093cef1b | |
parent | 2a9466723833caae0ec7b5c48953917b62a2e910 (diff) | |
download | scala-7b52a12b0a4b5c7e7dcc439714baf167cf2f6e84.tar.gz scala-7b52a12b0a4b5c7e7dcc439714baf167cf2f6e84.tar.bz2 scala-7b52a12b0a4b5c7e7dcc439714baf167cf2f6e84.zip |
Minor fixes in the optimizer
Fixes the variable indices in the local variable table (debug info)
for inlined locals.
After re-writing a closure invocation to the body method, mark the
callsite method as potentially having dead code. The body method may
return Nothing$, creating new unreachable code in the callsite method.
4 files changed, 10 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala index df8dcc690a..ede572dfb4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala @@ -308,14 +308,14 @@ object BytecodeUtils { * Clone the local variable descriptors of `methodNode` and map their `start` and `end` labels * according to the `labelMap`. */ - def cloneLocalVariableNodes(methodNode: MethodNode, labelMap: Map[LabelNode, LabelNode], prefix: String): List[LocalVariableNode] = { + def cloneLocalVariableNodes(methodNode: MethodNode, labelMap: Map[LabelNode, LabelNode], prefix: String, shift: Int): List[LocalVariableNode] = { methodNode.localVariables.iterator().asScala.map(localVariable => new LocalVariableNode( prefix + localVariable.name, localVariable.desc, localVariable.signature, labelMap(localVariable.start), labelMap(localVariable.end), - localVariable.index + localVariable.index + shift )).toList } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala index 30b7f2edad..1a1a6942dc 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala @@ -78,10 +78,10 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) { closureInstantiations.iterator.flatMap({ case (methodNode, closureInits) => // A lazy val to ensure the analysis only runs if necessary (the value is passed by name to `closureCallsites`) - lazy val prodCons = new ProdConsAnalyzer(methodNode, closureInits.valuesIterator.next.ownerClass.internalName) + lazy val prodCons = new ProdConsAnalyzer(methodNode, closureInits.valuesIterator.next().ownerClass.internalName) val sortedInits = immutable.TreeSet.empty ++ closureInits.values - sortedInits.iterator.map(init => (init, closureCallsites(init, prodCons))) - }).toList // mapping to a list (not a map) to keep the sorting of closureInstantiationsByMethod + sortedInits.iterator.map(init => (init, closureCallsites(init, prodCons))).filter(_._2.nonEmpty) + }).toList // mapping to a list (not a map) to keep the sorting } // Rewrite all closure callsites (or issue inliner warnings for those that cannot be rewritten) @@ -268,6 +268,10 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) { // Explanation: If the lambda body method is non-static, the receiver is a captured // value. It can only be captured within some instance method, so we know it's non-null. callGraph.addCallsite(bodyMethodCallsite) + + // Rewriting a closure invocation may render code unreachable. For example, the body method of + // (x: T) => ??? has return type Nothing$, and an ATHROW is added (see fixLoadedNothingOrNullValue). + unreachableCodeEliminated -= ownerMethod } /** 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 1550f942c7..8dff7ef446 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala @@ -406,7 +406,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { callsiteMethod.instructions.insert(callsiteInstruction, clonedInstructions) callsiteMethod.instructions.remove(callsiteInstruction) - callsiteMethod.localVariables.addAll(cloneLocalVariableNodes(callee, labelsMap, callee.name + "_").asJava) + callsiteMethod.localVariables.addAll(cloneLocalVariableNodes(callee, labelsMap, callee.name + "_", localVarShift).asJava) callsiteMethod.tryCatchBlocks.addAll(cloneTryCatchBlockNodes(callee, labelsMap).asJava) callsiteMethod.maxLocals += returnType.getSize + callee.maxLocals diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala index 4132710a96..f5e6653344 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala @@ -196,7 +196,6 @@ object LocalOptImpls { a.analyze(ownerClassName, method) val frames = a.getFrames - val initialSize = method.instructions.size var i = 0 var liveLabels = Set.empty[LabelNode] var removedInstructions = Set.empty[AbstractInsnNode] |