Home | History | Annotate | Download | only in stackmap
      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 
     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 
     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 
     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      */
     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 
    109     protected void visitBranch(int pos, byte[] code, int offset) throws BadBytecode {}
    110     protected void visitGoto(int pos, byte[] code, int offset) throws BadBytecode {}
    111     protected void visitReturn(int pos, byte[] code) throws BadBytecode {}
    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      */
    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      */
    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      */
    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      */
    151     protected void visitRET(int pos, byte[] code) throws BadBytecode {}
    152 
    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 
    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 
    298     private int doXLOAD(TypeData type, byte[] code, int pos) {
    299         int localVar = code[pos + 1] & 0xff;
    300         return doXLOAD(localVar, type);
    301     }
    302 
    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 
    311     private int doALOAD(int localVar) { // int localVar, TypeData type) {
    312         stackTypes[stackTop++] = localsTypes[localVar];
    313         return 2;
    314     }
    315 
    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 
    433     private int doXSTORE(int pos, byte[] code, TypeData type) {
    434         int index = code[pos + 1] & 0xff;
    435         return doXSTORE(index, type);
    436     }
    437 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    883     private static String getFieldClassName(String desc, int index) {
    884         return desc.substring(index + 1, desc.length() - 1).replace('/', '.');
    885     }
    886 
    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