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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
92
93 @NonNull
94 final Label owner;
95
96
97
98
99 int[] inputLocals;
100
101
102
103
104 int[] inputStack;
105
106
107
108
109 @Nullable
110 private int[] outputLocals;
111
112
113
114
115 private int[] outputStack;
116
117
118
119
120
121
122
123
124
125
126 @NonNegative
127 private int outputStackTop;
128
129
130
131
132
133
134 private int initializationCount;
135
136
137
138
139
140
141
142
143
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
154
155
156
157
158
159
160
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
203
204
205
206
207
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
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
291
292 void executeIINC(@NonNegative int varIndex) {
293 set(varIndex, INTEGER);
294 }
295
296
297
298
299
300
301
302
303
304 private void set(@NonNegative int local, int type) {
305
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
319 outputLocals[local] = type;
320 }
321
322
323
324
325
326
327
328
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
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
371
372 private void push(int type) {
373
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
387 outputStack[outputStackTop++] = type;
388
389 owner.updateOutputStackMaxHeight(outputStackTop);
390 }
391
392
393
394
395 private int pop() {
396 if (outputStackTop > 0) {
397 return outputStack[--outputStackTop];
398 }
399
400
401 return STACK | -owner.decrementInputStackTop();
402 }
403
404
405
406
407 void executeSWITCH() {
408 pop(1);
409 }
410
411
412
413
414
415
416
417 private void pop(@NonNegative int elements) {
418 if (outputStackTop >= elements) {
419 outputStackTop -= elements;
420 } else {
421
422
423
424 owner.decrementInputStackTop(elements - outputStackTop);
425 outputStackTop = 0;
426 }
427 }
428
429
430
431
432
433
434
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
451
452
453
454
455 private void init(int var) {
456
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
470 initializations[initializationCount++] = var;
471 }
472
473
474
475
476
477
478
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
514
515
516
517
518
519
520 void executeVAR(int opcode, @NonNegative int varIndex) {
521
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
553
554 @NonNegative
555 private int get(@NonNegative int localIndex) {
556 if (outputLocals == null || localIndex >= outputLocals.length) {
557
558
559 return LOCAL | localIndex;
560 }
561
562 int type = outputLocals[localIndex];
563
564 if (type == 0) {
565
566
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
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
604
605 void executeJUMP(@NonNegative int opcode) {
606
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
632
633 @SuppressWarnings({ "OverlyComplexMethod", "OverlyLongMethod" })
634 public void execute(@NonNegative int opcode) {
635
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
905
906
907
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
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
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
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
1007
1008
1009
1010
1011
1012
1013
1014
1015 void executeTYPE(@NonNegative int opcode, @NonNegative int codeLength, @NonNull StringItem item) {
1016
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
1046
1047
1048
1049
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
1076
1077
1078
1079
1080
1081
1082 void executeMULTIANEWARRAY(@NonNegative int dims, @NonNull StringItem arrayType) {
1083 pop(dims);
1084 push(arrayType.getValue());
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095 public void execute(@NonNegative int opcode, @NonNull TypeOrMemberItem item) {
1096 if (opcode == INVOKEDYNAMIC) {
1097 executeInvokeDynamic(item);
1098 } else {
1099
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
1147
1148
1149
1150
1151
1152
1153
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
1268
1269
1270
1271
1272
1273
1274
1275
1276
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
1283 return false;
1284 }
1285
1286 if ((type1 & ~DIM) == NULL) {
1287 if (type2 == NULL) {
1288 return false;
1289 }
1290
1291
1292 type1 = NULL;
1293 }
1294
1295 if (type2 == 0) {
1296
1297 types[index] = type1;
1298 return true;
1299 }
1300
1301 int v;
1302
1303 if ((type2 & BASE_KIND) == OBJECT || (type2 & DIM) != 0) {
1304
1305 if (type1 == NULL) {
1306
1307 return false;
1308 }
1309 if ((type1 & (DIM | BASE_KIND)) == (type2 & (DIM | BASE_KIND))) {
1310
1311 if ((type2 & BASE_KIND) == OBJECT) {
1312
1313
1314 v = type1 & DIM | OBJECT | cp.getMergedType(type1 & BASE_VALUE, type2 & BASE_VALUE);
1315 } else {
1316
1317
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
1323
1324
1325
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
1331 v = TOP;
1332 }
1333 } else if (type2 == NULL) {
1334
1335 v = (type1 & BASE_KIND) == OBJECT || (type1 & DIM) != 0 ? type1 : TOP;
1336 } else {
1337
1338 v = TOP;
1339 }
1340
1341 if (type2 != v) {
1342 types[index] = v;
1343 return true;
1344 }
1345
1346 return false;
1347 }
1348 }