summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-10-22 18:32:19 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-10-27 10:40:52 +0100
commit3a9581d32f9d3adb1dcb0b9c4bfeb9c86f0addcf (patch)
tree0128d61ec925cf385df4358bfcecb7d74ae09fcd /src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
parent4321ea458ad1258f273ee22a4c6a7606ab054501 (diff)
downloadscala-3a9581d32f9d3adb1dcb0b9c4bfeb9c86f0addcf.tar.gz
scala-3a9581d32f9d3adb1dcb0b9c4bfeb9c86f0addcf.tar.bz2
scala-3a9581d32f9d3adb1dcb0b9c4bfeb9c86f0addcf.zip
More efficient way to compute maxLocals / maxStack
In order to run an asm Analyzer, the maxLocals / maxStack values of the method need to be computed. Asm doesn't provide an efficient built-in for this purpose, but it computes these values while serializing a class. Previously, we used to serialize the method just to compute the max's, which is inefficient. This commit implements a separate, efficient traversal. The computed values are also smaller, allowing to save space when running an Analyzer: asm Analyzers only allocate a single stack slot for long/double values, while the JVM allocates two. The maxStack computed previously would always use two slots, which is not necessary. The new calculation was verified to be correct in the following way: as a test, i left the old computation in place, ran the new one in addition (in a special mode where the long/double values take two slots) and asserted equality. Bootstrapping and test suite passed.
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala34
1 files changed, 1 insertions, 33 deletions
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 38f3c51892..a80b3d0487 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
@@ -51,38 +51,6 @@ class LocalOpt[BT <: BTypes](val btypes: BT) {
import backendUtils._
/**
- * In order to run an Analyzer, the maxLocals / maxStack fields need to be available. The ASM
- * framework only computes these values during bytecode generation.
- *
- * Since there's currently no better way, we run a bytecode generator on the method and extract
- * the computed values. This required changes to the ASM codebase:
- * - the [[MethodWriter]] class was made public
- * - accessors for maxLocals / maxStack were added to the MethodWriter class
- *
- * We could probably make this faster (and allocate less memory) by hacking the ASM framework
- * more: create a subclass of MethodWriter with a /dev/null byteVector. Another option would be
- * to create a separate visitor for computing those values, duplicating the functionality from the
- * MethodWriter.
- *
- * NOTE: the maxStack value computed by this method allocates two slots for long / double values,
- * as required by the JVM spec. For running an Analyzer, one slot per long / double would be fine.
- * See comment in `analysis` package object.
- */
- def computeMaxLocalsMaxStack(method: MethodNode): Unit = {
- if (!maxLocalsMaxStackComputed(method)) {
- method.maxLocals = 0
- method.maxStack = 0
- val cw = new ClassWriter(ClassWriter.COMPUTE_MAXS)
- val excs = method.exceptions.asScala.toArray
- val mw = cw.visitMethod(method.access, method.name, method.desc, method.signature, excs).asInstanceOf[MethodWriter]
- method.accept(mw)
- method.maxLocals = mw.getMaxLocals
- method.maxStack = mw.getMaxStack
- maxLocalsMaxStackComputed += method
- }
- }
-
- /**
* Remove unreachable code from a method.
*
* This implementation only removes instructions that are unreachable for an ASM analyzer /
@@ -225,7 +193,7 @@ class LocalOpt[BT <: BTypes](val btypes: BT) {
var i = 0
var liveLabels = Set.empty[LabelNode]
var removedInstructions = Set.empty[AbstractInsnNode]
- var maxLocals = Type.getArgumentsAndReturnSizes(method.desc) >> 2 - (if (BytecodeUtils.isStaticMethod(method)) 1 else 0)
+ var maxLocals = (Type.getArgumentsAndReturnSizes(method.desc) >> 2) - (if (BytecodeUtils.isStaticMethod(method)) 1 else 0)
var maxStack = 0
val itr = method.instructions.iterator()
while (itr.hasNext) {