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