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