View Javadoc
1   package mockit.asm.controlFlow;
2   
3   import static mockit.asm.controlFlow.FrameTypeMask.ARRAY_OF;
4   import static mockit.asm.controlFlow.FrameTypeMask.BASE;
5   import static mockit.asm.controlFlow.FrameTypeMask.BASE_KIND;
6   import static mockit.asm.controlFlow.FrameTypeMask.BASE_VALUE;
7   import static mockit.asm.controlFlow.FrameTypeMask.BOOLEAN;
8   import static mockit.asm.controlFlow.FrameTypeMask.BYTE;
9   import static mockit.asm.controlFlow.FrameTypeMask.CHAR;
10  import static mockit.asm.controlFlow.FrameTypeMask.DIM;
11  import static mockit.asm.controlFlow.FrameTypeMask.DOUBLE;
12  import static mockit.asm.controlFlow.FrameTypeMask.ELEMENT_OF;
13  import static mockit.asm.controlFlow.FrameTypeMask.FLOAT;
14  import static mockit.asm.controlFlow.FrameTypeMask.INTEGER;
15  import static mockit.asm.controlFlow.FrameTypeMask.KIND;
16  import static mockit.asm.controlFlow.FrameTypeMask.LOCAL;
17  import static mockit.asm.controlFlow.FrameTypeMask.LONG;
18  import static mockit.asm.controlFlow.FrameTypeMask.NULL;
19  import static mockit.asm.controlFlow.FrameTypeMask.OBJECT;
20  import static mockit.asm.controlFlow.FrameTypeMask.SHORT;
21  import static mockit.asm.controlFlow.FrameTypeMask.STACK;
22  import static mockit.asm.controlFlow.FrameTypeMask.TOP;
23  import static mockit.asm.controlFlow.FrameTypeMask.TOP_IF_LONG_OR_DOUBLE;
24  import static mockit.asm.controlFlow.FrameTypeMask.UNINITIALIZED;
25  import static mockit.asm.controlFlow.FrameTypeMask.UNINITIALIZED_THIS;
26  import static mockit.asm.controlFlow.FrameTypeMask.VALUE;
27  import static mockit.asm.jvmConstants.Opcodes.*;
28  
29  import edu.umd.cs.findbugs.annotations.NonNull;
30  import edu.umd.cs.findbugs.annotations.Nullable;
31  
32  import mockit.asm.constantPool.ConstantPoolGeneration;
33  import mockit.asm.constantPool.DynamicItem;
34  import mockit.asm.constantPool.Item;
35  import mockit.asm.constantPool.StringItem;
36  import mockit.asm.constantPool.TypeOrMemberItem;
37  import mockit.asm.jvmConstants.Access;
38  import mockit.asm.jvmConstants.ArrayElementType;
39  import mockit.asm.jvmConstants.ConstantPoolTypes;
40  import mockit.asm.types.ArrayType;
41  import mockit.asm.types.JavaType;
42  import mockit.asm.types.PrimitiveType;
43  
44  import org.checkerframework.checker.index.qual.NonNegative;
45  
46  /**
47   * Information about the input and output stack map frames of a basic block.
48   * <p>
49   * Frames are computed in a two steps process: during the visit of each instruction, the state of the frame at the end
50   * of current basic block is updated by simulating the action of the instruction on the previous state of this so called
51   * "output frame". In visitMaxStack, a fix point algorithm is used to compute the "input frame" of each basic block,
52   * i.e. the stack map frame at the beginning of the basic block, starting from the input frame of the first basic block
53   * (which is computed from the method descriptor), and by using the previously computed output frames to compute the
54   * input state of the other blocks.
55   * <p>
56   * All output and input frames are stored as arrays of integers. Reference and array types are represented by an index
57   * into a type table (which is not the same as the constant pool of the class, in order to avoid adding unnecessary
58   * constants in the pool - not all computed frames will end up being stored in the stack map table). This allows very
59   * fast type comparisons.
60   * <p>
61   * Output stack map frames are computed relatively to the input frame of the basic block, which is not yet known when
62   * output frames are computed. It is therefore necessary to be able to represent abstract types such as "the type at
63   * position x in the input frame locals" or "the type at position x from the top of the input frame stack" or even "the
64   * type at position x in the input frame, with y more (or less) array dimensions". This explains the rather complicated
65   * type format used in output frames.
66   * <p>
67   * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a signed number of array dimensions (from -8
68   * to 7). KIND is either BASE, LOCAL or STACK. BASE is used for types that are not relative to the input frame. LOCAL is
69   * used for types that are relative to the input local variable types. STACK is used for types that are relative to the
70   * input stack types. VALUE depends on KIND. For LOCAL types, it is an index in the input local variable types. For
71   * STACK types, it is a position relatively to the top of input frame stack. For BASE types, it is either one of the
72   * constants defined below, or for OBJECT and UNINITIALIZED types, a tag and an index in the type table.
73   * <p>
74   * Output frames can contain types of any kind and with a positive or negative dimension (and even unassigned types,
75   * represented by 0 - which does not correspond to any valid type value). Input frames can only contain BASE types of
76   * positive or null dimension. In all cases the type table contains only internal type names (array type descriptors are
77   * forbidden - dimensions must be represented through the DIM field).
78   * <p>
79   * The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE + TOP), for local variable
80   * types as well as in the operand stack. This is necessary to be able to simulate DUPx_y instructions, whose effect
81   * would be dependent on the actual type values if types were always represented by a single slot in the stack (and this
82   * is not possible, since actual type values are not always known - cf LOCAL and STACK type kinds).
83   */
84  public final class Frame {
85      private static final int[] EMPTY_INPUT_STACK = {};
86  
87      @NonNull
88      private final ConstantPoolGeneration cp;
89  
90      /**
91       * The label (i.e. basic block) to which these input and output stack map frames correspond.
92       */
93      @NonNull
94      final Label owner;
95  
96      /**
97       * The input stack map frame locals.
98       */
99      int[] inputLocals;
100 
101     /**
102      * The input stack map frame stack.
103      */
104     int[] inputStack;
105 
106     /**
107      * The output stack map frame locals.
108      */
109     @Nullable
110     private int[] outputLocals;
111 
112     /**
113      * The output stack map frame stack.
114      */
115     private int[] outputStack;
116 
117     /**
118      * Relative size of the output stack. The exact semantics of this field depends on the algorithm that is used.
119      * <p>
120      * When only the maximum stack size is computed, this field is the size of the output stack relatively to the top of
121      * the input stack.
122      * <p>
123      * When the stack map frames are completely computed, this field is the actual number of types in
124      * {@link #outputStack}.
125      */
126     @NonNegative
127     private int outputStackTop;
128 
129     /**
130      * Number of types that are initialized in the basic block.
131      *
132      * @see #initializations
133      */
134     private int initializationCount;
135 
136     /**
137      * The types that are initialized in the basic block. A constructor invocation on an UNINITIALIZED or
138      * UNINITIALIZED_THIS type must replace <em>every occurrence</em> of this type in the local variables and in the
139      * operand stack. This cannot be done during the first phase of the algorithm since, during this phase, the local
140      * variables and the operand stack are not completely computed. It is therefore necessary to store the types on
141      * which constructors are invoked in the basic block, in order to do this replacement during the second phase of the
142      * algorithm, where the frames are fully computed. Note that this array can contain types that are relative to input
143      * locals or to the input stack.
144      */
145     private int[] initializations;
146 
147     Frame(@NonNull ConstantPoolGeneration cp, @NonNull Label owner) {
148         this.cp = cp;
149         this.owner = owner;
150     }
151 
152     /**
153      * Initializes the input frame of the first basic block from the method descriptor.
154      *
155      * @param access
156      *            the access flags of the method to which this label belongs.
157      * @param args
158      *            the formal parameter types of this method.
159      * @param maxLocals
160      *            the maximum number of local variables of this method.
161      */
162     void initInputFrame(@NonNull String classDesc, int access, @NonNull JavaType[] args, @NonNegative int maxLocals) {
163         inputLocals = new int[maxLocals];
164         inputStack = EMPTY_INPUT_STACK;
165 
166         int localIndex = initializeThisParameterIfApplicable(classDesc, access);
167         localIndex = initializeFormalParameterTypes(localIndex, args);
168 
169         while (localIndex < maxLocals) {
170             inputLocals[localIndex] = TOP;
171             localIndex++;
172         }
173     }
174 
175     @NonNegative
176     private int initializeThisParameterIfApplicable(@NonNull String classDesc, int access) {
177         if ((access & Access.STATIC) == 0) {
178             inputLocals[0] = Access.isConstructor(access) ? UNINITIALIZED_THIS : OBJECT | cp.addNormalType(classDesc);
179             return 1;
180         }
181 
182         return 0;
183     }
184 
185     @NonNegative
186     private int initializeFormalParameterTypes(@NonNegative int localIndex, @NonNull JavaType[] args) {
187         for (JavaType arg : args) {
188             int typeEncoding = getTypeEncoding(arg.getDescriptor());
189             inputLocals[localIndex] = typeEncoding;
190             localIndex++;
191 
192             if (typeEncoding == LONG || typeEncoding == DOUBLE) {
193                 inputLocals[localIndex] = TOP;
194                 localIndex++;
195             }
196         }
197 
198         return localIndex;
199     }
200 
201     /**
202      * Returns the {@linkplain FrameTypeMask int encoding} of the given type.
203      *
204      * @param typeDesc
205      *            a type descriptor
206      *
207      * @return the int encoding of the given type
208      */
209     @NonNegative
210     private int getTypeEncoding(@NonNull String typeDesc) {
211         int index = typeDesc.charAt(0) == '(' ? typeDesc.indexOf(')') + 1 : 0;
212 
213         switch (typeDesc.charAt(index)) {
214             case 'V':
215                 return 0;
216             case 'Z':
217             case 'C':
218             case 'B':
219             case 'S':
220             case 'I':
221                 return INTEGER;
222             case 'F':
223                 return FLOAT;
224             case 'J':
225                 return LONG;
226             case 'D':
227                 return DOUBLE;
228             case 'L':
229                 return getObjectTypeEncoding(typeDesc, index);
230             case '[':
231                 return getArrayTypeEncoding(typeDesc, index);
232             default:
233                 throw new IllegalArgumentException("Invalid type descriptor: " + typeDesc);
234         }
235     }
236 
237     @NonNegative
238     private int getObjectTypeEncoding(@NonNull String typeDesc, @NonNegative int index) {
239         // Stores the internal name, not the descriptor!
240         String t = typeDesc.substring(index + 1, typeDesc.length() - 1);
241         return OBJECT | cp.addNormalType(t);
242     }
243 
244     @NonNegative
245     private int getArrayTypeEncoding(@NonNull String typeDesc, @NonNegative int index) {
246         int dims = getNumberOfDimensions(typeDesc, index);
247         int data = getArrayElementTypeEncoding(typeDesc, index + dims);
248         return dims << 28 | data;
249     }
250 
251     @NonNegative
252     private static int getNumberOfDimensions(@NonNull String typeDesc, @NonNegative int index) {
253         int dims = 1;
254 
255         while (typeDesc.charAt(index + dims) == '[') {
256             dims++;
257         }
258 
259         return dims;
260     }
261 
262     @NonNegative
263     @SuppressWarnings("OverlyComplexMethod")
264     private int getArrayElementTypeEncoding(@NonNull String typeDesc, @NonNegative int index) {
265         switch (typeDesc.charAt(index)) {
266             case 'Z':
267                 return BOOLEAN;
268             case 'C':
269                 return CHAR;
270             case 'B':
271                 return BYTE;
272             case 'S':
273                 return SHORT;
274             case 'I':
275                 return INTEGER;
276             case 'F':
277                 return FLOAT;
278             case 'J':
279                 return LONG;
280             case 'D':
281                 return DOUBLE;
282             case 'L':
283                 return getObjectTypeEncoding(typeDesc, index);
284             default:
285                 throw new IllegalArgumentException("Invalid type descriptor: " + typeDesc);
286         }
287     }
288 
289     /**
290      * Simulates the action of a IINC instruction on the output stack frame.
291      */
292     void executeIINC(@NonNegative int varIndex) {
293         set(varIndex, INTEGER);
294     }
295 
296     /**
297      * Sets the output frame local variable type at the given index.
298      *
299      * @param local
300      *            the index of the local that must be set
301      * @param type
302      *            the value of the local that must be set
303      */
304     private void set(@NonNegative int local, int type) {
305         // Creates and/or resizes the output local variables array if necessary.
306         if (outputLocals == null) {
307             outputLocals = new int[10];
308         }
309 
310         int n = outputLocals.length;
311 
312         if (local >= n) {
313             int[] t = new int[Math.max(local + 1, 2 * n)];
314             System.arraycopy(outputLocals, 0, t, 0, n);
315             outputLocals = t;
316         }
317 
318         // Sets the local variable.
319         outputLocals[local] = type;
320     }
321 
322     /**
323      * Simulates the action of a BIPUSH, SIPUSH, or NEWARRAY instruction on the output stack frame.
324      *
325      * @param opcode
326      *            the opcode of the instruction
327      * @param operand
328      *            the operand of the instruction, if any
329      */
330     void executeINT(@NonNegative int opcode, int operand) {
331         if (opcode == NEWARRAY) {
332             executeNewArray(operand);
333         } else {
334             push(INTEGER);
335         }
336     }
337 
338     private void executeNewArray(@NonNegative int arrayElementType) {
339         pop();
340 
341         // noinspection SwitchStatementWithoutDefaultBranch
342         switch (arrayElementType) {
343             case ArrayElementType.BOOLEAN:
344                 push(ARRAY_OF | BOOLEAN);
345                 break;
346             case ArrayElementType.CHAR:
347                 push(ARRAY_OF | CHAR);
348                 break;
349             case ArrayElementType.BYTE:
350                 push(ARRAY_OF | BYTE);
351                 break;
352             case ArrayElementType.SHORT:
353                 push(ARRAY_OF | SHORT);
354                 break;
355             case ArrayElementType.INT:
356                 push(ARRAY_OF | INTEGER);
357                 break;
358             case ArrayElementType.FLOAT:
359                 push(ARRAY_OF | FLOAT);
360                 break;
361             case ArrayElementType.DOUBLE:
362                 push(ARRAY_OF | DOUBLE);
363                 break;
364             case ArrayElementType.LONG:
365                 push(ARRAY_OF | LONG);
366         }
367     }
368 
369     /**
370      * Pushes a new type onto the output frame stack.
371      */
372     private void push(int type) {
373         // Creates and/or resizes the output stack array if necessary.
374         if (outputStack == null) {
375             outputStack = new int[10];
376         }
377 
378         int n = outputStack.length;
379 
380         if (outputStackTop >= n) {
381             int[] t = new int[Math.max(outputStackTop + 1, 2 * n)];
382             System.arraycopy(outputStack, 0, t, 0, n);
383             outputStack = t;
384         }
385 
386         // Pushes the type on the output stack.
387         outputStack[outputStackTop++] = type;
388 
389         owner.updateOutputStackMaxHeight(outputStackTop);
390     }
391 
392     /**
393      * Pops a type from the output frame stack and returns its value.
394      */
395     private int pop() {
396         if (outputStackTop > 0) {
397             return outputStack[--outputStackTop];
398         }
399 
400         // If the output frame stack is empty, pops from the input stack.
401         return STACK | -owner.decrementInputStackTop();
402     }
403 
404     /**
405      * Simulates the action of a LOOKUPSWITCH or TABLESWITCH instruction on the output stack frame.
406      */
407     void executeSWITCH() {
408         pop(1);
409     }
410 
411     /**
412      * Pops the given number of types from the output frame stack.
413      *
414      * @param elements
415      *            the number of types that must be popped.
416      */
417     private void pop(@NonNegative int elements) {
418         if (outputStackTop >= elements) {
419             outputStackTop -= elements;
420         } else {
421             // If the number of elements to be popped is greater than the number of elements in the output stack, clear
422             // it,
423             // and pops the remaining elements from the input stack.
424             owner.decrementInputStackTop(elements - outputStackTop);
425             outputStackTop = 0;
426         }
427     }
428 
429     /**
430      * Pops a type from the output frame stack.
431      *
432      * @param desc
433      *            the descriptor of the type to be popped. Can also be a method descriptor (in this case this method
434      *            pops the types corresponding to the method arguments).
435      */
436     private void pop(@NonNull String desc) {
437         char c = desc.charAt(0);
438 
439         if (c == '(') {
440             int elements = (JavaType.getArgumentsAndReturnSizes(desc) >> 2) - 1;
441             pop(elements);
442         } else if (c == 'J' || c == 'D') {
443             pop(2);
444         } else {
445             pop(1);
446         }
447     }
448 
449     /**
450      * Adds a new type to the list of types on which a constructor is invoked in the basic block.
451      *
452      * @param var
453      *            a type on a which a constructor is invoked
454      */
455     private void init(int var) {
456         // Creates and/or resizes the initializations array if necessary.
457         if (initializations == null) {
458             initializations = new int[2];
459         }
460 
461         int n = initializations.length;
462 
463         if (initializationCount >= n) {
464             int[] t = new int[Math.max(initializationCount + 1, 2 * n)];
465             System.arraycopy(initializations, 0, t, 0, n);
466             initializations = t;
467         }
468 
469         // Stores the type to be initialized.
470         initializations[initializationCount++] = var;
471     }
472 
473     /**
474      * Replaces the given type with the appropriate type if it is one of the types on which a constructor is invoked in
475      * the basic block.
476      *
477      * @return the given type or, if <code>type</code> is one of the types on which a constructor is invoked in the
478      *         basic block, the type corresponding to this constructor
479      */
480     @NonNegative
481     private int init(@NonNull String classDesc, @NonNegative int type) {
482         int s;
483 
484         if (type == UNINITIALIZED_THIS) {
485             s = OBJECT | cp.addNormalType(classDesc);
486         } else if ((type & (DIM | BASE_KIND)) == UNINITIALIZED) {
487             String typeDesc = cp.getInternalName(type & BASE_VALUE);
488             s = OBJECT | cp.addNormalType(typeDesc);
489         } else {
490             return type;
491         }
492 
493         for (int j = 0; j < initializationCount; j++) {
494             int u = initializations[j];
495             int dim = u & DIM;
496             int kind = u & KIND;
497 
498             if (kind == LOCAL) {
499                 u = dim + inputLocals[u & VALUE];
500             } else if (kind == STACK) {
501                 u = dim + inputStack[inputStack.length - (u & VALUE)];
502             }
503 
504             if (type == u) {
505                 return s;
506             }
507         }
508 
509         return type;
510     }
511 
512     /**
513      * Simulates the action of an xLOAD or xSTORE instruction on the output stack frame.
514      *
515      * @param opcode
516      *            the opcode of the instruction
517      * @param varIndex
518      *            the local variable index
519      */
520     void executeVAR(int opcode, @NonNegative int varIndex) {
521         // noinspection SwitchStatementWithoutDefaultBranch
522         switch (opcode) {
523             case ILOAD:
524                 push(INTEGER);
525                 break;
526             case LLOAD:
527                 push(LONG);
528                 push(TOP);
529                 break;
530             case FLOAD:
531                 push(FLOAT);
532                 break;
533             case DLOAD:
534                 push(DOUBLE);
535                 push(TOP);
536                 break;
537             case ALOAD:
538                 push(get(varIndex));
539                 break;
540             case ISTORE:
541             case FSTORE:
542             case ASTORE:
543                 executeSingleWordStore(varIndex);
544                 break;
545             case LSTORE:
546             case DSTORE:
547                 executeDoubleWordStore(varIndex);
548         }
549     }
550 
551     /**
552      * Returns the output frame local variable type at the given index.
553      */
554     @NonNegative
555     private int get(@NonNegative int localIndex) {
556         if (outputLocals == null || localIndex >= outputLocals.length) {
557             // This local has never been assigned in this basic block, so it's still equal to its value in the input
558             // frame.
559             return LOCAL | localIndex;
560         }
561 
562         int type = outputLocals[localIndex];
563 
564         if (type == 0) {
565             // This local has never been assigned in this basic block, so it's still equal to its value in the input
566             // frame.
567             type = outputLocals[localIndex] = LOCAL | localIndex;
568         }
569 
570         return type;
571     }
572 
573     private void executeSingleWordStore(@NonNegative int arg) {
574         int type1 = pop();
575         set(arg, type1);
576         executeStore(arg);
577     }
578 
579     private void executeDoubleWordStore(@NonNegative int arg) {
580         pop(1);
581 
582         int type1 = pop();
583         set(arg, type1);
584         set(arg + 1, TOP);
585 
586         executeStore(arg);
587     }
588 
589     private void executeStore(@NonNegative int arg) {
590         if (arg > 0) {
591             int type2 = get(arg - 1);
592 
593             // If type2 is of kind STACK or LOCAL we cannot know its size!
594             if (type2 == LONG || type2 == DOUBLE) {
595                 set(arg - 1, TOP);
596             } else if ((type2 & KIND) != BASE) {
597                 set(arg - 1, type2 | TOP_IF_LONG_OR_DOUBLE);
598             }
599         }
600     }
601 
602     /**
603      * Simulates the action of a conditional/unconditional jump instruction on the output stack frame.
604      */
605     void executeJUMP(@NonNegative int opcode) {
606         // noinspection SwitchStatementWithoutDefaultBranch
607         switch (opcode) {
608             case IFEQ:
609             case IFNE:
610             case IFLT:
611             case IFGE:
612             case IFGT:
613             case IFLE:
614             case IFNULL:
615             case IFNONNULL:
616                 pop(1);
617                 break;
618             case IF_ICMPEQ:
619             case IF_ICMPNE:
620             case IF_ICMPLT:
621             case IF_ICMPGE:
622             case IF_ICMPGT:
623             case IF_ICMPLE:
624             case IF_ACMPEQ:
625             case IF_ACMPNE:
626                 pop(2);
627         }
628     }
629 
630     /**
631      * Simulates the action of the given zero-operand instruction on the output stack frame.
632      */
633     @SuppressWarnings({ "OverlyComplexMethod", "OverlyLongMethod" })
634     public void execute(@NonNegative int opcode) {
635         // noinspection SwitchStatementWithoutDefaultBranch
636         switch (opcode) {
637             case NOP:
638             case INEG:
639             case LNEG:
640             case FNEG:
641             case DNEG:
642             case I2B:
643             case I2C:
644             case I2S:
645             case GOTO:
646             case RETURN:
647                 break;
648             case ACONST_NULL:
649                 push(NULL);
650                 break;
651             case ICONST_M1:
652             case ICONST_0:
653             case ICONST_1:
654             case ICONST_2:
655             case ICONST_3:
656             case ICONST_4:
657             case ICONST_5:
658                 push(INTEGER);
659                 break;
660             case LCONST_0:
661             case LCONST_1:
662                 push(LONG);
663                 push(TOP);
664                 break;
665             case FCONST_0:
666             case FCONST_1:
667             case FCONST_2:
668                 push(FLOAT);
669                 break;
670             case DCONST_0:
671             case DCONST_1:
672                 push(DOUBLE);
673                 push(TOP);
674                 break;
675             case IALOAD:
676             case BALOAD:
677             case CALOAD:
678             case SALOAD:
679                 pop(2);
680                 push(INTEGER);
681                 break;
682             case LALOAD:
683             case D2L:
684                 pop(2);
685                 push(LONG);
686                 push(TOP);
687                 break;
688             case FALOAD:
689                 pop(2);
690                 push(FLOAT);
691                 break;
692             case DALOAD:
693             case L2D:
694                 pop(2);
695                 push(DOUBLE);
696                 push(TOP);
697                 break;
698             case AALOAD:
699                 executeAALOAD();
700                 break;
701             case IASTORE:
702             case BASTORE:
703             case CASTORE:
704             case SASTORE:
705             case FASTORE:
706             case AASTORE:
707                 pop(3);
708                 break;
709             case LASTORE:
710             case DASTORE:
711                 pop(4);
712                 break;
713             case POP:
714             case IRETURN:
715             case FRETURN:
716             case ARETURN:
717             case ATHROW:
718             case MONITORENTER:
719             case MONITOREXIT:
720                 pop(1);
721                 break;
722             case POP2:
723             case LRETURN:
724             case DRETURN:
725                 pop(2);
726                 break;
727             case DUP:
728                 executeDUP();
729                 break;
730             case DUP_X1:
731                 executeDUP_X1();
732                 break;
733             case DUP_X2:
734                 executeDUP_X2();
735                 break;
736             case DUP2:
737                 executeDUP2();
738                 break;
739             case DUP2_X1:
740                 executeDUP2_X1();
741                 break;
742             case DUP2_X2:
743                 executeDUP2_X2();
744                 break;
745             case SWAP:
746                 executeSWAP();
747                 break;
748             case IADD:
749             case ISUB:
750             case IMUL:
751             case IDIV:
752             case IREM:
753             case IAND:
754             case IOR:
755             case IXOR:
756             case ISHL:
757             case ISHR:
758             case IUSHR:
759             case L2I:
760             case D2I:
761             case FCMPL:
762             case FCMPG:
763                 pop(2);
764                 push(INTEGER);
765                 break;
766             case LADD:
767             case LSUB:
768             case LMUL:
769             case LDIV:
770             case LREM:
771             case LAND:
772             case LOR:
773             case LXOR:
774                 pop(4);
775                 push(LONG);
776                 push(TOP);
777                 break;
778             case FADD:
779             case FSUB:
780             case FMUL:
781             case FDIV:
782             case FREM:
783             case L2F:
784             case D2F:
785                 pop(2);
786                 push(FLOAT);
787                 break;
788             case DADD:
789             case DSUB:
790             case DMUL:
791             case DDIV:
792             case DREM:
793                 pop(4);
794                 push(DOUBLE);
795                 push(TOP);
796                 break;
797             case LSHL:
798             case LSHR:
799             case LUSHR:
800                 pop(3);
801                 push(LONG);
802                 push(TOP);
803                 break;
804             case I2L:
805             case F2L:
806                 pop(1);
807                 push(LONG);
808                 push(TOP);
809                 break;
810             case I2F:
811                 pop(1);
812                 push(FLOAT);
813                 break;
814             case I2D:
815             case F2D:
816                 pop(1);
817                 push(DOUBLE);
818                 push(TOP);
819                 break;
820             case F2I:
821             case ARRAYLENGTH:
822                 pop(1);
823                 push(INTEGER);
824                 break;
825             case LCMP:
826             case DCMPL:
827             case DCMPG:
828                 pop(4);
829                 push(INTEGER);
830         }
831     }
832 
833     private void executeAALOAD() {
834         pop(1);
835         int type = pop();
836         push(ELEMENT_OF + type);
837     }
838 
839     private void executeDUP() {
840         int type = pop();
841         push(type);
842         push(type);
843     }
844 
845     private void executeDUP_X1() {
846         int type1 = pop();
847         int type2 = pop();
848         push(type1);
849         push(type2);
850         push(type1);
851     }
852 
853     private void executeDUP_X2() {
854         int t1 = pop();
855         int t2 = pop();
856         int t3 = pop();
857         push(t1);
858         push(t3);
859         push(t2);
860         push(t1);
861     }
862 
863     private void executeDUP2() {
864         int t1 = pop();
865         int t2 = pop();
866         push(t2);
867         push(t1);
868         push(t2);
869         push(t1);
870     }
871 
872     private void executeDUP2_X1() {
873         int t1 = pop();
874         int t2 = pop();
875         int t3 = pop();
876         push(t2);
877         push(t1);
878         push(t3);
879         push(t2);
880         push(t1);
881     }
882 
883     private void executeDUP2_X2() {
884         int t1 = pop();
885         int t2 = pop();
886         int t3 = pop();
887         int t4 = pop();
888         push(t2);
889         push(t1);
890         push(t4);
891         push(t3);
892         push(t2);
893         push(t1);
894     }
895 
896     private void executeSWAP() {
897         int t1 = pop();
898         int t2 = pop();
899         push(t1);
900         push(t2);
901     }
902 
903     /**
904      * Simulates the action of an LCD instruction on the output stack frame.
905      *
906      * @param item
907      *            the operand of the instructions
908      */
909     void executeLDC(@NonNull Item item) {
910         switch (item.getType()) {
911             case ConstantPoolTypes.INTEGER:
912                 push(INTEGER);
913                 break;
914             case ConstantPoolTypes.LONG:
915                 push(LONG);
916                 push(TOP);
917                 break;
918             case ConstantPoolTypes.FLOAT:
919                 push(FLOAT);
920                 break;
921             case ConstantPoolTypes.DOUBLE:
922                 push(DOUBLE);
923                 push(TOP);
924                 break;
925             case ConstantPoolTypes.CLASS:
926                 push(OBJECT | cp.addNormalType("java/lang/Class"));
927                 break;
928             case ConstantPoolTypes.STRING:
929                 push(OBJECT | cp.addNormalType("java/lang/String"));
930                 break;
931             case ConstantPoolTypes.METHOD_TYPE:
932                 push(OBJECT | cp.addNormalType("java/lang/invoke/MethodType"));
933                 break;
934             case ConstantPoolTypes.METHOD_HANDLE:
935                 push(OBJECT | cp.addNormalType("java/lang/invoke/MethodHandle"));
936                 break;
937             case ConstantPoolTypes.DYNAMIC:
938                 DynamicItem dynamicItem = (DynamicItem) item;
939                 String desc = dynamicItem.getDesc();
940                 if (desc.length() == 1) {
941                     // primitive
942                     char descChar = desc.charAt(0);
943                     switch (descChar) {
944                         case 'Z':
945                         case 'B':
946                         case 'S':
947                         case 'I':
948                             push(INTEGER);
949                             break;
950                         case 'F':
951                             push(FLOAT);
952                             break;
953                         case 'D':
954                             push(DOUBLE);
955                             break;
956                         case 'J':
957                             push(LONG);
958                             break;
959                         default:
960                             throw new IllegalArgumentException("Unsupported dynamic local 'primitive' type: " + desc);
961                     }
962                 } else if (desc.charAt(0) == '[') {
963                     // array
964                     ArrayType arrayType = ArrayType.create(desc);
965                     JavaType elementType = arrayType.getElementType();
966                     int mask;
967                     if (elementType instanceof PrimitiveType) {
968                         PrimitiveType primitiveElementType = (PrimitiveType) elementType;
969                         char descChar = primitiveElementType.getTypeCode();
970                         switch (descChar) {
971                             case 'Z':
972                             case 'B':
973                             case 'C':
974                             case 'S':
975                             case 'I':
976                                 mask = INTEGER;
977                                 break;
978                             case 'F':
979                                 mask = FLOAT;
980                                 break;
981                             case 'D':
982                                 mask = DOUBLE;
983                                 break;
984                             case 'J':
985                                 mask = LONG;
986                                 break;
987                             default:
988                                 throw new IllegalArgumentException(
989                                         "Unsupported array element 'primitive' type: " + desc);
990                         }
991                     } else {
992                         mask = OBJECT;
993                     }
994                     push(ARRAY_OF | mask);
995                 } else {
996                     // object, substring 'L' and ';'
997                     push(OBJECT | cp.addNormalType(desc.substring(1, desc.length() - 1)));
998                 }
999                 break;
1000             default:
1001                 throw new IllegalArgumentException("Unknown item type, cannot execute frame: " + item.getType());
1002         }
1003     }
1004 
1005     /**
1006      * Simulates the action of a NEW, ANEWARRAY, CHECKCAST or INSTANCEOF instruction on the output stack frame.
1007      *
1008      * @param opcode
1009      *            the opcode of the instruction
1010      * @param codeLength
1011      *            the operand of the instruction, if any
1012      * @param item
1013      *            the operand of the instruction
1014      */
1015     void executeTYPE(@NonNegative int opcode, @NonNegative int codeLength, @NonNull StringItem item) {
1016         // noinspection SwitchStatementWithoutDefaultBranch
1017         switch (opcode) {
1018             case NEW:
1019                 push(UNINITIALIZED | cp.addUninitializedType(item.getValue(), codeLength));
1020                 break;
1021             case ANEWARRAY:
1022                 executeANewArray(item);
1023                 break;
1024             case CHECKCAST:
1025                 executeCheckCast(item);
1026                 break;
1027             case INSTANCEOF:
1028                 pop(1);
1029                 push(INTEGER);
1030         }
1031     }
1032 
1033     private void executeANewArray(@NonNull StringItem item) {
1034         String s = item.getValue();
1035         pop();
1036 
1037         if (s.charAt(0) == '[') {
1038             push('[' + s);
1039         } else {
1040             push(ARRAY_OF | OBJECT | cp.addNormalType(s));
1041         }
1042     }
1043 
1044     /**
1045      * Pushes a new type onto the output frame stack.
1046      *
1047      * @param desc
1048      *            the descriptor of the type to be pushed; can also be a method descriptor (in this case this method
1049      *            pushes its return type onto the output frame stack)
1050      */
1051     private void push(@NonNull String desc) {
1052         int type = getTypeEncoding(desc);
1053 
1054         if (type != 0) {
1055             push(type);
1056 
1057             if (type == LONG || type == DOUBLE) {
1058                 push(TOP);
1059             }
1060         }
1061     }
1062 
1063     private void executeCheckCast(@NonNull StringItem item) {
1064         String s = item.getValue();
1065         pop();
1066 
1067         if (s.charAt(0) == '[') {
1068             push(s);
1069         } else {
1070             push(OBJECT | cp.addNormalType(s));
1071         }
1072     }
1073 
1074     /**
1075      * Simulates the action of a MULTIANEWARRAY instruction on the output stack frame.
1076      *
1077      * @param dims
1078      *            the number of dimensions of the array
1079      * @param arrayType
1080      *            the type of the array elements
1081      */
1082     void executeMULTIANEWARRAY(@NonNegative int dims, @NonNull StringItem arrayType) {
1083         pop(dims);
1084         push(arrayType.getValue());
1085     }
1086 
1087     /**
1088      * Simulates the action of the given instruction on the output stack frame.
1089      *
1090      * @param opcode
1091      *            the opcode of the instruction
1092      * @param item
1093      *            the operand of the instruction
1094      */
1095     public void execute(@NonNegative int opcode, @NonNull TypeOrMemberItem item) {
1096         if (opcode == INVOKEDYNAMIC) {
1097             executeInvokeDynamic(item);
1098         } else {
1099             // noinspection SwitchStatementWithoutDefaultBranch
1100             switch (opcode) {
1101                 case GETSTATIC:
1102                     push(item.getDesc());
1103                     break;
1104                 case PUTSTATIC:
1105                     pop(item.getDesc());
1106                     break;
1107                 case GETFIELD:
1108                     pop(1);
1109                     push(item.getDesc());
1110                     break;
1111                 case PUTFIELD:
1112                     pop(item.getDesc());
1113                     pop();
1114                     break;
1115                 case INVOKEVIRTUAL:
1116                 case INVOKESPECIAL:
1117                 case INVOKESTATIC:
1118                 case INVOKEINTERFACE:
1119                     executeInvoke(opcode, item);
1120             }
1121         }
1122     }
1123 
1124     private void executeInvoke(@NonNegative int opcode, @NonNull TypeOrMemberItem item) {
1125         String methodDesc = item.getDesc();
1126         pop(methodDesc);
1127 
1128         if (opcode != INVOKESTATIC) {
1129             int var = pop();
1130 
1131             if (opcode == INVOKESPECIAL && item.getName().charAt(0) == '<') {
1132                 init(var);
1133             }
1134         }
1135 
1136         push(methodDesc);
1137     }
1138 
1139     private void executeInvokeDynamic(@NonNull TypeOrMemberItem item) {
1140         String desc = item.getDesc();
1141         pop(desc);
1142         push(desc);
1143     }
1144 
1145     /**
1146      * Merges the input frame of the given basic block with the input and output frames of this basic block.
1147      *
1148      * @param frame
1149      *            the basic block whose input frame must be updated
1150      * @param edge
1151      *            the kind of the {@link Edge} between this label and 'label'; see {@link Edge#info}
1152      *
1153      * @return <code>true</code> if the input frame of the given label has been changed by this operation
1154      */
1155     boolean merge(@NonNull String classDesc, @NonNull Frame frame, @NonNegative int edge) {
1156         int nLocal = inputLocals.length;
1157         int nStack = inputStack.length;
1158         boolean changed = false;
1159 
1160         if (frame.inputLocals == null) {
1161             frame.inputLocals = new int[nLocal];
1162             changed = true;
1163         }
1164 
1165         int i;
1166         int s;
1167         int dim;
1168         int type;
1169 
1170         for (i = 0; i < nLocal; i++) {
1171             if (outputLocals != null && i < outputLocals.length) {
1172                 s = outputLocals[i];
1173 
1174                 if (s == 0) {
1175                     type = inputLocals[i];
1176                 } else {
1177                     dim = s & DIM;
1178                     int kind = s & KIND;
1179 
1180                     if (kind == BASE) {
1181                         type = s;
1182                     } else {
1183                         if (kind == LOCAL) {
1184                             type = dim + inputLocals[s & VALUE];
1185                         } else {
1186                             type = dim + inputStack[nStack - (s & VALUE)];
1187                         }
1188 
1189                         if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (type == LONG || type == DOUBLE)) {
1190                             type = TOP;
1191                         }
1192                     }
1193                 }
1194             } else {
1195                 type = inputLocals[i];
1196             }
1197 
1198             if (initializations != null) {
1199                 type = init(classDesc, type);
1200             }
1201 
1202             changed |= merge(type, frame.inputLocals, i);
1203         }
1204 
1205         if (edge > 0) {
1206             for (i = 0; i < nLocal; ++i) {
1207                 type = inputLocals[i];
1208                 changed |= merge(type, frame.inputLocals, i);
1209             }
1210 
1211             if (frame.inputStack == null) {
1212                 frame.inputStack = new int[1];
1213                 changed = true;
1214             }
1215 
1216             changed |= merge(edge, frame.inputStack, 0);
1217             return changed;
1218         }
1219 
1220         int nInputStack = inputStack.length + owner.inputStackTop;
1221 
1222         if (frame.inputStack == null) {
1223             frame.inputStack = new int[nInputStack + outputStackTop];
1224             changed = true;
1225         }
1226 
1227         for (i = 0; i < nInputStack; i++) {
1228             type = inputStack[i];
1229 
1230             if (initializations != null) {
1231                 type = init(classDesc, type);
1232             }
1233 
1234             changed |= merge(type, frame.inputStack, i);
1235         }
1236 
1237         for (i = 0; i < outputStackTop; i++) {
1238             s = outputStack[i];
1239             dim = s & DIM;
1240             int kind = s & KIND;
1241 
1242             if (kind == BASE) {
1243                 type = s;
1244             } else {
1245                 if (kind == LOCAL) {
1246                     type = dim + inputLocals[s & VALUE];
1247                 } else {
1248                     type = dim + inputStack[nStack - (s & VALUE)];
1249                 }
1250 
1251                 if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (type == LONG || type == DOUBLE)) {
1252                     type = TOP;
1253                 }
1254             }
1255 
1256             if (initializations != null) {
1257                 type = init(classDesc, type);
1258             }
1259 
1260             changed |= merge(type, frame.inputStack, nInputStack + i);
1261         }
1262 
1263         return changed;
1264     }
1265 
1266     /**
1267      * Merges the type at the given index in the given type array with the given type.
1268      *
1269      * @param type1
1270      *            the type with which the type array element must be merged
1271      * @param types
1272      *            an array of types
1273      * @param index
1274      *            the index of the type that must be merged in 'types'
1275      *
1276      * @return <code>true</code> if the type array has been modified by this operation
1277      */
1278     private boolean merge(@NonNegative int type1, @NonNull int[] types, @NonNegative int index) {
1279         int type2 = types[index];
1280 
1281         if (type2 == type1) {
1282             // If the types are equal, there is no change.
1283             return false;
1284         }
1285 
1286         if ((type1 & ~DIM) == NULL) {
1287             if (type2 == NULL) {
1288                 return false;
1289             }
1290 
1291             // noinspection AssignmentToMethodParameter
1292             type1 = NULL;
1293         }
1294 
1295         if (type2 == 0) {
1296             // If types[index] has never been assigned, merge(type2, type1) = type1.
1297             types[index] = type1;
1298             return true;
1299         }
1300 
1301         int v;
1302 
1303         if ((type2 & BASE_KIND) == OBJECT || (type2 & DIM) != 0) {
1304             // If type2 is a reference type of any dimension.
1305             if (type1 == NULL) {
1306                 // If type1 is the NULL type, merge(type2, type1) = type2, so there is no change.
1307                 return false;
1308             }
1309             if ((type1 & (DIM | BASE_KIND)) == (type2 & (DIM | BASE_KIND))) {
1310                 // If type1 and type2 have the same dimension and same base kind.
1311                 if ((type2 & BASE_KIND) == OBJECT) {
1312                     // If type1 is also a reference type, and if type2 and type1 have the same dimension
1313                     // merge(type2, type1) = dim(type1) | common parent of the element types of type2 and type1.
1314                     v = type1 & DIM | OBJECT | cp.getMergedType(type1 & BASE_VALUE, type2 & BASE_VALUE);
1315                 } else {
1316                     // If type2 and type1 are array types, but not with the same element type,
1317                     // merge(type2, type1) = dim(type2) - 1 | java/lang/Object.
1318                     int dim = ELEMENT_OF + (type2 & DIM);
1319                     v = dim | OBJECT | cp.addNormalType("java/lang/Object");
1320                 }
1321             } else if ((type1 & BASE_KIND) == OBJECT || (type1 & DIM) != 0) {
1322                 // If type1 is any other reference or array type, the merged type is min(uDim, tDim) | java/lang/Object,
1323                 // where uDim is the array dimension of type2, minus 1 if type2 is an array type with a primitive
1324                 // element
1325                 // type (and similarly for tDim).
1326                 int tDim = ((type1 & DIM) == 0 || (type1 & BASE_KIND) == OBJECT ? 0 : ELEMENT_OF) + (type1 & DIM);
1327                 int uDim = ((type2 & DIM) == 0 || (type2 & BASE_KIND) == OBJECT ? 0 : ELEMENT_OF) + (type2 & DIM);
1328                 v = Math.min(tDim, uDim) | OBJECT | cp.addNormalType("java/lang/Object");
1329             } else {
1330                 // If type1 is any other type, merge(type2, type1) = TOP.
1331                 v = TOP;
1332             }
1333         } else if (type2 == NULL) {
1334             // If type2 is the NULL type, merge(type2, type1) = type1, or TOP if type1 is not a reference type.
1335             v = (type1 & BASE_KIND) == OBJECT || (type1 & DIM) != 0 ? type1 : TOP;
1336         } else {
1337             // If type2 is any other type, merge(type2, type1) = TOP whatever type1.
1338             v = TOP;
1339         }
1340 
1341         if (type2 != v) {
1342             types[index] = v;
1343             return true;
1344         }
1345 
1346         return false;
1347     }
1348 }