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