• 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 
17 package javassist.bytecode.stackmap;
18 
19 import javassist.ClassPool;
20 import javassist.bytecode.BadBytecode;
21 import javassist.bytecode.ByteArray;
22 import javassist.bytecode.ConstPool;
23 import javassist.bytecode.Descriptor;
24 import javassist.bytecode.Opcode;
25 
26 /*
27  * A class for performing abstract interpretation.
28  * See also MapMaker class.
29  */
30 
31 public abstract class Tracer implements TypeTag {
32     protected ClassPool classPool;
33     protected ConstPool cpool;
34     protected String returnType;    // used as the type of ARETURN
35 
36     protected int stackTop;
37     protected TypeData[] stackTypes;
38     protected TypeData[] localsTypes;
39 
Tracer(ClassPool classes, ConstPool cp, int maxStack, int maxLocals, String retType)40     public Tracer(ClassPool classes, ConstPool cp, int maxStack, int maxLocals,
41                   String retType) {
42         classPool = classes;
43         cpool = cp;
44         returnType = retType;
45         stackTop = 0;
46         stackTypes = TypeData.make(maxStack);
47         localsTypes = TypeData.make(maxLocals);
48     }
49 
Tracer(Tracer t)50     public Tracer(Tracer t) {
51         classPool = t.classPool;
52         cpool = t.cpool;
53         returnType = t.returnType;
54         stackTop = t.stackTop;
55         stackTypes = TypeData.make(t.stackTypes.length);
56         localsTypes = TypeData.make(t.localsTypes.length);
57     }
58 
59     /**
60      * Does abstract interpretation on the given bytecode instruction.
61      * It records whether or not a local variable (i.e. register) is accessed.
62      * If the instruction requires that a local variable or
63      * a stack element has a more specific type, this method updates the
64      * type of it.
65      *
66      * @param pos         the position of the instruction.
67      * @return      the size of the instruction at POS.
68      */
doOpcode(int pos, byte[] code)69     protected int doOpcode(int pos, byte[] code) throws BadBytecode {
70         try {
71             int op = code[pos] & 0xff;
72             if (op < 54)
73                 return doOpcode0_53(pos, code, op);
74             if (op < 96)
75                 return doOpcode54_95(pos, code, op);
76             if (op < 148)
77                 return doOpcode96_147(pos, code, op);
78             return doOpcode148_201(pos, code, op);
79         }
80         catch (ArrayIndexOutOfBoundsException e) {
81             throw new BadBytecode("inconsistent stack height " + e.getMessage(), e);
82         }
83     }
84 
visitBranch(int pos, byte[] code, int offset)85     protected void visitBranch(int pos, byte[] code, int offset) throws BadBytecode {}
visitGoto(int pos, byte[] code, int offset)86     protected void visitGoto(int pos, byte[] code, int offset) throws BadBytecode {}
visitReturn(int pos, byte[] code)87     protected void visitReturn(int pos, byte[] code) throws BadBytecode {}
visitThrow(int pos, byte[] code)88     protected void visitThrow(int pos, byte[] code) throws BadBytecode {}
89 
90     /**
91      * @param pos           the position of TABLESWITCH
92      * @param code          bytecode
93      * @param n             the number of case labels
94      * @param offsetPos     the position of the branch-target table.
95      * @param defaultOffset     the offset to the default branch target.
96      */
visitTableSwitch(int pos, byte[] code, int n, int offsetPos, int defaultOffset)97     protected void visitTableSwitch(int pos, byte[] code, int n,
98                 int offsetPos, int defaultOffset) throws BadBytecode {}
99 
100     /**
101      * @param pos           the position of LOOKUPSWITCH
102      * @param code          bytecode
103      * @param n             the number of case labels
104      * @param pairsPos      the position of the table of pairs of a value and a branch target.
105      * @param defaultOffset     the offset to the default branch target.
106      */
visitLookupSwitch(int pos, byte[] code, int n, int pairsPos, int defaultOffset)107     protected void visitLookupSwitch(int pos, byte[] code, int n,
108                 int pairsPos, int defaultOffset) throws BadBytecode {}
109 
110     /**
111      * Invoked when the visited instruction is jsr.
112      * Java6 or later does not allow using RET.
113      */
visitJSR(int pos, byte[] code)114     protected void visitJSR(int pos, byte[] code) throws BadBytecode {
115         /* Since JSR pushes a return address onto the operand stack,
116          * the stack map at the entry point of a subroutine is
117          * stackTypes resulting after executing the following code:
118          *
119          *     stackTypes[stackTop++] = TOP;
120          */
121     }
122 
123     /**
124      * Invoked when the visited instruction is ret or wide ret.
125      * Java6 or later does not allow using RET.
126      */
visitRET(int pos, byte[] code)127     protected void visitRET(int pos, byte[] code) throws BadBytecode {}
128 
doOpcode0_53(int pos, byte[] code, int op)129     private int doOpcode0_53(int pos, byte[] code, int op) throws BadBytecode {
130         int reg;
131         TypeData[] stackTypes = this.stackTypes;
132         switch (op) {
133         case Opcode.NOP :
134             break;
135         case Opcode.ACONST_NULL :
136             stackTypes[stackTop++] = new TypeData.NullType();
137             break;
138         case Opcode.ICONST_M1 :
139         case Opcode.ICONST_0 :
140         case Opcode.ICONST_1 :
141         case Opcode.ICONST_2 :
142         case Opcode.ICONST_3 :
143         case Opcode.ICONST_4 :
144         case Opcode.ICONST_5 :
145             stackTypes[stackTop++] = INTEGER;
146             break;
147         case Opcode.LCONST_0 :
148         case Opcode.LCONST_1 :
149             stackTypes[stackTop++] = LONG;
150             stackTypes[stackTop++] = TOP;
151             break;
152         case Opcode.FCONST_0 :
153         case Opcode.FCONST_1 :
154         case Opcode.FCONST_2 :
155             stackTypes[stackTop++] = FLOAT;
156             break;
157         case Opcode.DCONST_0 :
158         case Opcode.DCONST_1 :
159             stackTypes[stackTop++] = DOUBLE;
160             stackTypes[stackTop++] = TOP;
161             break;
162         case Opcode.BIPUSH :
163         case Opcode.SIPUSH :
164             stackTypes[stackTop++] = INTEGER;
165             return op == Opcode.SIPUSH ? 3 : 2;
166         case Opcode.LDC :
167             doLDC(code[pos + 1] & 0xff);
168             return 2;
169         case Opcode.LDC_W :
170         case Opcode.LDC2_W :
171             doLDC(ByteArray.readU16bit(code, pos + 1));
172             return 3;
173         case Opcode.ILOAD :
174             return doXLOAD(INTEGER, code, pos);
175         case Opcode.LLOAD :
176             return doXLOAD(LONG, code, pos);
177         case Opcode.FLOAD :
178             return doXLOAD(FLOAT, code, pos);
179         case Opcode.DLOAD :
180             return doXLOAD(DOUBLE, code, pos);
181         case Opcode.ALOAD :
182             return doALOAD(code[pos + 1] & 0xff);
183         case Opcode.ILOAD_0 :
184         case Opcode.ILOAD_1 :
185         case Opcode.ILOAD_2 :
186         case Opcode.ILOAD_3 :
187             stackTypes[stackTop++] = INTEGER;
188             break;
189         case Opcode.LLOAD_0 :
190         case Opcode.LLOAD_1 :
191         case Opcode.LLOAD_2 :
192         case Opcode.LLOAD_3 :
193             stackTypes[stackTop++] = LONG;
194             stackTypes[stackTop++] = TOP;
195             break;
196         case Opcode.FLOAD_0 :
197         case Opcode.FLOAD_1 :
198         case Opcode.FLOAD_2 :
199         case Opcode.FLOAD_3 :
200             stackTypes[stackTop++] = FLOAT;
201             break;
202         case Opcode.DLOAD_0 :
203         case Opcode.DLOAD_1 :
204         case Opcode.DLOAD_2 :
205         case Opcode.DLOAD_3 :
206             stackTypes[stackTop++] = DOUBLE;
207             stackTypes[stackTop++] = TOP;
208             break;
209         case Opcode.ALOAD_0 :
210         case Opcode.ALOAD_1 :
211         case Opcode.ALOAD_2 :
212         case Opcode.ALOAD_3 :
213             reg = op - Opcode.ALOAD_0;
214             stackTypes[stackTop++] = localsTypes[reg];
215             break;
216         case Opcode.IALOAD :
217             stackTypes[--stackTop - 1] = INTEGER;
218             break;
219         case Opcode.LALOAD :
220             stackTypes[stackTop - 2] = LONG;
221             stackTypes[stackTop - 1] = TOP;
222             break;
223         case Opcode.FALOAD :
224             stackTypes[--stackTop - 1] = FLOAT;
225             break;
226         case Opcode.DALOAD :
227             stackTypes[stackTop - 2] = DOUBLE;
228             stackTypes[stackTop - 1] = TOP;
229             break;
230         case Opcode.AALOAD : {
231             int s = --stackTop - 1;
232             TypeData data = stackTypes[s];
233             stackTypes[s] = TypeData.ArrayElement.make(data);
234             break; }
235         case Opcode.BALOAD :
236         case Opcode.CALOAD :
237         case Opcode.SALOAD :
238             stackTypes[--stackTop - 1] = INTEGER;
239             break;
240         default :
241             throw new RuntimeException("fatal");
242         }
243 
244         return 1;
245     }
246 
doLDC(int index)247     private void doLDC(int index) {
248         TypeData[] stackTypes = this.stackTypes;
249         int tag = cpool.getTag(index);
250         if (tag == ConstPool.CONST_String)
251             stackTypes[stackTop++] = new TypeData.ClassName("java.lang.String");
252         else if (tag == ConstPool.CONST_Integer)
253             stackTypes[stackTop++] = INTEGER;
254         else if (tag == ConstPool.CONST_Float)
255             stackTypes[stackTop++] = FLOAT;
256         else if (tag == ConstPool.CONST_Long) {
257             stackTypes[stackTop++] = LONG;
258             stackTypes[stackTop++] = TOP;
259         }
260         else if (tag == ConstPool.CONST_Double) {
261             stackTypes[stackTop++] = DOUBLE;
262             stackTypes[stackTop++] = TOP;
263         }
264         else if (tag == ConstPool.CONST_Class)
265             stackTypes[stackTop++] = new TypeData.ClassName("java.lang.Class");
266         else
267             throw new RuntimeException("bad LDC: " + tag);
268     }
269 
doXLOAD(TypeData type, byte[] code, int pos)270     private int doXLOAD(TypeData type, byte[] code, int pos) {
271         int localVar = code[pos + 1] & 0xff;
272         return doXLOAD(localVar, type);
273     }
274 
doXLOAD(int localVar, TypeData type)275     private int doXLOAD(int localVar, TypeData type) {
276         stackTypes[stackTop++] = type;
277         if (type.is2WordType())
278             stackTypes[stackTop++] = TOP;
279 
280         return 2;
281     }
282 
doALOAD(int localVar)283     private int doALOAD(int localVar) {
284         stackTypes[stackTop++] = localsTypes[localVar];
285         return 2;
286     }
287 
doOpcode54_95(int pos, byte[] code, int op)288     private int doOpcode54_95(int pos, byte[] code, int op) throws BadBytecode {
289         switch (op) {
290         case Opcode.ISTORE :
291             return doXSTORE(pos, code, INTEGER);
292         case Opcode.LSTORE :
293             return doXSTORE(pos, code, LONG);
294         case Opcode.FSTORE :
295             return doXSTORE(pos, code, FLOAT);
296         case Opcode.DSTORE :
297             return doXSTORE(pos, code, DOUBLE);
298         case Opcode.ASTORE :
299             return doASTORE(code[pos + 1] & 0xff);
300         case Opcode.ISTORE_0 :
301         case Opcode.ISTORE_1 :
302         case Opcode.ISTORE_2 :
303         case Opcode.ISTORE_3 :
304           { int var = op - Opcode.ISTORE_0;
305             localsTypes[var] = INTEGER;
306             stackTop--; }
307             break;
308         case Opcode.LSTORE_0 :
309         case Opcode.LSTORE_1 :
310         case Opcode.LSTORE_2 :
311         case Opcode.LSTORE_3 :
312           { int var = op - Opcode.LSTORE_0;
313             localsTypes[var] = LONG;
314             localsTypes[var + 1] = TOP;
315             stackTop -= 2; }
316             break;
317         case Opcode.FSTORE_0 :
318         case Opcode.FSTORE_1 :
319         case Opcode.FSTORE_2 :
320         case Opcode.FSTORE_3 :
321           { int var = op - Opcode.FSTORE_0;
322             localsTypes[var] = FLOAT;
323             stackTop--; }
324             break;
325         case Opcode.DSTORE_0 :
326         case Opcode.DSTORE_1 :
327         case Opcode.DSTORE_2 :
328         case Opcode.DSTORE_3 :
329           { int var = op - Opcode.DSTORE_0;
330             localsTypes[var] = DOUBLE;
331             localsTypes[var + 1] = TOP;
332             stackTop -= 2; }
333             break;
334         case Opcode.ASTORE_0 :
335         case Opcode.ASTORE_1 :
336         case Opcode.ASTORE_2 :
337         case Opcode.ASTORE_3 :
338           { int var = op - Opcode.ASTORE_0;
339             doASTORE(var);
340             break; }
341         case Opcode.IASTORE :
342         case Opcode.LASTORE :
343         case Opcode.FASTORE :
344         case Opcode.DASTORE :
345             stackTop -= (op == Opcode.LASTORE || op == Opcode.DASTORE) ? 4 : 3;
346             break;
347         case Opcode.AASTORE :
348             TypeData.ArrayElement.aastore(stackTypes[stackTop - 3],
349                                           stackTypes[stackTop - 1],
350                                           classPool);
351             stackTop -= 3;
352             break;
353         case Opcode.BASTORE :
354         case Opcode.CASTORE :
355         case Opcode.SASTORE :
356             stackTop -= 3;
357             break;
358         case Opcode.POP :
359             stackTop--;
360             break;
361         case Opcode.POP2 :
362             stackTop -= 2;
363             break;
364         case Opcode.DUP : {
365             int sp = stackTop;
366             stackTypes[sp] = stackTypes[sp - 1];
367             stackTop = sp + 1;
368             break; }
369         case Opcode.DUP_X1 :
370         case Opcode.DUP_X2 : {
371             int len = op - Opcode.DUP_X1 + 2;
372             doDUP_XX(1, len);
373             int sp = stackTop;
374             stackTypes[sp - len] = stackTypes[sp];
375             stackTop = sp + 1;
376             break; }
377         case Opcode.DUP2 :
378             doDUP_XX(2, 2);
379             stackTop += 2;
380             break;
381         case Opcode.DUP2_X1 :
382         case Opcode.DUP2_X2 : {
383             int len = op - Opcode.DUP2_X1 + 3;
384             doDUP_XX(2, len);
385             int sp = stackTop;
386             stackTypes[sp - len] = stackTypes[sp];
387             stackTypes[sp - len + 1] = stackTypes[sp + 1];
388             stackTop = sp + 2;
389             break; }
390         case Opcode.SWAP : {
391             int sp = stackTop - 1;
392             TypeData t = stackTypes[sp];
393             stackTypes[sp] = stackTypes[sp - 1];
394             stackTypes[sp - 1] = t;
395             break; }
396         default :
397             throw new RuntimeException("fatal");
398         }
399 
400         return 1;
401     }
402 
doXSTORE(int pos, byte[] code, TypeData type)403     private int doXSTORE(int pos, byte[] code, TypeData type) {
404         int index = code[pos + 1] & 0xff;
405         return doXSTORE(index, type);
406     }
407 
doXSTORE(int index, TypeData type)408     private int doXSTORE(int index, TypeData type) {
409         stackTop--;
410         localsTypes[index] = type;
411         if (type.is2WordType()) {
412             stackTop--;
413             localsTypes[index + 1] = TOP;
414         }
415 
416         return 2;
417     }
418 
doASTORE(int index)419     private int doASTORE(int index) {
420         stackTop--;
421         // implicit upcast might be done.
422         localsTypes[index] = stackTypes[stackTop];
423         return 2;
424     }
425 
doDUP_XX(int delta, int len)426     private void doDUP_XX(int delta, int len) {
427         TypeData types[] = stackTypes;
428         int sp = stackTop - 1;
429         int end = sp - len;
430         while (sp > end) {
431             types[sp + delta] = types[sp];
432             sp--;
433         }
434     }
435 
doOpcode96_147(int pos, byte[] code, int op)436     private int doOpcode96_147(int pos, byte[] code, int op) {
437         if (op <= Opcode.LXOR) {    // IADD...LXOR
438             stackTop += Opcode.STACK_GROW[op];
439             return 1;
440         }
441 
442         switch (op) {
443         case Opcode.IINC :
444             // this does not call writeLocal().
445             return 3;
446         case Opcode.I2L :
447             stackTypes[stackTop - 1] = LONG;
448             stackTypes[stackTop] = TOP;
449             stackTop++;
450             break;
451         case Opcode.I2F :
452             stackTypes[stackTop - 1] = FLOAT;
453             break;
454         case Opcode.I2D :
455             stackTypes[stackTop - 1] = DOUBLE;
456             stackTypes[stackTop] = TOP;
457             stackTop++;
458             break;
459         case Opcode.L2I :
460             stackTypes[--stackTop - 1] = INTEGER;
461             break;
462         case Opcode.L2F :
463             stackTypes[--stackTop - 1] = FLOAT;
464             break;
465         case Opcode.L2D :
466             stackTypes[stackTop - 2] = DOUBLE;
467             break;
468         case Opcode.F2I :
469             stackTypes[stackTop - 1] = INTEGER;
470             break;
471         case Opcode.F2L :
472             stackTypes[stackTop - 1] = LONG;
473             stackTypes[stackTop] = TOP;
474             stackTop++;
475             break;
476         case Opcode.F2D :
477             stackTypes[stackTop - 1] = DOUBLE;
478             stackTypes[stackTop] = TOP;
479             stackTop++;
480             break;
481         case Opcode.D2I :
482             stackTypes[--stackTop - 1] = INTEGER;
483             break;
484         case Opcode.D2L :
485             stackTypes[stackTop - 2] = LONG;
486             break;
487         case Opcode.D2F :
488             stackTypes[--stackTop - 1] = FLOAT;
489             break;
490         case Opcode.I2B :
491         case Opcode.I2C :
492         case Opcode.I2S :
493             break;
494         default :
495             throw new RuntimeException("fatal");
496         }
497 
498         return 1;
499     }
500 
doOpcode148_201(int pos, byte[] code, int op)501     private int doOpcode148_201(int pos, byte[] code, int op) throws BadBytecode {
502         switch (op) {
503         case Opcode.LCMP :
504             stackTypes[stackTop - 4] = INTEGER;
505             stackTop -= 3;
506             break;
507         case Opcode.FCMPL :
508         case Opcode.FCMPG :
509             stackTypes[--stackTop - 1] = INTEGER;
510             break;
511         case Opcode.DCMPL :
512         case Opcode.DCMPG :
513             stackTypes[stackTop - 4] = INTEGER;
514             stackTop -= 3;
515             break;
516         case Opcode.IFEQ :
517         case Opcode.IFNE :
518         case Opcode.IFLT :
519         case Opcode.IFGE :
520         case Opcode.IFGT :
521         case Opcode.IFLE :
522             stackTop--;     // branch
523             visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
524             return 3;
525         case Opcode.IF_ICMPEQ :
526         case Opcode.IF_ICMPNE :
527         case Opcode.IF_ICMPLT :
528         case Opcode.IF_ICMPGE :
529         case Opcode.IF_ICMPGT :
530         case Opcode.IF_ICMPLE :
531         case Opcode.IF_ACMPEQ :
532         case Opcode.IF_ACMPNE :
533             stackTop -= 2;  // branch
534             visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
535             return 3;
536         case Opcode.GOTO :
537             visitGoto(pos, code, ByteArray.readS16bit(code, pos + 1));
538             return 3;       // branch
539         case Opcode.JSR :
540             visitJSR(pos, code);
541             return 3;       // branch
542         case Opcode.RET :
543             visitRET(pos, code);
544             return 2;
545         case Opcode.TABLESWITCH : {
546             stackTop--;     // branch
547             int pos2 = (pos & ~3) + 8;
548             int low = ByteArray.read32bit(code, pos2);
549             int high = ByteArray.read32bit(code, pos2 + 4);
550             int n = high - low + 1;
551             visitTableSwitch(pos, code, n, pos2 + 8, ByteArray.read32bit(code, pos2 - 4));
552             return n * 4 + 16 - (pos & 3); }
553         case Opcode.LOOKUPSWITCH : {
554             stackTop--;     // branch
555             int pos2 = (pos & ~3) + 8;
556             int n = ByteArray.read32bit(code, pos2);
557             visitLookupSwitch(pos, code, n, pos2 + 4, ByteArray.read32bit(code, pos2 - 4));
558             return n * 8 + 12 - (pos & 3); }
559         case Opcode.IRETURN :
560             stackTop--;
561             visitReturn(pos, code);
562             break;
563         case Opcode.LRETURN :
564             stackTop -= 2;
565             visitReturn(pos, code);
566             break;
567         case Opcode.FRETURN :
568             stackTop--;
569             visitReturn(pos, code);
570             break;
571         case Opcode.DRETURN :
572             stackTop -= 2;
573             visitReturn(pos, code);
574             break;
575         case Opcode.ARETURN :
576             stackTypes[--stackTop].setType(returnType, classPool);
577             visitReturn(pos, code);
578             break;
579         case Opcode.RETURN :
580             visitReturn(pos, code);
581             break;
582         case Opcode.GETSTATIC :
583             return doGetField(pos, code, false);
584         case Opcode.PUTSTATIC :
585             return doPutField(pos, code, false);
586         case Opcode.GETFIELD :
587             return doGetField(pos, code, true);
588         case Opcode.PUTFIELD :
589             return doPutField(pos, code, true);
590         case Opcode.INVOKEVIRTUAL :
591         case Opcode.INVOKESPECIAL :
592             return doInvokeMethod(pos, code, true);
593         case Opcode.INVOKESTATIC :
594             return doInvokeMethod(pos, code, false);
595         case Opcode.INVOKEINTERFACE :
596             return doInvokeIntfMethod(pos, code);
597         case Opcode.INVOKEDYNAMIC :
598             return doInvokeDynamic(pos, code);
599         case Opcode.NEW : {
600             int i = ByteArray.readU16bit(code, pos + 1);
601             stackTypes[stackTop++]
602                       = new TypeData.UninitData(pos, cpool.getClassInfo(i));
603             return 3; }
604         case Opcode.NEWARRAY :
605             return doNEWARRAY(pos, code);
606         case Opcode.ANEWARRAY : {
607             int i = ByteArray.readU16bit(code, pos + 1);
608             String type = cpool.getClassInfo(i).replace('.', '/');
609             if (type.charAt(0) == '[')
610                 type = "[" + type;
611             else
612                 type = "[L" + type + ";";
613 
614             stackTypes[stackTop - 1]
615                     = new TypeData.ClassName(type);
616             return 3; }
617         case Opcode.ARRAYLENGTH :
618             stackTypes[stackTop - 1].setType("[Ljava.lang.Object;", classPool);
619             stackTypes[stackTop - 1] = INTEGER;
620             break;
621         case Opcode.ATHROW :
622             stackTypes[--stackTop].setType("java.lang.Throwable", classPool);
623             visitThrow(pos, code);
624             break;
625         case Opcode.CHECKCAST : {
626             // TypeData.setType(stackTypes[stackTop - 1], "java.lang.Object", classPool);
627             int i = ByteArray.readU16bit(code, pos + 1);
628             String type = cpool.getClassInfo(i);
629             if (type.charAt(0) == '[')
630                 type = type.replace('.', '/');  // getClassInfo() may return "[java.lang.Object;".
631 
632             stackTypes[stackTop - 1] = new TypeData.ClassName(type);
633             return 3; }
634         case Opcode.INSTANCEOF :
635             // TypeData.setType(stackTypes[stackTop - 1], "java.lang.Object", classPool);
636             stackTypes[stackTop - 1] = INTEGER;
637             return 3;
638         case Opcode.MONITORENTER :
639         case Opcode.MONITOREXIT :
640             stackTop--;
641             // TypeData.setType(stackTypes[stackTop], "java.lang.Object", classPool);
642             break;
643         case Opcode.WIDE :
644             return doWIDE(pos, code);
645         case Opcode.MULTIANEWARRAY :
646             return doMultiANewArray(pos, code);
647         case Opcode.IFNULL :
648         case Opcode.IFNONNULL :
649             stackTop--;         // branch
650             visitBranch(pos, code, ByteArray.readS16bit(code, pos + 1));
651             return 3;
652         case Opcode.GOTO_W :
653             visitGoto(pos, code, ByteArray.read32bit(code, pos + 1));
654             return 5;           // branch
655         case Opcode.JSR_W :
656             visitJSR(pos, code);
657             return 5;
658         }
659         return 1;
660     }
661 
doWIDE(int pos, byte[] code)662     private int doWIDE(int pos, byte[] code) throws BadBytecode {
663         int op = code[pos + 1] & 0xff;
664         switch (op) {
665         case Opcode.ILOAD :
666             doWIDE_XLOAD(pos, code, INTEGER);
667             break;
668         case Opcode.LLOAD :
669             doWIDE_XLOAD(pos, code, LONG);
670             break;
671         case Opcode.FLOAD :
672             doWIDE_XLOAD(pos, code, FLOAT);
673             break;
674         case Opcode.DLOAD :
675             doWIDE_XLOAD(pos, code, DOUBLE);
676             break;
677         case Opcode.ALOAD : {
678             int index = ByteArray.readU16bit(code, pos + 2);
679             doALOAD(index);
680             break; }
681         case Opcode.ISTORE :
682             doWIDE_STORE(pos, code, INTEGER);
683             break;
684         case Opcode.LSTORE :
685             doWIDE_STORE(pos, code, LONG);
686             break;
687         case Opcode.FSTORE :
688             doWIDE_STORE(pos, code, FLOAT);
689             break;
690         case Opcode.DSTORE :
691             doWIDE_STORE(pos, code, DOUBLE);
692             break;
693         case Opcode.ASTORE : {
694             int index = ByteArray.readU16bit(code, pos + 2);
695             doASTORE(index);
696             break; }
697         case Opcode.IINC :
698             // this does not call writeLocal().
699             return 6;
700         case Opcode.RET :
701             visitRET(pos, code);
702             break;
703         default :
704             throw new RuntimeException("bad WIDE instruction: " + op);
705         }
706 
707         return 4;
708     }
709 
doWIDE_XLOAD(int pos, byte[] code, TypeData type)710     private void doWIDE_XLOAD(int pos, byte[] code, TypeData type) {
711         int index = ByteArray.readU16bit(code, pos + 2);
712         doXLOAD(index, type);
713     }
714 
doWIDE_STORE(int pos, byte[] code, TypeData type)715     private void doWIDE_STORE(int pos, byte[] code, TypeData type) {
716         int index = ByteArray.readU16bit(code, pos + 2);
717         doXSTORE(index, type);
718     }
719 
doPutField(int pos, byte[] code, boolean notStatic)720     private int doPutField(int pos, byte[] code, boolean notStatic) throws BadBytecode {
721         int index = ByteArray.readU16bit(code, pos + 1);
722         String desc = cpool.getFieldrefType(index);
723         stackTop -= Descriptor.dataSize(desc);
724         char c = desc.charAt(0);
725         if (c == 'L')
726             stackTypes[stackTop].setType(getFieldClassName(desc, 0), classPool);
727         else if (c == '[')
728             stackTypes[stackTop].setType(desc, classPool);
729 
730         setFieldTarget(notStatic, index);
731         return 3;
732     }
733 
doGetField(int pos, byte[] code, boolean notStatic)734     private int doGetField(int pos, byte[] code, boolean notStatic) throws BadBytecode {
735         int index = ByteArray.readU16bit(code, pos + 1);
736         setFieldTarget(notStatic, index);
737         String desc = cpool.getFieldrefType(index);
738         pushMemberType(desc);
739         return 3;
740     }
741 
setFieldTarget(boolean notStatic, int index)742     private void setFieldTarget(boolean notStatic, int index) throws BadBytecode {
743         if (notStatic) {
744             String className = cpool.getFieldrefClassName(index);
745             stackTypes[--stackTop].setType(className, classPool);
746         }
747     }
748 
doNEWARRAY(int pos, byte[] code)749     private int doNEWARRAY(int pos, byte[] code) {
750         int s = stackTop - 1;
751         String type;
752         switch (code[pos + 1] & 0xff) {
753         case Opcode.T_BOOLEAN :
754             type = "[Z";
755             break;
756         case Opcode.T_CHAR :
757             type = "[C";
758             break;
759         case Opcode.T_FLOAT :
760             type = "[F";
761             break;
762         case Opcode.T_DOUBLE :
763             type = "[D";
764             break;
765         case Opcode.T_BYTE :
766             type = "[B";
767             break;
768         case Opcode.T_SHORT :
769             type = "[S";
770             break;
771         case Opcode.T_INT :
772             type = "[I";
773             break;
774         case Opcode.T_LONG :
775             type = "[J";
776             break;
777         default :
778             throw new RuntimeException("bad newarray");
779         }
780 
781         stackTypes[s] = new TypeData.ClassName(type);
782         return 2;
783     }
784 
doMultiANewArray(int pos, byte[] code)785     private int doMultiANewArray(int pos, byte[] code) {
786         int i = ByteArray.readU16bit(code, pos + 1);
787         int dim = code[pos + 3] & 0xff;
788         stackTop -= dim - 1;
789 
790         String type = cpool.getClassInfo(i).replace('.', '/');
791         stackTypes[stackTop - 1] = new TypeData.ClassName(type);
792         return 4;
793     }
794 
doInvokeMethod(int pos, byte[] code, boolean notStatic)795     private int doInvokeMethod(int pos, byte[] code, boolean notStatic) throws BadBytecode {
796         int i = ByteArray.readU16bit(code, pos + 1);
797         String desc = cpool.getMethodrefType(i);
798         checkParamTypes(desc, 1);
799         if (notStatic) {
800             String className = cpool.getMethodrefClassName(i);
801             TypeData target = stackTypes[--stackTop];
802             if (target instanceof TypeData.UninitTypeVar && target.isUninit())
803                 constructorCalled(target, ((TypeData.UninitTypeVar)target).offset());
804             else if (target instanceof TypeData.UninitData)
805                 constructorCalled(target, ((TypeData.UninitData)target).offset());
806 
807             target.setType(className, classPool);
808         }
809 
810         pushMemberType(desc);
811         return 3;
812     }
813 
814     /* This is a constructor call on an uninitialized object.
815      * Sets flags of other references to that object.
816      *
817      * @param offset        the offset where the object has been created.
818      */
constructorCalled(TypeData target, int offset)819     private void constructorCalled(TypeData target, int offset) {
820         target.constructorCalled(offset);
821         for (int i = 0; i < stackTop; i++)
822             stackTypes[i].constructorCalled(offset);
823 
824         for (int i = 0; i < localsTypes.length; i++)
825             localsTypes[i].constructorCalled(offset);
826     }
827 
doInvokeIntfMethod(int pos, byte[] code)828     private int doInvokeIntfMethod(int pos, byte[] code) throws BadBytecode {
829         int i = ByteArray.readU16bit(code, pos + 1);
830         String desc = cpool.getInterfaceMethodrefType(i);
831         checkParamTypes(desc, 1);
832         String className = cpool.getInterfaceMethodrefClassName(i);
833         stackTypes[--stackTop].setType(className, classPool);
834         pushMemberType(desc);
835         return 5;
836     }
837 
doInvokeDynamic(int pos, byte[] code)838     private int doInvokeDynamic(int pos, byte[] code) throws BadBytecode {
839         int i = ByteArray.readU16bit(code, pos + 1);
840         String desc = cpool.getInvokeDynamicType(i);
841         checkParamTypes(desc, 1);
842 
843      // assume CosntPool#REF_invokeStatic
844      /* TypeData target = stackTypes[--stackTop];
845         if (target instanceof TypeData.UninitTypeVar && target.isUninit())
846             constructorCalled((TypeData.UninitTypeVar)target);
847       */
848 
849         pushMemberType(desc);
850         return 5;
851     }
852 
pushMemberType(String descriptor)853     private void pushMemberType(String descriptor) {
854         int top = 0;
855         if (descriptor.charAt(0) == '(') {
856             top = descriptor.indexOf(')') + 1;
857             if (top < 1)
858                 throw new IndexOutOfBoundsException("bad descriptor: "
859                                                     + descriptor);
860         }
861 
862         TypeData[] types = stackTypes;
863         int index = stackTop;
864         switch (descriptor.charAt(top)) {
865         case '[' :
866             types[index] = new TypeData.ClassName(descriptor.substring(top));
867             break;
868         case 'L' :
869             types[index] = new TypeData.ClassName(getFieldClassName(descriptor, top));
870             break;
871         case 'J' :
872             types[index] = LONG;
873             types[index + 1] = TOP;
874             stackTop += 2;
875             return;
876         case 'F' :
877             types[index] = FLOAT;
878             break;
879         case 'D' :
880             types[index] = DOUBLE;
881             types[index + 1] = TOP;
882             stackTop += 2;
883             return;
884         case 'V' :
885             return;
886         default : // C, B, S, I, Z
887             types[index] = INTEGER;
888             break;
889         }
890 
891         stackTop++;
892     }
893 
getFieldClassName(String desc, int index)894     private static String getFieldClassName(String desc, int index) {
895         return desc.substring(index + 1, desc.length() - 1).replace('/', '.');
896     }
897 
checkParamTypes(String desc, int i)898     private void checkParamTypes(String desc, int i) throws BadBytecode {
899         char c = desc.charAt(i);
900         if (c == ')')
901             return;
902 
903         int k = i;
904         boolean array = false;
905         while (c == '[') {
906             array = true;
907             c = desc.charAt(++k);
908         }
909 
910         if (c == 'L') {
911             k = desc.indexOf(';', k) + 1;
912             if (k <= 0)
913                 throw new IndexOutOfBoundsException("bad descriptor");
914         }
915         else
916             k++;
917 
918         checkParamTypes(desc, k);
919         if (!array && (c == 'J' || c == 'D'))
920             stackTop -= 2;
921         else
922             stackTop--;
923 
924         if (array)
925             stackTypes[stackTop].setType(desc.substring(i, k), classPool);
926         else if (c == 'L')
927             stackTypes[stackTop].setType(desc.substring(i + 1, k - 1).replace('/', '.'),
928                                          classPool);
929     }
930 }
931