• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 package javassist.bytecode.analysis;
17 
18 import javassist.ClassPool;
19 import javassist.CtClass;
20 import javassist.NotFoundException;
21 import javassist.bytecode.BadBytecode;
22 import javassist.bytecode.CodeIterator;
23 import javassist.bytecode.ConstPool;
24 import javassist.bytecode.Descriptor;
25 import javassist.bytecode.MethodInfo;
26 import javassist.bytecode.Opcode;
27 
28 /**
29  * Executor is responsible for modeling the effects of a JVM instruction on a frame.
30  *
31  * @author Jason T. Greene
32  */
33 public class Executor implements Opcode {
34     private final ConstPool constPool;
35     private final ClassPool classPool;
36     private final Type STRING_TYPE;
37     private final Type CLASS_TYPE;
38     private final Type THROWABLE_TYPE;
39     private int lastPos;
40 
Executor(ClassPool classPool, ConstPool constPool)41     public Executor(ClassPool classPool, ConstPool constPool) {
42         this.constPool = constPool;
43         this.classPool = classPool;
44 
45         try {
46             STRING_TYPE = getType("java.lang.String");
47             CLASS_TYPE = getType("java.lang.Class");
48             THROWABLE_TYPE = getType("java.lang.Throwable");
49         } catch (Exception e) {
50             throw new RuntimeException(e);
51         }
52     }
53 
54 
55     /**
56      * Execute the instruction, modeling the effects on the specified frame and subroutine.
57      * If a subroutine is passed, the access flags will be modified if this instruction accesses
58      * the local variable table.
59      *
60      * @param method the method containing the instruction
61      * @param pos the position of the instruction in the method
62      * @param iter the code iterator used to find the instruction
63      * @param frame the frame to modify to represent the result of the instruction
64      * @param subroutine the optional subroutine this instruction belongs to.
65      * @throws BadBytecode if the bytecode violates the jvm spec
66      */
execute(MethodInfo method, int pos, CodeIterator iter, Frame frame, Subroutine subroutine)67     public void execute(MethodInfo method, int pos, CodeIterator iter, Frame frame, Subroutine subroutine) throws BadBytecode {
68         this.lastPos = pos;
69         int opcode = iter.byteAt(pos);
70 
71 
72         // Declared opcode in order
73         switch (opcode) {
74             case NOP:
75                 break;
76             case ACONST_NULL:
77                 frame.push(Type.UNINIT);
78                 break;
79             case ICONST_M1:
80             case ICONST_0:
81             case ICONST_1:
82             case ICONST_2:
83             case ICONST_3:
84             case ICONST_4:
85             case ICONST_5:
86                 frame.push(Type.INTEGER);
87                 break;
88             case LCONST_0:
89             case LCONST_1:
90                 frame.push(Type.LONG);
91                 frame.push(Type.TOP);
92                 break;
93             case FCONST_0:
94             case FCONST_1:
95             case FCONST_2:
96                 frame.push(Type.FLOAT);
97                 break;
98             case DCONST_0:
99             case DCONST_1:
100                 frame.push(Type.DOUBLE);
101                 frame.push(Type.TOP);
102                 break;
103             case BIPUSH:
104             case SIPUSH:
105                 frame.push(Type.INTEGER);
106                 break;
107             case LDC:
108                 evalLDC(iter.byteAt(pos + 1),  frame);
109                 break;
110             case LDC_W :
111             case LDC2_W :
112                 evalLDC(iter.u16bitAt(pos + 1), frame);
113                 break;
114             case ILOAD:
115                 evalLoad(Type.INTEGER, iter.byteAt(pos + 1), frame, subroutine);
116                 break;
117             case LLOAD:
118                 evalLoad(Type.LONG, iter.byteAt(pos + 1), frame, subroutine);
119                 break;
120             case FLOAD:
121                 evalLoad(Type.FLOAT, iter.byteAt(pos + 1), frame, subroutine);
122                 break;
123             case DLOAD:
124                 evalLoad(Type.DOUBLE, iter.byteAt(pos + 1), frame, subroutine);
125                 break;
126             case ALOAD:
127                 evalLoad(Type.OBJECT, iter.byteAt(pos + 1), frame, subroutine);
128                 break;
129             case ILOAD_0:
130             case ILOAD_1:
131             case ILOAD_2:
132             case ILOAD_3:
133                 evalLoad(Type.INTEGER, opcode - ILOAD_0, frame, subroutine);
134                 break;
135             case LLOAD_0:
136             case LLOAD_1:
137             case LLOAD_2:
138             case LLOAD_3:
139                 evalLoad(Type.LONG, opcode - LLOAD_0, frame, subroutine);
140                 break;
141             case FLOAD_0:
142             case FLOAD_1:
143             case FLOAD_2:
144             case FLOAD_3:
145                 evalLoad(Type.FLOAT, opcode - FLOAD_0, frame, subroutine);
146                 break;
147             case DLOAD_0:
148             case DLOAD_1:
149             case DLOAD_2:
150             case DLOAD_3:
151                 evalLoad(Type.DOUBLE, opcode - DLOAD_0, frame, subroutine);
152                 break;
153             case ALOAD_0:
154             case ALOAD_1:
155             case ALOAD_2:
156             case ALOAD_3:
157                 evalLoad(Type.OBJECT, opcode - ALOAD_0, frame, subroutine);
158                 break;
159             case IALOAD:
160                 evalArrayLoad(Type.INTEGER, frame);
161                 break;
162             case LALOAD:
163                 evalArrayLoad(Type.LONG, frame);
164                 break;
165             case FALOAD:
166                 evalArrayLoad(Type.FLOAT, frame);
167                 break;
168             case DALOAD:
169                 evalArrayLoad(Type.DOUBLE, frame);
170                 break;
171             case AALOAD:
172                 evalArrayLoad(Type.OBJECT, frame);
173                 break;
174             case BALOAD:
175             case CALOAD:
176             case SALOAD:
177                 evalArrayLoad(Type.INTEGER, frame);
178                 break;
179             case ISTORE:
180                 evalStore(Type.INTEGER, iter.byteAt(pos + 1), frame, subroutine);
181                 break;
182             case LSTORE:
183                 evalStore(Type.LONG, iter.byteAt(pos + 1), frame, subroutine);
184                 break;
185             case FSTORE:
186                 evalStore(Type.FLOAT, iter.byteAt(pos + 1), frame, subroutine);
187                 break;
188             case DSTORE:
189                 evalStore(Type.DOUBLE, iter.byteAt(pos + 1), frame, subroutine);
190                 break;
191             case ASTORE:
192                 evalStore(Type.OBJECT, iter.byteAt(pos + 1), frame, subroutine);
193                 break;
194             case ISTORE_0:
195             case ISTORE_1:
196             case ISTORE_2:
197             case ISTORE_3:
198                 evalStore(Type.INTEGER, opcode - ISTORE_0, frame, subroutine);
199                 break;
200             case LSTORE_0:
201             case LSTORE_1:
202             case LSTORE_2:
203             case LSTORE_3:
204                 evalStore(Type.LONG, opcode - LSTORE_0, frame, subroutine);
205                 break;
206             case FSTORE_0:
207             case FSTORE_1:
208             case FSTORE_2:
209             case FSTORE_3:
210                 evalStore(Type.FLOAT, opcode - FSTORE_0, frame, subroutine);
211                 break;
212             case DSTORE_0:
213             case DSTORE_1:
214             case DSTORE_2:
215             case DSTORE_3:
216                 evalStore(Type.DOUBLE, opcode - DSTORE_0, frame, subroutine);
217                 break;
218             case ASTORE_0:
219             case ASTORE_1:
220             case ASTORE_2:
221             case ASTORE_3:
222                 evalStore(Type.OBJECT, opcode - ASTORE_0, frame, subroutine);
223                 break;
224             case IASTORE:
225                 evalArrayStore(Type.INTEGER, frame);
226                 break;
227             case LASTORE:
228                 evalArrayStore(Type.LONG, frame);
229                 break;
230             case FASTORE:
231                 evalArrayStore(Type.FLOAT, frame);
232                 break;
233             case DASTORE:
234                 evalArrayStore(Type.DOUBLE, frame);
235                 break;
236             case AASTORE:
237                 evalArrayStore(Type.OBJECT, frame);
238                 break;
239             case BASTORE:
240             case CASTORE:
241             case SASTORE:
242                 evalArrayStore(Type.INTEGER, frame);
243                 break;
244             case POP:
245                 if (frame.pop() == Type.TOP)
246                     throw new BadBytecode("POP can not be used with a category 2 value, pos = " + pos);
247                 break;
248             case POP2:
249                 frame.pop();
250                 frame.pop();
251                 break;
252             case DUP: {
253                 Type type = frame.peek();
254                 if (type == Type.TOP)
255                     throw new BadBytecode("DUP can not be used with a category 2 value, pos = " + pos);
256 
257                 frame.push(frame.peek());
258                 break;
259             }
260             case DUP_X1:
261             case DUP_X2: {
262                 Type type = frame.peek();
263                 if (type == Type.TOP)
264                     throw new BadBytecode("DUP can not be used with a category 2 value, pos = " + pos);
265                 int end = frame.getTopIndex();
266                 int insert = end - (opcode - DUP_X1) - 1;
267                 frame.push(type);
268 
269                 while (end > insert) {
270                     frame.setStack(end, frame.getStack(end - 1));
271                     end--;
272                 }
273                 frame.setStack(insert, type);
274                 break;
275             }
276             case DUP2:
277                 frame.push(frame.getStack(frame.getTopIndex() - 1));
278                 frame.push(frame.getStack(frame.getTopIndex() - 1));
279                 break;
280             case DUP2_X1:
281             case DUP2_X2: {
282                 int end = frame.getTopIndex();
283                 int insert = end - (opcode - DUP2_X1) - 1;
284                 Type type1 = frame.getStack(frame.getTopIndex() - 1);
285                 Type type2 = frame.peek();
286                 frame.push(type1);
287                 frame.push(type2);
288                 while (end > insert) {
289                     frame.setStack(end, frame.getStack(end - 2));
290                     end--;
291                 }
292                 frame.setStack(insert, type2);
293                 frame.setStack(insert - 1, type1);
294                 break;
295             }
296             case SWAP: {
297                 Type type1 = frame.pop();
298                 Type type2 = frame.pop();
299                 if (type1.getSize() == 2 || type2.getSize() == 2)
300                     throw new BadBytecode("Swap can not be used with category 2 values, pos = " + pos);
301                 frame.push(type1);
302                 frame.push(type2);
303                 break;
304             }
305 
306             // Math
307             case IADD:
308                 evalBinaryMath(Type.INTEGER, frame);
309                 break;
310             case LADD:
311                 evalBinaryMath(Type.LONG, frame);
312                 break;
313             case FADD:
314                 evalBinaryMath(Type.FLOAT, frame);
315                 break;
316             case DADD:
317                 evalBinaryMath(Type.DOUBLE, frame);
318                 break;
319             case ISUB:
320                 evalBinaryMath(Type.INTEGER, frame);
321                 break;
322             case LSUB:
323                 evalBinaryMath(Type.LONG, frame);
324                 break;
325             case FSUB:
326                 evalBinaryMath(Type.FLOAT, frame);
327                 break;
328             case DSUB:
329                 evalBinaryMath(Type.DOUBLE, frame);
330                 break;
331             case IMUL:
332                 evalBinaryMath(Type.INTEGER, frame);
333                 break;
334             case LMUL:
335                 evalBinaryMath(Type.LONG, frame);
336                 break;
337             case FMUL:
338                 evalBinaryMath(Type.FLOAT, frame);
339                 break;
340             case DMUL:
341                 evalBinaryMath(Type.DOUBLE, frame);
342                 break;
343             case IDIV:
344                 evalBinaryMath(Type.INTEGER, frame);
345                 break;
346             case LDIV:
347                 evalBinaryMath(Type.LONG, frame);
348                 break;
349             case FDIV:
350                 evalBinaryMath(Type.FLOAT, frame);
351                 break;
352             case DDIV:
353                 evalBinaryMath(Type.DOUBLE, frame);
354                 break;
355             case IREM:
356                 evalBinaryMath(Type.INTEGER, frame);
357                 break;
358             case LREM:
359                 evalBinaryMath(Type.LONG, frame);
360                 break;
361             case FREM:
362                 evalBinaryMath(Type.FLOAT, frame);
363                 break;
364             case DREM:
365                 evalBinaryMath(Type.DOUBLE, frame);
366                 break;
367 
368             // Unary
369             case INEG:
370                 verifyAssignable(Type.INTEGER, simplePeek(frame));
371                 break;
372             case LNEG:
373                 verifyAssignable(Type.LONG, simplePeek(frame));
374                 break;
375             case FNEG:
376                 verifyAssignable(Type.FLOAT, simplePeek(frame));
377                 break;
378             case DNEG:
379                 verifyAssignable(Type.DOUBLE, simplePeek(frame));
380                 break;
381 
382             // Shifts
383             case ISHL:
384                 evalShift(Type.INTEGER, frame);
385                 break;
386             case LSHL:
387                 evalShift(Type.LONG, frame);
388                 break;
389             case ISHR:
390                 evalShift(Type.INTEGER, frame);
391                 break;
392             case LSHR:
393                 evalShift(Type.LONG, frame);
394                 break;
395             case IUSHR:
396                 evalShift(Type.INTEGER,frame);
397                 break;
398             case LUSHR:
399                 evalShift(Type.LONG, frame);
400                 break;
401 
402             // Bitwise Math
403             case IAND:
404                 evalBinaryMath(Type.INTEGER, frame);
405                 break;
406             case LAND:
407                 evalBinaryMath(Type.LONG, frame);
408                 break;
409             case IOR:
410                 evalBinaryMath(Type.INTEGER, frame);
411                 break;
412             case LOR:
413                 evalBinaryMath(Type.LONG, frame);
414                 break;
415             case IXOR:
416                 evalBinaryMath(Type.INTEGER, frame);
417                 break;
418             case LXOR:
419                 evalBinaryMath(Type.LONG, frame);
420                 break;
421 
422             case IINC: {
423                 int index = iter.byteAt(pos + 1);
424                 verifyAssignable(Type.INTEGER, frame.getLocal(index));
425                 access(index, Type.INTEGER, subroutine);
426                 break;
427             }
428 
429             // Conversion
430             case I2L:
431                 verifyAssignable(Type.INTEGER, simplePop(frame));
432                 simplePush(Type.LONG, frame);
433                 break;
434             case I2F:
435                 verifyAssignable(Type.INTEGER, simplePop(frame));
436                 simplePush(Type.FLOAT, frame);
437                 break;
438             case I2D:
439                 verifyAssignable(Type.INTEGER, simplePop(frame));
440                 simplePush(Type.DOUBLE, frame);
441                 break;
442             case L2I:
443                 verifyAssignable(Type.LONG, simplePop(frame));
444                 simplePush(Type.INTEGER, frame);
445                 break;
446             case L2F:
447                 verifyAssignable(Type.LONG, simplePop(frame));
448                 simplePush(Type.FLOAT, frame);
449                 break;
450             case L2D:
451                 verifyAssignable(Type.LONG, simplePop(frame));
452                 simplePush(Type.DOUBLE, frame);
453                 break;
454             case F2I:
455                 verifyAssignable(Type.FLOAT, simplePop(frame));
456                 simplePush(Type.INTEGER, frame);
457                 break;
458             case F2L:
459                 verifyAssignable(Type.FLOAT, simplePop(frame));
460                 simplePush(Type.LONG, frame);
461                 break;
462             case F2D:
463                 verifyAssignable(Type.FLOAT, simplePop(frame));
464                 simplePush(Type.DOUBLE, frame);
465                 break;
466             case D2I:
467                 verifyAssignable(Type.DOUBLE, simplePop(frame));
468                 simplePush(Type.INTEGER, frame);
469                 break;
470             case D2L:
471                 verifyAssignable(Type.DOUBLE, simplePop(frame));
472                 simplePush(Type.LONG, frame);
473                 break;
474             case D2F:
475                 verifyAssignable(Type.DOUBLE, simplePop(frame));
476                 simplePush(Type.FLOAT, frame);
477                 break;
478             case I2B:
479             case I2C:
480             case I2S:
481                 verifyAssignable(Type.INTEGER, frame.peek());
482                 break;
483             case LCMP:
484                 verifyAssignable(Type.LONG, simplePop(frame));
485                 verifyAssignable(Type.LONG, simplePop(frame));
486                 frame.push(Type.INTEGER);
487                 break;
488             case FCMPL:
489             case FCMPG:
490                 verifyAssignable(Type.FLOAT, simplePop(frame));
491                 verifyAssignable(Type.FLOAT, simplePop(frame));
492                 frame.push(Type.INTEGER);
493                 break;
494             case DCMPL:
495             case DCMPG:
496                 verifyAssignable(Type.DOUBLE, simplePop(frame));
497                 verifyAssignable(Type.DOUBLE, simplePop(frame));
498                 frame.push(Type.INTEGER);
499                 break;
500 
501             // Control flow
502             case IFEQ:
503             case IFNE:
504             case IFLT:
505             case IFGE:
506             case IFGT:
507             case IFLE:
508                 verifyAssignable(Type.INTEGER, simplePop(frame));
509                 break;
510             case IF_ICMPEQ:
511             case IF_ICMPNE:
512             case IF_ICMPLT:
513             case IF_ICMPGE:
514             case IF_ICMPGT:
515             case IF_ICMPLE:
516                 verifyAssignable(Type.INTEGER, simplePop(frame));
517                 verifyAssignable(Type.INTEGER, simplePop(frame));
518                 break;
519             case IF_ACMPEQ:
520             case IF_ACMPNE:
521                 verifyAssignable(Type.OBJECT, simplePop(frame));
522                 verifyAssignable(Type.OBJECT, simplePop(frame));
523                 break;
524             case GOTO:
525                 break;
526             case JSR:
527                 frame.push(Type.RETURN_ADDRESS);
528                 break;
529             case RET:
530                 verifyAssignable(Type.RETURN_ADDRESS, frame.getLocal(iter.byteAt(pos + 1)));
531                 break;
532             case TABLESWITCH:
533             case LOOKUPSWITCH:
534             case IRETURN:
535                 verifyAssignable(Type.INTEGER, simplePop(frame));
536                 break;
537             case LRETURN:
538                 verifyAssignable(Type.LONG, simplePop(frame));
539                 break;
540             case FRETURN:
541                 verifyAssignable(Type.FLOAT, simplePop(frame));
542                 break;
543             case DRETURN:
544                 verifyAssignable(Type.DOUBLE, simplePop(frame));
545                 break;
546             case ARETURN:
547                 try {
548                     CtClass returnType = Descriptor.getReturnType(method.getDescriptor(), classPool);
549                     verifyAssignable(Type.get(returnType), simplePop(frame));
550                 } catch (NotFoundException e) {
551                    throw new RuntimeException(e);
552                 }
553                 break;
554             case RETURN:
555                 break;
556             case GETSTATIC:
557                 evalGetField(opcode, iter.u16bitAt(pos + 1), frame);
558                 break;
559             case PUTSTATIC:
560                 evalPutField(opcode, iter.u16bitAt(pos + 1), frame);
561                 break;
562             case GETFIELD:
563                 evalGetField(opcode, iter.u16bitAt(pos + 1), frame);
564                 break;
565             case PUTFIELD:
566                 evalPutField(opcode, iter.u16bitAt(pos + 1), frame);
567                 break;
568             case INVOKEVIRTUAL:
569             case INVOKESPECIAL:
570             case INVOKESTATIC:
571                 evalInvokeMethod(opcode, iter.u16bitAt(pos + 1), frame);
572                 break;
573             case INVOKEINTERFACE:
574                 evalInvokeIntfMethod(opcode, iter.u16bitAt(pos + 1), frame);
575                 break;
576             case INVOKEDYNAMIC:
577                 evalInvokeDynamic(opcode, iter.u16bitAt(pos + 1), frame);
578                 break;
579             case NEW:
580                 frame.push(resolveClassInfo(constPool.getClassInfo(iter.u16bitAt(pos + 1))));
581                 break;
582             case NEWARRAY:
583                 evalNewArray(pos, iter, frame);
584                 break;
585             case ANEWARRAY:
586                 evalNewObjectArray(pos, iter, frame);
587                 break;
588             case ARRAYLENGTH: {
589                 Type array = simplePop(frame);
590                 if (! array.isArray() && array != Type.UNINIT)
591                     throw new BadBytecode("Array length passed a non-array [pos = " + pos + "]: " + array);
592                 frame.push(Type.INTEGER);
593                 break;
594             }
595             case ATHROW:
596                 verifyAssignable(THROWABLE_TYPE, simplePop(frame));
597                 break;
598             case CHECKCAST:
599                 verifyAssignable(Type.OBJECT, simplePop(frame));
600                 frame.push(typeFromDesc(constPool.getClassInfoByDescriptor(iter.u16bitAt(pos + 1))));
601                 break;
602             case INSTANCEOF:
603                 verifyAssignable(Type.OBJECT, simplePop(frame));
604                 frame.push(Type.INTEGER);
605                 break;
606             case MONITORENTER:
607             case MONITOREXIT:
608                 verifyAssignable(Type.OBJECT, simplePop(frame));
609                 break;
610             case WIDE:
611                 evalWide(pos, iter, frame, subroutine);
612                 break;
613             case MULTIANEWARRAY:
614                 evalNewObjectArray(pos, iter, frame);
615                 break;
616             case IFNULL:
617             case IFNONNULL:
618                 verifyAssignable(Type.OBJECT, simplePop(frame));
619                 break;
620             case GOTO_W:
621                 break;
622             case JSR_W:
623                 frame.push(Type.RETURN_ADDRESS);
624                 break;
625         }
626     }
627 
zeroExtend(Type type)628     private Type zeroExtend(Type type) {
629         if (type == Type.SHORT || type == Type.BYTE || type == Type.CHAR || type == Type.BOOLEAN)
630             return  Type.INTEGER;
631 
632         return type;
633     }
634 
evalArrayLoad(Type expectedComponent, Frame frame)635     private void evalArrayLoad(Type expectedComponent, Frame frame) throws BadBytecode {
636         Type index = frame.pop();
637         Type array = frame.pop();
638 
639         // Special case, an array defined by aconst_null
640         // TODO - we might need to be more inteligent about this
641         if (array == Type.UNINIT) {
642             verifyAssignable(Type.INTEGER, index);
643             if (expectedComponent == Type.OBJECT) {
644                 simplePush(Type.UNINIT, frame);
645             } else {
646                 simplePush(expectedComponent, frame);
647             }
648             return;
649         }
650 
651         Type component = array.getComponent();
652 
653         if (component == null)
654             throw new BadBytecode("Not an array! [pos = " + lastPos + "]: " + component);
655 
656         component = zeroExtend(component);
657 
658         verifyAssignable(expectedComponent, component);
659         verifyAssignable(Type.INTEGER, index);
660         simplePush(component, frame);
661     }
662 
evalArrayStore(Type expectedComponent, Frame frame)663     private void evalArrayStore(Type expectedComponent, Frame frame) throws BadBytecode {
664         Type value = simplePop(frame);
665         Type index = frame.pop();
666         Type array = frame.pop();
667 
668         if (array == Type.UNINIT) {
669             verifyAssignable(Type.INTEGER, index);
670             return;
671         }
672 
673         Type component = array.getComponent();
674 
675         if (component == null)
676             throw new BadBytecode("Not an array! [pos = " + lastPos + "]: " + component);
677 
678         component = zeroExtend(component);
679 
680         verifyAssignable(expectedComponent, component);
681         verifyAssignable(Type.INTEGER, index);
682 
683         // This intentionally only checks for Object on aastore
684         // downconverting of an array (no casts)
685         // e.g. Object[] blah = new String[];
686         //      blah[2] = (Object) "test";
687         //      blah[3] = new Integer(); // compiler doesnt catch it (has legal bytecode),
688         //                               // but will throw arraystoreexception
689         if (expectedComponent == Type.OBJECT) {
690             verifyAssignable(expectedComponent, value);
691         } else {
692             verifyAssignable(component, value);
693         }
694     }
695 
evalBinaryMath(Type expected, Frame frame)696     private void evalBinaryMath(Type expected, Frame frame) throws BadBytecode {
697         Type value2 = simplePop(frame);
698         Type value1 = simplePop(frame);
699 
700         verifyAssignable(expected, value2);
701         verifyAssignable(expected, value1);
702         simplePush(value1, frame);
703     }
704 
evalGetField(int opcode, int index, Frame frame)705     private void evalGetField(int opcode, int index, Frame frame) throws BadBytecode {
706         String desc = constPool.getFieldrefType(index);
707         Type type = zeroExtend(typeFromDesc(desc));
708 
709         if (opcode == GETFIELD) {
710             Type objectType = resolveClassInfo(constPool.getFieldrefClassName(index));
711             verifyAssignable(objectType, simplePop(frame));
712         }
713 
714         simplePush(type, frame);
715     }
716 
evalInvokeIntfMethod(int opcode, int index, Frame frame)717     private void evalInvokeIntfMethod(int opcode, int index, Frame frame) throws BadBytecode {
718         String desc = constPool.getInterfaceMethodrefType(index);
719         Type[] types = paramTypesFromDesc(desc);
720         int i = types.length;
721 
722         while (i > 0)
723             verifyAssignable(zeroExtend(types[--i]), simplePop(frame));
724 
725         String classInfo = constPool.getInterfaceMethodrefClassName(index);
726         Type objectType = resolveClassInfo(classInfo);
727         verifyAssignable(objectType, simplePop(frame));
728 
729         Type returnType = returnTypeFromDesc(desc);
730         if (returnType != Type.VOID)
731             simplePush(zeroExtend(returnType), frame);
732     }
733 
evalInvokeMethod(int opcode, int index, Frame frame)734     private void evalInvokeMethod(int opcode, int index, Frame frame) throws BadBytecode {
735         String desc = constPool.getMethodrefType(index);
736         Type[] types = paramTypesFromDesc(desc);
737         int i = types.length;
738 
739         while (i > 0)
740             verifyAssignable(zeroExtend(types[--i]), simplePop(frame));
741 
742         if (opcode != INVOKESTATIC) {
743             Type objectType = resolveClassInfo(constPool.getMethodrefClassName(index));
744             verifyAssignable(objectType, simplePop(frame));
745         }
746 
747         Type returnType = returnTypeFromDesc(desc);
748         if (returnType != Type.VOID)
749             simplePush(zeroExtend(returnType), frame);
750     }
751 
evalInvokeDynamic(int opcode, int index, Frame frame)752     private void evalInvokeDynamic(int opcode, int index, Frame frame) throws BadBytecode {
753         String desc = constPool.getInvokeDynamicType(index);
754         Type[] types = paramTypesFromDesc(desc);
755         int i = types.length;
756 
757         while (i > 0)
758             verifyAssignable(zeroExtend(types[--i]), simplePop(frame));
759 
760         // simplePop(frame);    // assume CosntPool#REF_invokeStatic
761 
762         Type returnType = returnTypeFromDesc(desc);
763         if (returnType != Type.VOID)
764             simplePush(zeroExtend(returnType), frame);
765     }
766 
evalLDC(int index, Frame frame)767     private void evalLDC(int index, Frame frame) throws BadBytecode {
768         int tag = constPool.getTag(index);
769         Type type;
770         switch (tag) {
771         case ConstPool.CONST_String:
772             type = STRING_TYPE;
773             break;
774         case ConstPool.CONST_Integer:
775             type = Type.INTEGER;
776             break;
777         case ConstPool.CONST_Float:
778             type = Type.FLOAT;
779             break;
780         case ConstPool.CONST_Long:
781             type = Type.LONG;
782             break;
783         case ConstPool.CONST_Double:
784             type = Type.DOUBLE;
785             break;
786         case ConstPool.CONST_Class:
787             type = CLASS_TYPE;
788             break;
789         default:
790             throw new BadBytecode("bad LDC [pos = " + lastPos + "]: " + tag);
791         }
792 
793         simplePush(type, frame);
794     }
795 
evalLoad(Type expected, int index, Frame frame, Subroutine subroutine)796     private void evalLoad(Type expected, int index, Frame frame, Subroutine subroutine) throws BadBytecode {
797         Type type = frame.getLocal(index);
798 
799         verifyAssignable(expected, type);
800 
801         simplePush(type, frame);
802         access(index, type, subroutine);
803     }
804 
evalNewArray(int pos, CodeIterator iter, Frame frame)805     private void evalNewArray(int pos, CodeIterator iter, Frame frame) throws BadBytecode {
806         verifyAssignable(Type.INTEGER, simplePop(frame));
807         Type type = null;
808         int typeInfo = iter.byteAt(pos + 1);
809         switch (typeInfo) {
810             case T_BOOLEAN:
811                 type = getType("boolean[]");
812                 break;
813             case T_CHAR:
814                 type = getType("char[]");
815                 break;
816             case T_BYTE:
817                 type = getType("byte[]");
818                 break;
819             case T_SHORT:
820                 type = getType("short[]");
821                 break;
822             case T_INT:
823                 type = getType("int[]");
824                 break;
825             case T_LONG:
826                 type = getType("long[]");
827                 break;
828             case T_FLOAT:
829                 type = getType("float[]");
830                 break;
831             case T_DOUBLE:
832                 type = getType("double[]");
833                 break;
834             default:
835                 throw new BadBytecode("Invalid array type [pos = " + pos + "]: " + typeInfo);
836 
837         }
838 
839         frame.push(type);
840     }
841 
evalNewObjectArray(int pos, CodeIterator iter, Frame frame)842     private void evalNewObjectArray(int pos, CodeIterator iter, Frame frame) throws BadBytecode {
843         // Convert to x[] format
844         Type type = resolveClassInfo(constPool.getClassInfo(iter.u16bitAt(pos + 1)));
845         String name = type.getCtClass().getName();
846         int opcode = iter.byteAt(pos);
847         int dimensions;
848 
849         if (opcode == MULTIANEWARRAY) {
850             dimensions = iter.byteAt(pos + 3);
851         } else {
852             name = name + "[]";
853             dimensions = 1;
854         }
855 
856         while (dimensions-- > 0) {
857             verifyAssignable(Type.INTEGER, simplePop(frame));
858         }
859 
860         simplePush(getType(name), frame);
861     }
862 
evalPutField(int opcode, int index, Frame frame)863     private void evalPutField(int opcode, int index, Frame frame) throws BadBytecode {
864         String desc = constPool.getFieldrefType(index);
865         Type type = zeroExtend(typeFromDesc(desc));
866 
867         verifyAssignable(type, simplePop(frame));
868 
869         if (opcode == PUTFIELD) {
870             Type objectType = resolveClassInfo(constPool.getFieldrefClassName(index));
871             verifyAssignable(objectType, simplePop(frame));
872         }
873     }
874 
evalShift(Type expected, Frame frame)875     private void evalShift(Type expected, Frame frame) throws BadBytecode {
876         Type value2 = simplePop(frame);
877         Type value1 = simplePop(frame);
878 
879         verifyAssignable(Type.INTEGER, value2);
880         verifyAssignable(expected, value1);
881         simplePush(value1, frame);
882     }
883 
evalStore(Type expected, int index, Frame frame, Subroutine subroutine)884     private void evalStore(Type expected, int index, Frame frame, Subroutine subroutine) throws BadBytecode {
885         Type type = simplePop(frame);
886 
887         // RETURN_ADDRESS is allowed by ASTORE
888         if (! (expected == Type.OBJECT && type == Type.RETURN_ADDRESS))
889             verifyAssignable(expected, type);
890         simpleSetLocal(index, type, frame);
891         access(index, type, subroutine);
892     }
893 
evalWide(int pos, CodeIterator iter, Frame frame, Subroutine subroutine)894     private void evalWide(int pos, CodeIterator iter, Frame frame, Subroutine subroutine) throws BadBytecode {
895         int opcode = iter.byteAt(pos + 1);
896         int index = iter.u16bitAt(pos + 2);
897         switch (opcode) {
898             case ILOAD:
899                 evalLoad(Type.INTEGER, index, frame, subroutine);
900                 break;
901             case LLOAD:
902                 evalLoad(Type.LONG, index, frame, subroutine);
903                 break;
904             case FLOAD:
905                 evalLoad(Type.FLOAT, index, frame, subroutine);
906                 break;
907             case DLOAD:
908                 evalLoad(Type.DOUBLE, index, frame, subroutine);
909                 break;
910             case ALOAD:
911                 evalLoad(Type.OBJECT, index, frame, subroutine);
912                 break;
913             case ISTORE:
914                 evalStore(Type.INTEGER, index, frame, subroutine);
915                 break;
916             case LSTORE:
917                 evalStore(Type.LONG, index, frame, subroutine);
918                 break;
919             case FSTORE:
920                 evalStore(Type.FLOAT, index, frame, subroutine);
921                 break;
922             case DSTORE:
923                 evalStore(Type.DOUBLE, index, frame, subroutine);
924                 break;
925             case ASTORE:
926                 evalStore(Type.OBJECT, index, frame, subroutine);
927                 break;
928             case IINC:
929                 verifyAssignable(Type.INTEGER, frame.getLocal(index));
930                 break;
931             case RET:
932                 verifyAssignable(Type.RETURN_ADDRESS, frame.getLocal(index));
933                 break;
934             default:
935                 throw new BadBytecode("Invalid WIDE operand [pos = " + pos + "]: " + opcode);
936         }
937 
938     }
939 
getType(String name)940     private Type getType(String name) throws BadBytecode {
941         try {
942             return Type.get(classPool.get(name));
943         } catch (NotFoundException e) {
944             throw new BadBytecode("Could not find class [pos = " + lastPos + "]: " + name);
945         }
946     }
947 
paramTypesFromDesc(String desc)948     private Type[] paramTypesFromDesc(String desc) throws BadBytecode {
949         CtClass classes[] = null;
950         try {
951             classes = Descriptor.getParameterTypes(desc, classPool);
952         } catch (NotFoundException e) {
953             throw new BadBytecode("Could not find class in descriptor [pos = " + lastPos + "]: " + e.getMessage());
954         }
955 
956         if (classes == null)
957             throw new BadBytecode("Could not obtain parameters for descriptor [pos = " + lastPos + "]: " + desc);
958 
959         Type[] types = new Type[classes.length];
960         for (int i = 0; i < types.length; i++)
961             types[i] = Type.get(classes[i]);
962 
963         return types;
964     }
965 
returnTypeFromDesc(String desc)966     private Type returnTypeFromDesc(String desc) throws BadBytecode {
967         CtClass clazz = null;
968         try {
969             clazz = Descriptor.getReturnType(desc, classPool);
970         } catch (NotFoundException e) {
971             throw new BadBytecode("Could not find class in descriptor [pos = " + lastPos + "]: " + e.getMessage());
972         }
973 
974         if (clazz == null)
975             throw new BadBytecode("Could not obtain return type for descriptor [pos = " + lastPos + "]: " + desc);
976 
977         return Type.get(clazz);
978     }
979 
simplePeek(Frame frame)980     private Type simplePeek(Frame frame) {
981         Type type = frame.peek();
982         return (type == Type.TOP) ? frame.getStack(frame.getTopIndex() - 1) : type;
983     }
984 
simplePop(Frame frame)985     private Type simplePop(Frame frame) {
986         Type type = frame.pop();
987         return (type == Type.TOP) ? frame.pop() : type;
988     }
989 
simplePush(Type type, Frame frame)990     private void simplePush(Type type, Frame frame) {
991         frame.push(type);
992         if (type.getSize() == 2)
993             frame.push(Type.TOP);
994     }
995 
access(int index, Type type, Subroutine subroutine)996     private void access(int index, Type type, Subroutine subroutine) {
997         if (subroutine == null)
998             return;
999         subroutine.access(index);
1000         if (type.getSize() == 2)
1001             subroutine.access(index + 1);
1002     }
1003 
simpleSetLocal(int index, Type type, Frame frame)1004     private void simpleSetLocal(int index, Type type, Frame frame) {
1005         frame.setLocal(index, type);
1006         if (type.getSize() == 2)
1007             frame.setLocal(index + 1, Type.TOP);
1008     }
1009 
resolveClassInfo(String info)1010     private Type resolveClassInfo(String info) throws BadBytecode {
1011         CtClass clazz = null;
1012         try {
1013             if (info.charAt(0) == '[') {
1014                 clazz = Descriptor.toCtClass(info, classPool);
1015             } else {
1016                 clazz = classPool.get(info);
1017             }
1018 
1019         } catch (NotFoundException e) {
1020             throw new BadBytecode("Could not find class in descriptor [pos = " + lastPos + "]: " + e.getMessage());
1021         }
1022 
1023         if (clazz == null)
1024             throw new BadBytecode("Could not obtain type for descriptor [pos = " + lastPos + "]: " + info);
1025 
1026         return Type.get(clazz);
1027     }
1028 
typeFromDesc(String desc)1029     private Type typeFromDesc(String desc) throws BadBytecode {
1030         CtClass clazz = null;
1031         try {
1032             clazz = Descriptor.toCtClass(desc, classPool);
1033         } catch (NotFoundException e) {
1034             throw new BadBytecode("Could not find class in descriptor [pos = " + lastPos + "]: " + e.getMessage());
1035         }
1036 
1037         if (clazz == null)
1038             throw new BadBytecode("Could not obtain type for descriptor [pos = " + lastPos + "]: " + desc);
1039 
1040         return Type.get(clazz);
1041     }
1042 
verifyAssignable(Type expected, Type type)1043     private void verifyAssignable(Type expected, Type type) throws BadBytecode {
1044         if (! expected.isAssignableFrom(type))
1045             throw new BadBytecode("Expected type: " + expected + " Got: " + type + " [pos = " + lastPos + "]");
1046     }
1047 }
1048