1
2
3
4
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
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
85
86
87
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
97
98 @NonNull
99 final Label owner;
100
101
102
103
104 int[] inputLocals;
105
106
107
108
109 int[] inputStack;
110
111
112
113
114 @Nullable
115 private int[] outputLocals;
116
117
118
119
120 private int[] outputStack;
121
122
123
124
125
126
127
128
129
130
131 @NonNegative
132 private int outputStackTop;
133
134
135
136
137
138
139 private int initializationCount;
140
141
142
143
144
145
146
147
148
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
159
160
161
162
163
164
165
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
208
209
210
211
212
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
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
296
297 void executeIINC(@NonNegative int varIndex) {
298 set(varIndex, INTEGER);
299 }
300
301
302
303
304
305
306
307
308
309 private void set(@NonNegative int local, int type) {
310
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
324 outputLocals[local] = type;
325 }
326
327
328
329
330
331
332
333
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
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
376
377 private void push(int type) {
378
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
392 outputStack[outputStackTop++] = type;
393
394 owner.updateOutputStackMaxHeight(outputStackTop);
395 }
396
397
398
399
400 private int pop() {
401 if (outputStackTop > 0) {
402 return outputStack[--outputStackTop];
403 }
404
405
406 return STACK | -owner.decrementInputStackTop();
407 }
408
409
410
411
412 void executeSWITCH() {
413 pop(1);
414 }
415
416
417
418
419
420
421
422 private void pop(@NonNegative int elements) {
423 if (outputStackTop >= elements) {
424 outputStackTop -= elements;
425 } else {
426
427
428
429 owner.decrementInputStackTop(elements - outputStackTop);
430 outputStackTop = 0;
431 }
432 }
433
434
435
436
437
438
439
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
456
457
458
459
460 private void init(int var) {
461
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
475 initializations[initializationCount++] = var;
476 }
477
478
479
480
481
482
483
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
519
520
521
522
523
524
525 void executeVAR(int opcode, @NonNegative int varIndex) {
526
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
558
559 @NonNegative
560 private int get(@NonNegative int localIndex) {
561 if (outputLocals == null || localIndex >= outputLocals.length) {
562
563
564 return LOCAL | localIndex;
565 }
566
567 int type = outputLocals[localIndex];
568
569 if (type == 0) {
570
571
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
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
609
610 void executeJUMP(@NonNegative int opcode) {
611
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
637
638 @SuppressWarnings({ "OverlyComplexMethod", "OverlyLongMethod" })
639 public void execute(@NonNegative int opcode) {
640
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
910
911
912
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
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
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
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
1012
1013
1014
1015
1016
1017
1018
1019
1020 void executeTYPE(@NonNegative int opcode, @NonNegative int codeLength, @NonNull StringItem item) {
1021
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
1051
1052
1053
1054
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
1081
1082
1083
1084
1085
1086
1087 void executeMULTIANEWARRAY(@NonNegative int dims, @NonNull StringItem arrayType) {
1088 pop(dims);
1089 push(arrayType.getValue());
1090 }
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100 public void execute(@NonNegative int opcode, @NonNull TypeOrMemberItem item) {
1101 if (opcode == INVOKEDYNAMIC) {
1102 executeInvokeDynamic(item);
1103 } else {
1104
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
1152
1153
1154
1155
1156
1157
1158
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
1273
1274
1275
1276
1277
1278
1279
1280
1281
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
1288 return false;
1289 }
1290
1291 if ((type1 & ~DIM) == NULL) {
1292 if (type2 == NULL) {
1293 return false;
1294 }
1295
1296
1297 type1 = NULL;
1298 }
1299
1300 if (type2 == 0) {
1301
1302 types[index] = type1;
1303 return true;
1304 }
1305
1306 int v;
1307
1308 if ((type2 & BASE_KIND) == OBJECT || (type2 & DIM) != 0) {
1309
1310 if (type1 == NULL) {
1311
1312 return false;
1313 }
1314 if ((type1 & (DIM | BASE_KIND)) == (type2 & (DIM | BASE_KIND))) {
1315
1316 if ((type2 & BASE_KIND) == OBJECT) {
1317
1318
1319 v = type1 & DIM | OBJECT | cp.getMergedType(type1 & BASE_VALUE, type2 & BASE_VALUE);
1320 } else {
1321
1322
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
1328
1329
1330
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
1336 v = TOP;
1337 }
1338 } else if (type2 == NULL) {
1339
1340 v = (type1 & BASE_KIND) == OBJECT || (type1 & DIM) != 0 ? type1 : TOP;
1341 } else {
1342
1343 v = TOP;
1344 }
1345
1346 if (type2 != v) {
1347 types[index] = v;
1348 return true;
1349 }
1350
1351 return false;
1352 }
1353 }