summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-05-24 14:05:24 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-05-25 13:40:43 +0200
commit460e10cdb2fdfb9becaed5590ec77c7d5324a4db (patch)
treeec1ec551628bac91f17c6354b0504709f7721ff5 /src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
parent53a274e3f1258bd7d26a72d4394108b2f4d04579 (diff)
downloadscala-460e10cdb2fdfb9becaed5590ec77c7d5324a4db.tar.gz
scala-460e10cdb2fdfb9becaed5590ec77c7d5324a4db.tar.bz2
scala-460e10cdb2fdfb9becaed5590ec77c7d5324a4db.zip
Address review feedback
Address feedback in #4516 / 57b8da4cd8. Save allocations of NullnessValue - there's only 4 possible instances. Also save tuple allocations in InstructionStackEffect.
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala104
1 files changed, 61 insertions, 43 deletions
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 56c8c2e4e3..a7d6f74557 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
@@ -8,8 +8,26 @@ import scala.tools.asm.Type
import scala.tools.asm.tree.{MultiANewArrayInsnNode, InvokeDynamicInsnNode, MethodInsnNode, AbstractInsnNode}
import scala.tools.asm.tree.analysis.{Frame, Value}
import opt.BytecodeUtils._
+import collection.immutable
object InstructionStackEffect {
+ private var cache: immutable.IntMap[(Int, Int)] = immutable.IntMap.empty
+ private def t(x: Int, y: Int): (Int, Int) = {
+ // x can go up to 255 (number of parameters of a method, dimensions in multianewarray) we cache
+ // x up to 10, which covers most cases and limits the cache. y doesn't go above 6 (see cases).
+ if (x > 10 || y > 6) (x, y)
+ else {
+ val key = (x << 8) + y // this would work for any x < 256
+ if (cache contains key) {
+ cache(key)
+ } else {
+ val r = (x, y)
+ cache += key -> r
+ r
+ }
+ }
+ }
+
/**
* Returns a pair with the number of stack values consumed and produced by `insn`.
* This method requires the `frame` to be in the state **before** executing / interpreting
@@ -20,7 +38,7 @@ object InstructionStackEffect {
(insn.getOpcode: @switch) match {
// The order of opcodes is the same as in Frame.execute.
- case NOP => (0, 0)
+ case NOP => t(0, 0)
case ACONST_NULL |
ICONST_M1 |
@@ -44,7 +62,7 @@ object InstructionStackEffect {
LLOAD |
FLOAD |
DLOAD |
- ALOAD => (0, 1)
+ ALOAD => t(0, 1)
case IALOAD |
LALOAD |
@@ -53,13 +71,13 @@ object InstructionStackEffect {
AALOAD |
BALOAD |
CALOAD |
- SALOAD => (2, 1)
+ SALOAD => t(2, 1)
case ISTORE |
LSTORE |
FSTORE |
DSTORE |
- ASTORE => (1, 0)
+ ASTORE => t(1, 0)
case IASTORE |
LASTORE |
@@ -68,41 +86,41 @@ object InstructionStackEffect {
AASTORE |
BASTORE |
CASTORE |
- SASTORE => (3, 0)
+ SASTORE => t(3, 0)
- case POP => (1, 0)
+ case POP => t(1, 0)
case POP2 =>
val isSize2 = peekStack(0).getSize == 2
- if (isSize2) (1, 0) else (2, 0)
+ if (isSize2) t(1, 0) else t(2, 0)
- case DUP => (0, 1)
+ case DUP => t(0, 1)
- case DUP_X1 => (2, 3)
+ case DUP_X1 => t(2, 3)
case DUP_X2 =>
val isSize2 = peekStack(1).getSize == 2
- if (isSize2) (2, 3) else (3, 4)
+ if (isSize2) t(2, 3) else t(3, 4)
case DUP2 =>
val isSize2 = peekStack(0).getSize == 2
- if (isSize2) (0, 1) else (0, 2)
+ if (isSize2) t(0, 1) else t(0, 2)
case DUP2_X1 =>
val isSize2 = peekStack(0).getSize == 2
- if (isSize2) (2, 3) else (3, 4)
+ if (isSize2) t(2, 3) else t(3, 4)
case DUP2_X2 =>
val v1isSize2 = peekStack(0).getSize == 2
if (v1isSize2) {
val v2isSize2 = peekStack(1).getSize == 2
- if (v2isSize2) (2, 3) else (3, 4)
+ if (v2isSize2) t(2, 3) else t(3, 4)
} else {
val v3isSize2 = peekStack(2).getSize == 2
- if (v3isSize2) (3, 5) else (4, 6)
+ if (v3isSize2) t(3, 5) else t(4, 6)
}
- case SWAP => (2, 2)
+ case SWAP => t(2, 2)
case IADD |
LADD |
@@ -123,12 +141,12 @@ object InstructionStackEffect {
IREM |
LREM |
FREM |
- DREM => (2, 1)
+ DREM => t(2, 1)
case INEG |
LNEG |
FNEG |
- DNEG => (1, 1)
+ DNEG => t(1, 1)
case ISHL |
LSHL |
@@ -141,9 +159,9 @@ object InstructionStackEffect {
IOR |
LOR |
IXOR |
- LXOR => (2, 1)
+ LXOR => t(2, 1)
- case IINC => (0, 0)
+ case IINC => t(0, 0)
case I2L |
I2F |
@@ -159,20 +177,20 @@ object InstructionStackEffect {
D2F |
I2B |
I2C |
- I2S => (1, 1)
+ I2S => t(1, 1)
case LCMP |
FCMPL |
FCMPG |
DCMPL |
- DCMPG => (2, 1)
+ DCMPG => t(2, 1)
case IFEQ |
IFNE |
IFLT |
IFGE |
IFGT |
- IFLE => (1, 0)
+ IFLE => t(1, 0)
case IF_ICMPEQ |
IF_ICMPNE |
@@ -181,32 +199,32 @@ object InstructionStackEffect {
IF_ICMPGT |
IF_ICMPLE |
IF_ACMPEQ |
- IF_ACMPNE => (2, 0)
+ IF_ACMPNE => t(2, 0)
- case GOTO => (0, 0)
+ case GOTO => t(0, 0)
- case JSR => (0, 1)
+ case JSR => t(0, 1)
- case RET => (0, 0)
+ case RET => t(0, 0)
case TABLESWITCH |
- LOOKUPSWITCH => (1, 0)
+ LOOKUPSWITCH => t(1, 0)
case IRETURN |
LRETURN |
FRETURN |
DRETURN |
- ARETURN => (1, 0) // Frame.execute consumes one stack value
+ ARETURN => t(1, 0) // Frame.execute consumes one stack value
- case RETURN => (0, 0) // Frame.execute does not change the stack
+ case RETURN => t(0, 0) // Frame.execute does not change the stack
- case GETSTATIC => (0, 1)
+ case GETSTATIC => t(0, 1)
- case PUTSTATIC => (1, 0)
+ case PUTSTATIC => t(1, 0)
- case GETFIELD => (1, 1)
+ case GETFIELD => t(1, 1)
- case PUTFIELD => (2, 0)
+ case PUTFIELD => t(2, 0)
case INVOKEVIRTUAL |
INVOKESPECIAL |
@@ -215,33 +233,33 @@ object InstructionStackEffect {
val desc = insn.asInstanceOf[MethodInsnNode].desc
val cons = Type.getArgumentTypes(desc).length + (if (insn.getOpcode == INVOKESTATIC) 0 else 1)
val prod = if (Type.getReturnType(desc) == Type.VOID_TYPE) 0 else 1
- (cons, prod)
+ t(cons, prod)
case INVOKEDYNAMIC =>
val desc = insn.asInstanceOf[InvokeDynamicInsnNode].desc
val cons = Type.getArgumentTypes(desc).length
val prod = if (Type.getReturnType(desc) == Type.VOID_TYPE) 0 else 1
- (cons, prod)
+ t(cons, prod)
- case NEW => (0, 1)
+ case NEW => t(0, 1)
case NEWARRAY |
ANEWARRAY |
- ARRAYLENGTH => (1, 1)
+ ARRAYLENGTH => t(1, 1)
- case ATHROW => (1, 0) // Frame.execute consumes one stack value
+ case ATHROW => t(1, 0) // Frame.execute consumes one stack value
- case CHECKCAST => (0, 0)
+ case CHECKCAST => t(0, 0)
- case INSTANCEOF => (1, 1)
+ case INSTANCEOF => t(1, 1)
case MONITORENTER |
- MONITOREXIT => (1, 0)
+ MONITOREXIT => t(1, 0)
- case MULTIANEWARRAY => (insn.asInstanceOf[MultiANewArrayInsnNode].dims, 1)
+ case MULTIANEWARRAY => t(insn.asInstanceOf[MultiANewArrayInsnNode].dims, 1)
case IFNULL |
- IFNONNULL => (1, 0)
+ IFNONNULL => t(1, 0)
}
}