rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 30 Apr 2014 15:04:10 +0200
branchclosure
changeset 1513 ba912ef24b27
parent 1085 6a4ef883e233
parent 1474 3775fe162073
child 1639 4b09a4b689a4
permissions -rw-r--r--
Merging from default branch and resolving conflicts. mvn install -DskipTests passes OK.
     1 /*
     2  * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package org.apidesign.vm4brwsr;
    26 
    27 import java.io.ByteArrayInputStream;
    28 import java.io.DataInputStream;
    29 import java.io.IOException;
    30 import java.io.InputStream;
    31 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    32 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
    33 
    34 /** This is a byte code parser heavily based on original code of JavaP utility.
    35  * As such I decided to keep the original Oracle's GPLv2 header.
    36  *
    37  * @author Jaroslav Tulach <jtulach@netbeans.org>
    38  */
    39 final class ByteCodeParser {
    40     private ByteCodeParser() {
    41     }
    42 
    43     /* Class File Constants */
    44     public static final int JAVA_MAGIC                   = 0xcafebabe;
    45     public static final int JAVA_VERSION                 = 45;
    46     public static final int JAVA_MINOR_VERSION           = 3;
    47 
    48     /* Constant table */
    49     public static final int CONSTANT_UTF8                = 1;
    50     public static final int CONSTANT_UNICODE             = 2;
    51     public static final int CONSTANT_INTEGER             = 3;
    52     public static final int CONSTANT_FLOAT               = 4;
    53     public static final int CONSTANT_LONG                = 5;
    54     public static final int CONSTANT_DOUBLE              = 6;
    55     public static final int CONSTANT_CLASS               = 7;
    56     public static final int CONSTANT_STRING              = 8;
    57     public static final int CONSTANT_FIELD               = 9;
    58     public static final int CONSTANT_METHOD              = 10;
    59     public static final int CONSTANT_INTERFACEMETHOD     = 11;
    60     public static final int CONSTANT_NAMEANDTYPE         = 12;
    61 
    62     /* Access Flags */
    63     public static final int ACC_PUBLIC                   = 0x00000001;
    64     public static final int ACC_PRIVATE                  = 0x00000002;
    65     public static final int ACC_PROTECTED                = 0x00000004;
    66     public static final int ACC_STATIC                   = 0x00000008;
    67     public static final int ACC_FINAL                    = 0x00000010;
    68     public static final int ACC_SYNCHRONIZED             = 0x00000020;
    69     public static final int ACC_SUPER                        = 0x00000020;
    70     public static final int ACC_VOLATILE                 = 0x00000040;
    71     public static final int ACC_TRANSIENT                = 0x00000080;
    72     public static final int ACC_NATIVE                   = 0x00000100;
    73     public static final int ACC_INTERFACE                = 0x00000200;
    74     public static final int ACC_ABSTRACT                 = 0x00000400;
    75     public static final int ACC_STRICT                   = 0x00000800;
    76     public static final int ACC_EXPLICIT                 = 0x00001000;
    77     public static final int ACC_SYNTHETIC                = 0x00010000; // actually, this is an attribute
    78 
    79     /* Type codes for StackMap attribute */
    80     public static final int ITEM_Bogus      =0; // an unknown or uninitialized value
    81     public static final int ITEM_Integer    =1; // a 32-bit integer
    82     public static final int ITEM_Float      =2; // not used
    83     public static final int ITEM_Double     =3; // not used
    84     public static final int ITEM_Long       =4; // a 64-bit integer
    85     public static final int ITEM_Null       =5; // the type of null
    86     public static final int ITEM_InitObject =6; // "this" in constructor
    87     public static final int ITEM_Object     =7; // followed by 2-byte index of class name
    88     public static final int ITEM_NewObject  =8; // followed by 2-byte ref to "new"
    89 
    90     /* Constants used in StackMapTable attribute */
    91     public static final int SAME_FRAME_BOUND                  = 64;
    92     public static final int SAME_LOCALS_1_STACK_ITEM_BOUND    = 128;
    93     public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
    94     public static final int SAME_FRAME_EXTENDED               = 251;
    95     public static final int FULL_FRAME                        = 255;
    96 
    97     /* Opcodes */
    98     public static final int opc_dead                     = -2;
    99     public static final int opc_label                    = -1;
   100     public static final int opc_nop                      = 0;
   101     public static final int opc_aconst_null              = 1;
   102     public static final int opc_iconst_m1                = 2;
   103     public static final int opc_iconst_0                 = 3;
   104     public static final int opc_iconst_1                 = 4;
   105     public static final int opc_iconst_2                 = 5;
   106     public static final int opc_iconst_3                 = 6;
   107     public static final int opc_iconst_4                 = 7;
   108     public static final int opc_iconst_5                 = 8;
   109     public static final int opc_lconst_0                 = 9;
   110     public static final int opc_lconst_1                 = 10;
   111     public static final int opc_fconst_0                 = 11;
   112     public static final int opc_fconst_1                 = 12;
   113     public static final int opc_fconst_2                 = 13;
   114     public static final int opc_dconst_0                 = 14;
   115     public static final int opc_dconst_1                 = 15;
   116     public static final int opc_bipush                   = 16;
   117     public static final int opc_sipush                   = 17;
   118     public static final int opc_ldc                      = 18;
   119     public static final int opc_ldc_w                    = 19;
   120     public static final int opc_ldc2_w                   = 20;
   121     public static final int opc_iload                    = 21;
   122     public static final int opc_lload                    = 22;
   123     public static final int opc_fload                    = 23;
   124     public static final int opc_dload                    = 24;
   125     public static final int opc_aload                    = 25;
   126     public static final int opc_iload_0                  = 26;
   127     public static final int opc_iload_1                  = 27;
   128     public static final int opc_iload_2                  = 28;
   129     public static final int opc_iload_3                  = 29;
   130     public static final int opc_lload_0                  = 30;
   131     public static final int opc_lload_1                  = 31;
   132     public static final int opc_lload_2                  = 32;
   133     public static final int opc_lload_3                  = 33;
   134     public static final int opc_fload_0                  = 34;
   135     public static final int opc_fload_1                  = 35;
   136     public static final int opc_fload_2                  = 36;
   137     public static final int opc_fload_3                  = 37;
   138     public static final int opc_dload_0                  = 38;
   139     public static final int opc_dload_1                  = 39;
   140     public static final int opc_dload_2                  = 40;
   141     public static final int opc_dload_3                  = 41;
   142     public static final int opc_aload_0                  = 42;
   143     public static final int opc_aload_1                  = 43;
   144     public static final int opc_aload_2                  = 44;
   145     public static final int opc_aload_3                  = 45;
   146     public static final int opc_iaload                   = 46;
   147     public static final int opc_laload                   = 47;
   148     public static final int opc_faload                   = 48;
   149     public static final int opc_daload                   = 49;
   150     public static final int opc_aaload                   = 50;
   151     public static final int opc_baload                   = 51;
   152     public static final int opc_caload                   = 52;
   153     public static final int opc_saload                   = 53;
   154     public static final int opc_istore                   = 54;
   155     public static final int opc_lstore                   = 55;
   156     public static final int opc_fstore                   = 56;
   157     public static final int opc_dstore                   = 57;
   158     public static final int opc_astore                   = 58;
   159     public static final int opc_istore_0                 = 59;
   160     public static final int opc_istore_1                 = 60;
   161     public static final int opc_istore_2                 = 61;
   162     public static final int opc_istore_3                 = 62;
   163     public static final int opc_lstore_0                 = 63;
   164     public static final int opc_lstore_1                 = 64;
   165     public static final int opc_lstore_2                 = 65;
   166     public static final int opc_lstore_3                 = 66;
   167     public static final int opc_fstore_0                 = 67;
   168     public static final int opc_fstore_1                 = 68;
   169     public static final int opc_fstore_2                 = 69;
   170     public static final int opc_fstore_3                 = 70;
   171     public static final int opc_dstore_0                 = 71;
   172     public static final int opc_dstore_1                 = 72;
   173     public static final int opc_dstore_2                 = 73;
   174     public static final int opc_dstore_3                 = 74;
   175     public static final int opc_astore_0                 = 75;
   176     public static final int opc_astore_1                 = 76;
   177     public static final int opc_astore_2                 = 77;
   178     public static final int opc_astore_3                 = 78;
   179     public static final int opc_iastore                  = 79;
   180     public static final int opc_lastore                  = 80;
   181     public static final int opc_fastore                  = 81;
   182     public static final int opc_dastore                  = 82;
   183     public static final int opc_aastore                  = 83;
   184     public static final int opc_bastore                  = 84;
   185     public static final int opc_castore                  = 85;
   186     public static final int opc_sastore                  = 86;
   187     public static final int opc_pop                      = 87;
   188     public static final int opc_pop2                     = 88;
   189     public static final int opc_dup                      = 89;
   190     public static final int opc_dup_x1                   = 90;
   191     public static final int opc_dup_x2                   = 91;
   192     public static final int opc_dup2                     = 92;
   193     public static final int opc_dup2_x1                  = 93;
   194     public static final int opc_dup2_x2                  = 94;
   195     public static final int opc_swap                     = 95;
   196     public static final int opc_iadd                     = 96;
   197     public static final int opc_ladd                     = 97;
   198     public static final int opc_fadd                     = 98;
   199     public static final int opc_dadd                     = 99;
   200     public static final int opc_isub                     = 100;
   201     public static final int opc_lsub                     = 101;
   202     public static final int opc_fsub                     = 102;
   203     public static final int opc_dsub                     = 103;
   204     public static final int opc_imul                     = 104;
   205     public static final int opc_lmul                     = 105;
   206     public static final int opc_fmul                     = 106;
   207     public static final int opc_dmul                     = 107;
   208     public static final int opc_idiv                     = 108;
   209     public static final int opc_ldiv                     = 109;
   210     public static final int opc_fdiv                     = 110;
   211     public static final int opc_ddiv                     = 111;
   212     public static final int opc_irem                     = 112;
   213     public static final int opc_lrem                     = 113;
   214     public static final int opc_frem                     = 114;
   215     public static final int opc_drem                     = 115;
   216     public static final int opc_ineg                     = 116;
   217     public static final int opc_lneg                     = 117;
   218     public static final int opc_fneg                     = 118;
   219     public static final int opc_dneg                     = 119;
   220     public static final int opc_ishl                     = 120;
   221     public static final int opc_lshl                     = 121;
   222     public static final int opc_ishr                     = 122;
   223     public static final int opc_lshr                     = 123;
   224     public static final int opc_iushr                    = 124;
   225     public static final int opc_lushr                    = 125;
   226     public static final int opc_iand                     = 126;
   227     public static final int opc_land                     = 127;
   228     public static final int opc_ior                      = 128;
   229     public static final int opc_lor                      = 129;
   230     public static final int opc_ixor                     = 130;
   231     public static final int opc_lxor                     = 131;
   232     public static final int opc_iinc                     = 132;
   233     public static final int opc_i2l                      = 133;
   234     public static final int opc_i2f                      = 134;
   235     public static final int opc_i2d                      = 135;
   236     public static final int opc_l2i                      = 136;
   237     public static final int opc_l2f                      = 137;
   238     public static final int opc_l2d                      = 138;
   239     public static final int opc_f2i                      = 139;
   240     public static final int opc_f2l                      = 140;
   241     public static final int opc_f2d                      = 141;
   242     public static final int opc_d2i                      = 142;
   243     public static final int opc_d2l                      = 143;
   244     public static final int opc_d2f                      = 144;
   245     public static final int opc_i2b                      = 145;
   246     public static final int opc_int2byte                 = 145;
   247     public static final int opc_i2c                      = 146;
   248     public static final int opc_int2char                 = 146;
   249     public static final int opc_i2s                      = 147;
   250     public static final int opc_int2short                = 147;
   251     public static final int opc_lcmp                     = 148;
   252     public static final int opc_fcmpl                    = 149;
   253     public static final int opc_fcmpg                    = 150;
   254     public static final int opc_dcmpl                    = 151;
   255     public static final int opc_dcmpg                    = 152;
   256     public static final int opc_ifeq                     = 153;
   257     public static final int opc_ifne                     = 154;
   258     public static final int opc_iflt                     = 155;
   259     public static final int opc_ifge                     = 156;
   260     public static final int opc_ifgt                     = 157;
   261     public static final int opc_ifle                     = 158;
   262     public static final int opc_if_icmpeq                = 159;
   263     public static final int opc_if_icmpne                = 160;
   264     public static final int opc_if_icmplt                = 161;
   265     public static final int opc_if_icmpge                = 162;
   266     public static final int opc_if_icmpgt                = 163;
   267     public static final int opc_if_icmple                = 164;
   268     public static final int opc_if_acmpeq                = 165;
   269     public static final int opc_if_acmpne                = 166;
   270     public static final int opc_goto                     = 167;
   271     public static final int opc_jsr                      = 168;
   272     public static final int opc_ret                      = 169;
   273     public static final int opc_tableswitch              = 170;
   274     public static final int opc_lookupswitch             = 171;
   275     public static final int opc_ireturn                  = 172;
   276     public static final int opc_lreturn                  = 173;
   277     public static final int opc_freturn                  = 174;
   278     public static final int opc_dreturn                  = 175;
   279     public static final int opc_areturn                  = 176;
   280     public static final int opc_return                   = 177;
   281     public static final int opc_getstatic                = 178;
   282     public static final int opc_putstatic                = 179;
   283     public static final int opc_getfield                 = 180;
   284     public static final int opc_putfield                 = 181;
   285     public static final int opc_invokevirtual            = 182;
   286     public static final int opc_invokenonvirtual         = 183;
   287     public static final int opc_invokespecial            = 183;
   288     public static final int opc_invokestatic             = 184;
   289     public static final int opc_invokeinterface          = 185;
   290 //    public static final int opc_xxxunusedxxx             = 186;
   291     public static final int opc_new                      = 187;
   292     public static final int opc_newarray                 = 188;
   293     public static final int opc_anewarray                = 189;
   294     public static final int opc_arraylength              = 190;
   295     public static final int opc_athrow                   = 191;
   296     public static final int opc_checkcast                = 192;
   297     public static final int opc_instanceof               = 193;
   298     public static final int opc_monitorenter             = 194;
   299     public static final int opc_monitorexit              = 195;
   300     public static final int opc_wide                     = 196;
   301     public static final int opc_multianewarray           = 197;
   302     public static final int opc_ifnull                   = 198;
   303     public static final int opc_ifnonnull                = 199;
   304     public static final int opc_goto_w                   = 200;
   305     public static final int opc_jsr_w                    = 201;
   306         /* Pseudo-instructions */
   307     public static final int opc_bytecode                 = 203;
   308     public static final int opc_try                      = 204;
   309     public static final int opc_endtry                   = 205;
   310     public static final int opc_catch                    = 206;
   311     public static final int opc_var                      = 207;
   312     public static final int opc_endvar                   = 208;
   313     public static final int opc_localsmap                = 209;
   314     public static final int opc_stackmap                 = 210;
   315         /* PicoJava prefixes */
   316     public static final int opc_nonpriv                  = 254;
   317     public static final int opc_priv                     = 255;
   318 
   319         /* Wide instructions *
   320     public static final int opc_iload_w         = (opc_wide<<8)|opc_iload;
   321     public static final int opc_lload_w         = (opc_wide<<8)|opc_lload;
   322     public static final int opc_fload_w         = (opc_wide<<8)|opc_fload;
   323     public static final int opc_dload_w         = (opc_wide<<8)|opc_dload;
   324     public static final int opc_aload_w         = (opc_wide<<8)|opc_aload;
   325     public static final int opc_istore_w        = (opc_wide<<8)|opc_istore;
   326     public static final int opc_lstore_w        = (opc_wide<<8)|opc_lstore;
   327     public static final int opc_fstore_w        = (opc_wide<<8)|opc_fstore;
   328     public static final int opc_dstore_w        = (opc_wide<<8)|opc_dstore;
   329     public static final int opc_astore_w        = (opc_wide<<8)|opc_astore;
   330     public static final int opc_ret_w           = (opc_wide<<8)|opc_ret;
   331     public static final int opc_iinc_w          = (opc_wide<<8)|opc_iinc;
   332 */
   333     static class AnnotationParser {
   334 
   335         private final boolean textual;
   336         private final boolean iterateArray;
   337 
   338         protected AnnotationParser(boolean textual, boolean iterateArray) {
   339             this.textual = textual;
   340             this.iterateArray = iterateArray;
   341         }
   342 
   343         protected void visitAnnotationStart(String type, boolean top) throws IOException {
   344         }
   345 
   346         protected void visitAnnotationEnd(String type, boolean top) throws IOException {
   347         }
   348 
   349         protected void visitValueStart(String attrName, char type) throws IOException {
   350         }
   351 
   352         protected void visitValueEnd(String attrName, char type) throws IOException {
   353         }
   354 
   355         protected void visitAttr(
   356             String annoType, String attr, String attrType, String value) throws IOException {
   357         }
   358 
   359         protected void visitEnumAttr(
   360             String annoType, String attr, String attrType, String value) throws IOException {
   361             visitAttr(annoType, attr, attrType, value);
   362         }
   363 
   364         /**
   365          * Initialize the parsing with constant pool from
   366          * <code>cd</code>.
   367          *
   368          * @param attr the attribute defining annotations
   369          * @param cd constant pool
   370          * @throws IOException in case I/O fails
   371          */
   372         public final void parse(byte[] attr, ClassData cd) throws IOException {
   373             ByteArrayInputStream is = new ByteArrayInputStream(attr);
   374             DataInputStream dis = new DataInputStream(is);
   375             try {
   376                 read(dis, cd);
   377             } finally {
   378                 is.close();
   379             }
   380         }
   381 
   382         private void read(DataInputStream dis, ClassData cd) throws IOException {
   383             int cnt = dis.readUnsignedShort();
   384             for (int i = 0; i < cnt; i++) {
   385                 readAnno(dis, cd, true);
   386             }
   387         }
   388 
   389         private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException {
   390             int type = dis.readUnsignedShort();
   391             String typeName = cd.StringValue(type);
   392             visitAnnotationStart(typeName, top);
   393             int cnt = dis.readUnsignedShort();
   394             for (int i = 0; i < cnt; i++) {
   395                 String attrName = cd.StringValue(dis.readUnsignedShort());
   396                 readValue(dis, cd, typeName, attrName);
   397             }
   398             visitAnnotationEnd(typeName, top);
   399             if (cnt == 0) {
   400                 visitAttr(typeName, null, null, null);
   401             }
   402         }
   403 
   404         private void readValue(
   405             DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException {
   406             char type = (char) dis.readByte();
   407             visitValueStart(attrName, type);
   408             if (type == '@') {
   409                 readAnno(dis, cd, false);
   410             } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N
   411                 int primitive = dis.readUnsignedShort();
   412                 String val = cd.stringValue(primitive, textual);
   413                 String attrType;
   414                 if (type == 's') {
   415                     attrType = "Ljava_lang_String_2";
   416                     if (textual) {
   417                         val = '"' + val + '"';
   418                     }
   419                 } else {
   420                     attrType = "" + type;
   421                 }
   422                 visitAttr(typeName, attrName, attrType, val);
   423             } else if (type == 'c') {
   424                 int cls = dis.readUnsignedShort();
   425             } else if (type == '[') {
   426                 int cnt = dis.readUnsignedShort();
   427                 for (int i = 0; i < cnt; i++) {
   428                     readValue(dis, cd, typeName, iterateArray ? attrName : null);
   429                 }
   430             } else if (type == 'e') {
   431                 int enumT = dis.readUnsignedShort();
   432                 String attrType = cd.stringValue(enumT, textual);
   433                 int enumN = dis.readUnsignedShort();
   434                 String val = cd.stringValue(enumN, textual);
   435                 visitEnumAttr(typeName, attrName, attrType, val);
   436             } else {
   437                 throw new IOException("Unknown type " + type);
   438             }
   439             visitValueEnd(attrName, type);
   440         }
   441     }
   442     
   443     /**
   444      * Reads and stores attribute information.
   445      *
   446      * @author Sucheta Dambalkar (Adopted code from jdis)
   447      */
   448     private static class AttrData {
   449 
   450         ClassData cls;
   451         int name_cpx;
   452         int datalen;
   453         byte data[];
   454 
   455         public AttrData(ClassData cls) {
   456             this.cls = cls;
   457         }
   458 
   459         /**
   460          * Reads unknown attribute.
   461          */
   462         public void read(int name_cpx, DataInputStream in) throws IOException {
   463             this.name_cpx = name_cpx;
   464             datalen = in.readInt();
   465             data = new byte[datalen];
   466             in.readFully(data);
   467         }
   468 
   469         /**
   470          * Reads just the name of known attribute.
   471          */
   472         public void read(int name_cpx) {
   473             this.name_cpx = name_cpx;
   474         }
   475 
   476         /**
   477          * Returns attribute name.
   478          */
   479         public String getAttrName() {
   480             return cls.getString(name_cpx);
   481         }
   482 
   483         /**
   484          * Returns attribute data.
   485          */
   486         public byte[] getData() {
   487             return data;
   488         }
   489     }
   490 
   491     /**
   492      * Stores constant pool entry information with one field.
   493      *
   494      * @author Sucheta Dambalkar (Adopted code from jdis)
   495      */
   496     private static class CPX {
   497 
   498         int cpx;
   499 
   500         CPX(int cpx) {
   501             this.cpx = cpx;
   502         }
   503     }
   504 
   505     /**
   506      * Stores constant pool entry information with two fields.
   507      *
   508      * @author Sucheta Dambalkar (Adopted code from jdis)
   509      */
   510     private static class CPX2 {
   511 
   512         int cpx1, cpx2;
   513 
   514         CPX2(int cpx1, int cpx2) {
   515             this.cpx1 = cpx1;
   516             this.cpx2 = cpx2;
   517         }
   518     }
   519 
   520     /**
   521      * Central data repository of the Java Disassembler. Stores all the
   522      * information in java class file.
   523      *
   524      * @author Sucheta Dambalkar (Adopted code from jdis)
   525      */
   526     static final class ClassData {
   527 
   528         private int magic;
   529         private int minor_version;
   530         private int major_version;
   531         private int cpool_count;
   532         private Object cpool[];
   533         private int access;
   534         private int this_class = 0;
   535         private int super_class;
   536         private int interfaces_count;
   537         private int[] interfaces = new int[0];
   538         private FieldData[] fields;
   539         private MethodData[] methods;
   540         private InnerClassData[] innerClasses;
   541         private int attributes_count;
   542         private AttrData[] attrs;
   543         private int source_cpx = 0;
   544         private byte tags[];
   545         private Hashtable indexHashAscii = new Hashtable();
   546         private String pkgPrefix = "";
   547         private int pkgPrefixLen = 0;
   548 
   549         /**
   550          * Read classfile to disassemble.
   551          */
   552         public ClassData(InputStream infile) throws IOException {
   553             this.read(new DataInputStream(infile));
   554         }
   555 
   556         /**
   557          * Reads and stores class file information.
   558          */
   559         public void read(DataInputStream in) throws IOException {
   560             // Read the header
   561             magic = in.readInt();
   562             if (magic != JAVA_MAGIC) {
   563                 throw new ClassFormatError("wrong magic: "
   564                     + toHex(magic) + ", expected "
   565                     + toHex(JAVA_MAGIC));
   566             }
   567             minor_version = in.readShort();
   568             major_version = in.readShort();
   569             if (major_version != JAVA_VERSION) {
   570             }
   571 
   572             // Read the constant pool
   573             readCP(in);
   574             access = in.readUnsignedShort();
   575             this_class = in.readUnsignedShort();
   576             super_class = in.readUnsignedShort();
   577 
   578             //Read interfaces.
   579             interfaces_count = in.readUnsignedShort();
   580             if (interfaces_count > 0) {
   581                 interfaces = new int[interfaces_count];
   582             }
   583             for (int i = 0; i < interfaces_count; i++) {
   584                 interfaces[i] = in.readShort();
   585             }
   586 
   587             // Read the fields
   588             readFields(in);
   589 
   590             // Read the methods
   591             readMethods(in);
   592 
   593             // Read the attributes
   594             attributes_count = in.readUnsignedShort();
   595             attrs = new AttrData[attributes_count];
   596             for (int k = 0; k < attributes_count; k++) {
   597                 int name_cpx = in.readUnsignedShort();
   598                 if (getTag(name_cpx) == CONSTANT_UTF8
   599                     && getString(name_cpx).equals("SourceFile")) {
   600                     if (in.readInt() != 2) {
   601                         throw new ClassFormatError("invalid attr length");
   602                     }
   603                     source_cpx = in.readUnsignedShort();
   604                     AttrData attr = new AttrData(this);
   605                     attr.read(name_cpx);
   606                     attrs[k] = attr;
   607 
   608                 } else if (getTag(name_cpx) == CONSTANT_UTF8
   609                     && getString(name_cpx).equals("InnerClasses")) {
   610                     int length = in.readInt();
   611                     int num = in.readUnsignedShort();
   612                     if (2 + num * 8 != length) {
   613                         throw new ClassFormatError("invalid attr length");
   614                     }
   615                     innerClasses = new InnerClassData[num];
   616                     for (int j = 0; j < num; j++) {
   617                         InnerClassData innerClass = new InnerClassData(this);
   618                         innerClass.read(in);
   619                         innerClasses[j] = innerClass;
   620                     }
   621                     AttrData attr = new AttrData(this);
   622                     attr.read(name_cpx);
   623                     attrs[k] = attr;
   624                 } else {
   625                     AttrData attr = new AttrData(this);
   626                     attr.read(name_cpx, in);
   627                     attrs[k] = attr;
   628                 }
   629             }
   630             in.close();
   631         } // end ClassData.read()
   632 
   633         /**
   634          * Reads and stores constant pool info.
   635          */
   636         void readCP(DataInputStream in) throws IOException {
   637             cpool_count = in.readUnsignedShort();
   638             tags = new byte[cpool_count];
   639             cpool = new Object[cpool_count];
   640             for (int i = 1; i < cpool_count; i++) {
   641                 byte tag = in.readByte();
   642 
   643                 switch (tags[i] = tag) {
   644                     case CONSTANT_UTF8:
   645                         String str = in.readUTF();
   646                         indexHashAscii.put(cpool[i] = str, new Integer(i));
   647                         break;
   648                     case CONSTANT_INTEGER:
   649                         cpool[i] = new Integer(in.readInt());
   650                         break;
   651                     case CONSTANT_FLOAT:
   652                         cpool[i] = new Float(in.readFloat());
   653                         break;
   654                     case CONSTANT_LONG:
   655                         cpool[i++] = new Long(in.readLong());
   656                         break;
   657                     case CONSTANT_DOUBLE:
   658                         cpool[i++] = new Double(in.readDouble());
   659                         break;
   660                     case CONSTANT_CLASS:
   661                     case CONSTANT_STRING:
   662                         cpool[i] = new CPX(in.readUnsignedShort());
   663                         break;
   664 
   665                     case CONSTANT_FIELD:
   666                     case CONSTANT_METHOD:
   667                     case CONSTANT_INTERFACEMETHOD:
   668                     case CONSTANT_NAMEANDTYPE:
   669                         cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
   670                         break;
   671 
   672                     case 0:
   673                     default:
   674                         throw new ClassFormatError("invalid constant type: " + (int) tags[i]);
   675                 }
   676             }
   677         }
   678 
   679         /**
   680          * Reads and strores field info.
   681          */
   682         protected void readFields(DataInputStream in) throws IOException {
   683             int fields_count = in.readUnsignedShort();
   684             fields = new FieldData[fields_count];
   685             for (int k = 0; k < fields_count; k++) {
   686                 FieldData field = new FieldData(this);
   687                 field.read(in);
   688                 fields[k] = field;
   689             }
   690         }
   691 
   692         /**
   693          * Reads and strores Method info.
   694          */
   695         protected void readMethods(DataInputStream in) throws IOException {
   696             int methods_count = in.readUnsignedShort();
   697             methods = new MethodData[methods_count];
   698             for (int k = 0; k < methods_count; k++) {
   699                 MethodData method = new MethodData(this);
   700                 method.read(in);
   701                 methods[k] = method;
   702             }
   703         }
   704 
   705         /**
   706          * get a string
   707          */
   708         public String getString(int n) {
   709             if (n == 0) {
   710                 return null;
   711             } else {
   712                 return (String) cpool[n];
   713             }
   714         }
   715 
   716         /**
   717          * get the type of constant given an index
   718          */
   719         public byte getTag(int n) {
   720             try {
   721                 return tags[n];
   722             } catch (ArrayIndexOutOfBoundsException e) {
   723                 return (byte) 100;
   724             }
   725         }
   726         static final String hexString = "0123456789ABCDEF";
   727         public static char hexTable[] = hexString.toCharArray();
   728 
   729         static String toHex(long val, int width) {
   730             StringBuffer s = new StringBuffer();
   731             for (int i = width - 1; i >= 0; i--) {
   732                 s.append(hexTable[((int) (val >> (4 * i))) & 0xF]);
   733             }
   734             return "0x" + s.toString();
   735         }
   736 
   737         static String toHex(long val) {
   738             int width;
   739             for (width = 16; width > 0; width--) {
   740                 if ((val >> (width - 1) * 4) != 0) {
   741                     break;
   742                 }
   743             }
   744             return toHex(val, width);
   745         }
   746 
   747         static String toHex(int val) {
   748             int width;
   749             for (width = 8; width > 0; width--) {
   750                 if ((val >> (width - 1) * 4) != 0) {
   751                     break;
   752                 }
   753             }
   754             return toHex(val, width);
   755         }
   756 
   757         /**
   758          * Returns the name of this class.
   759          */
   760         public String getClassName() {
   761             String res = null;
   762             if (this_class == 0) {
   763                 return res;
   764             }
   765             int tcpx;
   766             try {
   767                 if (tags[this_class] != CONSTANT_CLASS) {
   768                     return res; //"<CP["+cpx+"] is not a Class> ";
   769                 }
   770                 tcpx = ((CPX) cpool[this_class]).cpx;
   771             } catch (ArrayIndexOutOfBoundsException e) {
   772                 return res; // "#"+cpx+"// invalid constant pool index";
   773             } catch (Throwable e) {
   774                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   775             }
   776 
   777             try {
   778                 return (String) (cpool[tcpx]);
   779             } catch (ArrayIndexOutOfBoundsException e) {
   780                 return res; // "class #"+scpx+"// invalid constant pool index";
   781             } catch (ClassCastException e) {
   782                 return res; // "class #"+scpx+"// invalid constant pool reference";
   783             } catch (Throwable e) {
   784                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   785             }
   786 
   787         }
   788 
   789         /**
   790          * Returns the name of class at perticular index.
   791          */
   792         public String getClassName(int cpx) {
   793             String res = "#" + cpx;
   794             if (cpx == 0) {
   795                 return res;
   796             }
   797             int scpx;
   798             try {
   799                 if (tags[cpx] != CONSTANT_CLASS) {
   800                     return res; //"<CP["+cpx+"] is not a Class> ";
   801                 }
   802                 scpx = ((CPX) cpool[cpx]).cpx;
   803             } catch (ArrayIndexOutOfBoundsException e) {
   804                 return res; // "#"+cpx+"// invalid constant pool index";
   805             } catch (Throwable e) {
   806                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   807             }
   808             res = "#" + scpx;
   809             try {
   810                 return (String) (cpool[scpx]);
   811             } catch (ArrayIndexOutOfBoundsException e) {
   812                 return res; // "class #"+scpx+"// invalid constant pool index";
   813             } catch (ClassCastException e) {
   814                 return res; // "class #"+scpx+"// invalid constant pool reference";
   815             } catch (Throwable e) {
   816                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   817             }
   818         }
   819 
   820         public int getAccessFlags() {
   821             return access;
   822         }
   823 
   824         /**
   825          * Returns true if it is a class
   826          */
   827         public boolean isClass() {
   828             if ((access & ACC_INTERFACE) == 0) {
   829                 return true;
   830             }
   831             return false;
   832         }
   833 
   834         /**
   835          * Returns true if it is a interface.
   836          */
   837         public boolean isInterface() {
   838             if ((access & ACC_INTERFACE) != 0) {
   839                 return true;
   840             }
   841             return false;
   842         }
   843 
   844         /**
   845          * Returns true if this member is public, false otherwise.
   846          */
   847         public boolean isPublic() {
   848             return (access & ACC_PUBLIC) != 0;
   849         }
   850 
   851         /**
   852          * Returns the access of this class or interface.
   853          */
   854         public String[] getAccess() {
   855             Vector v = new Vector();
   856             if ((access & ACC_PUBLIC) != 0) {
   857                 v.addElement("public");
   858             }
   859             if ((access & ACC_FINAL) != 0) {
   860                 v.addElement("final");
   861             }
   862             if ((access & ACC_ABSTRACT) != 0) {
   863                 v.addElement("abstract");
   864             }
   865             String[] accflags = new String[v.size()];
   866             v.copyInto(accflags);
   867             return accflags;
   868         }
   869 
   870         /**
   871          * Returns list of innerclasses.
   872          */
   873         public InnerClassData[] getInnerClasses() {
   874             return innerClasses;
   875         }
   876 
   877         /**
   878          * Returns list of attributes.
   879          */
   880         final AttrData[] getAttributes() {
   881             return attrs;
   882         }
   883 
   884         public byte[] findAnnotationData(boolean classRetention) {
   885             String n = classRetention
   886                 ? "RuntimeInvisibleAnnotations" : // NOI18N
   887                 "RuntimeVisibleAnnotations"; // NOI18N
   888             return findAttr(n, attrs);
   889         }
   890 
   891         /**
   892          * Returns true if superbit is set.
   893          */
   894         public boolean isSuperSet() {
   895             if ((access & ACC_SUPER) != 0) {
   896                 return true;
   897             }
   898             return false;
   899         }
   900 
   901         /**
   902          * Returns super class name.
   903          */
   904         public String getSuperClassName() {
   905             String res = null;
   906             if (super_class == 0) {
   907                 return res;
   908             }
   909             int scpx;
   910             try {
   911                 if (tags[super_class] != CONSTANT_CLASS) {
   912                     return res; //"<CP["+cpx+"] is not a Class> ";
   913                 }
   914                 scpx = ((CPX) cpool[super_class]).cpx;
   915             } catch (ArrayIndexOutOfBoundsException e) {
   916                 return res; // "#"+cpx+"// invalid constant pool index";
   917             } catch (Throwable e) {
   918                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   919             }
   920 
   921             try {
   922                 return (String) (cpool[scpx]);
   923             } catch (ArrayIndexOutOfBoundsException e) {
   924                 return res; // "class #"+scpx+"// invalid constant pool index";
   925             } catch (ClassCastException e) {
   926                 return res; // "class #"+scpx+"// invalid constant pool reference";
   927             } catch (Throwable e) {
   928                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
   929             }
   930         }
   931 
   932         /**
   933          * Returns list of super interfaces.
   934          */
   935         public String[] getSuperInterfaces() {
   936             String interfacenames[] = new String[interfaces.length];
   937             int interfacecpx = -1;
   938             for (int i = 0; i < interfaces.length; i++) {
   939                 interfacecpx = ((CPX) cpool[interfaces[i]]).cpx;
   940                 interfacenames[i] = (String) (cpool[interfacecpx]);
   941             }
   942             return interfacenames;
   943         }
   944 
   945         /**
   946          * Returns string at prticular constant pool index.
   947          */
   948         public String getStringValue(int cpoolx) {
   949             try {
   950                 return ((String) cpool[cpoolx]);
   951             } catch (ArrayIndexOutOfBoundsException e) {
   952                 return "//invalid constant pool index:" + cpoolx;
   953             } catch (ClassCastException e) {
   954                 return "//invalid constant pool ref:" + cpoolx;
   955             }
   956         }
   957 
   958         /**
   959          * Returns list of field info.
   960          */
   961         public FieldData[] getFields() {
   962             return fields;
   963         }
   964 
   965         /**
   966          * Returns list of method info.
   967          */
   968         public MethodData[] getMethods() {
   969             return methods;
   970         }
   971 
   972         /**
   973          * Returns constant pool entry at that index.
   974          */
   975         public CPX2 getCpoolEntry(int cpx) {
   976             return ((CPX2) (cpool[cpx]));
   977         }
   978 
   979         public Object getCpoolEntryobj(int cpx) {
   980             return (cpool[cpx]);
   981         }
   982 
   983         /**
   984          * Returns index of this class.
   985          */
   986         public int getthis_cpx() {
   987             return this_class;
   988         }
   989 
   990         /**
   991          * Returns string at that index.
   992          */
   993         public String StringValue(int cpx) {
   994             return stringValue(cpx, false);
   995         }
   996 
   997         public String stringValue(int cpx, boolean textual) {
   998             return stringValue(cpx, textual, null);
   999         }
  1000 
  1001         public String stringValue(int cpx, String[] classRefs) {
  1002             return stringValue(cpx, true, classRefs);
  1003         }
  1004 
  1005         private String stringValue(int cpx, boolean textual, String[] refs) {
  1006             if (cpx == 0) {
  1007                 return "#0";
  1008             }
  1009             int tag;
  1010             Object x;
  1011             String suffix = "";
  1012             try {
  1013                 tag = tags[cpx];
  1014                 x = cpool[cpx];
  1015             } catch (IndexOutOfBoundsException e) {
  1016                 return "<Incorrect CP index:" + cpx + ">";
  1017             }
  1018 
  1019             if (x == null) {
  1020                 return "<NULL>";
  1021             }
  1022             switch (tag) {
  1023                 case CONSTANT_UTF8: {
  1024                     if (!textual) {
  1025                         return (String) x;
  1026                     }
  1027                     StringBuilder sb = new StringBuilder();
  1028                     String s = (String) x;
  1029                     for (int k = 0; k < s.length(); k++) {
  1030                         char c = s.charAt(k);
  1031                         switch (c) {
  1032                             case '\\':
  1033                                 sb.append('\\').append('\\');
  1034                                 break;
  1035                             case '\t':
  1036                                 sb.append('\\').append('t');
  1037                                 break;
  1038                             case '\n':
  1039                                 sb.append('\\').append('n');
  1040                                 break;
  1041                             case '\r':
  1042                                 sb.append('\\').append('r');
  1043                                 break;
  1044                             case '\"':
  1045                                 sb.append('\\').append('\"');
  1046                                 break;
  1047                             case '\u2028':
  1048                                 sb.append("\\u2028");
  1049                                 break;
  1050                             case '\u2029':
  1051                                 sb.append("\\u2029");
  1052                                 break;
  1053                             default:
  1054                                 sb.append(c);
  1055                         }
  1056                     }
  1057                     return sb.toString();
  1058                 }
  1059                 case CONSTANT_DOUBLE: {
  1060                     Double d = (Double) x;
  1061                     String sd = d.toString();
  1062                     if (textual) {
  1063                         return sd;
  1064                     }
  1065                     return sd + "d";
  1066                 }
  1067                 case CONSTANT_FLOAT: {
  1068                     Float f = (Float) x;
  1069                     String sf = (f).toString();
  1070                     if (textual) {
  1071                         return sf;
  1072                     }
  1073                     return sf + "f";
  1074                 }
  1075                 case CONSTANT_LONG: {
  1076                     Long ln = (Long) x;
  1077                     if (textual) {
  1078                         return ln.toString();
  1079                     }
  1080                     return ln.toString() + 'l';
  1081                 }
  1082                 case CONSTANT_INTEGER: {
  1083                     Integer in = (Integer) x;
  1084                     return in.toString();
  1085                 }
  1086                 case CONSTANT_CLASS:
  1087                     String jn = getClassName(cpx);
  1088                     if (textual) {
  1089                         if (refs != null) {
  1090                             refs[0] = jn;
  1091                         }
  1092                         return jn;
  1093                     }
  1094                     return javaName(jn);
  1095                 case CONSTANT_STRING:
  1096                     String sv = stringValue(((CPX) x).cpx, textual);
  1097                     if (textual) {
  1098                         return '"' + sv + '"';
  1099                     } else {
  1100                         return sv;
  1101                     }
  1102                 case CONSTANT_FIELD:
  1103                 case CONSTANT_METHOD:
  1104                 case CONSTANT_INTERFACEMETHOD:
  1105                     //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
  1106                     return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2);
  1107 
  1108                 case CONSTANT_NAMEANDTYPE:
  1109                     return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2);
  1110                 default:
  1111                     return "UnknownTag"; //TBD
  1112             }
  1113         }
  1114 
  1115         /**
  1116          * Returns resolved java type name.
  1117          */
  1118         public String javaName(String name) {
  1119             if (name == null) {
  1120                 return "null";
  1121             }
  1122             int len = name.length();
  1123             if (len == 0) {
  1124                 return "\"\"";
  1125             }
  1126             int cc = '/';
  1127             fullname:
  1128             { // xxx/yyy/zzz
  1129                 int cp;
  1130                 for (int k = 0; k < len; k += Character.charCount(cp)) {
  1131                     cp = name.codePointAt(k);
  1132                     if (cc == '/') {
  1133                         if (!isJavaIdentifierStart(cp)) {
  1134                             break fullname;
  1135                         }
  1136                     } else if (cp != '/') {
  1137                         if (!isJavaIdentifierPart(cp)) {
  1138                             break fullname;
  1139                         }
  1140                     }
  1141                     cc = cp;
  1142                 }
  1143                 return name;
  1144             }
  1145             return "\"" + name + "\"";
  1146         }
  1147 
  1148         public String getName(int cpx) {
  1149             String res;
  1150             try {
  1151                 return javaName((String) cpool[cpx]); //.replace('/','.');
  1152             } catch (ArrayIndexOutOfBoundsException e) {
  1153                 return "<invalid constant pool index:" + cpx + ">";
  1154             } catch (ClassCastException e) {
  1155                 return "<invalid constant pool ref:" + cpx + ">";
  1156             }
  1157         }
  1158 
  1159         /**
  1160          * Returns unqualified class name.
  1161          */
  1162         public String getShortClassName(int cpx) {
  1163             String classname = javaName(getClassName(cpx));
  1164             pkgPrefixLen = classname.lastIndexOf("/") + 1;
  1165             if (pkgPrefixLen != 0) {
  1166                 pkgPrefix = classname.substring(0, pkgPrefixLen);
  1167                 if (classname.startsWith(pkgPrefix)) {
  1168                     return classname.substring(pkgPrefixLen);
  1169                 }
  1170             }
  1171             return classname;
  1172         }
  1173 
  1174         /**
  1175          * Returns source file name.
  1176          */
  1177         public String getSourceName() {
  1178             return getName(source_cpx);
  1179         }
  1180 
  1181         /**
  1182          * Returns package name.
  1183          */
  1184         public String getPkgName() {
  1185             String classname = getClassName(this_class);
  1186             pkgPrefixLen = classname.lastIndexOf("/") + 1;
  1187             if (pkgPrefixLen != 0) {
  1188                 pkgPrefix = classname.substring(0, pkgPrefixLen);
  1189                 return /* ("package  " + */ pkgPrefix.substring(0, pkgPrefixLen - 1) /* + ";\n") */;
  1190             } else {
  1191                 return null;
  1192             }
  1193         }
  1194 
  1195         /**
  1196          * Returns total constant pool entry count.
  1197          */
  1198         public int getCpoolCount() {
  1199             return cpool_count;
  1200         }
  1201 
  1202         /**
  1203          * Returns minor version of class file.
  1204          */
  1205         public int getMinor_version() {
  1206             return minor_version;
  1207         }
  1208 
  1209         /**
  1210          * Returns major version of class file.
  1211          */
  1212         public int getMajor_version() {
  1213             return major_version;
  1214         }
  1215 
  1216         private boolean isJavaIdentifierStart(int cp) {
  1217             return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
  1218         }
  1219 
  1220         private boolean isJavaIdentifierPart(int cp) {
  1221             return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
  1222         }
  1223 
  1224         public String[] getNameAndType(int indx) {
  1225             return getNameAndType(indx, 0, new String[2]);
  1226         }
  1227 
  1228         private String[] getNameAndType(int indx, int at, String[] arr) {
  1229             CPX2 c2 = getCpoolEntry(indx);
  1230             arr[at] = StringValue(c2.cpx1);
  1231             arr[at + 1] = StringValue(c2.cpx2);
  1232             return arr;
  1233         }
  1234 
  1235         public String[] getFieldInfoName(int indx) {
  1236             CPX2 c2 = getCpoolEntry(indx);
  1237             String[] arr = new String[3];
  1238             arr[0] = getClassName(c2.cpx1);
  1239             return getNameAndType(c2.cpx2, 1, arr);
  1240         }
  1241 
  1242         public MethodData findMethod(String name, String signature) {
  1243             for (MethodData md: methods) {
  1244                 if (md.getName().equals(name)
  1245                         && md.getInternalSig().equals(signature)) {
  1246                     return md;
  1247                 }
  1248             }
  1249 
  1250             // not found
  1251             return null;
  1252         }
  1253 
  1254         public FieldData findField(String name, String signature) {
  1255             for (FieldData fd: fields) {
  1256                 if (fd.getName().equals(name)
  1257                         && fd.getInternalSig().equals(signature)) {
  1258                     return fd;
  1259                 }
  1260             }
  1261 
  1262             // not found
  1263             return null;
  1264         }
  1265 
  1266         static byte[] findAttr(String n, AttrData[] attrs) {
  1267             for (AttrData ad : attrs) {
  1268                 if (n.equals(ad.getAttrName())) {
  1269                     return ad.getData();
  1270                 }
  1271             }
  1272             return null;
  1273         }
  1274     }
  1275 
  1276     /**
  1277      * Strores field data informastion.
  1278      *
  1279      * @author Sucheta Dambalkar (Adopted code from jdis)
  1280      */
  1281     static class FieldData {
  1282 
  1283         ClassData cls;
  1284         int access;
  1285         int name_index;
  1286         int descriptor_index;
  1287         int attributes_count;
  1288         int value_cpx = -1;
  1289         boolean isSynthetic = false;
  1290         boolean isDeprecated = false;
  1291         Vector attrs;
  1292 
  1293         public FieldData(ClassData cls) {
  1294             this.cls = cls;
  1295         }
  1296 
  1297         /**
  1298          * Read and store field info.
  1299          */
  1300         public void read(DataInputStream in) throws IOException {
  1301             access = in.readUnsignedShort();
  1302             name_index = in.readUnsignedShort();
  1303             descriptor_index = in.readUnsignedShort();
  1304             // Read the attributes
  1305             int attributes_count = in.readUnsignedShort();
  1306             attrs = new Vector(attributes_count);
  1307             for (int i = 0; i < attributes_count; i++) {
  1308                 int attr_name_index = in.readUnsignedShort();
  1309                 if (cls.getTag(attr_name_index) != CONSTANT_UTF8) {
  1310                     continue;
  1311                 }
  1312                 String attr_name = cls.getString(attr_name_index);
  1313                 if (attr_name.equals("ConstantValue")) {
  1314                     if (in.readInt() != 2) {
  1315                         throw new ClassFormatError("invalid ConstantValue attr length");
  1316                     }
  1317                     value_cpx = in.readUnsignedShort();
  1318                     AttrData attr = new AttrData(cls);
  1319                     attr.read(attr_name_index);
  1320                     attrs.addElement(attr);
  1321                 } else if (attr_name.equals("Synthetic")) {
  1322                     if (in.readInt() != 0) {
  1323                         throw new ClassFormatError("invalid Synthetic attr length");
  1324                     }
  1325                     isSynthetic = true;
  1326                     AttrData attr = new AttrData(cls);
  1327                     attr.read(attr_name_index);
  1328                     attrs.addElement(attr);
  1329                 } else if (attr_name.equals("Deprecated")) {
  1330                     if (in.readInt() != 0) {
  1331                         throw new ClassFormatError("invalid Synthetic attr length");
  1332                     }
  1333                     isDeprecated = true;
  1334                     AttrData attr = new AttrData(cls);
  1335                     attr.read(attr_name_index);
  1336                     attrs.addElement(attr);
  1337                 } else {
  1338                     AttrData attr = new AttrData(cls);
  1339                     attr.read(attr_name_index, in);
  1340                     attrs.addElement(attr);
  1341                 }
  1342             }
  1343 
  1344         }  // end read
  1345 
  1346         public boolean isStatic() {
  1347             return (access & ACC_STATIC) != 0;
  1348         }
  1349 
  1350         /**
  1351          * Returns access of a field.
  1352          */
  1353         public String[] getAccess() {
  1354             Vector v = new Vector();
  1355             if ((access & ACC_PUBLIC) != 0) {
  1356                 v.addElement("public");
  1357             }
  1358             if ((access & ACC_PRIVATE) != 0) {
  1359                 v.addElement("private");
  1360             }
  1361             if ((access & ACC_PROTECTED) != 0) {
  1362                 v.addElement("protected");
  1363             }
  1364             if ((access & ACC_STATIC) != 0) {
  1365                 v.addElement("static");
  1366             }
  1367             if ((access & ACC_FINAL) != 0) {
  1368                 v.addElement("final");
  1369             }
  1370             if ((access & ACC_VOLATILE) != 0) {
  1371                 v.addElement("volatile");
  1372             }
  1373             if ((access & ACC_TRANSIENT) != 0) {
  1374                 v.addElement("transient");
  1375             }
  1376             String[] accflags = new String[v.size()];
  1377             v.copyInto(accflags);
  1378             return accflags;
  1379         }
  1380 
  1381         /**
  1382          * Returns name of a field.
  1383          */
  1384         public String getName() {
  1385             return cls.getStringValue(name_index);
  1386         }
  1387 
  1388         /**
  1389          * Returns internal signature of a field
  1390          */
  1391         public String getInternalSig() {
  1392             return cls.getStringValue(descriptor_index);
  1393         }
  1394 
  1395         /**
  1396          * Returns true if field is synthetic.
  1397          */
  1398         public boolean isSynthetic() {
  1399             return isSynthetic;
  1400         }
  1401 
  1402         /**
  1403          * Returns true if field is deprecated.
  1404          */
  1405         public boolean isDeprecated() {
  1406             return isDeprecated;
  1407         }
  1408 
  1409         public boolean hasConstantValue() {
  1410             return value_cpx != -1;
  1411         }
  1412 
  1413         /**
  1414          * Returns list of attributes of field.
  1415          */
  1416         public Vector getAttributes() {
  1417             return attrs;
  1418         }
  1419 
  1420         public byte[] findAnnotationData(boolean classRetention) {
  1421             String n = classRetention
  1422                 ? "RuntimeInvisibleAnnotations" : // NOI18N
  1423                 "RuntimeVisibleAnnotations"; // NOI18N
  1424             AttrData[] arr = new AttrData[attrs.size()];
  1425             attrs.copyInto(arr);
  1426             return ClassData.findAttr(n, arr);
  1427         }
  1428     }
  1429 
  1430     /**
  1431      * A JavaScript optimized replacement for Hashtable.
  1432      *
  1433      * @author Jaroslav Tulach <jtulach@netbeans.org>
  1434      */
  1435     private static final class Hashtable {
  1436 
  1437         private Object[] keys;
  1438         private Object[] values;
  1439 
  1440         Hashtable(int i) {
  1441             this();
  1442         }
  1443 
  1444         Hashtable(int i, double d) {
  1445             this();
  1446         }
  1447 
  1448         Hashtable() {
  1449         }
  1450 
  1451         synchronized void put(Object key, Object val) {
  1452             int[] where = {-1, -1};
  1453             Object found = get(key, where);
  1454             if (where[0] != -1) {
  1455                 // key exists
  1456                 values[where[0]] = val;
  1457             } else {
  1458                 if (where[1] != -1) {
  1459                     // null found
  1460                     keys[where[1]] = key;
  1461                     values[where[1]] = val;
  1462                 } else {
  1463                     if (keys == null) {
  1464                         keys = new Object[11];
  1465                         values = new Object[11];
  1466                         keys[0] = key;
  1467                         values[0] = val;
  1468                     } else {
  1469                         Object[] newKeys = new Object[keys.length * 2];
  1470                         Object[] newValues = new Object[values.length * 2];
  1471                         for (int i = 0; i < keys.length; i++) {
  1472                             newKeys[i] = keys[i];
  1473                             newValues[i] = values[i];
  1474                         }
  1475                         newKeys[keys.length] = key;
  1476                         newValues[keys.length] = val;
  1477                         keys = newKeys;
  1478                         values = newValues;
  1479                     }
  1480                 }
  1481             }
  1482         }
  1483 
  1484         Object get(Object key) {
  1485             return get(key, null);
  1486         }
  1487 
  1488         private synchronized Object get(Object key, int[] foundAndNull) {
  1489             if (keys == null) {
  1490                 return null;
  1491             }
  1492             for (int i = 0; i < keys.length; i++) {
  1493                 if (keys[i] == null) {
  1494                     if (foundAndNull != null) {
  1495                         foundAndNull[1] = i;
  1496                     }
  1497                 } else if (keys[i].equals(key)) {
  1498                     if (foundAndNull != null) {
  1499                         foundAndNull[0] = i;
  1500                     }
  1501                     return values[i];
  1502                 }
  1503             }
  1504             return null;
  1505         }
  1506     }
  1507 
  1508     /**
  1509      * Strores InnerClass data informastion.
  1510      *
  1511      * @author Sucheta Dambalkar (Adopted code from jdis)
  1512      */
  1513     private static class InnerClassData {
  1514 
  1515         ClassData cls;
  1516         int inner_class_info_index, outer_class_info_index, inner_name_index, access;
  1517 
  1518         public InnerClassData(ClassData cls) {
  1519             this.cls = cls;
  1520 
  1521         }
  1522 
  1523         /**
  1524          * Read Innerclass attribute data.
  1525          */
  1526         public void read(DataInputStream in) throws IOException {
  1527             inner_class_info_index = in.readUnsignedShort();
  1528             outer_class_info_index = in.readUnsignedShort();
  1529             inner_name_index = in.readUnsignedShort();
  1530             access = in.readUnsignedShort();
  1531         }  // end read
  1532 
  1533         /**
  1534          * Returns the access of this class or interface.
  1535          */
  1536         public String[] getAccess() {
  1537             Vector v = new Vector();
  1538             if ((access & ACC_PUBLIC) != 0) {
  1539                 v.addElement("public");
  1540             }
  1541             if ((access & ACC_FINAL) != 0) {
  1542                 v.addElement("final");
  1543             }
  1544             if ((access & ACC_ABSTRACT) != 0) {
  1545                 v.addElement("abstract");
  1546             }
  1547             String[] accflags = new String[v.size()];
  1548             v.copyInto(accflags);
  1549             return accflags;
  1550         }
  1551     } // end InnerClassData
  1552 
  1553     /**
  1554      * Strores LineNumberTable data information.
  1555      *
  1556      * @author Sucheta Dambalkar (Adopted code from jdis)
  1557      */
  1558     private static class LineNumData {
  1559 
  1560         short start_pc, line_number;
  1561 
  1562         public LineNumData() {
  1563         }
  1564 
  1565         /**
  1566          * Read LineNumberTable attribute.
  1567          */
  1568         public LineNumData(DataInputStream in) throws IOException {
  1569             start_pc = in.readShort();
  1570             line_number = in.readShort();
  1571 
  1572         }
  1573     }
  1574 
  1575     /**
  1576      * Strores LocalVariableTable data information.
  1577      *
  1578      * @author Sucheta Dambalkar (Adopted code from jdis)
  1579      */
  1580     private static class LocVarData {
  1581 
  1582         short start_pc, length, name_cpx, sig_cpx, slot;
  1583 
  1584         public LocVarData() {
  1585         }
  1586 
  1587         /**
  1588          * Read LocalVariableTable attribute.
  1589          */
  1590         public LocVarData(DataInputStream in) throws IOException {
  1591             start_pc = in.readShort();
  1592             length = in.readShort();
  1593             name_cpx = in.readShort();
  1594             sig_cpx = in.readShort();
  1595             slot = in.readShort();
  1596 
  1597         }
  1598     }
  1599     /**
  1600      * Strores method data informastion.
  1601      *
  1602      * @author Sucheta Dambalkar (Adopted code from jdis)
  1603      */
  1604     static class MethodData {
  1605 
  1606         ClassData cls;
  1607         int access;
  1608         int name_index;
  1609         int descriptor_index;
  1610         int attributes_count;
  1611         byte[] code;
  1612         Vector exception_table = new Vector(0);
  1613         Vector lin_num_tb = new Vector(0);
  1614         Vector loc_var_tb = new Vector(0);
  1615         StackMapTableData[] stackMapTable;
  1616         StackMapData[] stackMap;
  1617         int[] exc_index_table = null;
  1618         Vector attrs = new Vector(0);
  1619         Vector code_attrs = new Vector(0);
  1620         int max_stack, max_locals;
  1621         boolean isSynthetic = false;
  1622         boolean isDeprecated = false;
  1623 
  1624         public MethodData(ClassData cls) {
  1625             this.cls = cls;
  1626         }
  1627 
  1628         /**
  1629          * Read method info.
  1630          */
  1631         public void read(DataInputStream in) throws IOException {
  1632             access = in.readUnsignedShort();
  1633             name_index = in.readUnsignedShort();
  1634             descriptor_index = in.readUnsignedShort();
  1635             int attributes_count = in.readUnsignedShort();
  1636             for (int i = 0; i < attributes_count; i++) {
  1637                 int attr_name_index = in.readUnsignedShort();
  1638 
  1639                 readAttr:
  1640                 {
  1641                     if (cls.getTag(attr_name_index) == CONSTANT_UTF8) {
  1642                         String attr_name = cls.getString(attr_name_index);
  1643                         if (attr_name.equals("Code")) {
  1644                             readCode(in);
  1645                             AttrData attr = new AttrData(cls);
  1646                             attr.read(attr_name_index);
  1647                             attrs.addElement(attr);
  1648                             break readAttr;
  1649                         } else if (attr_name.equals("Exceptions")) {
  1650                             readExceptions(in);
  1651                             AttrData attr = new AttrData(cls);
  1652                             attr.read(attr_name_index);
  1653                             attrs.addElement(attr);
  1654                             break readAttr;
  1655                         } else if (attr_name.equals("Synthetic")) {
  1656                             if (in.readInt() != 0) {
  1657                                 throw new ClassFormatError("invalid Synthetic attr length");
  1658                             }
  1659                             isSynthetic = true;
  1660                             AttrData attr = new AttrData(cls);
  1661                             attr.read(attr_name_index);
  1662                             attrs.addElement(attr);
  1663                             break readAttr;
  1664                         } else if (attr_name.equals("Deprecated")) {
  1665                             if (in.readInt() != 0) {
  1666                                 throw new ClassFormatError("invalid Synthetic attr length");
  1667                             }
  1668                             isDeprecated = true;
  1669                             AttrData attr = new AttrData(cls);
  1670                             attr.read(attr_name_index);
  1671                             attrs.addElement(attr);
  1672                             break readAttr;
  1673                         }
  1674                     }
  1675                     AttrData attr = new AttrData(cls);
  1676                     attr.read(attr_name_index, in);
  1677                     attrs.addElement(attr);
  1678                 }
  1679             }
  1680         }
  1681 
  1682         /**
  1683          * Read code attribute info.
  1684          */
  1685         public void readCode(DataInputStream in) throws IOException {
  1686 
  1687             int attr_length = in.readInt();
  1688             max_stack = in.readUnsignedShort();
  1689             max_locals = in.readUnsignedShort();
  1690             int codelen = in.readInt();
  1691 
  1692             code = new byte[codelen];
  1693             int totalread = 0;
  1694             while (totalread < codelen) {
  1695                 totalread += in.read(code, totalread, codelen - totalread);
  1696             }
  1697             //      in.read(code, 0, codelen);
  1698             int clen = 0;
  1699             readExceptionTable(in);
  1700             int code_attributes_count = in.readUnsignedShort();
  1701 
  1702             for (int k = 0; k < code_attributes_count; k++) {
  1703                 int table_name_index = in.readUnsignedShort();
  1704                 int table_name_tag = cls.getTag(table_name_index);
  1705                 AttrData attr = new AttrData(cls);
  1706                 if (table_name_tag == CONSTANT_UTF8) {
  1707                     String table_name_tstr = cls.getString(table_name_index);
  1708                     if (table_name_tstr.equals("LineNumberTable")) {
  1709                         readLineNumTable(in);
  1710                         attr.read(table_name_index);
  1711                     } else if (table_name_tstr.equals("LocalVariableTable")) {
  1712                         readLocVarTable(in);
  1713                         attr.read(table_name_index);
  1714                     } else if (table_name_tstr.equals("StackMapTable")) {
  1715                         readStackMapTable(in);
  1716                         attr.read(table_name_index);
  1717                     } else if (table_name_tstr.equals("StackMap")) {
  1718                         readStackMap(in);
  1719                         attr.read(table_name_index);
  1720                     } else {
  1721                         attr.read(table_name_index, in);
  1722                     }
  1723                     code_attrs.addElement(attr);
  1724                     continue;
  1725                 }
  1726 
  1727                 attr.read(table_name_index, in);
  1728                 code_attrs.addElement(attr);
  1729             }
  1730         }
  1731 
  1732         /**
  1733          * Read exception table info.
  1734          */
  1735         void readExceptionTable(DataInputStream in) throws IOException {
  1736             int exception_table_len = in.readUnsignedShort();
  1737             exception_table = new Vector(exception_table_len);
  1738             for (int l = 0; l < exception_table_len; l++) {
  1739                 exception_table.addElement(new TrapData(in, l));
  1740             }
  1741         }
  1742 
  1743         /**
  1744          * Read LineNumberTable attribute info.
  1745          */
  1746         void readLineNumTable(DataInputStream in) throws IOException {
  1747             int attr_len = in.readInt(); // attr_length
  1748             int lin_num_tb_len = in.readUnsignedShort();
  1749             lin_num_tb = new Vector(lin_num_tb_len);
  1750             for (int l = 0; l < lin_num_tb_len; l++) {
  1751                 lin_num_tb.addElement(new LineNumData(in));
  1752             }
  1753         }
  1754 
  1755         /**
  1756          * Read LocalVariableTable attribute info.
  1757          */
  1758         void readLocVarTable(DataInputStream in) throws IOException {
  1759             int attr_len = in.readInt(); // attr_length
  1760             int loc_var_tb_len = in.readUnsignedShort();
  1761             loc_var_tb = new Vector(loc_var_tb_len);
  1762             for (int l = 0; l < loc_var_tb_len; l++) {
  1763                 loc_var_tb.addElement(new LocVarData(in));
  1764             }
  1765         }
  1766 
  1767         /**
  1768          * Read Exception attribute info.
  1769          */
  1770         public void readExceptions(DataInputStream in) throws IOException {
  1771             int attr_len = in.readInt(); // attr_length in prog
  1772             int num_exceptions = in.readUnsignedShort();
  1773             exc_index_table = new int[num_exceptions];
  1774             for (int l = 0; l < num_exceptions; l++) {
  1775                 int exc = in.readShort();
  1776                 exc_index_table[l] = exc;
  1777             }
  1778         }
  1779 
  1780         /**
  1781          * Read StackMapTable attribute info.
  1782          */
  1783         void readStackMapTable(DataInputStream in) throws IOException {
  1784             int attr_len = in.readInt();  //attr_length
  1785             int stack_map_tb_len = in.readUnsignedShort();
  1786             stackMapTable = new StackMapTableData[stack_map_tb_len];
  1787             for (int i = 0; i < stack_map_tb_len; i++) {
  1788                 stackMapTable[i] = StackMapTableData.getInstance(in, this);
  1789             }
  1790         }
  1791 
  1792         /**
  1793          * Read StackMap attribute info.
  1794          */
  1795         void readStackMap(DataInputStream in) throws IOException {
  1796             int attr_len = in.readInt();  //attr_length
  1797             int stack_map_len = in.readUnsignedShort();
  1798             stackMap = new StackMapData[stack_map_len];
  1799             for (int i = 0; i < stack_map_len; i++) {
  1800                 stackMap[i] = new StackMapData(in, this);
  1801             }
  1802         }
  1803 
  1804         /**
  1805          * Return access of the method.
  1806          */
  1807         public int getAccess() {
  1808             return access;
  1809         }
  1810 
  1811         /**
  1812          * Return name of the method.
  1813          */
  1814         public String getName() {
  1815             return cls.getStringValue(name_index);
  1816         }
  1817 
  1818         /**
  1819          * Return internal siganature of the method.
  1820          */
  1821         public String getInternalSig() {
  1822             return cls.getStringValue(descriptor_index);
  1823         }
  1824 
  1825         /**
  1826          * Return code attribute data of a method.
  1827          */
  1828         public byte[] getCode() {
  1829             return code;
  1830         }
  1831 
  1832         /**
  1833          * Return LineNumberTable size.
  1834          */
  1835         public int getnumlines() {
  1836             return lin_num_tb.size();
  1837         }
  1838 
  1839         /**
  1840          * Return LineNumberTable
  1841          */
  1842         public Vector getlin_num_tb() {
  1843             return lin_num_tb;
  1844         }
  1845 
  1846         /**
  1847          * Return LocalVariableTable size.
  1848          */
  1849         public int getloc_var_tbsize() {
  1850             return loc_var_tb.size();
  1851         }
  1852 
  1853         /**
  1854          * Return LocalVariableTable.
  1855          */
  1856         public Vector getloc_var_tb() {
  1857             return loc_var_tb;
  1858         }
  1859 
  1860         /**
  1861          * Return StackMap.
  1862          */
  1863         public StackMapData[] getStackMap() {
  1864             return stackMap;
  1865         }
  1866 
  1867         /**
  1868          * Return StackMapTable.
  1869          */
  1870         public StackMapTableData[] getStackMapTable() {
  1871             return stackMapTable;
  1872         }
  1873 
  1874         public StackMapIterator createStackMapIterator() {
  1875             return new StackMapIterator(this);
  1876         }
  1877 
  1878         /**
  1879          * Return true if method is static
  1880          */
  1881         public boolean isStatic() {
  1882             if ((access & ACC_STATIC) != 0) {
  1883                 return true;
  1884             }
  1885             return false;
  1886         }
  1887 
  1888         /**
  1889          * Return max depth of operand stack.
  1890          */
  1891         public int getMaxStack() {
  1892             return max_stack;
  1893         }
  1894 
  1895         /**
  1896          * Return number of local variables.
  1897          */
  1898         public int getMaxLocals() {
  1899             return max_locals;
  1900         }
  1901 
  1902         /**
  1903          * Return exception index table in Exception attribute.
  1904          */
  1905         public int[] get_exc_index_table() {
  1906             return exc_index_table;
  1907         }
  1908 
  1909         /**
  1910          * Return exception table in code attributre.
  1911          */
  1912         public TrapDataIterator getTrapDataIterator() {
  1913             return new TrapDataIterator(exception_table);
  1914         }
  1915 
  1916         /**
  1917          * Return method attributes.
  1918          */
  1919         public Vector getAttributes() {
  1920             return attrs;
  1921         }
  1922 
  1923         /**
  1924          * Return code attributes.
  1925          */
  1926         public Vector getCodeAttributes() {
  1927             return code_attrs;
  1928         }
  1929 
  1930         /**
  1931          * Return true if method id synthetic.
  1932          */
  1933         public boolean isSynthetic() {
  1934             return isSynthetic;
  1935         }
  1936 
  1937         /**
  1938          * Return true if method is deprecated.
  1939          */
  1940         public boolean isDeprecated() {
  1941             return isDeprecated;
  1942         }
  1943 
  1944         public byte[] findAnnotationData(boolean classRetention) {
  1945             String n = classRetention
  1946                 ? "RuntimeInvisibleAnnotations" : // NOI18N
  1947                 "RuntimeVisibleAnnotations"; // NOI18N
  1948             AttrData[] arr = new AttrData[attrs.size()];
  1949             attrs.copyInto(arr);
  1950             return ClassData.findAttr(n, arr);
  1951         }
  1952 
  1953         public boolean isConstructor() {
  1954             return "<init>".equals(getName());
  1955         }
  1956     }
  1957 
  1958     /* represents one entry of StackMap attribute
  1959      */
  1960     private static class StackMapData {
  1961 
  1962         final int offset;
  1963         final int[] locals;
  1964         final int[] stack;
  1965 
  1966         StackMapData(int offset, int[] locals, int[] stack) {
  1967             this.offset = offset;
  1968             this.locals = locals;
  1969             this.stack = stack;
  1970         }
  1971 
  1972         StackMapData(DataInputStream in, MethodData method) throws IOException {
  1973             offset = in.readUnsignedShort();
  1974             int local_size = in.readUnsignedShort();
  1975             locals = readTypeArray(in, local_size, method);
  1976             int stack_size = in.readUnsignedShort();
  1977             stack = readTypeArray(in, stack_size, method);
  1978         }
  1979 
  1980         static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException {
  1981             int[] types = new int[length];
  1982             for (int i = 0; i < length; i++) {
  1983                 types[i] = readType(in, method);
  1984             }
  1985             return types;
  1986         }
  1987 
  1988         static final int readType(DataInputStream in, MethodData method) throws IOException {
  1989             int type = in.readUnsignedByte();
  1990             if (type == ITEM_Object || type == ITEM_NewObject) {
  1991                 type = type | (in.readUnsignedShort() << 8);
  1992             }
  1993             return type;
  1994         }
  1995     }
  1996 
  1997     static final class StackMapIterator {
  1998 
  1999         private final StackMapTableData[] stackMapTable;
  2000         private final TypeArray argTypes;
  2001         private final TypeArray localTypes;
  2002         private final TypeArray stackTypes;
  2003         private int nextFrameIndex;
  2004         private int lastFrameByteCodeOffset;
  2005         private int byteCodeOffset;
  2006 
  2007         StackMapIterator(final MethodData methodData) {
  2008             this(methodData.getStackMapTable(),
  2009                 methodData.getInternalSig(),
  2010                 methodData.isStatic());
  2011         }
  2012 
  2013         StackMapIterator(final StackMapTableData[] stackMapTable,
  2014             final String methodSignature,
  2015             final boolean isStaticMethod) {
  2016             this.stackMapTable = (stackMapTable != null)
  2017                 ? stackMapTable
  2018                 : new StackMapTableData[0];
  2019 
  2020             argTypes = getArgTypes(methodSignature, isStaticMethod);
  2021             localTypes = new TypeArray();
  2022             stackTypes = new TypeArray();
  2023 
  2024             localTypes.addAll(argTypes);
  2025 
  2026             lastFrameByteCodeOffset = -1;
  2027             advanceBy(0);
  2028         }
  2029         
  2030         public boolean isEmpty() {
  2031             return stackMapTable.length == 0;
  2032         }
  2033 
  2034         public String getFrameAsString() {
  2035             return (nextFrameIndex == 0)
  2036                 ? StackMapTableData.toString("INITIAL", 0, null, null)
  2037                 : stackMapTable[nextFrameIndex - 1].toString();
  2038         }
  2039 
  2040         public int getFrameIndex() {
  2041             return nextFrameIndex;
  2042         }
  2043 
  2044         public TypeArray getFrameStack() {
  2045             return stackTypes;
  2046         }
  2047 
  2048         public TypeArray getFrameLocals() {
  2049             return localTypes;
  2050         }
  2051 
  2052         public TypeArray getArguments() {
  2053             return argTypes;
  2054         }
  2055 
  2056         public void advanceBy(final int numByteCodes) {
  2057             if (numByteCodes < 0) {
  2058                 throw new IllegalStateException("Forward only iterator");
  2059             }
  2060 
  2061             byteCodeOffset += numByteCodes;
  2062             while ((nextFrameIndex < stackMapTable.length)
  2063                 && ((byteCodeOffset - lastFrameByteCodeOffset)
  2064                 >= (stackMapTable[nextFrameIndex].offsetDelta
  2065                 + 1))) {
  2066                 final StackMapTableData nextFrame = stackMapTable[nextFrameIndex];
  2067 
  2068                 lastFrameByteCodeOffset += nextFrame.offsetDelta + 1;
  2069                 nextFrame.applyTo(localTypes, stackTypes);
  2070 
  2071                 ++nextFrameIndex;
  2072             }
  2073         }
  2074 
  2075         public void advanceTo(final int nextByteCodeOffset) {
  2076             advanceBy(nextByteCodeOffset - byteCodeOffset);
  2077         }
  2078 
  2079         private static TypeArray getArgTypes(final String methodSignature,
  2080             final boolean isStaticMethod) {
  2081             final TypeArray argTypes = new TypeArray();
  2082 
  2083             if (!isStaticMethod) {
  2084                 argTypes.add(ITEM_Object);
  2085             }
  2086 
  2087             if (methodSignature.charAt(0) != '(') {
  2088                 throw new IllegalArgumentException("Invalid method signature");
  2089             }
  2090 
  2091             final int length = methodSignature.length();
  2092             boolean skipType = false;
  2093             int argType;
  2094             for (int i = 1; i < length; ++i) {
  2095                 switch (methodSignature.charAt(i)) {
  2096                     case 'B':
  2097                     case 'C':
  2098                     case 'S':
  2099                     case 'Z':
  2100                     case 'I':
  2101                         argType = ITEM_Integer;
  2102                         break;
  2103                     case 'J':
  2104                         argType = ITEM_Long;
  2105                         break;
  2106                     case 'F':
  2107                         argType = ITEM_Float;
  2108                         break;
  2109                     case 'D':
  2110                         argType = ITEM_Double;
  2111                         break;
  2112                     case 'L': {
  2113                         i = methodSignature.indexOf(';', i + 1);
  2114                         if (i == -1) {
  2115                             throw new IllegalArgumentException(
  2116                                 "Invalid method signature");
  2117                         }
  2118                         argType = ITEM_Object;
  2119                         break;
  2120                     }
  2121                     case ')':
  2122                         // not interested in the return value type
  2123                         return argTypes;
  2124                     case '[':
  2125                         if (!skipType) {
  2126                             argTypes.add(ITEM_Object);
  2127                             skipType = true;
  2128                         }
  2129                         continue;
  2130 
  2131                     default:
  2132                         throw new IllegalArgumentException(
  2133                             "Invalid method signature");
  2134                 }
  2135 
  2136                 if (!skipType) {
  2137                     argTypes.add(argType);
  2138                 } else {
  2139                     skipType = false;
  2140                 }
  2141             }
  2142 
  2143             return argTypes;
  2144         }
  2145     }
  2146     /* represents one entry of StackMapTable attribute
  2147      */
  2148 
  2149     private static abstract class StackMapTableData {
  2150 
  2151         final int frameType;
  2152         int offsetDelta;
  2153 
  2154         StackMapTableData(int frameType) {
  2155             this.frameType = frameType;
  2156         }
  2157 
  2158         abstract void applyTo(TypeArray localTypes, TypeArray stackTypes);
  2159 
  2160         protected static String toString(
  2161             final String frameType,
  2162             final int offset,
  2163             final int[] localTypes,
  2164             final int[] stackTypes) {
  2165             final StringBuilder sb = new StringBuilder(frameType);
  2166 
  2167             sb.append("(off: +").append(offset);
  2168             if (localTypes != null) {
  2169                 sb.append(", locals: ");
  2170                 appendTypes(sb, localTypes);
  2171             }
  2172             if (stackTypes != null) {
  2173                 sb.append(", stack: ");
  2174                 appendTypes(sb, stackTypes);
  2175             }
  2176             sb.append(')');
  2177 
  2178             return sb.toString();
  2179         }
  2180 
  2181         private static void appendTypes(final StringBuilder sb, final int[] types) {
  2182             sb.append('[');
  2183             if (types.length > 0) {
  2184                 sb.append(TypeArray.typeString(types[0]));
  2185                 for (int i = 1; i < types.length; ++i) {
  2186                     sb.append(", ");
  2187                     sb.append(TypeArray.typeString(types[i]));
  2188                 }
  2189             }
  2190             sb.append(']');
  2191         }
  2192 
  2193         private static class SameFrame extends StackMapTableData {
  2194 
  2195             SameFrame(int frameType, int offsetDelta) {
  2196                 super(frameType);
  2197                 this.offsetDelta = offsetDelta;
  2198             }
  2199 
  2200             @Override
  2201             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  2202                 stackTypes.clear();
  2203             }
  2204 
  2205             @Override
  2206             public String toString() {
  2207                 return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED)
  2208                     ? "_FRAME_EXTENDED" : ""),
  2209                     offsetDelta,
  2210                     null, null);
  2211             }
  2212         }
  2213 
  2214         private static class SameLocals1StackItem extends StackMapTableData {
  2215 
  2216             final int[] stack;
  2217 
  2218             SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) {
  2219                 super(frameType);
  2220                 this.offsetDelta = offsetDelta;
  2221                 this.stack = stack;
  2222             }
  2223 
  2224             @Override
  2225             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  2226                 stackTypes.setAll(stack);
  2227             }
  2228 
  2229             @Override
  2230             public String toString() {
  2231                 return toString(
  2232                     "SAME_LOCALS_1_STACK_ITEM"
  2233                     + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED)
  2234                     ? "_EXTENDED" : ""),
  2235                     offsetDelta,
  2236                     null, stack);
  2237             }
  2238         }
  2239 
  2240         private static class ChopFrame extends StackMapTableData {
  2241 
  2242             ChopFrame(int frameType, int offsetDelta) {
  2243                 super(frameType);
  2244                 this.offsetDelta = offsetDelta;
  2245             }
  2246 
  2247             @Override
  2248             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  2249                 localTypes.setSize(localTypes.getSize()
  2250                     - (SAME_FRAME_EXTENDED - frameType));
  2251                 stackTypes.clear();
  2252             }
  2253 
  2254             @Override
  2255             public String toString() {
  2256                 return toString("CHOP", offsetDelta, null, null);
  2257             }
  2258         }
  2259 
  2260         private static class AppendFrame extends StackMapTableData {
  2261 
  2262             final int[] locals;
  2263 
  2264             AppendFrame(int frameType, int offsetDelta, int[] locals) {
  2265                 super(frameType);
  2266                 this.offsetDelta = offsetDelta;
  2267                 this.locals = locals;
  2268             }
  2269 
  2270             @Override
  2271             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  2272                 localTypes.addAll(locals);
  2273                 stackTypes.clear();
  2274             }
  2275 
  2276             @Override
  2277             public String toString() {
  2278                 return toString("APPEND", offsetDelta, locals, null);
  2279             }
  2280         }
  2281 
  2282         private static class FullFrame extends StackMapTableData {
  2283 
  2284             final int[] locals;
  2285             final int[] stack;
  2286 
  2287             FullFrame(int offsetDelta, int[] locals, int[] stack) {
  2288                 super(FULL_FRAME);
  2289                 this.offsetDelta = offsetDelta;
  2290                 this.locals = locals;
  2291                 this.stack = stack;
  2292             }
  2293 
  2294             @Override
  2295             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  2296                 localTypes.setAll(locals);
  2297                 stackTypes.setAll(stack);
  2298             }
  2299 
  2300             @Override
  2301             public String toString() {
  2302                 return toString("FULL", offsetDelta, locals, stack);
  2303             }
  2304         }
  2305 
  2306         static StackMapTableData getInstance(DataInputStream in, MethodData method)
  2307             throws IOException {
  2308             int frameType = in.readUnsignedByte();
  2309 
  2310             if (frameType < SAME_FRAME_BOUND) {
  2311                 // same_frame
  2312                 return new SameFrame(frameType, frameType);
  2313             } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) {
  2314                 // same_locals_1_stack_item_frame
  2315                 // read additional single stack element
  2316                 return new SameLocals1StackItem(frameType,
  2317                     (frameType - SAME_FRAME_BOUND),
  2318                     StackMapData.readTypeArray(in, 1, method));
  2319             } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
  2320                 // same_locals_1_stack_item_extended
  2321                 return new SameLocals1StackItem(frameType,
  2322                     in.readUnsignedShort(),
  2323                     StackMapData.readTypeArray(in, 1, method));
  2324             } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) {
  2325                 // chop_frame or same_frame_extended
  2326                 return new ChopFrame(frameType, in.readUnsignedShort());
  2327             } else if (frameType == SAME_FRAME_EXTENDED) {
  2328                 // chop_frame or same_frame_extended
  2329                 return new SameFrame(frameType, in.readUnsignedShort());
  2330             } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) {
  2331                 // append_frame
  2332                 return new AppendFrame(frameType, in.readUnsignedShort(),
  2333                     StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method));
  2334             } else if (frameType == FULL_FRAME) {
  2335                 // full_frame
  2336                 int offsetDelta = in.readUnsignedShort();
  2337                 int locals_size = in.readUnsignedShort();
  2338                 int[] locals = StackMapData.readTypeArray(in, locals_size, method);
  2339                 int stack_size = in.readUnsignedShort();
  2340                 int[] stack = StackMapData.readTypeArray(in, stack_size, method);
  2341                 return new FullFrame(offsetDelta, locals, stack);
  2342             } else {
  2343                 throw new ClassFormatError("unrecognized frame_type in StackMapTable");
  2344             }
  2345         }
  2346     }
  2347 
  2348     /**
  2349      * Stores exception table data in code attribute.
  2350      *
  2351      * @author Sucheta Dambalkar (Adopted code from jdis)
  2352      */
  2353     static final class TrapData {
  2354 
  2355         public final short start_pc;
  2356         public final short end_pc;
  2357         public final short handler_pc;
  2358         public final short catch_cpx;
  2359         final int num;
  2360 
  2361         /**
  2362          * Read and store exception table data in code attribute.
  2363          */
  2364         TrapData(DataInputStream in, int num) throws IOException {
  2365             this.num = num;
  2366             start_pc = in.readShort();
  2367             end_pc = in.readShort();
  2368             handler_pc = in.readShort();
  2369             catch_cpx = in.readShort();
  2370         }
  2371 
  2372         /**
  2373          * returns recommended identifier
  2374          */
  2375         public String ident() {
  2376             return "t" + num;
  2377         }
  2378     }
  2379     /**
  2380      *
  2381      * @author Jaroslav Tulach <jtulach@netbeans.org>
  2382      */
  2383     static final class TrapDataIterator {
  2384 
  2385         private final Hashtable exStart = new Hashtable();
  2386         private final Hashtable exStop = new Hashtable();
  2387         private TrapData[] current = new TrapData[10];
  2388         private int currentCount;
  2389 
  2390         TrapDataIterator(Vector exceptionTable) {
  2391             for (int i = 0; i < exceptionTable.size(); i++) {
  2392                 final TrapData td = (TrapData) exceptionTable.elementAt(i);
  2393                 put(exStart, td.start_pc, td);
  2394                 put(exStop, td.end_pc, td);
  2395             }
  2396         }
  2397 
  2398         private static void put(Hashtable h, short key, TrapData td) {
  2399             Short s = Short.valueOf((short) key);
  2400             Vector v = (Vector) h.get(s);
  2401             if (v == null) {
  2402                 v = new Vector(1);
  2403                 h.put(s, v);
  2404             }
  2405             v.add(td);
  2406         }
  2407 
  2408         private boolean processAll(Hashtable h, Short key, boolean add) {
  2409             boolean change = false;
  2410             Vector v = (Vector) h.get(key);
  2411             if (v != null) {
  2412                 int s = v.size();
  2413                 for (int i = 0; i < s; i++) {
  2414                     TrapData td = (TrapData) v.elementAt(i);
  2415                     if (add) {
  2416                         add(td);
  2417                         change = true;
  2418                     } else {
  2419                         remove(td);
  2420                         change = true;
  2421                     }
  2422                 }
  2423             }
  2424             return change;
  2425         }
  2426 
  2427         public boolean advanceTo(int i) {
  2428             Short s = Short.valueOf((short) i);
  2429             boolean ch1 = processAll(exStart, s, true);
  2430             boolean ch2 = processAll(exStop, s, false);
  2431             return ch1 || ch2;
  2432         }
  2433 
  2434         public boolean useTry() {
  2435             return currentCount > 0;
  2436         }
  2437 
  2438         public TrapData[] current() {
  2439             TrapData[] copy = new TrapData[currentCount];
  2440             for (int i = 0; i < currentCount; i++) {
  2441                 copy[i] = current[i];
  2442             }
  2443             return copy;
  2444         }
  2445 
  2446         private void add(TrapData e) {
  2447             if (currentCount == current.length) {
  2448                 TrapData[] data = new TrapData[currentCount * 2];
  2449                 for (int i = 0; i < currentCount; i++) {
  2450                     data[i] = current[i];
  2451                 }
  2452                 current = data;
  2453             }
  2454             current[currentCount++] = e;
  2455         }
  2456 
  2457         private void remove(TrapData e) {
  2458             if (currentCount == 0) {
  2459                 return;
  2460             }
  2461             int from = 0;
  2462             while (from < currentCount) {
  2463                 if (e == current[from++]) {
  2464                     break;
  2465                 }
  2466             }
  2467             while (from < currentCount) {
  2468                 current[from - 1] = current[from];
  2469                 current[from] = null;
  2470                 from++;
  2471             }
  2472             currentCount--;
  2473         }
  2474     }
  2475     static final class TypeArray {
  2476 
  2477         private static final int CAPACITY_INCREMENT = 16;
  2478         private int[] types;
  2479         private int size;
  2480 
  2481         public TypeArray() {
  2482         }
  2483 
  2484         public TypeArray(final TypeArray initialTypes) {
  2485             setAll(initialTypes);
  2486         }
  2487 
  2488         public void add(final int newType) {
  2489             ensureCapacity(size + 1);
  2490             types[size++] = newType;
  2491         }
  2492 
  2493         public void addAll(final TypeArray newTypes) {
  2494             addAll(newTypes.types, 0, newTypes.size);
  2495         }
  2496 
  2497         public void addAll(final int[] newTypes) {
  2498             addAll(newTypes, 0, newTypes.length);
  2499         }
  2500 
  2501         public void addAll(final int[] newTypes,
  2502             final int offset,
  2503             final int count) {
  2504             if (count > 0) {
  2505                 ensureCapacity(size + count);
  2506                 arraycopy(newTypes, offset, types, size, count);
  2507                 size += count;
  2508             }
  2509         }
  2510 
  2511         public void set(final int index, final int newType) {
  2512             types[index] = newType;
  2513         }
  2514 
  2515         public void setAll(final TypeArray newTypes) {
  2516             setAll(newTypes.types, 0, newTypes.size);
  2517         }
  2518 
  2519         public void setAll(final int[] newTypes) {
  2520             setAll(newTypes, 0, newTypes.length);
  2521         }
  2522 
  2523         public void setAll(final int[] newTypes,
  2524             final int offset,
  2525             final int count) {
  2526             if (count > 0) {
  2527                 ensureCapacity(count);
  2528                 arraycopy(newTypes, offset, types, 0, count);
  2529                 size = count;
  2530             } else {
  2531                 clear();
  2532             }
  2533         }
  2534 
  2535         public void setSize(final int newSize) {
  2536             if (size != newSize) {
  2537                 ensureCapacity(newSize);
  2538 
  2539                 for (int i = size; i < newSize; ++i) {
  2540                     types[i] = 0;
  2541                 }
  2542                 size = newSize;
  2543             }
  2544         }
  2545 
  2546         public void clear() {
  2547             size = 0;
  2548         }
  2549 
  2550         public int getSize() {
  2551             return size;
  2552         }
  2553 
  2554         public int get(final int index) {
  2555             return types[index];
  2556         }
  2557 
  2558         public static String typeString(final int type) {
  2559             switch (type & 0xff) {
  2560                 case ITEM_Bogus:
  2561                     return "_top_";
  2562                 case ITEM_Integer:
  2563                     return "_int_";
  2564                 case ITEM_Float:
  2565                     return "_float_";
  2566                 case ITEM_Double:
  2567                     return "_double_";
  2568                 case ITEM_Long:
  2569                     return "_long_";
  2570                 case ITEM_Null:
  2571                     return "_null_";
  2572                 case ITEM_InitObject: // UninitializedThis
  2573                     return "_init_";
  2574                 case ITEM_Object:
  2575                     return "_object_";
  2576                 case ITEM_NewObject: // Uninitialized
  2577                     return "_new_";
  2578                 default:
  2579                     throw new IllegalArgumentException("Unknown type");
  2580             }
  2581         }
  2582 
  2583         @Override
  2584         public String toString() {
  2585             final StringBuilder sb = new StringBuilder("[");
  2586             if (size > 0) {
  2587                 sb.append(typeString(types[0]));
  2588                 for (int i = 1; i < size; ++i) {
  2589                     sb.append(", ");
  2590                     sb.append(typeString(types[i]));
  2591                 }
  2592             }
  2593 
  2594             return sb.append(']').toString();
  2595         }
  2596 
  2597         private void ensureCapacity(final int minCapacity) {
  2598             if ((minCapacity == 0)
  2599                 || (types != null) && (minCapacity <= types.length)) {
  2600                 return;
  2601             }
  2602 
  2603             final int newCapacity =
  2604                 ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT)
  2605                 * CAPACITY_INCREMENT;
  2606             final int[] newTypes = new int[newCapacity];
  2607 
  2608             if (size > 0) {
  2609                 arraycopy(types, 0, newTypes, 0, size);
  2610             }
  2611 
  2612             types = newTypes;
  2613         }
  2614 
  2615         // no System.arraycopy
  2616         private void arraycopy(final int[] src, final int srcPos,
  2617             final int[] dest, final int destPos,
  2618             final int length) {
  2619             for (int i = 0; i < length; ++i) {
  2620                 dest[destPos + i] = src[srcPos + i];
  2621             }
  2622         }
  2623     }
  2624     /**
  2625      * A JavaScript ready replacement for java.util.Vector
  2626      *
  2627      * @author Jaroslav Tulach <jtulach@netbeans.org>
  2628      */
  2629     @JavaScriptPrototype(prototype = "new Array")
  2630     private static final class Vector {
  2631 
  2632         private Object[] arr;
  2633 
  2634         Vector() {
  2635         }
  2636 
  2637         Vector(int i) {
  2638         }
  2639 
  2640         void add(Object objectType) {
  2641             addElement(objectType);
  2642         }
  2643 
  2644         @JavaScriptBody(args = {"obj"}, body =
  2645             "this.push(obj);")
  2646         void addElement(Object obj) {
  2647             final int s = size();
  2648             setSize(s + 1);
  2649             setElementAt(obj, s);
  2650         }
  2651 
  2652         @JavaScriptBody(args = {}, body =
  2653             "return this.length;")
  2654         int size() {
  2655             return arr == null ? 0 : arr.length;
  2656         }
  2657 
  2658         @JavaScriptBody(args = {"newArr"}, body =
  2659             "for (var i = 0; i < this.length; i++) {\n"
  2660             + "  newArr[i] = this[i];\n"
  2661             + "}\n")
  2662         void copyInto(Object[] newArr) {
  2663             if (arr == null) {
  2664                 return;
  2665             }
  2666             int min = Math.min(newArr.length, arr.length);
  2667             for (int i = 0; i < min; i++) {
  2668                 newArr[i] = arr[i];
  2669             }
  2670         }
  2671 
  2672         @JavaScriptBody(args = {"index"}, body =
  2673             "return this[index];")
  2674         Object elementAt(int index) {
  2675             return arr[index];
  2676         }
  2677 
  2678         private void setSize(int len) {
  2679             Object[] newArr = new Object[len];
  2680             copyInto(newArr);
  2681             arr = newArr;
  2682         }
  2683 
  2684         @JavaScriptBody(args = {"val", "index"}, body =
  2685             "this[index] = val;")
  2686         void setElementAt(Object val, int index) {
  2687             arr[index] = val;
  2688         }
  2689     }
  2690     
  2691 }