rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 09 Oct 2013 16:53:45 +0200
changeset 1354 43f89d9f7238
parent 810 9eb750594b15
child 1469 f57fa856ffc4
permissions -rw-r--r--
Unicode has some special new line characters that need to be encoded too
     1 /*
     2  * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package org.apidesign.vm4brwsr;
    26 
    27 import java.io.ByteArrayInputStream;
    28 import java.io.DataInputStream;
    29 import java.io.IOException;
    30 import java.io.InputStream;
    31 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    32 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
    33 
    34 /** This is a byte code parser heavily based on original code of JavaP utility.
    35  * As such I decided to keep the original Oracle's GPLv2 header.
    36  *
    37  * @author Jaroslav Tulach <jtulach@netbeans.org>
    38  */
    39 final class ByteCodeParser {
    40     private ByteCodeParser() {
    41     }
    42     /* Signature Characters */
    43     public static final char   SIGC_VOID                  = 'V';
    44     public static final String SIG_VOID                   = "V";
    45     public static final char   SIGC_BOOLEAN               = 'Z';
    46     public static final String SIG_BOOLEAN                = "Z";
    47     public static final char   SIGC_BYTE                  = 'B';
    48     public static final String SIG_BYTE                   = "B";
    49     public static final char   SIGC_CHAR                  = 'C';
    50     public static final String SIG_CHAR                   = "C";
    51     public static final char   SIGC_SHORT                 = 'S';
    52     public static final String SIG_SHORT                  = "S";
    53     public static final char   SIGC_INT                   = 'I';
    54     public static final String SIG_INT                    = "I";
    55     public static final char   SIGC_LONG                  = 'J';
    56     public static final String SIG_LONG                   = "J";
    57     public static final char   SIGC_FLOAT                 = 'F';
    58     public static final String SIG_FLOAT                  = "F";
    59     public static final char   SIGC_DOUBLE                = 'D';
    60     public static final String SIG_DOUBLE                 = "D";
    61     public static final char   SIGC_ARRAY                 = '[';
    62     public static final String SIG_ARRAY                  = "[";
    63     public static final char   SIGC_CLASS                 = 'L';
    64     public static final String SIG_CLASS                  = "L";
    65     public static final char   SIGC_METHOD                = '(';
    66     public static final String SIG_METHOD                 = "(";
    67     public static final char   SIGC_ENDCLASS              = ';';
    68     public static final String SIG_ENDCLASS               = ";";
    69     public static final char   SIGC_ENDMETHOD             = ')';
    70     public static final String SIG_ENDMETHOD              = ")";
    71     public static final char   SIGC_PACKAGE               = '/';
    72     public static final String SIG_PACKAGE                = "/";
    73 
    74     /* Class File Constants */
    75     public static final int JAVA_MAGIC                   = 0xcafebabe;
    76     public static final int JAVA_VERSION                 = 45;
    77     public static final int JAVA_MINOR_VERSION           = 3;
    78 
    79     /* Constant table */
    80     public static final int CONSTANT_UTF8                = 1;
    81     public static final int CONSTANT_UNICODE             = 2;
    82     public static final int CONSTANT_INTEGER             = 3;
    83     public static final int CONSTANT_FLOAT               = 4;
    84     public static final int CONSTANT_LONG                = 5;
    85     public static final int CONSTANT_DOUBLE              = 6;
    86     public static final int CONSTANT_CLASS               = 7;
    87     public static final int CONSTANT_STRING              = 8;
    88     public static final int CONSTANT_FIELD               = 9;
    89     public static final int CONSTANT_METHOD              = 10;
    90     public static final int CONSTANT_INTERFACEMETHOD     = 11;
    91     public static final int CONSTANT_NAMEANDTYPE         = 12;
    92 
    93     /* Access Flags */
    94     public static final int ACC_PUBLIC                   = 0x00000001;
    95     public static final int ACC_PRIVATE                  = 0x00000002;
    96     public static final int ACC_PROTECTED                = 0x00000004;
    97     public static final int ACC_STATIC                   = 0x00000008;
    98     public static final int ACC_FINAL                    = 0x00000010;
    99     public static final int ACC_SYNCHRONIZED             = 0x00000020;
   100     public static final int ACC_SUPER                        = 0x00000020;
   101     public static final int ACC_VOLATILE                 = 0x00000040;
   102     public static final int ACC_TRANSIENT                = 0x00000080;
   103     public static final int ACC_NATIVE                   = 0x00000100;
   104     public static final int ACC_INTERFACE                = 0x00000200;
   105     public static final int ACC_ABSTRACT                 = 0x00000400;
   106     public static final int ACC_STRICT                   = 0x00000800;
   107     public static final int ACC_EXPLICIT                 = 0x00001000;
   108     public static final int ACC_SYNTHETIC                = 0x00010000; // actually, this is an attribute
   109 
   110     /* Type codes */
   111     public static final int T_CLASS                      = 0x00000002;
   112     public static final int T_BOOLEAN                    = 0x00000004;
   113     public static final int T_CHAR                       = 0x00000005;
   114     public static final int T_FLOAT                      = 0x00000006;
   115     public static final int T_DOUBLE                     = 0x00000007;
   116     public static final int T_BYTE                       = 0x00000008;
   117     public static final int T_SHORT                      = 0x00000009;
   118     public static final int T_INT                        = 0x0000000a;
   119     public static final int T_LONG                       = 0x0000000b;
   120 
   121     /* Type codes for StackMap attribute */
   122     public static final int ITEM_Bogus      =0; // an unknown or uninitialized value
   123     public static final int ITEM_Integer    =1; // a 32-bit integer
   124     public static final int ITEM_Float      =2; // not used
   125     public static final int ITEM_Double     =3; // not used
   126     public static final int ITEM_Long       =4; // a 64-bit integer
   127     public static final int ITEM_Null       =5; // the type of null
   128     public static final int ITEM_InitObject =6; // "this" in constructor
   129     public static final int ITEM_Object     =7; // followed by 2-byte index of class name
   130     public static final int ITEM_NewObject  =8; // followed by 2-byte ref to "new"
   131 
   132     /* Constants used in StackMapTable attribute */
   133     public static final int SAME_FRAME_BOUND                  = 64;
   134     public static final int SAME_LOCALS_1_STACK_ITEM_BOUND    = 128;
   135     public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
   136     public static final int SAME_FRAME_EXTENDED               = 251;
   137     public static final int FULL_FRAME                        = 255;
   138 
   139     /* Opcodes */
   140     public static final int opc_dead                     = -2;
   141     public static final int opc_label                    = -1;
   142     public static final int opc_nop                      = 0;
   143     public static final int opc_aconst_null              = 1;
   144     public static final int opc_iconst_m1                = 2;
   145     public static final int opc_iconst_0                 = 3;
   146     public static final int opc_iconst_1                 = 4;
   147     public static final int opc_iconst_2                 = 5;
   148     public static final int opc_iconst_3                 = 6;
   149     public static final int opc_iconst_4                 = 7;
   150     public static final int opc_iconst_5                 = 8;
   151     public static final int opc_lconst_0                 = 9;
   152     public static final int opc_lconst_1                 = 10;
   153     public static final int opc_fconst_0                 = 11;
   154     public static final int opc_fconst_1                 = 12;
   155     public static final int opc_fconst_2                 = 13;
   156     public static final int opc_dconst_0                 = 14;
   157     public static final int opc_dconst_1                 = 15;
   158     public static final int opc_bipush                   = 16;
   159     public static final int opc_sipush                   = 17;
   160     public static final int opc_ldc                      = 18;
   161     public static final int opc_ldc_w                    = 19;
   162     public static final int opc_ldc2_w                   = 20;
   163     public static final int opc_iload                    = 21;
   164     public static final int opc_lload                    = 22;
   165     public static final int opc_fload                    = 23;
   166     public static final int opc_dload                    = 24;
   167     public static final int opc_aload                    = 25;
   168     public static final int opc_iload_0                  = 26;
   169     public static final int opc_iload_1                  = 27;
   170     public static final int opc_iload_2                  = 28;
   171     public static final int opc_iload_3                  = 29;
   172     public static final int opc_lload_0                  = 30;
   173     public static final int opc_lload_1                  = 31;
   174     public static final int opc_lload_2                  = 32;
   175     public static final int opc_lload_3                  = 33;
   176     public static final int opc_fload_0                  = 34;
   177     public static final int opc_fload_1                  = 35;
   178     public static final int opc_fload_2                  = 36;
   179     public static final int opc_fload_3                  = 37;
   180     public static final int opc_dload_0                  = 38;
   181     public static final int opc_dload_1                  = 39;
   182     public static final int opc_dload_2                  = 40;
   183     public static final int opc_dload_3                  = 41;
   184     public static final int opc_aload_0                  = 42;
   185     public static final int opc_aload_1                  = 43;
   186     public static final int opc_aload_2                  = 44;
   187     public static final int opc_aload_3                  = 45;
   188     public static final int opc_iaload                   = 46;
   189     public static final int opc_laload                   = 47;
   190     public static final int opc_faload                   = 48;
   191     public static final int opc_daload                   = 49;
   192     public static final int opc_aaload                   = 50;
   193     public static final int opc_baload                   = 51;
   194     public static final int opc_caload                   = 52;
   195     public static final int opc_saload                   = 53;
   196     public static final int opc_istore                   = 54;
   197     public static final int opc_lstore                   = 55;
   198     public static final int opc_fstore                   = 56;
   199     public static final int opc_dstore                   = 57;
   200     public static final int opc_astore                   = 58;
   201     public static final int opc_istore_0                 = 59;
   202     public static final int opc_istore_1                 = 60;
   203     public static final int opc_istore_2                 = 61;
   204     public static final int opc_istore_3                 = 62;
   205     public static final int opc_lstore_0                 = 63;
   206     public static final int opc_lstore_1                 = 64;
   207     public static final int opc_lstore_2                 = 65;
   208     public static final int opc_lstore_3                 = 66;
   209     public static final int opc_fstore_0                 = 67;
   210     public static final int opc_fstore_1                 = 68;
   211     public static final int opc_fstore_2                 = 69;
   212     public static final int opc_fstore_3                 = 70;
   213     public static final int opc_dstore_0                 = 71;
   214     public static final int opc_dstore_1                 = 72;
   215     public static final int opc_dstore_2                 = 73;
   216     public static final int opc_dstore_3                 = 74;
   217     public static final int opc_astore_0                 = 75;
   218     public static final int opc_astore_1                 = 76;
   219     public static final int opc_astore_2                 = 77;
   220     public static final int opc_astore_3                 = 78;
   221     public static final int opc_iastore                  = 79;
   222     public static final int opc_lastore                  = 80;
   223     public static final int opc_fastore                  = 81;
   224     public static final int opc_dastore                  = 82;
   225     public static final int opc_aastore                  = 83;
   226     public static final int opc_bastore                  = 84;
   227     public static final int opc_castore                  = 85;
   228     public static final int opc_sastore                  = 86;
   229     public static final int opc_pop                      = 87;
   230     public static final int opc_pop2                     = 88;
   231     public static final int opc_dup                      = 89;
   232     public static final int opc_dup_x1                   = 90;
   233     public static final int opc_dup_x2                   = 91;
   234     public static final int opc_dup2                     = 92;
   235     public static final int opc_dup2_x1                  = 93;
   236     public static final int opc_dup2_x2                  = 94;
   237     public static final int opc_swap                     = 95;
   238     public static final int opc_iadd                     = 96;
   239     public static final int opc_ladd                     = 97;
   240     public static final int opc_fadd                     = 98;
   241     public static final int opc_dadd                     = 99;
   242     public static final int opc_isub                     = 100;
   243     public static final int opc_lsub                     = 101;
   244     public static final int opc_fsub                     = 102;
   245     public static final int opc_dsub                     = 103;
   246     public static final int opc_imul                     = 104;
   247     public static final int opc_lmul                     = 105;
   248     public static final int opc_fmul                     = 106;
   249     public static final int opc_dmul                     = 107;
   250     public static final int opc_idiv                     = 108;
   251     public static final int opc_ldiv                     = 109;
   252     public static final int opc_fdiv                     = 110;
   253     public static final int opc_ddiv                     = 111;
   254     public static final int opc_irem                     = 112;
   255     public static final int opc_lrem                     = 113;
   256     public static final int opc_frem                     = 114;
   257     public static final int opc_drem                     = 115;
   258     public static final int opc_ineg                     = 116;
   259     public static final int opc_lneg                     = 117;
   260     public static final int opc_fneg                     = 118;
   261     public static final int opc_dneg                     = 119;
   262     public static final int opc_ishl                     = 120;
   263     public static final int opc_lshl                     = 121;
   264     public static final int opc_ishr                     = 122;
   265     public static final int opc_lshr                     = 123;
   266     public static final int opc_iushr                    = 124;
   267     public static final int opc_lushr                    = 125;
   268     public static final int opc_iand                     = 126;
   269     public static final int opc_land                     = 127;
   270     public static final int opc_ior                      = 128;
   271     public static final int opc_lor                      = 129;
   272     public static final int opc_ixor                     = 130;
   273     public static final int opc_lxor                     = 131;
   274     public static final int opc_iinc                     = 132;
   275     public static final int opc_i2l                      = 133;
   276     public static final int opc_i2f                      = 134;
   277     public static final int opc_i2d                      = 135;
   278     public static final int opc_l2i                      = 136;
   279     public static final int opc_l2f                      = 137;
   280     public static final int opc_l2d                      = 138;
   281     public static final int opc_f2i                      = 139;
   282     public static final int opc_f2l                      = 140;
   283     public static final int opc_f2d                      = 141;
   284     public static final int opc_d2i                      = 142;
   285     public static final int opc_d2l                      = 143;
   286     public static final int opc_d2f                      = 144;
   287     public static final int opc_i2b                      = 145;
   288     public static final int opc_int2byte                 = 145;
   289     public static final int opc_i2c                      = 146;
   290     public static final int opc_int2char                 = 146;
   291     public static final int opc_i2s                      = 147;
   292     public static final int opc_int2short                = 147;
   293     public static final int opc_lcmp                     = 148;
   294     public static final int opc_fcmpl                    = 149;
   295     public static final int opc_fcmpg                    = 150;
   296     public static final int opc_dcmpl                    = 151;
   297     public static final int opc_dcmpg                    = 152;
   298     public static final int opc_ifeq                     = 153;
   299     public static final int opc_ifne                     = 154;
   300     public static final int opc_iflt                     = 155;
   301     public static final int opc_ifge                     = 156;
   302     public static final int opc_ifgt                     = 157;
   303     public static final int opc_ifle                     = 158;
   304     public static final int opc_if_icmpeq                = 159;
   305     public static final int opc_if_icmpne                = 160;
   306     public static final int opc_if_icmplt                = 161;
   307     public static final int opc_if_icmpge                = 162;
   308     public static final int opc_if_icmpgt                = 163;
   309     public static final int opc_if_icmple                = 164;
   310     public static final int opc_if_acmpeq                = 165;
   311     public static final int opc_if_acmpne                = 166;
   312     public static final int opc_goto                     = 167;
   313     public static final int opc_jsr                      = 168;
   314     public static final int opc_ret                      = 169;
   315     public static final int opc_tableswitch              = 170;
   316     public static final int opc_lookupswitch             = 171;
   317     public static final int opc_ireturn                  = 172;
   318     public static final int opc_lreturn                  = 173;
   319     public static final int opc_freturn                  = 174;
   320     public static final int opc_dreturn                  = 175;
   321     public static final int opc_areturn                  = 176;
   322     public static final int opc_return                   = 177;
   323     public static final int opc_getstatic                = 178;
   324     public static final int opc_putstatic                = 179;
   325     public static final int opc_getfield                 = 180;
   326     public static final int opc_putfield                 = 181;
   327     public static final int opc_invokevirtual            = 182;
   328     public static final int opc_invokenonvirtual         = 183;
   329     public static final int opc_invokespecial            = 183;
   330     public static final int opc_invokestatic             = 184;
   331     public static final int opc_invokeinterface          = 185;
   332 //    public static final int opc_xxxunusedxxx             = 186;
   333     public static final int opc_new                      = 187;
   334     public static final int opc_newarray                 = 188;
   335     public static final int opc_anewarray                = 189;
   336     public static final int opc_arraylength              = 190;
   337     public static final int opc_athrow                   = 191;
   338     public static final int opc_checkcast                = 192;
   339     public static final int opc_instanceof               = 193;
   340     public static final int opc_monitorenter             = 194;
   341     public static final int opc_monitorexit              = 195;
   342     public static final int opc_wide                     = 196;
   343     public static final int opc_multianewarray           = 197;
   344     public static final int opc_ifnull                   = 198;
   345     public static final int opc_ifnonnull                = 199;
   346     public static final int opc_goto_w                   = 200;
   347     public static final int opc_jsr_w                    = 201;
   348         /* Pseudo-instructions */
   349     public static final int opc_bytecode                 = 203;
   350     public static final int opc_try                      = 204;
   351     public static final int opc_endtry                   = 205;
   352     public static final int opc_catch                    = 206;
   353     public static final int opc_var                      = 207;
   354     public static final int opc_endvar                   = 208;
   355     public static final int opc_localsmap                = 209;
   356     public static final int opc_stackmap                 = 210;
   357         /* PicoJava prefixes */
   358     public static final int opc_nonpriv                  = 254;
   359     public static final int opc_priv                     = 255;
   360 
   361         /* Wide instructions */
   362     public static final int opc_iload_w         = (opc_wide<<8)|opc_iload;
   363     public static final int opc_lload_w         = (opc_wide<<8)|opc_lload;
   364     public static final int opc_fload_w         = (opc_wide<<8)|opc_fload;
   365     public static final int opc_dload_w         = (opc_wide<<8)|opc_dload;
   366     public static final int opc_aload_w         = (opc_wide<<8)|opc_aload;
   367     public static final int opc_istore_w        = (opc_wide<<8)|opc_istore;
   368     public static final int opc_lstore_w        = (opc_wide<<8)|opc_lstore;
   369     public static final int opc_fstore_w        = (opc_wide<<8)|opc_fstore;
   370     public static final int opc_dstore_w        = (opc_wide<<8)|opc_dstore;
   371     public static final int opc_astore_w        = (opc_wide<<8)|opc_astore;
   372     public static final int opc_ret_w           = (opc_wide<<8)|opc_ret;
   373     public static final int opc_iinc_w          = (opc_wide<<8)|opc_iinc;
   374 
   375     /* Opcode Names */
   376   public static final String opcNamesTab[] = {
   377         "nop",
   378         "aconst_null",
   379         "iconst_m1",
   380         "iconst_0",
   381         "iconst_1",
   382         "iconst_2",
   383         "iconst_3",
   384         "iconst_4",
   385         "iconst_5",
   386         "lconst_0",
   387         "lconst_1",
   388         "fconst_0",
   389         "fconst_1",
   390         "fconst_2",
   391         "dconst_0",
   392         "dconst_1",
   393         "bipush",
   394         "sipush",
   395         "ldc",
   396         "ldc_w",
   397         "ldc2_w",
   398         "iload",
   399         "lload",
   400         "fload",
   401         "dload",
   402         "aload",
   403         "iload_0",
   404         "iload_1",
   405         "iload_2",
   406         "iload_3",
   407         "lload_0",
   408         "lload_1",
   409         "lload_2",
   410         "lload_3",
   411         "fload_0",
   412         "fload_1",
   413         "fload_2",
   414         "fload_3",
   415         "dload_0",
   416         "dload_1",
   417         "dload_2",
   418         "dload_3",
   419         "aload_0",
   420         "aload_1",
   421         "aload_2",
   422         "aload_3",
   423         "iaload",
   424         "laload",
   425         "faload",
   426         "daload",
   427         "aaload",
   428         "baload",
   429         "caload",
   430         "saload",
   431         "istore",
   432         "lstore",
   433         "fstore",
   434         "dstore",
   435         "astore",
   436         "istore_0",
   437         "istore_1",
   438         "istore_2",
   439         "istore_3",
   440         "lstore_0",
   441         "lstore_1",
   442         "lstore_2",
   443         "lstore_3",
   444         "fstore_0",
   445         "fstore_1",
   446         "fstore_2",
   447         "fstore_3",
   448         "dstore_0",
   449         "dstore_1",
   450         "dstore_2",
   451         "dstore_3",
   452         "astore_0",
   453         "astore_1",
   454         "astore_2",
   455         "astore_3",
   456         "iastore",
   457         "lastore",
   458         "fastore",
   459         "dastore",
   460         "aastore",
   461         "bastore",
   462         "castore",
   463         "sastore",
   464         "pop",
   465         "pop2",
   466         "dup",
   467         "dup_x1",
   468         "dup_x2",
   469         "dup2",
   470         "dup2_x1",
   471         "dup2_x2",
   472         "swap",
   473         "iadd",
   474         "ladd",
   475         "fadd",
   476         "dadd",
   477         "isub",
   478         "lsub",
   479         "fsub",
   480         "dsub",
   481         "imul",
   482         "lmul",
   483         "fmul",
   484         "dmul",
   485         "idiv",
   486         "ldiv",
   487         "fdiv",
   488         "ddiv",
   489         "irem",
   490         "lrem",
   491         "frem",
   492         "drem",
   493         "ineg",
   494         "lneg",
   495         "fneg",
   496         "dneg",
   497         "ishl",
   498         "lshl",
   499         "ishr",
   500         "lshr",
   501         "iushr",
   502         "lushr",
   503         "iand",
   504         "land",
   505         "ior",
   506         "lor",
   507         "ixor",
   508         "lxor",
   509         "iinc",
   510         "i2l",
   511         "i2f",
   512         "i2d",
   513         "l2i",
   514         "l2f",
   515         "l2d",
   516         "f2i",
   517         "f2l",
   518         "f2d",
   519         "d2i",
   520         "d2l",
   521         "d2f",
   522         "i2b",
   523         "i2c",
   524         "i2s",
   525         "lcmp",
   526         "fcmpl",
   527         "fcmpg",
   528         "dcmpl",
   529         "dcmpg",
   530         "ifeq",
   531         "ifne",
   532         "iflt",
   533         "ifge",
   534         "ifgt",
   535         "ifle",
   536         "if_icmpeq",
   537         "if_icmpne",
   538         "if_icmplt",
   539         "if_icmpge",
   540         "if_icmpgt",
   541         "if_icmple",
   542         "if_acmpeq",
   543         "if_acmpne",
   544         "goto",
   545         "jsr",
   546         "ret",
   547         "tableswitch",
   548         "lookupswitch",
   549         "ireturn",
   550         "lreturn",
   551         "freturn",
   552         "dreturn",
   553         "areturn",
   554         "return",
   555         "getstatic",
   556         "putstatic",
   557         "getfield",
   558         "putfield",
   559         "invokevirtual",
   560         "invokespecial", //     was "invokenonvirtual",
   561         "invokestatic",
   562         "invokeinterface",
   563         "bytecode 186", //"xxxunusedxxx",
   564         "new",
   565         "newarray",
   566         "anewarray",
   567         "arraylength",
   568         "athrow",
   569         "checkcast",
   570         "instanceof",
   571         "monitorenter",
   572         "monitorexit",
   573          null, // "wide",
   574         "multianewarray",
   575         "ifnull",
   576         "ifnonnull",
   577         "goto_w",
   578         "jsr_w",
   579         "bytecode 202", // "breakpoint",
   580         "bytecode",
   581         "try",
   582         "endtry",
   583         "catch",
   584         "var",
   585         "endvar",
   586         "locals_map",
   587         "stack_map"
   588   };
   589 
   590     /* Opcode Lengths */
   591   public static final int opcLengthsTab[] = {
   592         1,
   593         1,
   594         1,
   595         1,
   596         1,
   597         1,
   598         1,
   599         1,
   600         1,
   601         1,
   602         1,
   603         1,
   604         1,
   605         1,
   606         1,
   607         1,
   608         2,
   609         3,
   610         2,
   611         3,
   612         3,
   613         2,
   614         2,
   615         2,
   616         2,
   617         2,
   618         1,
   619         1,
   620         1,
   621         1,
   622         1,
   623         1,
   624         1,
   625         1,
   626         1,
   627         1,
   628         1,
   629         1,
   630         1,
   631         1,
   632         1,
   633         1,
   634         1,
   635         1,
   636         1,
   637         1,
   638         1,
   639         1,
   640         1,
   641         1,
   642         1,
   643         1,
   644         1,
   645         1,
   646         2,
   647         2,
   648         2,
   649         2,
   650         2,
   651         1,
   652         1,
   653         1,
   654         1,
   655         1,
   656         1,
   657         1,
   658         1,
   659         1,
   660         1,
   661         1,
   662         1,
   663         1,
   664         1,
   665         1,
   666         1,
   667         1,
   668         1,
   669         1,
   670         1,
   671         1,
   672         1,
   673         1,
   674         1,
   675         1,
   676         1,
   677         1,
   678         1,
   679         1,
   680         1,
   681         1,
   682         1,
   683         1,
   684         1,
   685         1,
   686         1,
   687         1,
   688         1,
   689         1,
   690         1,
   691         1,
   692         1,
   693         1,
   694         1,
   695         1,
   696         1,
   697         1,
   698         1,
   699         1,
   700         1,
   701         1,
   702         1,
   703         1,
   704         1,
   705         1,
   706         1,
   707         1,
   708         1,
   709         1,
   710         1,
   711         1,
   712         1,
   713         1,
   714         1,
   715         1,
   716         1,
   717         1,
   718         1,
   719         1,
   720         1,
   721         1,
   722         1,
   723         1,
   724         3,
   725         1,
   726         1,
   727         1,
   728         1,
   729         1,
   730         1,
   731         1,
   732         1,
   733         1,
   734         1,
   735         1,
   736         1,
   737         1,
   738         1,
   739         1,
   740         1,
   741         1,
   742         1,
   743         1,
   744         1,
   745         3,
   746         3,
   747         3,
   748         3,
   749         3,
   750         3,
   751         3,
   752         3,
   753         3,
   754         3,
   755         3,
   756         3,
   757         3,
   758         3,
   759         3,
   760         3,
   761         2,
   762         99,
   763         99,
   764         1,
   765         1,
   766         1,
   767         1,
   768         1,
   769         1,
   770         3,
   771         3,
   772         3,
   773         3,
   774         3,
   775         3,
   776         3,
   777         5,
   778         0,
   779         3,
   780         2,
   781         3,
   782         1,
   783         1,
   784         3,
   785         3,
   786         1,
   787         1,
   788         0, // wide
   789         4,
   790         3,
   791         3,
   792         5,
   793         5,
   794         1,
   795         1, 0, 0, 0, 0, 0 // pseudo
   796   };
   797 
   798      /**
   799      * End of input
   800      */
   801     public static final int EOF = -1;
   802 
   803    /*
   804      * Flags
   805      */
   806     public static final int F_VERBOSE           = 1 << 0;
   807     public static final int F_DUMP              = 1 << 1;
   808     public static final int F_WARNINGS          = 1 << 2;
   809     public static final int F_DEBUG             = 1 << 3;
   810     public static final int F_OPTIMIZE          = 1 << 4;
   811     public static final int F_DEPENDENCIES      = 1 << 5;
   812 
   813     /*
   814      * Type codes
   815      */
   816     public static final int TC_BOOLEAN   = 0;
   817     public static final int TC_BYTE      = 1;
   818     public static final int TC_CHAR      = 2;
   819     public static final int TC_SHORT     = 3;
   820     public static final int TC_INT       = 4;
   821     public static final int TC_LONG      = 5;
   822     public static final int TC_FLOAT     = 6;
   823     public static final int TC_DOUBLE    = 7;
   824     public static final int TC_NULL      = 8;
   825     public static final int TC_ARRAY     = 9;
   826     public static final int TC_CLASS     = 10;
   827     public static final int TC_VOID      = 11;
   828     public static final int TC_METHOD    = 12;
   829     public static final int TC_ERROR     = 13;
   830 
   831     /*
   832      * Type Masks
   833      */
   834     public static final int TM_NULL      = 1 << TC_NULL;
   835     public static final int TM_VOID      = 1 << TC_VOID;
   836     public static final int TM_BOOLEAN   = 1 << TC_BOOLEAN;
   837     public static final int TM_BYTE      = 1 << TC_BYTE;
   838     public static final int TM_CHAR      = 1 << TC_CHAR;
   839     public static final int TM_SHORT     = 1 << TC_SHORT;
   840     public static final int TM_INT       = 1 << TC_INT;
   841     public static final int TM_LONG      = 1 << TC_LONG;
   842     public static final int TM_FLOAT     = 1 << TC_FLOAT;
   843     public static final int TM_DOUBLE    = 1 << TC_DOUBLE;
   844     public static final int TM_ARRAY     = 1 << TC_ARRAY;
   845     public static final int TM_CLASS     = 1 << TC_CLASS;
   846     public static final int TM_METHOD    = 1 << TC_METHOD;
   847     public static final int TM_ERROR     = 1 << TC_ERROR;
   848 
   849     public static final int TM_INT32     = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT;
   850     public static final int TM_NUM32     = TM_INT32 | TM_FLOAT;
   851     public static final int TM_NUM64     = TM_LONG | TM_DOUBLE;
   852     public static final int TM_INTEGER   = TM_INT32 | TM_LONG;
   853     public static final int TM_REAL      = TM_FLOAT | TM_DOUBLE;
   854     public static final int TM_NUMBER    = TM_INTEGER | TM_REAL;
   855     public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL;
   856 
   857     /*
   858      * Class status
   859      */
   860     public static final int CS_UNDEFINED        = 0;
   861     public static final int CS_UNDECIDED        = 1;
   862     public static final int CS_BINARY           = 2;
   863     public static final int CS_SOURCE           = 3;
   864     public static final int CS_PARSED           = 4;
   865     public static final int CS_COMPILED         = 5;
   866     public static final int CS_NOTFOUND         = 6;
   867 
   868     /*
   869      * Attributes
   870      */
   871     public static final int ATT_ALL             = -1;
   872     public static final int ATT_CODE            = 1;
   873 
   874     /*
   875      * Number of bits used in file offsets
   876      */
   877     public static final int OFFSETBITS          = 19;
   878     public static final int MAXFILESIZE         = (1 << OFFSETBITS) - 1;
   879     public static final int MAXLINENUMBER       = (1 << (32 - OFFSETBITS)) - 1;
   880 
   881     /*
   882      * Operators
   883      */
   884     public final int COMMA              = 0;
   885     public final int ASSIGN             = 1;
   886 
   887     public final int ASGMUL             = 2;
   888     public final int ASGDIV             = 3;
   889     public final int ASGREM             = 4;
   890     public final int ASGADD             = 5;
   891     public final int ASGSUB             = 6;
   892     public final int ASGLSHIFT          = 7;
   893     public final int ASGRSHIFT          = 8;
   894     public final int ASGURSHIFT         = 9;
   895     public final int ASGBITAND          = 10;
   896     public final int ASGBITOR           = 11;
   897     public final int ASGBITXOR          = 12;
   898 
   899     public final int COND               = 13;
   900     public final int OR                 = 14;
   901     public final int AND                = 15;
   902     public final int BITOR              = 16;
   903     public final int BITXOR             = 17;
   904     public final int BITAND             = 18;
   905     public final int NE                 = 19;
   906     public final int EQ                 = 20;
   907     public final int GE                 = 21;
   908     public final int GT                 = 22;
   909     public final int LE                 = 23;
   910     public final int LT                 = 24;
   911     public final int INSTANCEOF         = 25;
   912     public final int LSHIFT             = 26;
   913     public final int RSHIFT             = 27;
   914     public final int URSHIFT            = 28;
   915     public final int ADD                = 29;
   916     public final int SUB                = 30;
   917     public final int DIV                = 31;
   918     public final int REM                = 32;
   919     public final int MUL                = 33;
   920     public final int CAST               = 34;           // (x)y
   921     public final int POS                = 35;           // +x
   922     public final int NEG                = 36;           // -x
   923     public final int NOT                = 37;
   924     public final int BITNOT             = 38;
   925     public final int PREINC             = 39;           // ++x
   926     public final int PREDEC             = 40;           // --x
   927     public final int NEWARRAY           = 41;
   928     public final int NEWINSTANCE        = 42;
   929     public final int NEWFROMNAME        = 43;
   930     public final int POSTINC            = 44;           // x++
   931     public final int POSTDEC            = 45;           // x--
   932     public final int FIELD              = 46;
   933     public final int METHOD             = 47;           // x(y)
   934     public final int ARRAYACCESS        = 48;           // x[y]
   935     public final int NEW                = 49;
   936     public final int INC                = 50;
   937     public final int DEC                = 51;
   938 
   939     public final int CONVERT            = 55;           // implicit conversion
   940     public final int EXPR               = 56;           // (x)
   941     public final int ARRAY              = 57;           // {x, y, ...}
   942     public final int GOTO               = 58;
   943 
   944     /*
   945      * Value tokens
   946      */
   947     public final int IDENT              = 60;
   948     public final int BOOLEANVAL         = 61;
   949     public final int BYTEVAL            = 62;
   950     public final int CHARVAL            = 63;
   951     public final int SHORTVAL           = 64;
   952     public final int INTVAL                     = 65;
   953     public final int LONGVAL            = 66;
   954     public final int FLOATVAL           = 67;
   955     public final int DOUBLEVAL          = 68;
   956     public final int STRINGVAL          = 69;
   957 
   958     /*
   959      * Type keywords
   960      */
   961     public final int BYTE               = 70;
   962     public final int CHAR               = 71;
   963     public final int SHORT              = 72;
   964     public final int INT                = 73;
   965     public final int LONG               = 74;
   966     public final int FLOAT              = 75;
   967     public final int DOUBLE             = 76;
   968     public final int VOID               = 77;
   969     public final int BOOLEAN            = 78;
   970 
   971     /*
   972      * Expression keywords
   973      */
   974     public final int TRUE               = 80;
   975     public final int FALSE              = 81;
   976     public final int THIS               = 82;
   977     public final int SUPER              = 83;
   978     public final int NULL               = 84;
   979 
   980     /*
   981      * Statement keywords
   982      */
   983     public final int IF                 = 90;
   984     public final int ELSE               = 91;
   985     public final int FOR                = 92;
   986     public final int WHILE              = 93;
   987     public final int DO                 = 94;
   988     public final int SWITCH             = 95;
   989     public final int CASE               = 96;
   990     public final int DEFAULT            = 97;
   991     public final int BREAK              = 98;
   992     public final int CONTINUE           = 99;
   993     public final int RETURN             = 100;
   994     public final int TRY                = 101;
   995     public final int CATCH              = 102;
   996     public final int FINALLY            = 103;
   997     public final int THROW              = 104;
   998     public final int STAT               = 105;
   999     public final int EXPRESSION         = 106;
  1000     public final int DECLARATION        = 107;
  1001     public final int VARDECLARATION     = 108;
  1002 
  1003     /*
  1004      * Declaration keywords
  1005      */
  1006     public final int IMPORT             = 110;
  1007     public final int CLASS              = 111;
  1008     public final int EXTENDS            = 112;
  1009     public final int IMPLEMENTS         = 113;
  1010     public final int INTERFACE          = 114;
  1011     public final int PACKAGE            = 115;
  1012 
  1013     /*
  1014      * Modifier keywords
  1015      */
  1016     public final int PRIVATE    = 120;
  1017     public final int PUBLIC             = 121;
  1018     public final int PROTECTED  = 122;
  1019     public final int CONST              = 123;
  1020     public final int STATIC             = 124;
  1021     public final int TRANSIENT          = 125;
  1022     public final int SYNCHRONIZED       = 126;
  1023     public final int NATIVE             = 127;
  1024     public final int FINAL              = 128;
  1025     public final int VOLATILE   = 129;
  1026     public final int ABSTRACT   = 130;
  1027     public final int STRICT             = 165;
  1028 
  1029     /*
  1030      * Punctuation
  1031      */
  1032     public final int SEMICOLON  = 135;
  1033     public final int COLON              = 136;
  1034     public final int QUESTIONMARK       = 137;
  1035     public final int LBRACE             = 138;
  1036     public final int RBRACE             = 139;
  1037     public final int LPAREN             = 140;
  1038     public final int RPAREN             = 141;
  1039     public final int LSQBRACKET = 142;
  1040     public final int RSQBRACKET = 143;
  1041     public final int THROWS     = 144;
  1042 
  1043     /*
  1044      * Special tokens
  1045      */
  1046     public final int ERROR              = 145;          // an error
  1047     public final int COMMENT    = 146;          // not used anymore.
  1048     public final int TYPE               = 147;
  1049     public final int LENGTH             = 148;
  1050     public final int INLINERETURN       = 149;
  1051     public final int INLINEMETHOD       = 150;
  1052     public final int INLINENEWINSTANCE  = 151;
  1053 
  1054     /*
  1055      * Added for jasm
  1056      */
  1057         public final int METHODREF      = 152;
  1058         public final int FIELDREF       = 153;
  1059     public final int STACK              = 154;
  1060     public final int LOCAL              = 155;
  1061     public final int CPINDEX    = 156;
  1062     public final int CPNAME             = 157;
  1063     public final int SIGN               = 158;
  1064     public final int BITS               = 159;
  1065     public final int INF                = 160;
  1066     public final int NAN                = 161;
  1067     public final int INNERCLASS = 162;
  1068     public final int OF         = 163;
  1069     public final int SYNTHETIC          = 164;
  1070 // last used=165;
  1071 
  1072    /*
  1073      * Operator precedence
  1074      */
  1075     public static final int opPrecedence[] = {
  1076         10,     11,     11,     11,     11,     11,     11,     11,     11,     11,
  1077         11,     11,     11,     12,     13,     14,     15,     16,     17,     18,
  1078         18,     19,     19,     19,     19,     19,     20,     20,     20,     21,
  1079         21,     22,     22,     22,     23,     24,     24,     24,     24,     24,
  1080         24,     25,     25,     26,     26,     26,     26,     26,     26
  1081     };
  1082 
  1083     /*
  1084      * Operator names
  1085      */
  1086     public static final String opNames[] = {
  1087         ",",            "=",            "*=",           "/=",           "%=",
  1088         "+=",           "-=",           "<<=",          ">>=",          "<<<=",
  1089         "&=",           "|=",           "^=",           "?:",           "||",
  1090         "&&",           "|",            "^",            "&",            "!=",
  1091         "==",           ">=",           ">",            "<=",           "<",
  1092         "instanceof",   "<<",           ">>",           "<<<",          "+",
  1093         "-",            "/",            "%",            "*",            "cast",
  1094         "+",            "-",            "!",            "~",            "++",
  1095         "--",           "new",          "new",          "new",          "++",
  1096         "--",           "field",        "method",       "[]",           "new",
  1097         "++",           "--",           null,           null,           null,
  1098 
  1099         "convert",      "expr",         "array",        "goto",         null,
  1100 
  1101         "Identifier",   "Boolean",      "Byte",         "Char",         "Short",
  1102         "Integer",              "Long",         "Float",        "Double",       "String",
  1103 
  1104         "byte",         "char",         "short",        "int",          "long",
  1105         "float",        "double",       "void",         "boolean",      null,
  1106 
  1107         "true",         "false",        "this",         "super",        "null",
  1108         null,           null,           null,           null,           null,
  1109 
  1110         "if",           "else",         "for",          "while",        "do",
  1111         "switch",       "case",         "default",      "break",        "continue",
  1112         "return",       "try",          "catch",        "finally",      "throw",
  1113         "stat",         "expression",   "declaration",  "declaration",  null,
  1114 
  1115         "import",       "class",        "extends",      "implements",   "interface",
  1116         "package",      null,           null,           null,           null,
  1117 
  1118         "private",      "public",       "protected",    "const",        "static",
  1119         "transient",    "synchronized", "native",       "final",        "volatile",
  1120         "abstract",     null,           null,           null,           null,
  1121 
  1122         ";",            ":",            "?",            "{",            "}",
  1123         "(",            ")",            "[",            "]",            "throws",
  1124         "error",        "comment",      "type",         "length",       "inline-return",
  1125         "inline-method", "inline-new",
  1126         "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN",
  1127         "bits", "INF", "NaN", "InnerClass", "of", "synthetic"
  1128     };
  1129     
  1130     static class AnnotationParser {
  1131 
  1132         private final boolean textual;
  1133         private final boolean iterateArray;
  1134 
  1135         protected AnnotationParser(boolean textual, boolean iterateArray) {
  1136             this.textual = textual;
  1137             this.iterateArray = iterateArray;
  1138         }
  1139 
  1140         protected void visitAnnotationStart(String type, boolean top) throws IOException {
  1141         }
  1142 
  1143         protected void visitAnnotationEnd(String type, boolean top) throws IOException {
  1144         }
  1145 
  1146         protected void visitValueStart(String attrName, char type) throws IOException {
  1147         }
  1148 
  1149         protected void visitValueEnd(String attrName, char type) throws IOException {
  1150         }
  1151 
  1152         protected void visitAttr(
  1153             String annoType, String attr, String attrType, String value) throws IOException {
  1154         }
  1155 
  1156         protected void visitEnumAttr(
  1157             String annoType, String attr, String attrType, String value) throws IOException {
  1158             visitAttr(annoType, attr, attrType, value);
  1159         }
  1160 
  1161         /**
  1162          * Initialize the parsing with constant pool from
  1163          * <code>cd</code>.
  1164          *
  1165          * @param attr the attribute defining annotations
  1166          * @param cd constant pool
  1167          * @throws IOException in case I/O fails
  1168          */
  1169         public final void parse(byte[] attr, ClassData cd) throws IOException {
  1170             ByteArrayInputStream is = new ByteArrayInputStream(attr);
  1171             DataInputStream dis = new DataInputStream(is);
  1172             try {
  1173                 read(dis, cd);
  1174             } finally {
  1175                 is.close();
  1176             }
  1177         }
  1178 
  1179         private void read(DataInputStream dis, ClassData cd) throws IOException {
  1180             int cnt = dis.readUnsignedShort();
  1181             for (int i = 0; i < cnt; i++) {
  1182                 readAnno(dis, cd, true);
  1183             }
  1184         }
  1185 
  1186         private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException {
  1187             int type = dis.readUnsignedShort();
  1188             String typeName = cd.StringValue(type);
  1189             visitAnnotationStart(typeName, top);
  1190             int cnt = dis.readUnsignedShort();
  1191             for (int i = 0; i < cnt; i++) {
  1192                 String attrName = cd.StringValue(dis.readUnsignedShort());
  1193                 readValue(dis, cd, typeName, attrName);
  1194             }
  1195             visitAnnotationEnd(typeName, top);
  1196             if (cnt == 0) {
  1197                 visitAttr(typeName, null, null, null);
  1198             }
  1199         }
  1200 
  1201         private void readValue(
  1202             DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException {
  1203             char type = (char) dis.readByte();
  1204             visitValueStart(attrName, type);
  1205             if (type == '@') {
  1206                 readAnno(dis, cd, false);
  1207             } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N
  1208                 int primitive = dis.readUnsignedShort();
  1209                 String val = cd.stringValue(primitive, textual);
  1210                 String attrType;
  1211                 if (type == 's') {
  1212                     attrType = "Ljava_lang_String_2";
  1213                     if (textual) {
  1214                         val = '"' + val + '"';
  1215                     }
  1216                 } else {
  1217                     attrType = "" + type;
  1218                 }
  1219                 visitAttr(typeName, attrName, attrType, val);
  1220             } else if (type == 'c') {
  1221                 int cls = dis.readUnsignedShort();
  1222             } else if (type == '[') {
  1223                 int cnt = dis.readUnsignedShort();
  1224                 for (int i = 0; i < cnt; i++) {
  1225                     readValue(dis, cd, typeName, iterateArray ? attrName : null);
  1226                 }
  1227             } else if (type == 'e') {
  1228                 int enumT = dis.readUnsignedShort();
  1229                 String attrType = cd.stringValue(enumT, textual);
  1230                 int enumN = dis.readUnsignedShort();
  1231                 String val = cd.stringValue(enumN, textual);
  1232                 visitEnumAttr(typeName, attrName, attrType, val);
  1233             } else {
  1234                 throw new IOException("Unknown type " + type);
  1235             }
  1236             visitValueEnd(attrName, type);
  1237         }
  1238     }
  1239     
  1240     /**
  1241      * Reads and stores attribute information.
  1242      *
  1243      * @author Sucheta Dambalkar (Adopted code from jdis)
  1244      */
  1245     private static class AttrData {
  1246 
  1247         ClassData cls;
  1248         int name_cpx;
  1249         int datalen;
  1250         byte data[];
  1251 
  1252         public AttrData(ClassData cls) {
  1253             this.cls = cls;
  1254         }
  1255 
  1256         /**
  1257          * Reads unknown attribute.
  1258          */
  1259         public void read(int name_cpx, DataInputStream in) throws IOException {
  1260             this.name_cpx = name_cpx;
  1261             datalen = in.readInt();
  1262             data = new byte[datalen];
  1263             in.readFully(data);
  1264         }
  1265 
  1266         /**
  1267          * Reads just the name of known attribute.
  1268          */
  1269         public void read(int name_cpx) {
  1270             this.name_cpx = name_cpx;
  1271         }
  1272 
  1273         /**
  1274          * Returns attribute name.
  1275          */
  1276         public String getAttrName() {
  1277             return cls.getString(name_cpx);
  1278         }
  1279 
  1280         /**
  1281          * Returns attribute data.
  1282          */
  1283         public byte[] getData() {
  1284             return data;
  1285         }
  1286     }
  1287 
  1288     /**
  1289      * Stores constant pool entry information with one field.
  1290      *
  1291      * @author Sucheta Dambalkar (Adopted code from jdis)
  1292      */
  1293     private static class CPX {
  1294 
  1295         int cpx;
  1296 
  1297         CPX(int cpx) {
  1298             this.cpx = cpx;
  1299         }
  1300     }
  1301 
  1302     /**
  1303      * Stores constant pool entry information with two fields.
  1304      *
  1305      * @author Sucheta Dambalkar (Adopted code from jdis)
  1306      */
  1307     private static class CPX2 {
  1308 
  1309         int cpx1, cpx2;
  1310 
  1311         CPX2(int cpx1, int cpx2) {
  1312             this.cpx1 = cpx1;
  1313             this.cpx2 = cpx2;
  1314         }
  1315     }
  1316 
  1317     /**
  1318      * Central data repository of the Java Disassembler. Stores all the
  1319      * information in java class file.
  1320      *
  1321      * @author Sucheta Dambalkar (Adopted code from jdis)
  1322      */
  1323     static final class ClassData {
  1324 
  1325         private int magic;
  1326         private int minor_version;
  1327         private int major_version;
  1328         private int cpool_count;
  1329         private Object cpool[];
  1330         private int access;
  1331         private int this_class = 0;
  1332         private int super_class;
  1333         private int interfaces_count;
  1334         private int[] interfaces = new int[0];
  1335         private int fields_count;
  1336         private FieldData[] fields;
  1337         private int methods_count;
  1338         private MethodData[] methods;
  1339         private InnerClassData[] innerClasses;
  1340         private int attributes_count;
  1341         private AttrData[] attrs;
  1342         private String classname;
  1343         private String superclassname;
  1344         private int source_cpx = 0;
  1345         private byte tags[];
  1346         private Hashtable indexHashAscii = new Hashtable();
  1347         private String pkgPrefix = "";
  1348         private int pkgPrefixLen = 0;
  1349 
  1350         /**
  1351          * Read classfile to disassemble.
  1352          */
  1353         public ClassData(InputStream infile) throws IOException {
  1354             this.read(new DataInputStream(infile));
  1355         }
  1356 
  1357         /**
  1358          * Reads and stores class file information.
  1359          */
  1360         public void read(DataInputStream in) throws IOException {
  1361             // Read the header
  1362             magic = in.readInt();
  1363             if (magic != JAVA_MAGIC) {
  1364                 throw new ClassFormatError("wrong magic: "
  1365                     + toHex(magic) + ", expected "
  1366                     + toHex(JAVA_MAGIC));
  1367             }
  1368             minor_version = in.readShort();
  1369             major_version = in.readShort();
  1370             if (major_version != JAVA_VERSION) {
  1371             }
  1372 
  1373             // Read the constant pool
  1374             readCP(in);
  1375             access = in.readUnsignedShort();
  1376             this_class = in.readUnsignedShort();
  1377             super_class = in.readUnsignedShort();
  1378 
  1379             //Read interfaces.
  1380             interfaces_count = in.readUnsignedShort();
  1381             if (interfaces_count > 0) {
  1382                 interfaces = new int[interfaces_count];
  1383             }
  1384             for (int i = 0; i < interfaces_count; i++) {
  1385                 interfaces[i] = in.readShort();
  1386             }
  1387 
  1388             // Read the fields
  1389             readFields(in);
  1390 
  1391             // Read the methods
  1392             readMethods(in);
  1393 
  1394             // Read the attributes
  1395             attributes_count = in.readUnsignedShort();
  1396             attrs = new AttrData[attributes_count];
  1397             for (int k = 0; k < attributes_count; k++) {
  1398                 int name_cpx = in.readUnsignedShort();
  1399                 if (getTag(name_cpx) == CONSTANT_UTF8
  1400                     && getString(name_cpx).equals("SourceFile")) {
  1401                     if (in.readInt() != 2) {
  1402                         throw new ClassFormatError("invalid attr length");
  1403                     }
  1404                     source_cpx = in.readUnsignedShort();
  1405                     AttrData attr = new AttrData(this);
  1406                     attr.read(name_cpx);
  1407                     attrs[k] = attr;
  1408 
  1409                 } else if (getTag(name_cpx) == CONSTANT_UTF8
  1410                     && getString(name_cpx).equals("InnerClasses")) {
  1411                     int length = in.readInt();
  1412                     int num = in.readUnsignedShort();
  1413                     if (2 + num * 8 != length) {
  1414                         throw new ClassFormatError("invalid attr length");
  1415                     }
  1416                     innerClasses = new InnerClassData[num];
  1417                     for (int j = 0; j < num; j++) {
  1418                         InnerClassData innerClass = new InnerClassData(this);
  1419                         innerClass.read(in);
  1420                         innerClasses[j] = innerClass;
  1421                     }
  1422                     AttrData attr = new AttrData(this);
  1423                     attr.read(name_cpx);
  1424                     attrs[k] = attr;
  1425                 } else {
  1426                     AttrData attr = new AttrData(this);
  1427                     attr.read(name_cpx, in);
  1428                     attrs[k] = attr;
  1429                 }
  1430             }
  1431             in.close();
  1432         } // end ClassData.read()
  1433 
  1434         /**
  1435          * Reads and stores constant pool info.
  1436          */
  1437         void readCP(DataInputStream in) throws IOException {
  1438             cpool_count = in.readUnsignedShort();
  1439             tags = new byte[cpool_count];
  1440             cpool = new Object[cpool_count];
  1441             for (int i = 1; i < cpool_count; i++) {
  1442                 byte tag = in.readByte();
  1443 
  1444                 switch (tags[i] = tag) {
  1445                     case CONSTANT_UTF8:
  1446                         String str = in.readUTF();
  1447                         indexHashAscii.put(cpool[i] = str, new Integer(i));
  1448                         break;
  1449                     case CONSTANT_INTEGER:
  1450                         cpool[i] = new Integer(in.readInt());
  1451                         break;
  1452                     case CONSTANT_FLOAT:
  1453                         cpool[i] = new Float(in.readFloat());
  1454                         break;
  1455                     case CONSTANT_LONG:
  1456                         cpool[i++] = new Long(in.readLong());
  1457                         break;
  1458                     case CONSTANT_DOUBLE:
  1459                         cpool[i++] = new Double(in.readDouble());
  1460                         break;
  1461                     case CONSTANT_CLASS:
  1462                     case CONSTANT_STRING:
  1463                         cpool[i] = new CPX(in.readUnsignedShort());
  1464                         break;
  1465 
  1466                     case CONSTANT_FIELD:
  1467                     case CONSTANT_METHOD:
  1468                     case CONSTANT_INTERFACEMETHOD:
  1469                     case CONSTANT_NAMEANDTYPE:
  1470                         cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
  1471                         break;
  1472 
  1473                     case 0:
  1474                     default:
  1475                         throw new ClassFormatError("invalid constant type: " + (int) tags[i]);
  1476                 }
  1477             }
  1478         }
  1479 
  1480         /**
  1481          * Reads and strores field info.
  1482          */
  1483         protected void readFields(DataInputStream in) throws IOException {
  1484             int fields_count = in.readUnsignedShort();
  1485             fields = new FieldData[fields_count];
  1486             for (int k = 0; k < fields_count; k++) {
  1487                 FieldData field = new FieldData(this);
  1488                 field.read(in);
  1489                 fields[k] = field;
  1490             }
  1491         }
  1492 
  1493         /**
  1494          * Reads and strores Method info.
  1495          */
  1496         protected void readMethods(DataInputStream in) throws IOException {
  1497             int methods_count = in.readUnsignedShort();
  1498             methods = new MethodData[methods_count];
  1499             for (int k = 0; k < methods_count; k++) {
  1500                 MethodData method = new MethodData(this);
  1501                 method.read(in);
  1502                 methods[k] = method;
  1503             }
  1504         }
  1505 
  1506         /**
  1507          * get a string
  1508          */
  1509         public String getString(int n) {
  1510             if (n == 0) {
  1511                 return null;
  1512             } else {
  1513                 return (String) cpool[n];
  1514             }
  1515         }
  1516 
  1517         /**
  1518          * get the type of constant given an index
  1519          */
  1520         public byte getTag(int n) {
  1521             try {
  1522                 return tags[n];
  1523             } catch (ArrayIndexOutOfBoundsException e) {
  1524                 return (byte) 100;
  1525             }
  1526         }
  1527         static final String hexString = "0123456789ABCDEF";
  1528         public static char hexTable[] = hexString.toCharArray();
  1529 
  1530         static String toHex(long val, int width) {
  1531             StringBuffer s = new StringBuffer();
  1532             for (int i = width - 1; i >= 0; i--) {
  1533                 s.append(hexTable[((int) (val >> (4 * i))) & 0xF]);
  1534             }
  1535             return "0x" + s.toString();
  1536         }
  1537 
  1538         static String toHex(long val) {
  1539             int width;
  1540             for (width = 16; width > 0; width--) {
  1541                 if ((val >> (width - 1) * 4) != 0) {
  1542                     break;
  1543                 }
  1544             }
  1545             return toHex(val, width);
  1546         }
  1547 
  1548         static String toHex(int val) {
  1549             int width;
  1550             for (width = 8; width > 0; width--) {
  1551                 if ((val >> (width - 1) * 4) != 0) {
  1552                     break;
  1553                 }
  1554             }
  1555             return toHex(val, width);
  1556         }
  1557 
  1558         /**
  1559          * Returns the name of this class.
  1560          */
  1561         public String getClassName() {
  1562             String res = null;
  1563             if (this_class == 0) {
  1564                 return res;
  1565             }
  1566             int tcpx;
  1567             try {
  1568                 if (tags[this_class] != CONSTANT_CLASS) {
  1569                     return res; //"<CP["+cpx+"] is not a Class> ";
  1570                 }
  1571                 tcpx = ((CPX) cpool[this_class]).cpx;
  1572             } catch (ArrayIndexOutOfBoundsException e) {
  1573                 return res; // "#"+cpx+"// invalid constant pool index";
  1574             } catch (Throwable e) {
  1575                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
  1576             }
  1577 
  1578             try {
  1579                 return (String) (cpool[tcpx]);
  1580             } catch (ArrayIndexOutOfBoundsException e) {
  1581                 return res; // "class #"+scpx+"// invalid constant pool index";
  1582             } catch (ClassCastException e) {
  1583                 return res; // "class #"+scpx+"// invalid constant pool reference";
  1584             } catch (Throwable e) {
  1585                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
  1586             }
  1587 
  1588         }
  1589 
  1590         /**
  1591          * Returns the name of class at perticular index.
  1592          */
  1593         public String getClassName(int cpx) {
  1594             String res = "#" + cpx;
  1595             if (cpx == 0) {
  1596                 return res;
  1597             }
  1598             int scpx;
  1599             try {
  1600                 if (tags[cpx] != CONSTANT_CLASS) {
  1601                     return res; //"<CP["+cpx+"] is not a Class> ";
  1602                 }
  1603                 scpx = ((CPX) cpool[cpx]).cpx;
  1604             } catch (ArrayIndexOutOfBoundsException e) {
  1605                 return res; // "#"+cpx+"// invalid constant pool index";
  1606             } catch (Throwable e) {
  1607                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
  1608             }
  1609             res = "#" + scpx;
  1610             try {
  1611                 return (String) (cpool[scpx]);
  1612             } catch (ArrayIndexOutOfBoundsException e) {
  1613                 return res; // "class #"+scpx+"// invalid constant pool index";
  1614             } catch (ClassCastException e) {
  1615                 return res; // "class #"+scpx+"// invalid constant pool reference";
  1616             } catch (Throwable e) {
  1617                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
  1618             }
  1619         }
  1620 
  1621         public int getAccessFlags() {
  1622             return access;
  1623         }
  1624 
  1625         /**
  1626          * Returns true if it is a class
  1627          */
  1628         public boolean isClass() {
  1629             if ((access & ACC_INTERFACE) == 0) {
  1630                 return true;
  1631             }
  1632             return false;
  1633         }
  1634 
  1635         /**
  1636          * Returns true if it is a interface.
  1637          */
  1638         public boolean isInterface() {
  1639             if ((access & ACC_INTERFACE) != 0) {
  1640                 return true;
  1641             }
  1642             return false;
  1643         }
  1644 
  1645         /**
  1646          * Returns true if this member is public, false otherwise.
  1647          */
  1648         public boolean isPublic() {
  1649             return (access & ACC_PUBLIC) != 0;
  1650         }
  1651 
  1652         /**
  1653          * Returns the access of this class or interface.
  1654          */
  1655         public String[] getAccess() {
  1656             Vector v = new Vector();
  1657             if ((access & ACC_PUBLIC) != 0) {
  1658                 v.addElement("public");
  1659             }
  1660             if ((access & ACC_FINAL) != 0) {
  1661                 v.addElement("final");
  1662             }
  1663             if ((access & ACC_ABSTRACT) != 0) {
  1664                 v.addElement("abstract");
  1665             }
  1666             String[] accflags = new String[v.size()];
  1667             v.copyInto(accflags);
  1668             return accflags;
  1669         }
  1670 
  1671         /**
  1672          * Returns list of innerclasses.
  1673          */
  1674         public InnerClassData[] getInnerClasses() {
  1675             return innerClasses;
  1676         }
  1677 
  1678         /**
  1679          * Returns list of attributes.
  1680          */
  1681         final AttrData[] getAttributes() {
  1682             return attrs;
  1683         }
  1684 
  1685         public byte[] findAnnotationData(boolean classRetention) {
  1686             String n = classRetention
  1687                 ? "RuntimeInvisibleAnnotations" : // NOI18N
  1688                 "RuntimeVisibleAnnotations"; // NOI18N
  1689             return findAttr(n, attrs);
  1690         }
  1691 
  1692         /**
  1693          * Returns true if superbit is set.
  1694          */
  1695         public boolean isSuperSet() {
  1696             if ((access & ACC_SUPER) != 0) {
  1697                 return true;
  1698             }
  1699             return false;
  1700         }
  1701 
  1702         /**
  1703          * Returns super class name.
  1704          */
  1705         public String getSuperClassName() {
  1706             String res = null;
  1707             if (super_class == 0) {
  1708                 return res;
  1709             }
  1710             int scpx;
  1711             try {
  1712                 if (tags[super_class] != CONSTANT_CLASS) {
  1713                     return res; //"<CP["+cpx+"] is not a Class> ";
  1714                 }
  1715                 scpx = ((CPX) cpool[super_class]).cpx;
  1716             } catch (ArrayIndexOutOfBoundsException e) {
  1717                 return res; // "#"+cpx+"// invalid constant pool index";
  1718             } catch (Throwable e) {
  1719                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
  1720             }
  1721 
  1722             try {
  1723                 return (String) (cpool[scpx]);
  1724             } catch (ArrayIndexOutOfBoundsException e) {
  1725                 return res; // "class #"+scpx+"// invalid constant pool index";
  1726             } catch (ClassCastException e) {
  1727                 return res; // "class #"+scpx+"// invalid constant pool reference";
  1728             } catch (Throwable e) {
  1729                 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
  1730             }
  1731         }
  1732 
  1733         /**
  1734          * Returns list of super interfaces.
  1735          */
  1736         public String[] getSuperInterfaces() {
  1737             String interfacenames[] = new String[interfaces.length];
  1738             int interfacecpx = -1;
  1739             for (int i = 0; i < interfaces.length; i++) {
  1740                 interfacecpx = ((CPX) cpool[interfaces[i]]).cpx;
  1741                 interfacenames[i] = (String) (cpool[interfacecpx]);
  1742             }
  1743             return interfacenames;
  1744         }
  1745 
  1746         /**
  1747          * Returns string at prticular constant pool index.
  1748          */
  1749         public String getStringValue(int cpoolx) {
  1750             try {
  1751                 return ((String) cpool[cpoolx]);
  1752             } catch (ArrayIndexOutOfBoundsException e) {
  1753                 return "//invalid constant pool index:" + cpoolx;
  1754             } catch (ClassCastException e) {
  1755                 return "//invalid constant pool ref:" + cpoolx;
  1756             }
  1757         }
  1758 
  1759         /**
  1760          * Returns list of field info.
  1761          */
  1762         public FieldData[] getFields() {
  1763             return fields;
  1764         }
  1765 
  1766         /**
  1767          * Returns list of method info.
  1768          */
  1769         public MethodData[] getMethods() {
  1770             return methods;
  1771         }
  1772 
  1773         /**
  1774          * Returns constant pool entry at that index.
  1775          */
  1776         public CPX2 getCpoolEntry(int cpx) {
  1777             return ((CPX2) (cpool[cpx]));
  1778         }
  1779 
  1780         public Object getCpoolEntryobj(int cpx) {
  1781             return (cpool[cpx]);
  1782         }
  1783 
  1784         /**
  1785          * Returns index of this class.
  1786          */
  1787         public int getthis_cpx() {
  1788             return this_class;
  1789         }
  1790 
  1791         /**
  1792          * Returns string at that index.
  1793          */
  1794         public String StringValue(int cpx) {
  1795             return stringValue(cpx, false);
  1796         }
  1797 
  1798         public String stringValue(int cpx, boolean textual) {
  1799             return stringValue(cpx, textual, null);
  1800         }
  1801 
  1802         public String stringValue(int cpx, String[] classRefs) {
  1803             return stringValue(cpx, true, classRefs);
  1804         }
  1805 
  1806         private String stringValue(int cpx, boolean textual, String[] refs) {
  1807             if (cpx == 0) {
  1808                 return "#0";
  1809             }
  1810             int tag;
  1811             Object x;
  1812             String suffix = "";
  1813             try {
  1814                 tag = tags[cpx];
  1815                 x = cpool[cpx];
  1816             } catch (IndexOutOfBoundsException e) {
  1817                 return "<Incorrect CP index:" + cpx + ">";
  1818             }
  1819 
  1820             if (x == null) {
  1821                 return "<NULL>";
  1822             }
  1823             switch (tag) {
  1824                 case CONSTANT_UTF8: {
  1825                     if (!textual) {
  1826                         return (String) x;
  1827                     }
  1828                     StringBuilder sb = new StringBuilder();
  1829                     String s = (String) x;
  1830                     for (int k = 0; k < s.length(); k++) {
  1831                         char c = s.charAt(k);
  1832                         switch (c) {
  1833                             case '\\':
  1834                                 sb.append('\\').append('\\');
  1835                                 break;
  1836                             case '\t':
  1837                                 sb.append('\\').append('t');
  1838                                 break;
  1839                             case '\n':
  1840                                 sb.append('\\').append('n');
  1841                                 break;
  1842                             case '\r':
  1843                                 sb.append('\\').append('r');
  1844                                 break;
  1845                             case '\"':
  1846                                 sb.append('\\').append('\"');
  1847                                 break;
  1848                             case '\u2028':
  1849                                 sb.append("\\u2028");
  1850                                 break;
  1851                             case '\u2029':
  1852                                 sb.append("\\u2029");
  1853                                 break;
  1854                             default:
  1855                                 sb.append(c);
  1856                         }
  1857                     }
  1858                     return sb.toString();
  1859                 }
  1860                 case CONSTANT_DOUBLE: {
  1861                     Double d = (Double) x;
  1862                     String sd = d.toString();
  1863                     if (textual) {
  1864                         return sd;
  1865                     }
  1866                     return sd + "d";
  1867                 }
  1868                 case CONSTANT_FLOAT: {
  1869                     Float f = (Float) x;
  1870                     String sf = (f).toString();
  1871                     if (textual) {
  1872                         return sf;
  1873                     }
  1874                     return sf + "f";
  1875                 }
  1876                 case CONSTANT_LONG: {
  1877                     Long ln = (Long) x;
  1878                     if (textual) {
  1879                         return ln.toString();
  1880                     }
  1881                     return ln.toString() + 'l';
  1882                 }
  1883                 case CONSTANT_INTEGER: {
  1884                     Integer in = (Integer) x;
  1885                     return in.toString();
  1886                 }
  1887                 case CONSTANT_CLASS:
  1888                     String jn = getClassName(cpx);
  1889                     if (textual) {
  1890                         if (refs != null) {
  1891                             refs[0] = jn;
  1892                         }
  1893                         return jn;
  1894                     }
  1895                     return javaName(jn);
  1896                 case CONSTANT_STRING:
  1897                     String sv = stringValue(((CPX) x).cpx, textual);
  1898                     if (textual) {
  1899                         return '"' + sv + '"';
  1900                     } else {
  1901                         return sv;
  1902                     }
  1903                 case CONSTANT_FIELD:
  1904                 case CONSTANT_METHOD:
  1905                 case CONSTANT_INTERFACEMETHOD:
  1906                     //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
  1907                     return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2);
  1908 
  1909                 case CONSTANT_NAMEANDTYPE:
  1910                     return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2);
  1911                 default:
  1912                     return "UnknownTag"; //TBD
  1913             }
  1914         }
  1915 
  1916         /**
  1917          * Returns resolved java type name.
  1918          */
  1919         public String javaName(String name) {
  1920             if (name == null) {
  1921                 return "null";
  1922             }
  1923             int len = name.length();
  1924             if (len == 0) {
  1925                 return "\"\"";
  1926             }
  1927             int cc = '/';
  1928             fullname:
  1929             { // xxx/yyy/zzz
  1930                 int cp;
  1931                 for (int k = 0; k < len; k += Character.charCount(cp)) {
  1932                     cp = name.codePointAt(k);
  1933                     if (cc == '/') {
  1934                         if (!isJavaIdentifierStart(cp)) {
  1935                             break fullname;
  1936                         }
  1937                     } else if (cp != '/') {
  1938                         if (!isJavaIdentifierPart(cp)) {
  1939                             break fullname;
  1940                         }
  1941                     }
  1942                     cc = cp;
  1943                 }
  1944                 return name;
  1945             }
  1946             return "\"" + name + "\"";
  1947         }
  1948 
  1949         public String getName(int cpx) {
  1950             String res;
  1951             try {
  1952                 return javaName((String) cpool[cpx]); //.replace('/','.');
  1953             } catch (ArrayIndexOutOfBoundsException e) {
  1954                 return "<invalid constant pool index:" + cpx + ">";
  1955             } catch (ClassCastException e) {
  1956                 return "<invalid constant pool ref:" + cpx + ">";
  1957             }
  1958         }
  1959 
  1960         /**
  1961          * Returns unqualified class name.
  1962          */
  1963         public String getShortClassName(int cpx) {
  1964             String classname = javaName(getClassName(cpx));
  1965             pkgPrefixLen = classname.lastIndexOf("/") + 1;
  1966             if (pkgPrefixLen != 0) {
  1967                 pkgPrefix = classname.substring(0, pkgPrefixLen);
  1968                 if (classname.startsWith(pkgPrefix)) {
  1969                     return classname.substring(pkgPrefixLen);
  1970                 }
  1971             }
  1972             return classname;
  1973         }
  1974 
  1975         /**
  1976          * Returns source file name.
  1977          */
  1978         public String getSourceName() {
  1979             return getName(source_cpx);
  1980         }
  1981 
  1982         /**
  1983          * Returns package name.
  1984          */
  1985         public String getPkgName() {
  1986             String classname = getClassName(this_class);
  1987             pkgPrefixLen = classname.lastIndexOf("/") + 1;
  1988             if (pkgPrefixLen != 0) {
  1989                 pkgPrefix = classname.substring(0, pkgPrefixLen);
  1990                 return ("package  " + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";\n");
  1991             } else {
  1992                 return null;
  1993             }
  1994         }
  1995 
  1996         /**
  1997          * Returns total constant pool entry count.
  1998          */
  1999         public int getCpoolCount() {
  2000             return cpool_count;
  2001         }
  2002 
  2003         /**
  2004          * Returns minor version of class file.
  2005          */
  2006         public int getMinor_version() {
  2007             return minor_version;
  2008         }
  2009 
  2010         /**
  2011          * Returns major version of class file.
  2012          */
  2013         public int getMajor_version() {
  2014             return major_version;
  2015         }
  2016 
  2017         private boolean isJavaIdentifierStart(int cp) {
  2018             return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
  2019         }
  2020 
  2021         private boolean isJavaIdentifierPart(int cp) {
  2022             return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
  2023         }
  2024 
  2025         public String[] getNameAndType(int indx) {
  2026             return getNameAndType(indx, 0, new String[2]);
  2027         }
  2028 
  2029         private String[] getNameAndType(int indx, int at, String[] arr) {
  2030             CPX2 c2 = getCpoolEntry(indx);
  2031             arr[at] = StringValue(c2.cpx1);
  2032             arr[at + 1] = StringValue(c2.cpx2);
  2033             return arr;
  2034         }
  2035 
  2036         public String[] getFieldInfoName(int indx) {
  2037             CPX2 c2 = getCpoolEntry(indx);
  2038             String[] arr = new String[3];
  2039             arr[0] = getClassName(c2.cpx1);
  2040             return getNameAndType(c2.cpx2, 1, arr);
  2041         }
  2042 
  2043         static byte[] findAttr(String n, AttrData[] attrs) {
  2044             for (AttrData ad : attrs) {
  2045                 if (n.equals(ad.getAttrName())) {
  2046                     return ad.getData();
  2047                 }
  2048             }
  2049             return null;
  2050         }
  2051     }
  2052 
  2053     /**
  2054      * Strores field data informastion.
  2055      *
  2056      * @author Sucheta Dambalkar (Adopted code from jdis)
  2057      */
  2058     static class FieldData {
  2059 
  2060         ClassData cls;
  2061         int access;
  2062         int name_index;
  2063         int descriptor_index;
  2064         int attributes_count;
  2065         int value_cpx = 0;
  2066         boolean isSynthetic = false;
  2067         boolean isDeprecated = false;
  2068         Vector attrs;
  2069 
  2070         public FieldData(ClassData cls) {
  2071             this.cls = cls;
  2072         }
  2073 
  2074         /**
  2075          * Read and store field info.
  2076          */
  2077         public void read(DataInputStream in) throws IOException {
  2078             access = in.readUnsignedShort();
  2079             name_index = in.readUnsignedShort();
  2080             descriptor_index = in.readUnsignedShort();
  2081             // Read the attributes
  2082             int attributes_count = in.readUnsignedShort();
  2083             attrs = new Vector(attributes_count);
  2084             for (int i = 0; i < attributes_count; i++) {
  2085                 int attr_name_index = in.readUnsignedShort();
  2086                 if (cls.getTag(attr_name_index) != CONSTANT_UTF8) {
  2087                     continue;
  2088                 }
  2089                 String attr_name = cls.getString(attr_name_index);
  2090                 if (attr_name.equals("ConstantValue")) {
  2091                     if (in.readInt() != 2) {
  2092                         throw new ClassFormatError("invalid ConstantValue attr length");
  2093                     }
  2094                     value_cpx = in.readUnsignedShort();
  2095                     AttrData attr = new AttrData(cls);
  2096                     attr.read(attr_name_index);
  2097                     attrs.addElement(attr);
  2098                 } else if (attr_name.equals("Synthetic")) {
  2099                     if (in.readInt() != 0) {
  2100                         throw new ClassFormatError("invalid Synthetic attr length");
  2101                     }
  2102                     isSynthetic = true;
  2103                     AttrData attr = new AttrData(cls);
  2104                     attr.read(attr_name_index);
  2105                     attrs.addElement(attr);
  2106                 } else if (attr_name.equals("Deprecated")) {
  2107                     if (in.readInt() != 0) {
  2108                         throw new ClassFormatError("invalid Synthetic attr length");
  2109                     }
  2110                     isDeprecated = true;
  2111                     AttrData attr = new AttrData(cls);
  2112                     attr.read(attr_name_index);
  2113                     attrs.addElement(attr);
  2114                 } else {
  2115                     AttrData attr = new AttrData(cls);
  2116                     attr.read(attr_name_index, in);
  2117                     attrs.addElement(attr);
  2118                 }
  2119             }
  2120 
  2121         }  // end read
  2122 
  2123         public boolean isStatic() {
  2124             return (access & ACC_STATIC) != 0;
  2125         }
  2126 
  2127         /**
  2128          * Returns access of a field.
  2129          */
  2130         public String[] getAccess() {
  2131             Vector v = new Vector();
  2132             if ((access & ACC_PUBLIC) != 0) {
  2133                 v.addElement("public");
  2134             }
  2135             if ((access & ACC_PRIVATE) != 0) {
  2136                 v.addElement("private");
  2137             }
  2138             if ((access & ACC_PROTECTED) != 0) {
  2139                 v.addElement("protected");
  2140             }
  2141             if ((access & ACC_STATIC) != 0) {
  2142                 v.addElement("static");
  2143             }
  2144             if ((access & ACC_FINAL) != 0) {
  2145                 v.addElement("final");
  2146             }
  2147             if ((access & ACC_VOLATILE) != 0) {
  2148                 v.addElement("volatile");
  2149             }
  2150             if ((access & ACC_TRANSIENT) != 0) {
  2151                 v.addElement("transient");
  2152             }
  2153             String[] accflags = new String[v.size()];
  2154             v.copyInto(accflags);
  2155             return accflags;
  2156         }
  2157 
  2158         /**
  2159          * Returns name of a field.
  2160          */
  2161         public String getName() {
  2162             return cls.getStringValue(name_index);
  2163         }
  2164 
  2165         /**
  2166          * Returns internal signature of a field
  2167          */
  2168         public String getInternalSig() {
  2169             return cls.getStringValue(descriptor_index);
  2170         }
  2171 
  2172         /**
  2173          * Returns true if field is synthetic.
  2174          */
  2175         public boolean isSynthetic() {
  2176             return isSynthetic;
  2177         }
  2178 
  2179         /**
  2180          * Returns true if field is deprecated.
  2181          */
  2182         public boolean isDeprecated() {
  2183             return isDeprecated;
  2184         }
  2185 
  2186         /**
  2187          * Returns index of constant value in cpool.
  2188          */
  2189         public int getConstantValueIndex() {
  2190             return (value_cpx);
  2191         }
  2192 
  2193         /**
  2194          * Returns list of attributes of field.
  2195          */
  2196         public Vector getAttributes() {
  2197             return attrs;
  2198         }
  2199 
  2200         public byte[] findAnnotationData(boolean classRetention) {
  2201             String n = classRetention
  2202                 ? "RuntimeInvisibleAnnotations" : // NOI18N
  2203                 "RuntimeVisibleAnnotations"; // NOI18N
  2204             AttrData[] arr = new AttrData[attrs.size()];
  2205             attrs.copyInto(arr);
  2206             return ClassData.findAttr(n, arr);
  2207         }
  2208     }
  2209 
  2210     /**
  2211      * A JavaScript optimized replacement for Hashtable.
  2212      *
  2213      * @author Jaroslav Tulach <jtulach@netbeans.org>
  2214      */
  2215     private static final class Hashtable {
  2216 
  2217         private Object[] keys;
  2218         private Object[] values;
  2219 
  2220         Hashtable(int i) {
  2221             this();
  2222         }
  2223 
  2224         Hashtable(int i, double d) {
  2225             this();
  2226         }
  2227 
  2228         Hashtable() {
  2229         }
  2230 
  2231         synchronized void put(Object key, Object val) {
  2232             int[] where = {-1, -1};
  2233             Object found = get(key, where);
  2234             if (where[0] != -1) {
  2235                 // key exists
  2236                 values[where[0]] = val;
  2237             } else {
  2238                 if (where[1] != -1) {
  2239                     // null found
  2240                     keys[where[1]] = key;
  2241                     values[where[1]] = val;
  2242                 } else {
  2243                     if (keys == null) {
  2244                         keys = new Object[11];
  2245                         values = new Object[11];
  2246                         keys[0] = key;
  2247                         values[0] = val;
  2248                     } else {
  2249                         Object[] newKeys = new Object[keys.length * 2];
  2250                         Object[] newValues = new Object[values.length * 2];
  2251                         for (int i = 0; i < keys.length; i++) {
  2252                             newKeys[i] = keys[i];
  2253                             newValues[i] = values[i];
  2254                         }
  2255                         newKeys[keys.length] = key;
  2256                         newValues[keys.length] = val;
  2257                         keys = newKeys;
  2258                         values = newValues;
  2259                     }
  2260                 }
  2261             }
  2262         }
  2263 
  2264         Object get(Object key) {
  2265             return get(key, null);
  2266         }
  2267 
  2268         private synchronized Object get(Object key, int[] foundAndNull) {
  2269             if (keys == null) {
  2270                 return null;
  2271             }
  2272             for (int i = 0; i < keys.length; i++) {
  2273                 if (keys[i] == null) {
  2274                     if (foundAndNull != null) {
  2275                         foundAndNull[1] = i;
  2276                     }
  2277                 } else if (keys[i].equals(key)) {
  2278                     if (foundAndNull != null) {
  2279                         foundAndNull[0] = i;
  2280                     }
  2281                     return values[i];
  2282                 }
  2283             }
  2284             return null;
  2285         }
  2286     }
  2287 
  2288     /**
  2289      * Strores InnerClass data informastion.
  2290      *
  2291      * @author Sucheta Dambalkar (Adopted code from jdis)
  2292      */
  2293     private static class InnerClassData {
  2294 
  2295         ClassData cls;
  2296         int inner_class_info_index, outer_class_info_index, inner_name_index, access;
  2297 
  2298         public InnerClassData(ClassData cls) {
  2299             this.cls = cls;
  2300 
  2301         }
  2302 
  2303         /**
  2304          * Read Innerclass attribute data.
  2305          */
  2306         public void read(DataInputStream in) throws IOException {
  2307             inner_class_info_index = in.readUnsignedShort();
  2308             outer_class_info_index = in.readUnsignedShort();
  2309             inner_name_index = in.readUnsignedShort();
  2310             access = in.readUnsignedShort();
  2311         }  // end read
  2312 
  2313         /**
  2314          * Returns the access of this class or interface.
  2315          */
  2316         public String[] getAccess() {
  2317             Vector v = new Vector();
  2318             if ((access & ACC_PUBLIC) != 0) {
  2319                 v.addElement("public");
  2320             }
  2321             if ((access & ACC_FINAL) != 0) {
  2322                 v.addElement("final");
  2323             }
  2324             if ((access & ACC_ABSTRACT) != 0) {
  2325                 v.addElement("abstract");
  2326             }
  2327             String[] accflags = new String[v.size()];
  2328             v.copyInto(accflags);
  2329             return accflags;
  2330         }
  2331     } // end InnerClassData
  2332 
  2333     /**
  2334      * Strores LineNumberTable data information.
  2335      *
  2336      * @author Sucheta Dambalkar (Adopted code from jdis)
  2337      */
  2338     private static class LineNumData {
  2339 
  2340         short start_pc, line_number;
  2341 
  2342         public LineNumData() {
  2343         }
  2344 
  2345         /**
  2346          * Read LineNumberTable attribute.
  2347          */
  2348         public LineNumData(DataInputStream in) throws IOException {
  2349             start_pc = in.readShort();
  2350             line_number = in.readShort();
  2351 
  2352         }
  2353     }
  2354 
  2355     /**
  2356      * Strores LocalVariableTable data information.
  2357      *
  2358      * @author Sucheta Dambalkar (Adopted code from jdis)
  2359      */
  2360     private static class LocVarData {
  2361 
  2362         short start_pc, length, name_cpx, sig_cpx, slot;
  2363 
  2364         public LocVarData() {
  2365         }
  2366 
  2367         /**
  2368          * Read LocalVariableTable attribute.
  2369          */
  2370         public LocVarData(DataInputStream in) throws IOException {
  2371             start_pc = in.readShort();
  2372             length = in.readShort();
  2373             name_cpx = in.readShort();
  2374             sig_cpx = in.readShort();
  2375             slot = in.readShort();
  2376 
  2377         }
  2378     }
  2379     /**
  2380      * Strores method data informastion.
  2381      *
  2382      * @author Sucheta Dambalkar (Adopted code from jdis)
  2383      */
  2384     static class MethodData {
  2385 
  2386         ClassData cls;
  2387         int access;
  2388         int name_index;
  2389         int descriptor_index;
  2390         int attributes_count;
  2391         byte[] code;
  2392         Vector exception_table = new Vector(0);
  2393         Vector lin_num_tb = new Vector(0);
  2394         Vector loc_var_tb = new Vector(0);
  2395         StackMapTableData[] stackMapTable;
  2396         StackMapData[] stackMap;
  2397         int[] exc_index_table = null;
  2398         Vector attrs = new Vector(0);
  2399         Vector code_attrs = new Vector(0);
  2400         int max_stack, max_locals;
  2401         boolean isSynthetic = false;
  2402         boolean isDeprecated = false;
  2403 
  2404         public MethodData(ClassData cls) {
  2405             this.cls = cls;
  2406         }
  2407 
  2408         /**
  2409          * Read method info.
  2410          */
  2411         public void read(DataInputStream in) throws IOException {
  2412             access = in.readUnsignedShort();
  2413             name_index = in.readUnsignedShort();
  2414             descriptor_index = in.readUnsignedShort();
  2415             int attributes_count = in.readUnsignedShort();
  2416             for (int i = 0; i < attributes_count; i++) {
  2417                 int attr_name_index = in.readUnsignedShort();
  2418 
  2419                 readAttr:
  2420                 {
  2421                     if (cls.getTag(attr_name_index) == CONSTANT_UTF8) {
  2422                         String attr_name = cls.getString(attr_name_index);
  2423                         if (attr_name.equals("Code")) {
  2424                             readCode(in);
  2425                             AttrData attr = new AttrData(cls);
  2426                             attr.read(attr_name_index);
  2427                             attrs.addElement(attr);
  2428                             break readAttr;
  2429                         } else if (attr_name.equals("Exceptions")) {
  2430                             readExceptions(in);
  2431                             AttrData attr = new AttrData(cls);
  2432                             attr.read(attr_name_index);
  2433                             attrs.addElement(attr);
  2434                             break readAttr;
  2435                         } else if (attr_name.equals("Synthetic")) {
  2436                             if (in.readInt() != 0) {
  2437                                 throw new ClassFormatError("invalid Synthetic attr length");
  2438                             }
  2439                             isSynthetic = true;
  2440                             AttrData attr = new AttrData(cls);
  2441                             attr.read(attr_name_index);
  2442                             attrs.addElement(attr);
  2443                             break readAttr;
  2444                         } else if (attr_name.equals("Deprecated")) {
  2445                             if (in.readInt() != 0) {
  2446                                 throw new ClassFormatError("invalid Synthetic attr length");
  2447                             }
  2448                             isDeprecated = true;
  2449                             AttrData attr = new AttrData(cls);
  2450                             attr.read(attr_name_index);
  2451                             attrs.addElement(attr);
  2452                             break readAttr;
  2453                         }
  2454                     }
  2455                     AttrData attr = new AttrData(cls);
  2456                     attr.read(attr_name_index, in);
  2457                     attrs.addElement(attr);
  2458                 }
  2459             }
  2460         }
  2461 
  2462         /**
  2463          * Read code attribute info.
  2464          */
  2465         public void readCode(DataInputStream in) throws IOException {
  2466 
  2467             int attr_length = in.readInt();
  2468             max_stack = in.readUnsignedShort();
  2469             max_locals = in.readUnsignedShort();
  2470             int codelen = in.readInt();
  2471 
  2472             code = new byte[codelen];
  2473             int totalread = 0;
  2474             while (totalread < codelen) {
  2475                 totalread += in.read(code, totalread, codelen - totalread);
  2476             }
  2477             //      in.read(code, 0, codelen);
  2478             int clen = 0;
  2479             readExceptionTable(in);
  2480             int code_attributes_count = in.readUnsignedShort();
  2481 
  2482             for (int k = 0; k < code_attributes_count; k++) {
  2483                 int table_name_index = in.readUnsignedShort();
  2484                 int table_name_tag = cls.getTag(table_name_index);
  2485                 AttrData attr = new AttrData(cls);
  2486                 if (table_name_tag == CONSTANT_UTF8) {
  2487                     String table_name_tstr = cls.getString(table_name_index);
  2488                     if (table_name_tstr.equals("LineNumberTable")) {
  2489                         readLineNumTable(in);
  2490                         attr.read(table_name_index);
  2491                     } else if (table_name_tstr.equals("LocalVariableTable")) {
  2492                         readLocVarTable(in);
  2493                         attr.read(table_name_index);
  2494                     } else if (table_name_tstr.equals("StackMapTable")) {
  2495                         readStackMapTable(in);
  2496                         attr.read(table_name_index);
  2497                     } else if (table_name_tstr.equals("StackMap")) {
  2498                         readStackMap(in);
  2499                         attr.read(table_name_index);
  2500                     } else {
  2501                         attr.read(table_name_index, in);
  2502                     }
  2503                     code_attrs.addElement(attr);
  2504                     continue;
  2505                 }
  2506 
  2507                 attr.read(table_name_index, in);
  2508                 code_attrs.addElement(attr);
  2509             }
  2510         }
  2511 
  2512         /**
  2513          * Read exception table info.
  2514          */
  2515         void readExceptionTable(DataInputStream in) throws IOException {
  2516             int exception_table_len = in.readUnsignedShort();
  2517             exception_table = new Vector(exception_table_len);
  2518             for (int l = 0; l < exception_table_len; l++) {
  2519                 exception_table.addElement(new TrapData(in, l));
  2520             }
  2521         }
  2522 
  2523         /**
  2524          * Read LineNumberTable attribute info.
  2525          */
  2526         void readLineNumTable(DataInputStream in) throws IOException {
  2527             int attr_len = in.readInt(); // attr_length
  2528             int lin_num_tb_len = in.readUnsignedShort();
  2529             lin_num_tb = new Vector(lin_num_tb_len);
  2530             for (int l = 0; l < lin_num_tb_len; l++) {
  2531                 lin_num_tb.addElement(new LineNumData(in));
  2532             }
  2533         }
  2534 
  2535         /**
  2536          * Read LocalVariableTable attribute info.
  2537          */
  2538         void readLocVarTable(DataInputStream in) throws IOException {
  2539             int attr_len = in.readInt(); // attr_length
  2540             int loc_var_tb_len = in.readUnsignedShort();
  2541             loc_var_tb = new Vector(loc_var_tb_len);
  2542             for (int l = 0; l < loc_var_tb_len; l++) {
  2543                 loc_var_tb.addElement(new LocVarData(in));
  2544             }
  2545         }
  2546 
  2547         /**
  2548          * Read Exception attribute info.
  2549          */
  2550         public void readExceptions(DataInputStream in) throws IOException {
  2551             int attr_len = in.readInt(); // attr_length in prog
  2552             int num_exceptions = in.readUnsignedShort();
  2553             exc_index_table = new int[num_exceptions];
  2554             for (int l = 0; l < num_exceptions; l++) {
  2555                 int exc = in.readShort();
  2556                 exc_index_table[l] = exc;
  2557             }
  2558         }
  2559 
  2560         /**
  2561          * Read StackMapTable attribute info.
  2562          */
  2563         void readStackMapTable(DataInputStream in) throws IOException {
  2564             int attr_len = in.readInt();  //attr_length
  2565             int stack_map_tb_len = in.readUnsignedShort();
  2566             stackMapTable = new StackMapTableData[stack_map_tb_len];
  2567             for (int i = 0; i < stack_map_tb_len; i++) {
  2568                 stackMapTable[i] = StackMapTableData.getInstance(in, this);
  2569             }
  2570         }
  2571 
  2572         /**
  2573          * Read StackMap attribute info.
  2574          */
  2575         void readStackMap(DataInputStream in) throws IOException {
  2576             int attr_len = in.readInt();  //attr_length
  2577             int stack_map_len = in.readUnsignedShort();
  2578             stackMap = new StackMapData[stack_map_len];
  2579             for (int i = 0; i < stack_map_len; i++) {
  2580                 stackMap[i] = new StackMapData(in, this);
  2581             }
  2582         }
  2583 
  2584         /**
  2585          * Return access of the method.
  2586          */
  2587         public int getAccess() {
  2588             return access;
  2589         }
  2590 
  2591         /**
  2592          * Return name of the method.
  2593          */
  2594         public String getName() {
  2595             return cls.getStringValue(name_index);
  2596         }
  2597 
  2598         /**
  2599          * Return internal siganature of the method.
  2600          */
  2601         public String getInternalSig() {
  2602             return cls.getStringValue(descriptor_index);
  2603         }
  2604 
  2605         /**
  2606          * Return code attribute data of a method.
  2607          */
  2608         public byte[] getCode() {
  2609             return code;
  2610         }
  2611 
  2612         /**
  2613          * Return LineNumberTable size.
  2614          */
  2615         public int getnumlines() {
  2616             return lin_num_tb.size();
  2617         }
  2618 
  2619         /**
  2620          * Return LineNumberTable
  2621          */
  2622         public Vector getlin_num_tb() {
  2623             return lin_num_tb;
  2624         }
  2625 
  2626         /**
  2627          * Return LocalVariableTable size.
  2628          */
  2629         public int getloc_var_tbsize() {
  2630             return loc_var_tb.size();
  2631         }
  2632 
  2633         /**
  2634          * Return LocalVariableTable.
  2635          */
  2636         public Vector getloc_var_tb() {
  2637             return loc_var_tb;
  2638         }
  2639 
  2640         /**
  2641          * Return StackMap.
  2642          */
  2643         public StackMapData[] getStackMap() {
  2644             return stackMap;
  2645         }
  2646 
  2647         /**
  2648          * Return StackMapTable.
  2649          */
  2650         public StackMapTableData[] getStackMapTable() {
  2651             return stackMapTable;
  2652         }
  2653 
  2654         public StackMapIterator createStackMapIterator() {
  2655             return new StackMapIterator(this);
  2656         }
  2657 
  2658         /**
  2659          * Return true if method is static
  2660          */
  2661         public boolean isStatic() {
  2662             if ((access & ACC_STATIC) != 0) {
  2663                 return true;
  2664             }
  2665             return false;
  2666         }
  2667 
  2668         /**
  2669          * Return max depth of operand stack.
  2670          */
  2671         public int getMaxStack() {
  2672             return max_stack;
  2673         }
  2674 
  2675         /**
  2676          * Return number of local variables.
  2677          */
  2678         public int getMaxLocals() {
  2679             return max_locals;
  2680         }
  2681 
  2682         /**
  2683          * Return exception index table in Exception attribute.
  2684          */
  2685         public int[] get_exc_index_table() {
  2686             return exc_index_table;
  2687         }
  2688 
  2689         /**
  2690          * Return exception table in code attributre.
  2691          */
  2692         public TrapDataIterator getTrapDataIterator() {
  2693             return new TrapDataIterator(exception_table);
  2694         }
  2695 
  2696         /**
  2697          * Return method attributes.
  2698          */
  2699         public Vector getAttributes() {
  2700             return attrs;
  2701         }
  2702 
  2703         /**
  2704          * Return code attributes.
  2705          */
  2706         public Vector getCodeAttributes() {
  2707             return code_attrs;
  2708         }
  2709 
  2710         /**
  2711          * Return true if method id synthetic.
  2712          */
  2713         public boolean isSynthetic() {
  2714             return isSynthetic;
  2715         }
  2716 
  2717         /**
  2718          * Return true if method is deprecated.
  2719          */
  2720         public boolean isDeprecated() {
  2721             return isDeprecated;
  2722         }
  2723 
  2724         public byte[] findAnnotationData(boolean classRetention) {
  2725             String n = classRetention
  2726                 ? "RuntimeInvisibleAnnotations" : // NOI18N
  2727                 "RuntimeVisibleAnnotations"; // NOI18N
  2728             AttrData[] arr = new AttrData[attrs.size()];
  2729             attrs.copyInto(arr);
  2730             return ClassData.findAttr(n, arr);
  2731         }
  2732 
  2733         public boolean isConstructor() {
  2734             return "<init>".equals(getName());
  2735         }
  2736     }
  2737 
  2738     /* represents one entry of StackMap attribute
  2739      */
  2740     private static class StackMapData {
  2741 
  2742         final int offset;
  2743         final int[] locals;
  2744         final int[] stack;
  2745 
  2746         StackMapData(int offset, int[] locals, int[] stack) {
  2747             this.offset = offset;
  2748             this.locals = locals;
  2749             this.stack = stack;
  2750         }
  2751 
  2752         StackMapData(DataInputStream in, MethodData method) throws IOException {
  2753             offset = in.readUnsignedShort();
  2754             int local_size = in.readUnsignedShort();
  2755             locals = readTypeArray(in, local_size, method);
  2756             int stack_size = in.readUnsignedShort();
  2757             stack = readTypeArray(in, stack_size, method);
  2758         }
  2759 
  2760         static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException {
  2761             int[] types = new int[length];
  2762             for (int i = 0; i < length; i++) {
  2763                 types[i] = readType(in, method);
  2764             }
  2765             return types;
  2766         }
  2767 
  2768         static final int readType(DataInputStream in, MethodData method) throws IOException {
  2769             int type = in.readUnsignedByte();
  2770             if (type == ITEM_Object || type == ITEM_NewObject) {
  2771                 type = type | (in.readUnsignedShort() << 8);
  2772             }
  2773             return type;
  2774         }
  2775     }
  2776 
  2777     static final class StackMapIterator {
  2778 
  2779         private final StackMapTableData[] stackMapTable;
  2780         private final TypeArray argTypes;
  2781         private final TypeArray localTypes;
  2782         private final TypeArray stackTypes;
  2783         private int nextFrameIndex;
  2784         private int lastFrameByteCodeOffset;
  2785         private int byteCodeOffset;
  2786 
  2787         StackMapIterator(final MethodData methodData) {
  2788             this(methodData.getStackMapTable(),
  2789                 methodData.getInternalSig(),
  2790                 methodData.isStatic());
  2791         }
  2792 
  2793         StackMapIterator(final StackMapTableData[] stackMapTable,
  2794             final String methodSignature,
  2795             final boolean isStaticMethod) {
  2796             this.stackMapTable = (stackMapTable != null)
  2797                 ? stackMapTable
  2798                 : new StackMapTableData[0];
  2799 
  2800             argTypes = getArgTypes(methodSignature, isStaticMethod);
  2801             localTypes = new TypeArray();
  2802             stackTypes = new TypeArray();
  2803 
  2804             localTypes.addAll(argTypes);
  2805 
  2806             lastFrameByteCodeOffset = -1;
  2807             advanceBy(0);
  2808         }
  2809 
  2810         public String getFrameAsString() {
  2811             return (nextFrameIndex == 0)
  2812                 ? StackMapTableData.toString("INITIAL", 0, null, null)
  2813                 : stackMapTable[nextFrameIndex - 1].toString();
  2814         }
  2815 
  2816         public int getFrameIndex() {
  2817             return nextFrameIndex;
  2818         }
  2819 
  2820         public TypeArray getFrameStack() {
  2821             return stackTypes;
  2822         }
  2823 
  2824         public TypeArray getFrameLocals() {
  2825             return localTypes;
  2826         }
  2827 
  2828         public TypeArray getArguments() {
  2829             return argTypes;
  2830         }
  2831 
  2832         public void advanceBy(final int numByteCodes) {
  2833             if (numByteCodes < 0) {
  2834                 throw new IllegalStateException("Forward only iterator");
  2835             }
  2836 
  2837             byteCodeOffset += numByteCodes;
  2838             while ((nextFrameIndex < stackMapTable.length)
  2839                 && ((byteCodeOffset - lastFrameByteCodeOffset)
  2840                 >= (stackMapTable[nextFrameIndex].offsetDelta
  2841                 + 1))) {
  2842                 final StackMapTableData nextFrame = stackMapTable[nextFrameIndex];
  2843 
  2844                 lastFrameByteCodeOffset += nextFrame.offsetDelta + 1;
  2845                 nextFrame.applyTo(localTypes, stackTypes);
  2846 
  2847                 ++nextFrameIndex;
  2848             }
  2849         }
  2850 
  2851         public void advanceTo(final int nextByteCodeOffset) {
  2852             advanceBy(nextByteCodeOffset - byteCodeOffset);
  2853         }
  2854 
  2855         private static TypeArray getArgTypes(final String methodSignature,
  2856             final boolean isStaticMethod) {
  2857             final TypeArray argTypes = new TypeArray();
  2858 
  2859             if (!isStaticMethod) {
  2860                 argTypes.add(ITEM_Object);
  2861             }
  2862 
  2863             if (methodSignature.charAt(0) != '(') {
  2864                 throw new IllegalArgumentException("Invalid method signature");
  2865             }
  2866 
  2867             final int length = methodSignature.length();
  2868             boolean skipType = false;
  2869             int argType;
  2870             for (int i = 1; i < length; ++i) {
  2871                 switch (methodSignature.charAt(i)) {
  2872                     case 'B':
  2873                     case 'C':
  2874                     case 'S':
  2875                     case 'Z':
  2876                     case 'I':
  2877                         argType = ITEM_Integer;
  2878                         break;
  2879                     case 'J':
  2880                         argType = ITEM_Long;
  2881                         break;
  2882                     case 'F':
  2883                         argType = ITEM_Float;
  2884                         break;
  2885                     case 'D':
  2886                         argType = ITEM_Double;
  2887                         break;
  2888                     case 'L': {
  2889                         i = methodSignature.indexOf(';', i + 1);
  2890                         if (i == -1) {
  2891                             throw new IllegalArgumentException(
  2892                                 "Invalid method signature");
  2893                         }
  2894                         argType = ITEM_Object;
  2895                         break;
  2896                     }
  2897                     case ')':
  2898                         // not interested in the return value type
  2899                         return argTypes;
  2900                     case '[':
  2901                         if (!skipType) {
  2902                             argTypes.add(ITEM_Object);
  2903                             skipType = true;
  2904                         }
  2905                         continue;
  2906 
  2907                     default:
  2908                         throw new IllegalArgumentException(
  2909                             "Invalid method signature");
  2910                 }
  2911 
  2912                 if (!skipType) {
  2913                     argTypes.add(argType);
  2914                 } else {
  2915                     skipType = false;
  2916                 }
  2917             }
  2918 
  2919             return argTypes;
  2920         }
  2921     }
  2922     /* represents one entry of StackMapTable attribute
  2923      */
  2924 
  2925     private static abstract class StackMapTableData {
  2926 
  2927         final int frameType;
  2928         int offsetDelta;
  2929 
  2930         StackMapTableData(int frameType) {
  2931             this.frameType = frameType;
  2932         }
  2933 
  2934         abstract void applyTo(TypeArray localTypes, TypeArray stackTypes);
  2935 
  2936         protected static String toString(
  2937             final String frameType,
  2938             final int offset,
  2939             final int[] localTypes,
  2940             final int[] stackTypes) {
  2941             final StringBuilder sb = new StringBuilder(frameType);
  2942 
  2943             sb.append("(off: +").append(offset);
  2944             if (localTypes != null) {
  2945                 sb.append(", locals: ");
  2946                 appendTypes(sb, localTypes);
  2947             }
  2948             if (stackTypes != null) {
  2949                 sb.append(", stack: ");
  2950                 appendTypes(sb, stackTypes);
  2951             }
  2952             sb.append(')');
  2953 
  2954             return sb.toString();
  2955         }
  2956 
  2957         private static void appendTypes(final StringBuilder sb, final int[] types) {
  2958             sb.append('[');
  2959             if (types.length > 0) {
  2960                 sb.append(TypeArray.typeString(types[0]));
  2961                 for (int i = 1; i < types.length; ++i) {
  2962                     sb.append(", ");
  2963                     sb.append(TypeArray.typeString(types[i]));
  2964                 }
  2965             }
  2966             sb.append(']');
  2967         }
  2968 
  2969         private static class SameFrame extends StackMapTableData {
  2970 
  2971             SameFrame(int frameType, int offsetDelta) {
  2972                 super(frameType);
  2973                 this.offsetDelta = offsetDelta;
  2974             }
  2975 
  2976             @Override
  2977             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  2978                 stackTypes.clear();
  2979             }
  2980 
  2981             @Override
  2982             public String toString() {
  2983                 return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED)
  2984                     ? "_FRAME_EXTENDED" : ""),
  2985                     offsetDelta,
  2986                     null, null);
  2987             }
  2988         }
  2989 
  2990         private static class SameLocals1StackItem extends StackMapTableData {
  2991 
  2992             final int[] stack;
  2993 
  2994             SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) {
  2995                 super(frameType);
  2996                 this.offsetDelta = offsetDelta;
  2997                 this.stack = stack;
  2998             }
  2999 
  3000             @Override
  3001             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  3002                 stackTypes.setAll(stack);
  3003             }
  3004 
  3005             @Override
  3006             public String toString() {
  3007                 return toString(
  3008                     "SAME_LOCALS_1_STACK_ITEM"
  3009                     + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED)
  3010                     ? "_EXTENDED" : ""),
  3011                     offsetDelta,
  3012                     null, stack);
  3013             }
  3014         }
  3015 
  3016         private static class ChopFrame extends StackMapTableData {
  3017 
  3018             ChopFrame(int frameType, int offsetDelta) {
  3019                 super(frameType);
  3020                 this.offsetDelta = offsetDelta;
  3021             }
  3022 
  3023             @Override
  3024             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  3025                 localTypes.setSize(localTypes.getSize()
  3026                     - (SAME_FRAME_EXTENDED - frameType));
  3027                 stackTypes.clear();
  3028             }
  3029 
  3030             @Override
  3031             public String toString() {
  3032                 return toString("CHOP", offsetDelta, null, null);
  3033             }
  3034         }
  3035 
  3036         private static class AppendFrame extends StackMapTableData {
  3037 
  3038             final int[] locals;
  3039 
  3040             AppendFrame(int frameType, int offsetDelta, int[] locals) {
  3041                 super(frameType);
  3042                 this.offsetDelta = offsetDelta;
  3043                 this.locals = locals;
  3044             }
  3045 
  3046             @Override
  3047             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  3048                 localTypes.addAll(locals);
  3049                 stackTypes.clear();
  3050             }
  3051 
  3052             @Override
  3053             public String toString() {
  3054                 return toString("APPEND", offsetDelta, locals, null);
  3055             }
  3056         }
  3057 
  3058         private static class FullFrame extends StackMapTableData {
  3059 
  3060             final int[] locals;
  3061             final int[] stack;
  3062 
  3063             FullFrame(int offsetDelta, int[] locals, int[] stack) {
  3064                 super(FULL_FRAME);
  3065                 this.offsetDelta = offsetDelta;
  3066                 this.locals = locals;
  3067                 this.stack = stack;
  3068             }
  3069 
  3070             @Override
  3071             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  3072                 localTypes.setAll(locals);
  3073                 stackTypes.setAll(stack);
  3074             }
  3075 
  3076             @Override
  3077             public String toString() {
  3078                 return toString("FULL", offsetDelta, locals, stack);
  3079             }
  3080         }
  3081 
  3082         static StackMapTableData getInstance(DataInputStream in, MethodData method)
  3083             throws IOException {
  3084             int frameType = in.readUnsignedByte();
  3085 
  3086             if (frameType < SAME_FRAME_BOUND) {
  3087                 // same_frame
  3088                 return new SameFrame(frameType, frameType);
  3089             } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) {
  3090                 // same_locals_1_stack_item_frame
  3091                 // read additional single stack element
  3092                 return new SameLocals1StackItem(frameType,
  3093                     (frameType - SAME_FRAME_BOUND),
  3094                     StackMapData.readTypeArray(in, 1, method));
  3095             } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
  3096                 // same_locals_1_stack_item_extended
  3097                 return new SameLocals1StackItem(frameType,
  3098                     in.readUnsignedShort(),
  3099                     StackMapData.readTypeArray(in, 1, method));
  3100             } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) {
  3101                 // chop_frame or same_frame_extended
  3102                 return new ChopFrame(frameType, in.readUnsignedShort());
  3103             } else if (frameType == SAME_FRAME_EXTENDED) {
  3104                 // chop_frame or same_frame_extended
  3105                 return new SameFrame(frameType, in.readUnsignedShort());
  3106             } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) {
  3107                 // append_frame
  3108                 return new AppendFrame(frameType, in.readUnsignedShort(),
  3109                     StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method));
  3110             } else if (frameType == FULL_FRAME) {
  3111                 // full_frame
  3112                 int offsetDelta = in.readUnsignedShort();
  3113                 int locals_size = in.readUnsignedShort();
  3114                 int[] locals = StackMapData.readTypeArray(in, locals_size, method);
  3115                 int stack_size = in.readUnsignedShort();
  3116                 int[] stack = StackMapData.readTypeArray(in, stack_size, method);
  3117                 return new FullFrame(offsetDelta, locals, stack);
  3118             } else {
  3119                 throw new ClassFormatError("unrecognized frame_type in StackMapTable");
  3120             }
  3121         }
  3122     }
  3123 
  3124     /**
  3125      * Stores exception table data in code attribute.
  3126      *
  3127      * @author Sucheta Dambalkar (Adopted code from jdis)
  3128      */
  3129     static final class TrapData {
  3130 
  3131         public final short start_pc;
  3132         public final short end_pc;
  3133         public final short handler_pc;
  3134         public final short catch_cpx;
  3135         final int num;
  3136 
  3137         /**
  3138          * Read and store exception table data in code attribute.
  3139          */
  3140         TrapData(DataInputStream in, int num) throws IOException {
  3141             this.num = num;
  3142             start_pc = in.readShort();
  3143             end_pc = in.readShort();
  3144             handler_pc = in.readShort();
  3145             catch_cpx = in.readShort();
  3146         }
  3147 
  3148         /**
  3149          * returns recommended identifier
  3150          */
  3151         public String ident() {
  3152             return "t" + num;
  3153         }
  3154     }
  3155     /**
  3156      *
  3157      * @author Jaroslav Tulach <jtulach@netbeans.org>
  3158      */
  3159     static final class TrapDataIterator {
  3160 
  3161         private final Hashtable exStart = new Hashtable();
  3162         private final Hashtable exStop = new Hashtable();
  3163         private TrapData[] current = new TrapData[10];
  3164         private int currentCount;
  3165 
  3166         TrapDataIterator(Vector exceptionTable) {
  3167             for (int i = 0; i < exceptionTable.size(); i++) {
  3168                 final TrapData td = (TrapData) exceptionTable.elementAt(i);
  3169                 put(exStart, td.start_pc, td);
  3170                 put(exStop, td.end_pc, td);
  3171             }
  3172         }
  3173 
  3174         private static void put(Hashtable h, short key, TrapData td) {
  3175             Short s = Short.valueOf((short) key);
  3176             Vector v = (Vector) h.get(s);
  3177             if (v == null) {
  3178                 v = new Vector(1);
  3179                 h.put(s, v);
  3180             }
  3181             v.add(td);
  3182         }
  3183 
  3184         private boolean processAll(Hashtable h, Short key, boolean add) {
  3185             boolean change = false;
  3186             Vector v = (Vector) h.get(key);
  3187             if (v != null) {
  3188                 int s = v.size();
  3189                 for (int i = 0; i < s; i++) {
  3190                     TrapData td = (TrapData) v.elementAt(i);
  3191                     if (add) {
  3192                         add(td);
  3193                         change = true;
  3194                     } else {
  3195                         remove(td);
  3196                         change = true;
  3197                     }
  3198                 }
  3199             }
  3200             return change;
  3201         }
  3202 
  3203         public boolean advanceTo(int i) {
  3204             Short s = Short.valueOf((short) i);
  3205             boolean ch1 = processAll(exStart, s, true);
  3206             boolean ch2 = processAll(exStop, s, false);
  3207             return ch1 || ch2;
  3208         }
  3209 
  3210         public boolean useTry() {
  3211             return currentCount > 0;
  3212         }
  3213 
  3214         public TrapData[] current() {
  3215             TrapData[] copy = new TrapData[currentCount];
  3216             for (int i = 0; i < currentCount; i++) {
  3217                 copy[i] = current[i];
  3218             }
  3219             return copy;
  3220         }
  3221 
  3222         private void add(TrapData e) {
  3223             if (currentCount == current.length) {
  3224                 TrapData[] data = new TrapData[currentCount * 2];
  3225                 for (int i = 0; i < currentCount; i++) {
  3226                     data[i] = current[i];
  3227                 }
  3228                 current = data;
  3229             }
  3230             current[currentCount++] = e;
  3231         }
  3232 
  3233         private void remove(TrapData e) {
  3234             if (currentCount == 0) {
  3235                 return;
  3236             }
  3237             int from = 0;
  3238             while (from < currentCount) {
  3239                 if (e == current[from++]) {
  3240                     break;
  3241                 }
  3242             }
  3243             while (from < currentCount) {
  3244                 current[from - 1] = current[from];
  3245                 current[from] = null;
  3246                 from++;
  3247             }
  3248             currentCount--;
  3249         }
  3250     }
  3251     static final class TypeArray {
  3252 
  3253         private static final int CAPACITY_INCREMENT = 16;
  3254         private int[] types;
  3255         private int size;
  3256 
  3257         public TypeArray() {
  3258         }
  3259 
  3260         public TypeArray(final TypeArray initialTypes) {
  3261             setAll(initialTypes);
  3262         }
  3263 
  3264         public void add(final int newType) {
  3265             ensureCapacity(size + 1);
  3266             types[size++] = newType;
  3267         }
  3268 
  3269         public void addAll(final TypeArray newTypes) {
  3270             addAll(newTypes.types, 0, newTypes.size);
  3271         }
  3272 
  3273         public void addAll(final int[] newTypes) {
  3274             addAll(newTypes, 0, newTypes.length);
  3275         }
  3276 
  3277         public void addAll(final int[] newTypes,
  3278             final int offset,
  3279             final int count) {
  3280             if (count > 0) {
  3281                 ensureCapacity(size + count);
  3282                 arraycopy(newTypes, offset, types, size, count);
  3283                 size += count;
  3284             }
  3285         }
  3286 
  3287         public void set(final int index, final int newType) {
  3288             types[index] = newType;
  3289         }
  3290 
  3291         public void setAll(final TypeArray newTypes) {
  3292             setAll(newTypes.types, 0, newTypes.size);
  3293         }
  3294 
  3295         public void setAll(final int[] newTypes) {
  3296             setAll(newTypes, 0, newTypes.length);
  3297         }
  3298 
  3299         public void setAll(final int[] newTypes,
  3300             final int offset,
  3301             final int count) {
  3302             if (count > 0) {
  3303                 ensureCapacity(count);
  3304                 arraycopy(newTypes, offset, types, 0, count);
  3305                 size = count;
  3306             } else {
  3307                 clear();
  3308             }
  3309         }
  3310 
  3311         public void setSize(final int newSize) {
  3312             if (size != newSize) {
  3313                 ensureCapacity(newSize);
  3314 
  3315                 for (int i = size; i < newSize; ++i) {
  3316                     types[i] = 0;
  3317                 }
  3318                 size = newSize;
  3319             }
  3320         }
  3321 
  3322         public void clear() {
  3323             size = 0;
  3324         }
  3325 
  3326         public int getSize() {
  3327             return size;
  3328         }
  3329 
  3330         public int get(final int index) {
  3331             return types[index];
  3332         }
  3333 
  3334         public static String typeString(final int type) {
  3335             switch (type & 0xff) {
  3336                 case ITEM_Bogus:
  3337                     return "_top_";
  3338                 case ITEM_Integer:
  3339                     return "_int_";
  3340                 case ITEM_Float:
  3341                     return "_float_";
  3342                 case ITEM_Double:
  3343                     return "_double_";
  3344                 case ITEM_Long:
  3345                     return "_long_";
  3346                 case ITEM_Null:
  3347                     return "_null_";
  3348                 case ITEM_InitObject: // UninitializedThis
  3349                     return "_init_";
  3350                 case ITEM_Object:
  3351                     return "_object_";
  3352                 case ITEM_NewObject: // Uninitialized
  3353                     return "_new_";
  3354                 default:
  3355                     throw new IllegalArgumentException("Unknown type");
  3356             }
  3357         }
  3358 
  3359         @Override
  3360         public String toString() {
  3361             final StringBuilder sb = new StringBuilder("[");
  3362             if (size > 0) {
  3363                 sb.append(typeString(types[0]));
  3364                 for (int i = 1; i < size; ++i) {
  3365                     sb.append(", ");
  3366                     sb.append(typeString(types[i]));
  3367                 }
  3368             }
  3369 
  3370             return sb.append(']').toString();
  3371         }
  3372 
  3373         private void ensureCapacity(final int minCapacity) {
  3374             if ((minCapacity == 0)
  3375                 || (types != null) && (minCapacity <= types.length)) {
  3376                 return;
  3377             }
  3378 
  3379             final int newCapacity =
  3380                 ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT)
  3381                 * CAPACITY_INCREMENT;
  3382             final int[] newTypes = new int[newCapacity];
  3383 
  3384             if (size > 0) {
  3385                 arraycopy(types, 0, newTypes, 0, size);
  3386             }
  3387 
  3388             types = newTypes;
  3389         }
  3390 
  3391         // no System.arraycopy
  3392         private void arraycopy(final int[] src, final int srcPos,
  3393             final int[] dest, final int destPos,
  3394             final int length) {
  3395             for (int i = 0; i < length; ++i) {
  3396                 dest[destPos + i] = src[srcPos + i];
  3397             }
  3398         }
  3399     }
  3400     /**
  3401      * A JavaScript ready replacement for java.util.Vector
  3402      *
  3403      * @author Jaroslav Tulach <jtulach@netbeans.org>
  3404      */
  3405     @JavaScriptPrototype(prototype = "new Array")
  3406     private static final class Vector {
  3407 
  3408         private Object[] arr;
  3409 
  3410         Vector() {
  3411         }
  3412 
  3413         Vector(int i) {
  3414         }
  3415 
  3416         void add(Object objectType) {
  3417             addElement(objectType);
  3418         }
  3419 
  3420         @JavaScriptBody(args = {"obj"}, body =
  3421             "this.push(obj);")
  3422         void addElement(Object obj) {
  3423             final int s = size();
  3424             setSize(s + 1);
  3425             setElementAt(obj, s);
  3426         }
  3427 
  3428         @JavaScriptBody(args = {}, body =
  3429             "return this.length;")
  3430         int size() {
  3431             return arr == null ? 0 : arr.length;
  3432         }
  3433 
  3434         @JavaScriptBody(args = {"newArr"}, body =
  3435             "for (var i = 0; i < this.length; i++) {\n"
  3436             + "  newArr[i] = this[i];\n"
  3437             + "}\n")
  3438         void copyInto(Object[] newArr) {
  3439             if (arr == null) {
  3440                 return;
  3441             }
  3442             int min = Math.min(newArr.length, arr.length);
  3443             for (int i = 0; i < min; i++) {
  3444                 newArr[i] = arr[i];
  3445             }
  3446         }
  3447 
  3448         @JavaScriptBody(args = {"index"}, body =
  3449             "return this[index];")
  3450         Object elementAt(int index) {
  3451             return arr[index];
  3452         }
  3453 
  3454         private void setSize(int len) {
  3455             Object[] newArr = new Object[len];
  3456             copyInto(newArr);
  3457             arr = newArr;
  3458         }
  3459 
  3460         @JavaScriptBody(args = {"val", "index"}, body =
  3461             "this[index] = val;")
  3462         void setElementAt(Object val, int index) {
  3463             arr[index] = val;
  3464         }
  3465     }
  3466     
  3467 }