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