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