summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-10-26 19:47:43 +0100
committerLukas Rytz <lukas.rytz@gmail.com>2015-10-27 10:45:23 +0100
commit51e1489aaa6684298906b06ce0a6d95fa5b2fae5 (patch)
tree017d783408fa5e572f742c579f07424466aa32e9 /src/compiler
parent4e994933c4b40a90555fe8acbe630f1c2fd03f55 (diff)
downloadscala-51e1489aaa6684298906b06ce0a6d95fa5b2fae5.tar.gz
scala-51e1489aaa6684298906b06ce0a6d95fa5b2fae5.tar.bz2
scala-51e1489aaa6684298906b06ce0a6d95fa5b2fae5.zip
Use a single Int for the prod / cons values of InstructionStackEffect
The maximal number of produced values of any instruction is 6, so we can safely encode the number of consumed and produced values into a single Int as (prod << 3) + cons.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/AliasingFrame.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala60
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala8
4 files changed, 33 insertions, 44 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/AliasingFrame.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/AliasingFrame.scala
index 337f7787bd..596ee55290 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/AliasingFrame.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/AliasingFrame.scala
@@ -92,10 +92,9 @@ class AliasingFrame[V <: Value](nLocals: Int, nStack: Int) extends Frame[V](nLoc
def stackTop: Int = this.stackTop
def peekStack(n: Int): V = this.peekStack(n)
- // the val pattern `val (p, c) = f` still allocates a tuple (https://github.com/scala-opt/scala/issues/28)
val prodCons = InstructionStackEffect.forAsmAnalysis(insn, this) // needs to be called before super.execute, see its doc
- val consumed = prodCons._1
- val produced = prodCons._2
+ val consumed = InstructionStackEffect.cons(prodCons)
+ val produced = InstructionStackEffect.prod(prodCons)
super.execute(insn, interpreter)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
index efeaa54a7b..b02bc7c96e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
@@ -337,8 +337,8 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
if (insn.getOpcode == -1) { // frames, labels, line numbers
enqInsnIndex(insnIndex + 1, initHeight)
} else {
- val (cons, prod) = InstructionStackEffect.forAsmAnalysisConservative(insn)
- val heightAfter = initHeight - cons + prod
+ val stackGrowth = InstructionStackEffect.maxStackGrowth(insn)
+ val heightAfter = initHeight + stackGrowth
if (heightAfter > maxStack) maxStack = heightAfter
// update maxLocals
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
index 1f81736a5d..4e81018451 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
@@ -10,59 +10,49 @@ import scala.tools.asm.tree.analysis.{Frame, Value}
import opt.BytecodeUtils._
object InstructionStackEffect {
- // x up to 10, which covers most cases and limits the cache. y doesn't go above 6 (see cases).
- val maxCachedX = 10
- val maxCachedY = 6
- val xShift = 3
- private val cache = new Array[(Int, Int)]((maxCachedX << xShift) + maxCachedY + 1)
- private def t(x: Int, y: Int): (Int, Int) = {
- if (x > maxCachedX || y > maxCachedY) (x, y)
- else {
- val key = (x << xShift) + y
- if (cache(key) != null) {
- cache(key)
- } else {
- val r = (x, y)
- cache(key) = r
- r
- }
- }
- }
+ val consShift = 3
+ val prodMask = (1 << consShift) - 1
+
+ def cons(i: Int) = i >>> consShift
+ def prod(i: Int) = i & prodMask
+
+ private def t(x: Int, y: Int): Int = (x << consShift) | y
/**
- * Returns a pair with the number of stack values consumed and produced by `insn`. The returned
- * values are correct for use in asm's Analyzer framework. For example, a LLOAD instruction
- * produces one stack value. See also doc in `analysis` package object.
+ * Returns the number of stack values consumed and produced by `insn`, encoded in a single `Int`
+ * (the `cons` / `prod` extract individual values). The returned values are correct for use in
+ * asm's Analyzer framework. For example, a LLOAD instruction produces one stack value. See also
+ * doc in `analysis` package object.
*
* This method requires the `frame` to be in the state **before** executing / interpreting the
* `insn`.
*/
- def forAsmAnalysis[V <: Value](insn: AbstractInsnNode, frame: Frame[V]): (Int, Int) = computeConsProd(insn, frame = frame)
+ def forAsmAnalysis[V <: Value](insn: AbstractInsnNode, frame: Frame[V]): Int = computeConsProd(insn, frame = frame)
/**
- * Returns a pair with the number of stack values consumed and produced by `insn`. The returned
- * values are usually the same as used in asm's Analyzer framework, but they may be larger. For
+ * Returns the maximal possible growth of the stack when executing `insn`. The returned value
+ * is usually the same as expected by asm's Analyzer framework, but it may be larger. For
* example, consider a POP2 instruction:
* - if two size-1 values are popped, then the asm Analyzer consumes two values
* - if a size-2 value is popped, the asm Analyzer consumes only one stack slot (see doc in the
- * `analysis` package object
+ * `analysis` package object)
*
* If a precise result is needed, invoke the `forAsmAnalysis` and provide a `frame` value that
* allows looking up the sizes of values on the stack.
- *
- * When the precise stack effect is unknown, this method returns values that are safe for
- * computing an upper bound on the stack size for running an Analyzer: (prod - cons) is the
- * largest possible value for any input sizes.
*/
- def forAsmAnalysisConservative(insn: AbstractInsnNode): (Int, Int) = computeConsProd(insn, conservative = true)
+ def maxStackGrowth(insn: AbstractInsnNode): Int = {
+ val prodCons = computeConsProd(insn, conservative = true)
+ prod(prodCons) - cons(prodCons)
+ }
/**
- * Returns a pair with the number of stack values consumed and produced by `insn`. The returned
- * values are correct for writing into a classfile (see doc on `analysis` package object).
+ * Returns the number of stack values consumed and produced by `insn`, encoded in a single `Int`
+ * (the `cons` / `prod` extract individual values). The returned values are correct for writing
+ * into a classfile (see doc on the `analysis` package object).
*/
- def forClassfile(insn: AbstractInsnNode): (Int, Int) = computeConsProd(insn, forClassfile = true)
+ def forClassfile(insn: AbstractInsnNode): Int = computeConsProd(insn, forClassfile = true)
- private def invokeConsProd(methodDesc: String, insn: AbstractInsnNode, forClassfile: Boolean): (Int, Int) = {
+ private def invokeConsProd(methodDesc: String, insn: AbstractInsnNode, forClassfile: Boolean): Int = {
val consumesReceiver = insn.getOpcode != INVOKESTATIC && insn.getOpcode != INVOKEDYNAMIC
if (forClassfile) {
val sizes = Type.getArgumentsAndReturnSizes(methodDesc)
@@ -81,7 +71,7 @@ object InstructionStackEffect {
d == "J" || d == "D"
}
- private def computeConsProd[V <: Value](insn: AbstractInsnNode, forClassfile: Boolean = false, conservative: Boolean = false, frame: Frame[V] = null): (Int, Int) = {
+ private def computeConsProd[V <: Value](insn: AbstractInsnNode, forClassfile: Boolean = false, conservative: Boolean = false, frame: Frame[V] = null): Int = {
// not used if `forClassfile || conservative`: in these cases, `frame` is allowed to be `null`
def peekStack(n: Int): V = frame.peekStack(n)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
index 33bbbe5728..c933341492 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
@@ -368,9 +368,9 @@ trait ProdConsAnalyzerImpl {
Seq(insn.asInstanceOf[IincInsnNode].`var`)
} else {
val frame = frameAt(insn)
- val stackEffect = InstructionStackEffect.forAsmAnalysis(insn, frame)
+ val prodCons = InstructionStackEffect.forAsmAnalysis(insn, frame)
val stackSize = frame.getLocals + frame.getStackSize
- (stackSize - stackEffect._1) until stackSize
+ (stackSize - InstructionStackEffect.cons(prodCons)) until stackSize
}
}
@@ -387,10 +387,10 @@ trait ProdConsAnalyzerImpl {
Seq(insn.asInstanceOf[IincInsnNode].`var`)
} else {
val frame = frameAt(insn)
- val stackEffect = InstructionStackEffect.forAsmAnalysis(insn, frame)
+ val prodCons = InstructionStackEffect.forAsmAnalysis(insn, frame)
val nextFrame = frameAt(insn.getNext)
val stackSize = nextFrame.getLocals + nextFrame.getStackSize
- (stackSize - stackEffect._2) until stackSize
+ (stackSize - InstructionStackEffect.prod(prodCons)) until stackSize
}
}