diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2015-10-27 10:39:54 +0100 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2015-10-27 10:45:23 +0100 |
commit | 4e994933c4b40a90555fe8acbe630f1c2fd03f55 (patch) | |
tree | e659744f926ab3dbb3a61e25b47be0a21be4d99d | |
parent | 3a9581d32f9d3adb1dcb0b9c4bfeb9c86f0addcf (diff) | |
download | scala-4e994933c4b40a90555fe8acbe630f1c2fd03f55.tar.gz scala-4e994933c4b40a90555fe8acbe630f1c2fd03f55.tar.bz2 scala-4e994933c4b40a90555fe8acbe630f1c2fd03f55.zip |
Support JSR / RET in computeMaxLocalsMaxStack
Even though the two bytecodes are not allowed in classfiles of
version 51+ (see [1]), we could encounter them when inlining from a
JAR file containing classfiles of older version.
[1] https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.9.1
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala | 21 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/opt/InstructionResultSize.scala | 8 |
2 files changed, 20 insertions, 9 deletions
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 aeb0f41237..efeaa54a7b 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala @@ -303,6 +303,8 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { r } + val subroutineRetTargets = new mutable.Stack[AbstractInsnNode] + // for each instruction in the queue, contains the stack height at this instruction. // once an instruction has been treated, contains -1 to prevent re-enqueuing val stackHeights = new Array[Int](size) @@ -353,21 +355,34 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { insn match { case j: JumpInsnNode => - enqInsn(j.label, heightAfter) - val opc = j.getOpcode - if (opc != GOTO) enqInsnIndex(insnIndex + 1, heightAfter) // jump is conditional, so the successor is also a possible control flow target + if (j.getOpcode == JSR) { + val jsrTargetHeight = heightAfter + 1 + if (jsrTargetHeight > maxStack) maxStack = jsrTargetHeight + subroutineRetTargets.push(j.getNext) + enqInsn(j.label, jsrTargetHeight) + } else { + enqInsn(j.label, heightAfter) + val opc = j.getOpcode + if (opc != GOTO) enqInsnIndex(insnIndex + 1, heightAfter) // jump is conditional, so the successor is also a possible control flow target + } + case l: LookupSwitchInsnNode => var j = 0 while (j < l.labels.size) { enqInsn(l.labels.get(j), heightAfter); j += 1 } enqInsn(l.dflt, heightAfter) + case t: TableSwitchInsnNode => var j = 0 while (j < t.labels.size) { enqInsn(t.labels.get(j), heightAfter); j += 1 } enqInsn(t.dflt, heightAfter) + + case r: VarInsnNode if r.getOpcode == RET => + enqInsn(subroutineRetTargets.pop(), heightAfter) + case _ => val opc = insn.getOpcode if (opc != ATHROW && !isReturn(insn)) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InstructionResultSize.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InstructionResultSize.scala index 8d744f6d13..79e44a8503 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InstructionResultSize.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InstructionResultSize.scala @@ -33,14 +33,10 @@ object InstructionResultSize { case LDC => instruction.asInstanceOf[LdcInsnNode].cst match { - case _: java.lang.Integer | - _: java.lang.Float | - _: String | - _: Type | - _: Handle => 1 - case _: java.lang.Long | _: java.lang.Double => 2 + + case _ => 1 } case ILOAD | |