Mercurial > lasercutter
comparison src/clojure/asm/Frame.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9:35cf337adfcf | 10:ef7dbbd6452c |
---|---|
1 /*** | |
2 * ASM: a very small and fast Java bytecode manipulation framework | |
3 * Copyright (c) 2000-2005 INRIA, France Telecom | |
4 * All rights reserved. | |
5 * | |
6 * Redistribution and use in source and binary forms, with or without | |
7 * modification, are permitted provided that the following conditions | |
8 * are met: | |
9 * 1. Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * 2. Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in the | |
13 * documentation and/or other materials provided with the distribution. | |
14 * 3. Neither the name of the copyright holders nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
28 * THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 package clojure.asm; | |
31 | |
32 /** | |
33 * Information about the input and output stack map frames of a basic block. | |
34 * | |
35 * @author Eric Bruneton | |
36 */ | |
37 final class Frame{ | |
38 | |
39 /* | |
40 * Frames are computed in a two steps process: during the visit of each | |
41 * instruction, the state of the frame at the end of current basic block is | |
42 * updated by simulating the action of the instruction on the previous state | |
43 * of this so called "output frame". In visitMaxs, a fix point algorithm is | |
44 * used to compute the "input frame" of each basic block, i.e. the stack map | |
45 * frame at the begining of the basic block, starting from the input frame | |
46 * of the first basic block (which is computed from the method descriptor), | |
47 * and by using the previously computed output frames to compute the input | |
48 * state of the other blocks. | |
49 * | |
50 * All output and input frames are stored as arrays of integers. Reference | |
51 * and array types are represented by an index into a type table (which is | |
52 * not the same as the constant pool of the class, in order to avoid adding | |
53 * unnecessary constants in the pool - not all computed frames will end up | |
54 * being stored in the stack map table). This allows very fast type | |
55 * comparisons. | |
56 * | |
57 * Output stack map frames are computed relatively to the input frame of the | |
58 * basic block, which is not yet known when output frames are computed. It | |
59 * is therefore necessary to be able to represent abstract types such as | |
60 * "the type at position x in the input frame locals" or "the type at | |
61 * position x from the top of the input frame stack" or even "the type at | |
62 * position x in the input frame, with y more (or less) array dimensions". | |
63 * This explains the rather complicated type format used in output frames. | |
64 * | |
65 * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a | |
66 * signed number of array dimensions (from -8 to 7). KIND is either BASE, | |
67 * LOCAL or STACK. BASE is used for types that are not relative to the input | |
68 * frame. LOCAL is used for types that are relative to the input local | |
69 * variable types. STACK is used for types that are relative to the input | |
70 * stack types. VALUE depends on KIND. For LOCAL types, it is an index in | |
71 * the input local variable types. For STACK types, it is a position | |
72 * relatively to the top of input frame stack. For BASE types, it is either | |
73 * one of the constants defined in FrameVisitor, or for OBJECT and | |
74 * UNINITIALIZED types, a tag and an index in the type table. | |
75 * | |
76 * Output frames can contain types of any kind and with a positive or | |
77 * negative dimension (and even unassigned types, represented by 0 - which | |
78 * does not correspond to any valid type value). Input frames can only | |
79 * contain BASE types of positive or null dimension. In all cases the type | |
80 * table contains only internal type names (array type descriptors are | |
81 * forbidden - dimensions must be represented through the DIM field). | |
82 * | |
83 * The LONG and DOUBLE types are always represented by using two slots (LONG + | |
84 * TOP or DOUBLE + TOP), for local variable types as well as in the operand | |
85 * stack. This is necessary to be able to simulate DUPx_y instructions, | |
86 * whose effect would be dependent on the actual type values if types were | |
87 * always represented by a single slot in the stack (and this is not | |
88 * possible, since actual type values are not always known - cf LOCAL and | |
89 * STACK type kinds). | |
90 */ | |
91 | |
92 /** | |
93 * Mask to get the dimension of a frame type. This dimension is a signed | |
94 * integer between -8 and 7. | |
95 */ | |
96 final static int DIM = 0xF0000000; | |
97 | |
98 /** | |
99 * Constant to be added to a type to get a type with one more dimension. | |
100 */ | |
101 final static int ARRAY_OF = 0x10000000; | |
102 | |
103 /** | |
104 * Constant to be added to a type to get a type with one less dimension. | |
105 */ | |
106 final static int ELEMENT_OF = 0xF0000000; | |
107 | |
108 /** | |
109 * Mask to get the kind of a frame type. | |
110 * | |
111 * @see #BASE | |
112 * @see #LOCAL | |
113 * @see #STACK | |
114 */ | |
115 final static int KIND = 0xF000000; | |
116 | |
117 /** | |
118 * Mask to get the value of a frame type. | |
119 */ | |
120 final static int VALUE = 0xFFFFFF; | |
121 | |
122 /** | |
123 * Mask to get the kind of base types. | |
124 */ | |
125 final static int BASE_KIND = 0xFF00000; | |
126 | |
127 /** | |
128 * Mask to get the value of base types. | |
129 */ | |
130 final static int BASE_VALUE = 0xFFFFF; | |
131 | |
132 /** | |
133 * Kind of the types that are not relative to an input stack map frame. | |
134 */ | |
135 final static int BASE = 0x1000000; | |
136 | |
137 /** | |
138 * Base kind of the base reference types. The BASE_VALUE of such types is an | |
139 * index into the type table. | |
140 */ | |
141 final static int OBJECT = BASE | 0x700000; | |
142 | |
143 /** | |
144 * Base kind of the uninitialized base types. The BASE_VALUE of such types | |
145 * in an index into the type table (the Item at that index contains both an | |
146 * instruction offset and an internal class name). | |
147 */ | |
148 final static int UNINITIALIZED = BASE | 0x800000; | |
149 | |
150 /** | |
151 * Kind of the types that are relative to the local variable types of an | |
152 * input stack map frame. The value of such types is a local variable index. | |
153 */ | |
154 private final static int LOCAL = 0x2000000; | |
155 | |
156 /** | |
157 * Kind of the the types that are relative to the stack of an input stack | |
158 * map frame. The value of such types is a position relatively to the top of | |
159 * this stack. | |
160 */ | |
161 private final static int STACK = 0x3000000; | |
162 | |
163 /** | |
164 * The TOP type. This is a BASE type. | |
165 */ | |
166 final static int TOP = BASE | 0; | |
167 | |
168 /** | |
169 * The BOOLEAN type. This is a BASE type mainly used for array types. | |
170 */ | |
171 final static int BOOLEAN = BASE | 9; | |
172 | |
173 /** | |
174 * The BYTE type. This is a BASE type mainly used for array types. | |
175 */ | |
176 final static int BYTE = BASE | 10; | |
177 | |
178 /** | |
179 * The CHAR type. This is a BASE type mainly used for array types. | |
180 */ | |
181 final static int CHAR = BASE | 11; | |
182 | |
183 /** | |
184 * The SHORT type. This is a BASE type mainly used for array types. | |
185 */ | |
186 final static int SHORT = BASE | 12; | |
187 | |
188 /** | |
189 * The INTEGER type. This is a BASE type. | |
190 */ | |
191 final static int INTEGER = BASE | 1; | |
192 | |
193 /** | |
194 * The FLOAT type. This is a BASE type. | |
195 */ | |
196 final static int FLOAT = BASE | 2; | |
197 | |
198 /** | |
199 * The DOUBLE type. This is a BASE type. | |
200 */ | |
201 final static int DOUBLE = BASE | 3; | |
202 | |
203 /** | |
204 * The LONG type. This is a BASE type. | |
205 */ | |
206 final static int LONG = BASE | 4; | |
207 | |
208 /** | |
209 * The NULL type. This is a BASE type. | |
210 */ | |
211 final static int NULL = BASE | 5; | |
212 | |
213 /** | |
214 * The UNINITIALIZED_THIS type. This is a BASE type. | |
215 */ | |
216 final static int UNINITIALIZED_THIS = BASE | 6; | |
217 | |
218 /** | |
219 * The stack size variation corresponding to each JVM instruction. This | |
220 * stack variation is equal to the size of the values produced by an | |
221 * instruction, minus the size of the values consumed by this instruction. | |
222 */ | |
223 final static int[] SIZE; | |
224 | |
225 /** | |
226 * Computes the stack size variation corresponding to each JVM instruction. | |
227 */ | |
228 static | |
229 { | |
230 int i; | |
231 int[] b = new int[202]; | |
232 String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" | |
233 + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" | |
234 + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" | |
235 + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; | |
236 for(i = 0; i < b.length; ++i) | |
237 { | |
238 b[i] = s.charAt(i) - 'E'; | |
239 } | |
240 SIZE = b; | |
241 | |
242 // code to generate the above string | |
243 // | |
244 // int NA = 0; // not applicable (unused opcode or variable size opcode) | |
245 // | |
246 // b = new int[] { | |
247 // 0, //NOP, // visitInsn | |
248 // 1, //ACONST_NULL, // - | |
249 // 1, //ICONST_M1, // - | |
250 // 1, //ICONST_0, // - | |
251 // 1, //ICONST_1, // - | |
252 // 1, //ICONST_2, // - | |
253 // 1, //ICONST_3, // - | |
254 // 1, //ICONST_4, // - | |
255 // 1, //ICONST_5, // - | |
256 // 2, //LCONST_0, // - | |
257 // 2, //LCONST_1, // - | |
258 // 1, //FCONST_0, // - | |
259 // 1, //FCONST_1, // - | |
260 // 1, //FCONST_2, // - | |
261 // 2, //DCONST_0, // - | |
262 // 2, //DCONST_1, // - | |
263 // 1, //BIPUSH, // visitIntInsn | |
264 // 1, //SIPUSH, // - | |
265 // 1, //LDC, // visitLdcInsn | |
266 // NA, //LDC_W, // - | |
267 // NA, //LDC2_W, // - | |
268 // 1, //ILOAD, // visitVarInsn | |
269 // 2, //LLOAD, // - | |
270 // 1, //FLOAD, // - | |
271 // 2, //DLOAD, // - | |
272 // 1, //ALOAD, // - | |
273 // NA, //ILOAD_0, // - | |
274 // NA, //ILOAD_1, // - | |
275 // NA, //ILOAD_2, // - | |
276 // NA, //ILOAD_3, // - | |
277 // NA, //LLOAD_0, // - | |
278 // NA, //LLOAD_1, // - | |
279 // NA, //LLOAD_2, // - | |
280 // NA, //LLOAD_3, // - | |
281 // NA, //FLOAD_0, // - | |
282 // NA, //FLOAD_1, // - | |
283 // NA, //FLOAD_2, // - | |
284 // NA, //FLOAD_3, // - | |
285 // NA, //DLOAD_0, // - | |
286 // NA, //DLOAD_1, // - | |
287 // NA, //DLOAD_2, // - | |
288 // NA, //DLOAD_3, // - | |
289 // NA, //ALOAD_0, // - | |
290 // NA, //ALOAD_1, // - | |
291 // NA, //ALOAD_2, // - | |
292 // NA, //ALOAD_3, // - | |
293 // -1, //IALOAD, // visitInsn | |
294 // 0, //LALOAD, // - | |
295 // -1, //FALOAD, // - | |
296 // 0, //DALOAD, // - | |
297 // -1, //AALOAD, // - | |
298 // -1, //BALOAD, // - | |
299 // -1, //CALOAD, // - | |
300 // -1, //SALOAD, // - | |
301 // -1, //ISTORE, // visitVarInsn | |
302 // -2, //LSTORE, // - | |
303 // -1, //FSTORE, // - | |
304 // -2, //DSTORE, // - | |
305 // -1, //ASTORE, // - | |
306 // NA, //ISTORE_0, // - | |
307 // NA, //ISTORE_1, // - | |
308 // NA, //ISTORE_2, // - | |
309 // NA, //ISTORE_3, // - | |
310 // NA, //LSTORE_0, // - | |
311 // NA, //LSTORE_1, // - | |
312 // NA, //LSTORE_2, // - | |
313 // NA, //LSTORE_3, // - | |
314 // NA, //FSTORE_0, // - | |
315 // NA, //FSTORE_1, // - | |
316 // NA, //FSTORE_2, // - | |
317 // NA, //FSTORE_3, // - | |
318 // NA, //DSTORE_0, // - | |
319 // NA, //DSTORE_1, // - | |
320 // NA, //DSTORE_2, // - | |
321 // NA, //DSTORE_3, // - | |
322 // NA, //ASTORE_0, // - | |
323 // NA, //ASTORE_1, // - | |
324 // NA, //ASTORE_2, // - | |
325 // NA, //ASTORE_3, // - | |
326 // -3, //IASTORE, // visitInsn | |
327 // -4, //LASTORE, // - | |
328 // -3, //FASTORE, // - | |
329 // -4, //DASTORE, // - | |
330 // -3, //AASTORE, // - | |
331 // -3, //BASTORE, // - | |
332 // -3, //CASTORE, // - | |
333 // -3, //SASTORE, // - | |
334 // -1, //POP, // - | |
335 // -2, //POP2, // - | |
336 // 1, //DUP, // - | |
337 // 1, //DUP_X1, // - | |
338 // 1, //DUP_X2, // - | |
339 // 2, //DUP2, // - | |
340 // 2, //DUP2_X1, // - | |
341 // 2, //DUP2_X2, // - | |
342 // 0, //SWAP, // - | |
343 // -1, //IADD, // - | |
344 // -2, //LADD, // - | |
345 // -1, //FADD, // - | |
346 // -2, //DADD, // - | |
347 // -1, //ISUB, // - | |
348 // -2, //LSUB, // - | |
349 // -1, //FSUB, // - | |
350 // -2, //DSUB, // - | |
351 // -1, //IMUL, // - | |
352 // -2, //LMUL, // - | |
353 // -1, //FMUL, // - | |
354 // -2, //DMUL, // - | |
355 // -1, //IDIV, // - | |
356 // -2, //LDIV, // - | |
357 // -1, //FDIV, // - | |
358 // -2, //DDIV, // - | |
359 // -1, //IREM, // - | |
360 // -2, //LREM, // - | |
361 // -1, //FREM, // - | |
362 // -2, //DREM, // - | |
363 // 0, //INEG, // - | |
364 // 0, //LNEG, // - | |
365 // 0, //FNEG, // - | |
366 // 0, //DNEG, // - | |
367 // -1, //ISHL, // - | |
368 // -1, //LSHL, // - | |
369 // -1, //ISHR, // - | |
370 // -1, //LSHR, // - | |
371 // -1, //IUSHR, // - | |
372 // -1, //LUSHR, // - | |
373 // -1, //IAND, // - | |
374 // -2, //LAND, // - | |
375 // -1, //IOR, // - | |
376 // -2, //LOR, // - | |
377 // -1, //IXOR, // - | |
378 // -2, //LXOR, // - | |
379 // 0, //IINC, // visitIincInsn | |
380 // 1, //I2L, // visitInsn | |
381 // 0, //I2F, // - | |
382 // 1, //I2D, // - | |
383 // -1, //L2I, // - | |
384 // -1, //L2F, // - | |
385 // 0, //L2D, // - | |
386 // 0, //F2I, // - | |
387 // 1, //F2L, // - | |
388 // 1, //F2D, // - | |
389 // -1, //D2I, // - | |
390 // 0, //D2L, // - | |
391 // -1, //D2F, // - | |
392 // 0, //I2B, // - | |
393 // 0, //I2C, // - | |
394 // 0, //I2S, // - | |
395 // -3, //LCMP, // - | |
396 // -1, //FCMPL, // - | |
397 // -1, //FCMPG, // - | |
398 // -3, //DCMPL, // - | |
399 // -3, //DCMPG, // - | |
400 // -1, //IFEQ, // visitJumpInsn | |
401 // -1, //IFNE, // - | |
402 // -1, //IFLT, // - | |
403 // -1, //IFGE, // - | |
404 // -1, //IFGT, // - | |
405 // -1, //IFLE, // - | |
406 // -2, //IF_ICMPEQ, // - | |
407 // -2, //IF_ICMPNE, // - | |
408 // -2, //IF_ICMPLT, // - | |
409 // -2, //IF_ICMPGE, // - | |
410 // -2, //IF_ICMPGT, // - | |
411 // -2, //IF_ICMPLE, // - | |
412 // -2, //IF_ACMPEQ, // - | |
413 // -2, //IF_ACMPNE, // - | |
414 // 0, //GOTO, // - | |
415 // 1, //JSR, // - | |
416 // 0, //RET, // visitVarInsn | |
417 // -1, //TABLESWITCH, // visiTableSwitchInsn | |
418 // -1, //LOOKUPSWITCH, // visitLookupSwitch | |
419 // -1, //IRETURN, // visitInsn | |
420 // -2, //LRETURN, // - | |
421 // -1, //FRETURN, // - | |
422 // -2, //DRETURN, // - | |
423 // -1, //ARETURN, // - | |
424 // 0, //RETURN, // - | |
425 // NA, //GETSTATIC, // visitFieldInsn | |
426 // NA, //PUTSTATIC, // - | |
427 // NA, //GETFIELD, // - | |
428 // NA, //PUTFIELD, // - | |
429 // NA, //INVOKEVIRTUAL, // visitMethodInsn | |
430 // NA, //INVOKESPECIAL, // - | |
431 // NA, //INVOKESTATIC, // - | |
432 // NA, //INVOKEINTERFACE, // - | |
433 // NA, //UNUSED, // NOT VISITED | |
434 // 1, //NEW, // visitTypeInsn | |
435 // 0, //NEWARRAY, // visitIntInsn | |
436 // 0, //ANEWARRAY, // visitTypeInsn | |
437 // 0, //ARRAYLENGTH, // visitInsn | |
438 // NA, //ATHROW, // - | |
439 // 0, //CHECKCAST, // visitTypeInsn | |
440 // 0, //INSTANCEOF, // - | |
441 // -1, //MONITORENTER, // visitInsn | |
442 // -1, //MONITOREXIT, // - | |
443 // NA, //WIDE, // NOT VISITED | |
444 // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn | |
445 // -1, //IFNULL, // visitJumpInsn | |
446 // -1, //IFNONNULL, // - | |
447 // NA, //GOTO_W, // - | |
448 // NA, //JSR_W, // - | |
449 // }; | |
450 // for (i = 0; i < b.length; ++i) { | |
451 // System.err.print((char)('E' + b[i])); | |
452 // } | |
453 // System.err.println(); | |
454 } | |
455 | |
456 /** | |
457 * The label (i.e. basic block) to which these input and output stack map | |
458 * frames correspond. | |
459 */ | |
460 Label owner; | |
461 | |
462 /** | |
463 * The input stack map frame locals. | |
464 */ | |
465 int[] inputLocals; | |
466 | |
467 /** | |
468 * The input stack map frame stack. | |
469 */ | |
470 int[] inputStack; | |
471 | |
472 /** | |
473 * The output stack map frame locals. | |
474 */ | |
475 private int[] outputLocals; | |
476 | |
477 /** | |
478 * The output stack map frame stack. | |
479 */ | |
480 private int[] outputStack; | |
481 | |
482 /** | |
483 * Relative size of the output stack. The exact semantics of this field | |
484 * depends on the algorithm that is used. | |
485 * <p/> | |
486 * When only the maximum stack size is computed, this field is the size of | |
487 * the output stack relatively to the top of the input stack. | |
488 * <p/> | |
489 * When the stack map frames are completely computed, this field is the | |
490 * actual number of types in {@link #outputStack}. | |
491 */ | |
492 private int outputStackTop; | |
493 | |
494 /** | |
495 * Number of types that are initialized in the basic block. | |
496 * | |
497 * @see #initializations | |
498 */ | |
499 private int initializationCount; | |
500 | |
501 /** | |
502 * The types that are initialized in the basic block. A constructor | |
503 * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace | |
504 * <i>every occurence</i> of this type in the local variables and in the | |
505 * operand stack. This cannot be done during the first phase of the | |
506 * algorithm since, during this phase, the local variables and the operand | |
507 * stack are not completely computed. It is therefore necessary to store the | |
508 * types on which constructors are invoked in the basic block, in order to | |
509 * do this replacement during the second phase of the algorithm, where the | |
510 * frames are fully computed. Note that this array can contain types that | |
511 * are relative to input locals or to the input stack (see below for the | |
512 * description of the algorithm). | |
513 */ | |
514 private int[] initializations; | |
515 | |
516 /** | |
517 * Returns the output frame local variable type at the given index. | |
518 * | |
519 * @param local the index of the local that must be returned. | |
520 * @return the output frame local variable type at the given index. | |
521 */ | |
522 private int get(final int local){ | |
523 if(outputLocals == null || local >= outputLocals.length) | |
524 { | |
525 // this local has never been assigned in this basic block, | |
526 // so it is still equal to its value in the input frame | |
527 return LOCAL | local; | |
528 } | |
529 else | |
530 { | |
531 int type = outputLocals[local]; | |
532 if(type == 0) | |
533 { | |
534 // this local has never been assigned in this basic block, | |
535 // so it is still equal to its value in the input frame | |
536 type = outputLocals[local] = LOCAL | local; | |
537 } | |
538 return type; | |
539 } | |
540 } | |
541 | |
542 /** | |
543 * Sets the output frame local variable type at the given index. | |
544 * | |
545 * @param local the index of the local that must be set. | |
546 * @param type the value of the local that must be set. | |
547 */ | |
548 private void set(final int local, final int type){ | |
549 // creates and/or resizes the output local variables array if necessary | |
550 if(outputLocals == null) | |
551 { | |
552 outputLocals = new int[10]; | |
553 } | |
554 int n = outputLocals.length; | |
555 if(local >= n) | |
556 { | |
557 int[] t = new int[Math.max(local + 1, 2 * n)]; | |
558 System.arraycopy(outputLocals, 0, t, 0, n); | |
559 outputLocals = t; | |
560 } | |
561 // sets the local variable | |
562 outputLocals[local] = type; | |
563 } | |
564 | |
565 /** | |
566 * Pushes a new type onto the output frame stack. | |
567 * | |
568 * @param type the type that must be pushed. | |
569 */ | |
570 private void push(final int type){ | |
571 // creates and/or resizes the output stack array if necessary | |
572 if(outputStack == null) | |
573 { | |
574 outputStack = new int[10]; | |
575 } | |
576 int n = outputStack.length; | |
577 if(outputStackTop >= n) | |
578 { | |
579 int[] t = new int[Math.max(outputStackTop + 1, 2 * n)]; | |
580 System.arraycopy(outputStack, 0, t, 0, n); | |
581 outputStack = t; | |
582 } | |
583 // pushes the type on the output stack | |
584 outputStack[outputStackTop++] = type; | |
585 // updates the maximun height reached by the output stack, if needed | |
586 int top = owner.inputStackTop + outputStackTop; | |
587 if(top > owner.outputStackMax) | |
588 { | |
589 owner.outputStackMax = top; | |
590 } | |
591 } | |
592 | |
593 /** | |
594 * Pushes a new type onto the output frame stack. | |
595 * | |
596 * @param cw the ClassWriter to which this label belongs. | |
597 * @param desc the descriptor of the type to be pushed. Can also be a method | |
598 * descriptor (in this case this method pushes its return type onto | |
599 * the output frame stack). | |
600 */ | |
601 private void push(final ClassWriter cw, final String desc){ | |
602 int type = type(cw, desc); | |
603 if(type != 0) | |
604 { | |
605 push(type); | |
606 if(type == LONG || type == DOUBLE) | |
607 { | |
608 push(TOP); | |
609 } | |
610 } | |
611 } | |
612 | |
613 /** | |
614 * Returns the int encoding of the given type. | |
615 * | |
616 * @param cw the ClassWriter to which this label belongs. | |
617 * @param desc a type descriptor. | |
618 * @return the int encoding of the given type. | |
619 */ | |
620 private int type(final ClassWriter cw, final String desc){ | |
621 String t; | |
622 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; | |
623 switch(desc.charAt(index)) | |
624 { | |
625 case'V': | |
626 return 0; | |
627 case'Z': | |
628 case'C': | |
629 case'B': | |
630 case'S': | |
631 case'I': | |
632 return INTEGER; | |
633 case'F': | |
634 return FLOAT; | |
635 case'J': | |
636 return LONG; | |
637 case'D': | |
638 return DOUBLE; | |
639 case'L': | |
640 // stores the internal name, not the descriptor! | |
641 t = desc.substring(index + 1, desc.length() - 1); | |
642 return OBJECT | cw.addType(t); | |
643 // case '[': | |
644 default: | |
645 // extracts the dimensions and the element type | |
646 int data; | |
647 int dims = index + 1; | |
648 while(desc.charAt(dims) == '[') | |
649 { | |
650 ++dims; | |
651 } | |
652 switch(desc.charAt(dims)) | |
653 { | |
654 case'Z': | |
655 data = BOOLEAN; | |
656 break; | |
657 case'C': | |
658 data = CHAR; | |
659 break; | |
660 case'B': | |
661 data = BYTE; | |
662 break; | |
663 case'S': | |
664 data = SHORT; | |
665 break; | |
666 case'I': | |
667 data = INTEGER; | |
668 break; | |
669 case'F': | |
670 data = FLOAT; | |
671 break; | |
672 case'J': | |
673 data = LONG; | |
674 break; | |
675 case'D': | |
676 data = DOUBLE; | |
677 break; | |
678 // case 'L': | |
679 default: | |
680 // stores the internal name, not the descriptor | |
681 t = desc.substring(dims + 1, desc.length() - 1); | |
682 data = OBJECT | cw.addType(t); | |
683 } | |
684 return (dims - index) << 28 | data; | |
685 } | |
686 } | |
687 | |
688 /** | |
689 * Pops a type from the output frame stack and returns its value. | |
690 * | |
691 * @return the type that has been popped from the output frame stack. | |
692 */ | |
693 private int pop(){ | |
694 if(outputStackTop > 0) | |
695 { | |
696 return outputStack[--outputStackTop]; | |
697 } | |
698 else | |
699 { | |
700 // if the output frame stack is empty, pops from the input stack | |
701 return STACK | -(--owner.inputStackTop); | |
702 } | |
703 } | |
704 | |
705 /** | |
706 * Pops the given number of types from the output frame stack. | |
707 * | |
708 * @param elements the number of types that must be popped. | |
709 */ | |
710 private void pop(final int elements){ | |
711 if(outputStackTop >= elements) | |
712 { | |
713 outputStackTop -= elements; | |
714 } | |
715 else | |
716 { | |
717 // if the number of elements to be popped is greater than the number | |
718 // of elements in the output stack, clear it, and pops the remaining | |
719 // elements from the input stack. | |
720 owner.inputStackTop -= elements - outputStackTop; | |
721 outputStackTop = 0; | |
722 } | |
723 } | |
724 | |
725 /** | |
726 * Pops a type from the output frame stack. | |
727 * | |
728 * @param desc the descriptor of the type to be popped. Can also be a method | |
729 * descriptor (in this case this method pops the types corresponding | |
730 * to the method arguments). | |
731 */ | |
732 private void pop(final String desc){ | |
733 char c = desc.charAt(0); | |
734 if(c == '(') | |
735 { | |
736 pop((MethodWriter.getArgumentsAndReturnSizes(desc) >> 2) - 1); | |
737 } | |
738 else if(c == 'J' || c == 'D') | |
739 { | |
740 pop(2); | |
741 } | |
742 else | |
743 { | |
744 pop(1); | |
745 } | |
746 } | |
747 | |
748 /** | |
749 * Adds a new type to the list of types on which a constructor is invoked in | |
750 * the basic block. | |
751 * | |
752 * @param var a type on a which a constructor is invoked. | |
753 */ | |
754 private void init(final int var){ | |
755 // creates and/or resizes the initializations array if necessary | |
756 if(initializations == null) | |
757 { | |
758 initializations = new int[2]; | |
759 } | |
760 int n = initializations.length; | |
761 if(initializationCount >= n) | |
762 { | |
763 int[] t = new int[Math.max(initializationCount + 1, 2 * n)]; | |
764 System.arraycopy(initializations, 0, t, 0, n); | |
765 initializations = t; | |
766 } | |
767 // stores the type to be initialized | |
768 initializations[initializationCount++] = var; | |
769 } | |
770 | |
771 /** | |
772 * Replaces the given type with the appropriate type if it is one of the | |
773 * types on which a constructor is invoked in the basic block. | |
774 * | |
775 * @param cw the ClassWriter to which this label belongs. | |
776 * @param t a type | |
777 * @return t or, if t is one of the types on which a constructor is invoked | |
778 * in the basic block, the type corresponding to this constructor. | |
779 */ | |
780 private int init(final ClassWriter cw, final int t){ | |
781 int s; | |
782 if(t == UNINITIALIZED_THIS) | |
783 { | |
784 s = OBJECT | cw.addType(cw.thisName); | |
785 } | |
786 else if((t & (DIM | BASE_KIND)) == UNINITIALIZED) | |
787 { | |
788 String type = cw.typeTable[t & BASE_VALUE].strVal1; | |
789 s = OBJECT | cw.addType(type); | |
790 } | |
791 else | |
792 { | |
793 return t; | |
794 } | |
795 for(int j = 0; j < initializationCount; ++j) | |
796 { | |
797 int u = initializations[j]; | |
798 int dim = u & DIM; | |
799 int kind = u & KIND; | |
800 if(kind == LOCAL) | |
801 { | |
802 u = dim + inputLocals[u & VALUE]; | |
803 } | |
804 else if(kind == STACK) | |
805 { | |
806 u = dim + inputStack[inputStack.length - (u & VALUE)]; | |
807 } | |
808 if(t == u) | |
809 { | |
810 return s; | |
811 } | |
812 } | |
813 return t; | |
814 } | |
815 | |
816 /** | |
817 * Initializes the input frame of the first basic block from the method | |
818 * descriptor. | |
819 * | |
820 * @param cw the ClassWriter to which this label belongs. | |
821 * @param access the access flags of the method to which this label belongs. | |
822 * @param args the formal parameter types of this method. | |
823 * @param maxLocals the maximum number of local variables of this method. | |
824 */ | |
825 void initInputFrame( | |
826 final ClassWriter cw, | |
827 final int access, | |
828 final Type[] args, | |
829 final int maxLocals){ | |
830 inputLocals = new int[maxLocals]; | |
831 inputStack = new int[0]; | |
832 int i = 0; | |
833 if((access & Opcodes.ACC_STATIC) == 0) | |
834 { | |
835 if((access & MethodWriter.ACC_CONSTRUCTOR) == 0) | |
836 { | |
837 inputLocals[i++] = OBJECT | cw.addType(cw.thisName); | |
838 } | |
839 else | |
840 { | |
841 inputLocals[i++] = UNINITIALIZED_THIS; | |
842 } | |
843 } | |
844 for(int j = 0; j < args.length; ++j) | |
845 { | |
846 int t = type(cw, args[j].getDescriptor()); | |
847 inputLocals[i++] = t; | |
848 if(t == LONG || t == DOUBLE) | |
849 { | |
850 inputLocals[i++] = TOP; | |
851 } | |
852 } | |
853 while(i < maxLocals) | |
854 { | |
855 inputLocals[i++] = TOP; | |
856 } | |
857 } | |
858 | |
859 /** | |
860 * Simulates the action of the given instruction on the output stack frame. | |
861 * | |
862 * @param opcode the opcode of the instruction. | |
863 * @param arg the operand of the instruction, if any. | |
864 * @param cw the class writer to which this label belongs. | |
865 * @param item the operand of the instructions, if any. | |
866 */ | |
867 void execute( | |
868 final int opcode, | |
869 final int arg, | |
870 final ClassWriter cw, | |
871 final Item item){ | |
872 int t1, t2, t3, t4; | |
873 switch(opcode) | |
874 { | |
875 case Opcodes.NOP: | |
876 case Opcodes.INEG: | |
877 case Opcodes.LNEG: | |
878 case Opcodes.FNEG: | |
879 case Opcodes.DNEG: | |
880 case Opcodes.I2B: | |
881 case Opcodes.I2C: | |
882 case Opcodes.I2S: | |
883 case Opcodes.GOTO: | |
884 case Opcodes.RETURN: | |
885 break; | |
886 case Opcodes.ACONST_NULL: | |
887 push(NULL); | |
888 break; | |
889 case Opcodes.ICONST_M1: | |
890 case Opcodes.ICONST_0: | |
891 case Opcodes.ICONST_1: | |
892 case Opcodes.ICONST_2: | |
893 case Opcodes.ICONST_3: | |
894 case Opcodes.ICONST_4: | |
895 case Opcodes.ICONST_5: | |
896 case Opcodes.BIPUSH: | |
897 case Opcodes.SIPUSH: | |
898 case Opcodes.ILOAD: | |
899 push(INTEGER); | |
900 break; | |
901 case Opcodes.LCONST_0: | |
902 case Opcodes.LCONST_1: | |
903 case Opcodes.LLOAD: | |
904 push(LONG); | |
905 push(TOP); | |
906 break; | |
907 case Opcodes.FCONST_0: | |
908 case Opcodes.FCONST_1: | |
909 case Opcodes.FCONST_2: | |
910 case Opcodes.FLOAD: | |
911 push(FLOAT); | |
912 break; | |
913 case Opcodes.DCONST_0: | |
914 case Opcodes.DCONST_1: | |
915 case Opcodes.DLOAD: | |
916 push(DOUBLE); | |
917 push(TOP); | |
918 break; | |
919 case Opcodes.LDC: | |
920 switch(item.type) | |
921 { | |
922 case ClassWriter.INT: | |
923 push(INTEGER); | |
924 break; | |
925 case ClassWriter.LONG: | |
926 push(LONG); | |
927 push(TOP); | |
928 break; | |
929 case ClassWriter.FLOAT: | |
930 push(FLOAT); | |
931 break; | |
932 case ClassWriter.DOUBLE: | |
933 push(DOUBLE); | |
934 push(TOP); | |
935 break; | |
936 case ClassWriter.CLASS: | |
937 push(OBJECT | cw.addType("java/lang/Class")); | |
938 break; | |
939 // case ClassWriter.STR: | |
940 default: | |
941 push(OBJECT | cw.addType("java/lang/String")); | |
942 } | |
943 break; | |
944 case Opcodes.ALOAD: | |
945 push(get(arg)); | |
946 break; | |
947 case Opcodes.IALOAD: | |
948 case Opcodes.BALOAD: | |
949 case Opcodes.CALOAD: | |
950 case Opcodes.SALOAD: | |
951 pop(2); | |
952 push(INTEGER); | |
953 break; | |
954 case Opcodes.LALOAD: | |
955 case Opcodes.D2L: | |
956 pop(2); | |
957 push(LONG); | |
958 push(TOP); | |
959 break; | |
960 case Opcodes.FALOAD: | |
961 pop(2); | |
962 push(FLOAT); | |
963 break; | |
964 case Opcodes.DALOAD: | |
965 case Opcodes.L2D: | |
966 pop(2); | |
967 push(DOUBLE); | |
968 push(TOP); | |
969 break; | |
970 case Opcodes.AALOAD: | |
971 pop(1); | |
972 t1 = pop(); | |
973 push(ELEMENT_OF + t1); | |
974 break; | |
975 case Opcodes.ISTORE: | |
976 case Opcodes.FSTORE: | |
977 case Opcodes.ASTORE: | |
978 t1 = pop(); | |
979 set(arg, t1); | |
980 if(arg > 0) | |
981 { | |
982 t2 = get(arg - 1); | |
983 // if t2 is of kind STACK or LOCAL we cannot know its size! | |
984 if(t2 == LONG || t2 == DOUBLE) | |
985 { | |
986 set(arg - 1, TOP); | |
987 } | |
988 } | |
989 break; | |
990 case Opcodes.LSTORE: | |
991 case Opcodes.DSTORE: | |
992 pop(1); | |
993 t1 = pop(); | |
994 set(arg, t1); | |
995 set(arg + 1, TOP); | |
996 if(arg > 0) | |
997 { | |
998 t2 = get(arg - 1); | |
999 // if t2 is of kind STACK or LOCAL we cannot know its size! | |
1000 if(t2 == LONG || t2 == DOUBLE) | |
1001 { | |
1002 set(arg - 1, TOP); | |
1003 } | |
1004 } | |
1005 break; | |
1006 case Opcodes.IASTORE: | |
1007 case Opcodes.BASTORE: | |
1008 case Opcodes.CASTORE: | |
1009 case Opcodes.SASTORE: | |
1010 case Opcodes.FASTORE: | |
1011 case Opcodes.AASTORE: | |
1012 pop(3); | |
1013 break; | |
1014 case Opcodes.LASTORE: | |
1015 case Opcodes.DASTORE: | |
1016 pop(4); | |
1017 break; | |
1018 case Opcodes.POP: | |
1019 case Opcodes.IFEQ: | |
1020 case Opcodes.IFNE: | |
1021 case Opcodes.IFLT: | |
1022 case Opcodes.IFGE: | |
1023 case Opcodes.IFGT: | |
1024 case Opcodes.IFLE: | |
1025 case Opcodes.IRETURN: | |
1026 case Opcodes.FRETURN: | |
1027 case Opcodes.ARETURN: | |
1028 case Opcodes.TABLESWITCH: | |
1029 case Opcodes.LOOKUPSWITCH: | |
1030 case Opcodes.ATHROW: | |
1031 case Opcodes.MONITORENTER: | |
1032 case Opcodes.MONITOREXIT: | |
1033 case Opcodes.IFNULL: | |
1034 case Opcodes.IFNONNULL: | |
1035 pop(1); | |
1036 break; | |
1037 case Opcodes.POP2: | |
1038 case Opcodes.IF_ICMPEQ: | |
1039 case Opcodes.IF_ICMPNE: | |
1040 case Opcodes.IF_ICMPLT: | |
1041 case Opcodes.IF_ICMPGE: | |
1042 case Opcodes.IF_ICMPGT: | |
1043 case Opcodes.IF_ICMPLE: | |
1044 case Opcodes.IF_ACMPEQ: | |
1045 case Opcodes.IF_ACMPNE: | |
1046 case Opcodes.LRETURN: | |
1047 case Opcodes.DRETURN: | |
1048 pop(2); | |
1049 break; | |
1050 case Opcodes.DUP: | |
1051 t1 = pop(); | |
1052 push(t1); | |
1053 push(t1); | |
1054 break; | |
1055 case Opcodes.DUP_X1: | |
1056 t1 = pop(); | |
1057 t2 = pop(); | |
1058 push(t1); | |
1059 push(t2); | |
1060 push(t1); | |
1061 break; | |
1062 case Opcodes.DUP_X2: | |
1063 t1 = pop(); | |
1064 t2 = pop(); | |
1065 t3 = pop(); | |
1066 push(t1); | |
1067 push(t3); | |
1068 push(t2); | |
1069 push(t1); | |
1070 break; | |
1071 case Opcodes.DUP2: | |
1072 t1 = pop(); | |
1073 t2 = pop(); | |
1074 push(t2); | |
1075 push(t1); | |
1076 push(t2); | |
1077 push(t1); | |
1078 break; | |
1079 case Opcodes.DUP2_X1: | |
1080 t1 = pop(); | |
1081 t2 = pop(); | |
1082 t3 = pop(); | |
1083 push(t2); | |
1084 push(t1); | |
1085 push(t3); | |
1086 push(t2); | |
1087 push(t1); | |
1088 break; | |
1089 case Opcodes.DUP2_X2: | |
1090 t1 = pop(); | |
1091 t2 = pop(); | |
1092 t3 = pop(); | |
1093 t4 = pop(); | |
1094 push(t2); | |
1095 push(t1); | |
1096 push(t4); | |
1097 push(t3); | |
1098 push(t2); | |
1099 push(t1); | |
1100 break; | |
1101 case Opcodes.SWAP: | |
1102 t1 = pop(); | |
1103 t2 = pop(); | |
1104 push(t1); | |
1105 push(t2); | |
1106 break; | |
1107 case Opcodes.IADD: | |
1108 case Opcodes.ISUB: | |
1109 case Opcodes.IMUL: | |
1110 case Opcodes.IDIV: | |
1111 case Opcodes.IREM: | |
1112 case Opcodes.IAND: | |
1113 case Opcodes.IOR: | |
1114 case Opcodes.IXOR: | |
1115 case Opcodes.ISHL: | |
1116 case Opcodes.ISHR: | |
1117 case Opcodes.IUSHR: | |
1118 case Opcodes.L2I: | |
1119 case Opcodes.D2I: | |
1120 case Opcodes.FCMPL: | |
1121 case Opcodes.FCMPG: | |
1122 pop(2); | |
1123 push(INTEGER); | |
1124 break; | |
1125 case Opcodes.LADD: | |
1126 case Opcodes.LSUB: | |
1127 case Opcodes.LMUL: | |
1128 case Opcodes.LDIV: | |
1129 case Opcodes.LREM: | |
1130 case Opcodes.LAND: | |
1131 case Opcodes.LOR: | |
1132 case Opcodes.LXOR: | |
1133 pop(4); | |
1134 push(LONG); | |
1135 push(TOP); | |
1136 break; | |
1137 case Opcodes.FADD: | |
1138 case Opcodes.FSUB: | |
1139 case Opcodes.FMUL: | |
1140 case Opcodes.FDIV: | |
1141 case Opcodes.FREM: | |
1142 case Opcodes.L2F: | |
1143 case Opcodes.D2F: | |
1144 pop(2); | |
1145 push(FLOAT); | |
1146 break; | |
1147 case Opcodes.DADD: | |
1148 case Opcodes.DSUB: | |
1149 case Opcodes.DMUL: | |
1150 case Opcodes.DDIV: | |
1151 case Opcodes.DREM: | |
1152 pop(4); | |
1153 push(DOUBLE); | |
1154 push(TOP); | |
1155 break; | |
1156 case Opcodes.LSHL: | |
1157 case Opcodes.LSHR: | |
1158 case Opcodes.LUSHR: | |
1159 pop(3); | |
1160 push(LONG); | |
1161 push(TOP); | |
1162 break; | |
1163 case Opcodes.IINC: | |
1164 set(arg, INTEGER); | |
1165 break; | |
1166 case Opcodes.I2L: | |
1167 case Opcodes.F2L: | |
1168 pop(1); | |
1169 push(LONG); | |
1170 push(TOP); | |
1171 break; | |
1172 case Opcodes.I2F: | |
1173 pop(1); | |
1174 push(FLOAT); | |
1175 break; | |
1176 case Opcodes.I2D: | |
1177 case Opcodes.F2D: | |
1178 pop(1); | |
1179 push(DOUBLE); | |
1180 push(TOP); | |
1181 break; | |
1182 case Opcodes.F2I: | |
1183 case Opcodes.ARRAYLENGTH: | |
1184 case Opcodes.INSTANCEOF: | |
1185 pop(1); | |
1186 push(INTEGER); | |
1187 break; | |
1188 case Opcodes.LCMP: | |
1189 case Opcodes.DCMPL: | |
1190 case Opcodes.DCMPG: | |
1191 pop(4); | |
1192 push(INTEGER); | |
1193 break; | |
1194 case Opcodes.JSR: | |
1195 case Opcodes.RET: | |
1196 throw new RuntimeException("JSR/RET are not supported with computeFrames option"); | |
1197 case Opcodes.GETSTATIC: | |
1198 push(cw, item.strVal3); | |
1199 break; | |
1200 case Opcodes.PUTSTATIC: | |
1201 pop(item.strVal3); | |
1202 break; | |
1203 case Opcodes.GETFIELD: | |
1204 pop(1); | |
1205 push(cw, item.strVal3); | |
1206 break; | |
1207 case Opcodes.PUTFIELD: | |
1208 pop(item.strVal3); | |
1209 pop(); | |
1210 break; | |
1211 case Opcodes.INVOKEVIRTUAL: | |
1212 case Opcodes.INVOKESPECIAL: | |
1213 case Opcodes.INVOKESTATIC: | |
1214 case Opcodes.INVOKEINTERFACE: | |
1215 pop(item.strVal3); | |
1216 if(opcode != Opcodes.INVOKESTATIC) | |
1217 { | |
1218 t1 = pop(); | |
1219 if(opcode == Opcodes.INVOKESPECIAL | |
1220 && item.strVal2.charAt(0) == '<') | |
1221 { | |
1222 init(t1); | |
1223 } | |
1224 } | |
1225 push(cw, item.strVal3); | |
1226 break; | |
1227 case Opcodes.NEW: | |
1228 push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); | |
1229 break; | |
1230 case Opcodes.NEWARRAY: | |
1231 pop(); | |
1232 switch(arg) | |
1233 { | |
1234 case Opcodes.T_BOOLEAN: | |
1235 push(ARRAY_OF | BOOLEAN); | |
1236 break; | |
1237 case Opcodes.T_CHAR: | |
1238 push(ARRAY_OF | CHAR); | |
1239 break; | |
1240 case Opcodes.T_BYTE: | |
1241 push(ARRAY_OF | BYTE); | |
1242 break; | |
1243 case Opcodes.T_SHORT: | |
1244 push(ARRAY_OF | SHORT); | |
1245 break; | |
1246 case Opcodes.T_INT: | |
1247 push(ARRAY_OF | INTEGER); | |
1248 break; | |
1249 case Opcodes.T_FLOAT: | |
1250 push(ARRAY_OF | FLOAT); | |
1251 break; | |
1252 case Opcodes.T_DOUBLE: | |
1253 push(ARRAY_OF | DOUBLE); | |
1254 break; | |
1255 // case Opcodes.T_LONG: | |
1256 default: | |
1257 push(ARRAY_OF | LONG); | |
1258 break; | |
1259 } | |
1260 break; | |
1261 case Opcodes.ANEWARRAY: | |
1262 String s = item.strVal1; | |
1263 pop(); | |
1264 if(s.charAt(0) == '[') | |
1265 { | |
1266 push(cw, "[" + s); | |
1267 } | |
1268 else | |
1269 { | |
1270 push(ARRAY_OF | OBJECT | cw.addType(s)); | |
1271 } | |
1272 break; | |
1273 case Opcodes.CHECKCAST: | |
1274 s = item.strVal1; | |
1275 pop(); | |
1276 if(s.charAt(0) == '[') | |
1277 { | |
1278 push(cw, s); | |
1279 } | |
1280 else | |
1281 { | |
1282 push(OBJECT | cw.addType(s)); | |
1283 } | |
1284 break; | |
1285 // case Opcodes.MULTIANEWARRAY: | |
1286 default: | |
1287 pop(arg); | |
1288 push(cw, item.strVal1); | |
1289 break; | |
1290 } | |
1291 } | |
1292 | |
1293 /** | |
1294 * Merges the input frame of the given basic block with the input and output | |
1295 * frames of this basic block. Returns <tt>true</tt> if the input frame of | |
1296 * the given label has been changed by this operation. | |
1297 * | |
1298 * @param cw the ClassWriter to which this label belongs. | |
1299 * @param frame the basic block whose input frame must be updated. | |
1300 * @param edge the kind of the {@link Edge} between this label and 'label'. | |
1301 * See {@link Edge#info}. | |
1302 * @return <tt>true</tt> if the input frame of the given label has been | |
1303 * changed by this operation. | |
1304 */ | |
1305 boolean merge(final ClassWriter cw, final Frame frame, final int edge){ | |
1306 boolean changed = false; | |
1307 int i, s, dim, kind, t; | |
1308 | |
1309 int nLocal = inputLocals.length; | |
1310 int nStack = inputStack.length; | |
1311 if(frame.inputLocals == null) | |
1312 { | |
1313 frame.inputLocals = new int[nLocal]; | |
1314 changed = true; | |
1315 } | |
1316 | |
1317 for(i = 0; i < nLocal; ++i) | |
1318 { | |
1319 if(outputLocals != null && i < outputLocals.length) | |
1320 { | |
1321 s = outputLocals[i]; | |
1322 if(s == 0) | |
1323 { | |
1324 t = inputLocals[i]; | |
1325 } | |
1326 else | |
1327 { | |
1328 dim = s & DIM; | |
1329 kind = s & KIND; | |
1330 if(kind == LOCAL) | |
1331 { | |
1332 t = dim + inputLocals[s & VALUE]; | |
1333 } | |
1334 else if(kind == STACK) | |
1335 { | |
1336 t = dim + inputStack[nStack - (s & VALUE)]; | |
1337 } | |
1338 else | |
1339 { | |
1340 t = s; | |
1341 } | |
1342 } | |
1343 } | |
1344 else | |
1345 { | |
1346 t = inputLocals[i]; | |
1347 } | |
1348 if(initializations != null) | |
1349 { | |
1350 t = init(cw, t); | |
1351 } | |
1352 changed |= merge(cw, t, frame.inputLocals, i); | |
1353 } | |
1354 | |
1355 if(edge > 0) | |
1356 { | |
1357 for(i = 0; i < nLocal; ++i) | |
1358 { | |
1359 t = inputLocals[i]; | |
1360 changed |= merge(cw, t, frame.inputLocals, i); | |
1361 } | |
1362 if(frame.inputStack == null) | |
1363 { | |
1364 frame.inputStack = new int[1]; | |
1365 changed = true; | |
1366 } | |
1367 changed |= merge(cw, edge, frame.inputStack, 0); | |
1368 return changed; | |
1369 } | |
1370 | |
1371 int nInputStack = inputStack.length + owner.inputStackTop; | |
1372 if(frame.inputStack == null) | |
1373 { | |
1374 frame.inputStack = new int[nInputStack + outputStackTop]; | |
1375 changed = true; | |
1376 } | |
1377 | |
1378 for(i = 0; i < nInputStack; ++i) | |
1379 { | |
1380 t = inputStack[i]; | |
1381 if(initializations != null) | |
1382 { | |
1383 t = init(cw, t); | |
1384 } | |
1385 changed |= merge(cw, t, frame.inputStack, i); | |
1386 } | |
1387 for(i = 0; i < outputStackTop; ++i) | |
1388 { | |
1389 s = outputStack[i]; | |
1390 dim = s & DIM; | |
1391 kind = s & KIND; | |
1392 if(kind == LOCAL) | |
1393 { | |
1394 t = dim + inputLocals[s & VALUE]; | |
1395 } | |
1396 else if(kind == STACK) | |
1397 { | |
1398 t = dim + inputStack[nStack - (s & VALUE)]; | |
1399 } | |
1400 else | |
1401 { | |
1402 t = s; | |
1403 } | |
1404 if(initializations != null) | |
1405 { | |
1406 t = init(cw, t); | |
1407 } | |
1408 changed |= merge(cw, t, frame.inputStack, nInputStack + i); | |
1409 } | |
1410 return changed; | |
1411 } | |
1412 | |
1413 /** | |
1414 * Merges the type at the given index in the given type array with the given | |
1415 * type. Returns <tt>true</tt> if the type array has been modified by this | |
1416 * operation. | |
1417 * | |
1418 * @param cw the ClassWriter to which this label belongs. | |
1419 * @param t the type with which the type array element must be merged. | |
1420 * @param types an array of types. | |
1421 * @param index the index of the type that must be merged in 'types'. | |
1422 * @return <tt>true</tt> if the type array has been modified by this | |
1423 * operation. | |
1424 */ | |
1425 private boolean merge( | |
1426 final ClassWriter cw, | |
1427 int t, | |
1428 final int[] types, | |
1429 final int index){ | |
1430 int u = types[index]; | |
1431 if(u == t) | |
1432 { | |
1433 // if the types are equal, merge(u,t)=u, so there is no change | |
1434 return false; | |
1435 } | |
1436 if((t & ~DIM) == NULL) | |
1437 { | |
1438 if(u == NULL) | |
1439 { | |
1440 return false; | |
1441 } | |
1442 t = NULL; | |
1443 } | |
1444 if(u == 0) | |
1445 { | |
1446 // if types[index] has never been assigned, merge(u,t)=t | |
1447 types[index] = t; | |
1448 return true; | |
1449 } | |
1450 int v; | |
1451 if((u & BASE_KIND) == OBJECT || (u & DIM) != 0) | |
1452 { | |
1453 // if u is a reference type of any dimension | |
1454 if(t == NULL) | |
1455 { | |
1456 // if t is the NULL type, merge(u,t)=u, so there is no change | |
1457 return false; | |
1458 } | |
1459 else if((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) | |
1460 { | |
1461 if((u & BASE_KIND) == OBJECT) | |
1462 { | |
1463 // if t is also a reference type, and if u and t have the | |
1464 // same dimension merge(u,t) = dim(t) | common parent of the | |
1465 // element types of u and t | |
1466 v = (t & DIM) | OBJECT | |
1467 | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); | |
1468 } | |
1469 else | |
1470 { | |
1471 // if u and t are array types, but not with the same element | |
1472 // type, merge(u,t)=java/lang/Object | |
1473 v = OBJECT | cw.addType("java/lang/Object"); | |
1474 } | |
1475 } | |
1476 else if((t & BASE_KIND) == OBJECT || (t & DIM) != 0) | |
1477 { | |
1478 // if t is any other reference or array type, | |
1479 // merge(u,t)=java/lang/Object | |
1480 v = OBJECT | cw.addType("java/lang/Object"); | |
1481 } | |
1482 else | |
1483 { | |
1484 // if t is any other type, merge(u,t)=TOP | |
1485 v = TOP; | |
1486 } | |
1487 } | |
1488 else if(u == NULL) | |
1489 { | |
1490 // if u is the NULL type, merge(u,t)=t, | |
1491 // or TOP if t is not a reference type | |
1492 v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP; | |
1493 } | |
1494 else | |
1495 { | |
1496 // if u is any other type, merge(u,t)=TOP whatever t | |
1497 v = TOP; | |
1498 } | |
1499 if(u != v) | |
1500 { | |
1501 types[index] = v; | |
1502 return true; | |
1503 } | |
1504 return false; | |
1505 } | |
1506 } |