@@ -8,8 +8,26 @@ import scala.tools.asm.Type
8
8
import scala .tools .asm .tree .{MultiANewArrayInsnNode , InvokeDynamicInsnNode , MethodInsnNode , AbstractInsnNode }
9
9
import scala .tools .asm .tree .analysis .{Frame , Value }
10
10
import opt .BytecodeUtils ._
11
+ import collection .immutable
11
12
12
13
object InstructionStackEffect {
14
+ private var cache : immutable.IntMap [(Int , Int )] = immutable.IntMap .empty
15
+ private def t (x : Int , y : Int ): (Int , Int ) = {
16
+ // x can go up to 255 (number of parameters of a method, dimensions in multianewarray) we cache
17
+ // x up to 10, which covers most cases and limits the cache. y doesn't go above 6 (see cases).
18
+ if (x > 10 || y > 6 ) (x, y)
19
+ else {
20
+ val key = (x << 8 ) + y // this would work for any x < 256
21
+ if (cache contains key) {
22
+ cache(key)
23
+ } else {
24
+ val r = (x, y)
25
+ cache += key -> r
26
+ r
27
+ }
28
+ }
29
+ }
30
+
13
31
/**
14
32
* Returns a pair with the number of stack values consumed and produced by `insn`.
15
33
* This method requires the `frame` to be in the state **before** executing / interpreting
@@ -20,7 +38,7 @@ object InstructionStackEffect {
20
38
21
39
(insn.getOpcode: @ switch) match {
22
40
// The order of opcodes is the same as in Frame.execute.
23
- case NOP => (0 , 0 )
41
+ case NOP => t (0 , 0 )
24
42
25
43
case ACONST_NULL |
26
44
ICONST_M1 |
@@ -44,7 +62,7 @@ object InstructionStackEffect {
44
62
LLOAD |
45
63
FLOAD |
46
64
DLOAD |
47
- ALOAD => (0 , 1 )
65
+ ALOAD => t (0 , 1 )
48
66
49
67
case IALOAD |
50
68
LALOAD |
@@ -53,13 +71,13 @@ object InstructionStackEffect {
53
71
AALOAD |
54
72
BALOAD |
55
73
CALOAD |
56
- SALOAD => (2 , 1 )
74
+ SALOAD => t (2 , 1 )
57
75
58
76
case ISTORE |
59
77
LSTORE |
60
78
FSTORE |
61
79
DSTORE |
62
- ASTORE => (1 , 0 )
80
+ ASTORE => t (1 , 0 )
63
81
64
82
case IASTORE |
65
83
LASTORE |
@@ -68,41 +86,41 @@ object InstructionStackEffect {
68
86
AASTORE |
69
87
BASTORE |
70
88
CASTORE |
71
- SASTORE => (3 , 0 )
89
+ SASTORE => t (3 , 0 )
72
90
73
- case POP => (1 , 0 )
91
+ case POP => t (1 , 0 )
74
92
75
93
case POP2 =>
76
94
val isSize2 = peekStack(0 ).getSize == 2
77
- if (isSize2) (1 , 0 ) else (2 , 0 )
95
+ if (isSize2) t (1 , 0 ) else t (2 , 0 )
78
96
79
- case DUP => (0 , 1 )
97
+ case DUP => t (0 , 1 )
80
98
81
- case DUP_X1 => (2 , 3 )
99
+ case DUP_X1 => t (2 , 3 )
82
100
83
101
case DUP_X2 =>
84
102
val isSize2 = peekStack(1 ).getSize == 2
85
- if (isSize2) (2 , 3 ) else (3 , 4 )
103
+ if (isSize2) t (2 , 3 ) else t (3 , 4 )
86
104
87
105
case DUP2 =>
88
106
val isSize2 = peekStack(0 ).getSize == 2
89
- if (isSize2) (0 , 1 ) else (0 , 2 )
107
+ if (isSize2) t (0 , 1 ) else t (0 , 2 )
90
108
91
109
case DUP2_X1 =>
92
110
val isSize2 = peekStack(0 ).getSize == 2
93
- if (isSize2) (2 , 3 ) else (3 , 4 )
111
+ if (isSize2) t (2 , 3 ) else t (3 , 4 )
94
112
95
113
case DUP2_X2 =>
96
114
val v1isSize2 = peekStack(0 ).getSize == 2
97
115
if (v1isSize2) {
98
116
val v2isSize2 = peekStack(1 ).getSize == 2
99
- if (v2isSize2) (2 , 3 ) else (3 , 4 )
117
+ if (v2isSize2) t (2 , 3 ) else t (3 , 4 )
100
118
} else {
101
119
val v3isSize2 = peekStack(2 ).getSize == 2
102
- if (v3isSize2) (3 , 5 ) else (4 , 6 )
120
+ if (v3isSize2) t (3 , 5 ) else t (4 , 6 )
103
121
}
104
122
105
- case SWAP => (2 , 2 )
123
+ case SWAP => t (2 , 2 )
106
124
107
125
case IADD |
108
126
LADD |
@@ -123,12 +141,12 @@ object InstructionStackEffect {
123
141
IREM |
124
142
LREM |
125
143
FREM |
126
- DREM => (2 , 1 )
144
+ DREM => t (2 , 1 )
127
145
128
146
case INEG |
129
147
LNEG |
130
148
FNEG |
131
- DNEG => (1 , 1 )
149
+ DNEG => t (1 , 1 )
132
150
133
151
case ISHL |
134
152
LSHL |
@@ -141,9 +159,9 @@ object InstructionStackEffect {
141
159
IOR |
142
160
LOR |
143
161
IXOR |
144
- LXOR => (2 , 1 )
162
+ LXOR => t (2 , 1 )
145
163
146
- case IINC => (0 , 0 )
164
+ case IINC => t (0 , 0 )
147
165
148
166
case I2L |
149
167
I2F |
@@ -159,20 +177,20 @@ object InstructionStackEffect {
159
177
D2F |
160
178
I2B |
161
179
I2C |
162
- I2S => (1 , 1 )
180
+ I2S => t (1 , 1 )
163
181
164
182
case LCMP |
165
183
FCMPL |
166
184
FCMPG |
167
185
DCMPL |
168
- DCMPG => (2 , 1 )
186
+ DCMPG => t (2 , 1 )
169
187
170
188
case IFEQ |
171
189
IFNE |
172
190
IFLT |
173
191
IFGE |
174
192
IFGT |
175
- IFLE => (1 , 0 )
193
+ IFLE => t (1 , 0 )
176
194
177
195
case IF_ICMPEQ |
178
196
IF_ICMPNE |
@@ -181,32 +199,32 @@ object InstructionStackEffect {
181
199
IF_ICMPGT |
182
200
IF_ICMPLE |
183
201
IF_ACMPEQ |
184
- IF_ACMPNE => (2 , 0 )
202
+ IF_ACMPNE => t (2 , 0 )
185
203
186
- case GOTO => (0 , 0 )
204
+ case GOTO => t (0 , 0 )
187
205
188
- case JSR => (0 , 1 )
206
+ case JSR => t (0 , 1 )
189
207
190
- case RET => (0 , 0 )
208
+ case RET => t (0 , 0 )
191
209
192
210
case TABLESWITCH |
193
- LOOKUPSWITCH => (1 , 0 )
211
+ LOOKUPSWITCH => t (1 , 0 )
194
212
195
213
case IRETURN |
196
214
LRETURN |
197
215
FRETURN |
198
216
DRETURN |
199
- ARETURN => (1 , 0 ) // Frame.execute consumes one stack value
217
+ ARETURN => t (1 , 0 ) // Frame.execute consumes one stack value
200
218
201
- case RETURN => (0 , 0 ) // Frame.execute does not change the stack
219
+ case RETURN => t (0 , 0 ) // Frame.execute does not change the stack
202
220
203
- case GETSTATIC => (0 , 1 )
221
+ case GETSTATIC => t (0 , 1 )
204
222
205
- case PUTSTATIC => (1 , 0 )
223
+ case PUTSTATIC => t (1 , 0 )
206
224
207
- case GETFIELD => (1 , 1 )
225
+ case GETFIELD => t (1 , 1 )
208
226
209
- case PUTFIELD => (2 , 0 )
227
+ case PUTFIELD => t (2 , 0 )
210
228
211
229
case INVOKEVIRTUAL |
212
230
INVOKESPECIAL |
@@ -215,33 +233,33 @@ object InstructionStackEffect {
215
233
val desc = insn.asInstanceOf [MethodInsnNode ].desc
216
234
val cons = Type .getArgumentTypes(desc).length + (if (insn.getOpcode == INVOKESTATIC ) 0 else 1 )
217
235
val prod = if (Type .getReturnType(desc) == Type .VOID_TYPE ) 0 else 1
218
- (cons, prod)
236
+ t (cons, prod)
219
237
220
238
case INVOKEDYNAMIC =>
221
239
val desc = insn.asInstanceOf [InvokeDynamicInsnNode ].desc
222
240
val cons = Type .getArgumentTypes(desc).length
223
241
val prod = if (Type .getReturnType(desc) == Type .VOID_TYPE ) 0 else 1
224
- (cons, prod)
242
+ t (cons, prod)
225
243
226
- case NEW => (0 , 1 )
244
+ case NEW => t (0 , 1 )
227
245
228
246
case NEWARRAY |
229
247
ANEWARRAY |
230
- ARRAYLENGTH => (1 , 1 )
248
+ ARRAYLENGTH => t (1 , 1 )
231
249
232
- case ATHROW => (1 , 0 ) // Frame.execute consumes one stack value
250
+ case ATHROW => t (1 , 0 ) // Frame.execute consumes one stack value
233
251
234
- case CHECKCAST => (0 , 0 )
252
+ case CHECKCAST => t (0 , 0 )
235
253
236
- case INSTANCEOF => (1 , 1 )
254
+ case INSTANCEOF => t (1 , 1 )
237
255
238
256
case MONITORENTER |
239
- MONITOREXIT => (1 , 0 )
257
+ MONITOREXIT => t (1 , 0 )
240
258
241
- case MULTIANEWARRAY => (insn.asInstanceOf [MultiANewArrayInsnNode ].dims, 1 )
259
+ case MULTIANEWARRAY => t (insn.asInstanceOf [MultiANewArrayInsnNode ].dims, 1 )
242
260
243
261
case IFNULL |
244
- IFNONNULL => (1 , 0 )
262
+ IFNONNULL => t (1 , 0 )
245
263
}
246
264
}
247
265
0 commit comments