rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java
author Lubomir Nerad <lubomir.nerad@oracle.com>
Tue, 07 May 2013 19:01:14 +0200
branchclosure
changeset 1085 6a4ef883e233
parent 967 f19f17f8f8dc
child 1513 ba912ef24b27
permissions -rw-r--r--
Access non-final exported methods through "invoker"
     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                             default:
  1849                                 sb.append(c);
  1850                         }
  1851                     }
  1852                     return sb.toString();
  1853                 }
  1854                 case CONSTANT_DOUBLE: {
  1855                     Double d = (Double) x;
  1856                     String sd = d.toString();
  1857                     if (textual) {
  1858                         return sd;
  1859                     }
  1860                     return sd + "d";
  1861                 }
  1862                 case CONSTANT_FLOAT: {
  1863                     Float f = (Float) x;
  1864                     String sf = (f).toString();
  1865                     if (textual) {
  1866                         return sf;
  1867                     }
  1868                     return sf + "f";
  1869                 }
  1870                 case CONSTANT_LONG: {
  1871                     Long ln = (Long) x;
  1872                     if (textual) {
  1873                         return ln.toString();
  1874                     }
  1875                     return ln.toString() + 'l';
  1876                 }
  1877                 case CONSTANT_INTEGER: {
  1878                     Integer in = (Integer) x;
  1879                     return in.toString();
  1880                 }
  1881                 case CONSTANT_CLASS:
  1882                     String jn = getClassName(cpx);
  1883                     if (textual) {
  1884                         if (refs != null) {
  1885                             refs[0] = jn;
  1886                         }
  1887                         return jn;
  1888                     }
  1889                     return javaName(jn);
  1890                 case CONSTANT_STRING:
  1891                     String sv = stringValue(((CPX) x).cpx, textual);
  1892                     if (textual) {
  1893                         return '"' + sv + '"';
  1894                     } else {
  1895                         return sv;
  1896                     }
  1897                 case CONSTANT_FIELD:
  1898                 case CONSTANT_METHOD:
  1899                 case CONSTANT_INTERFACEMETHOD:
  1900                     //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
  1901                     return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2);
  1902 
  1903                 case CONSTANT_NAMEANDTYPE:
  1904                     return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2);
  1905                 default:
  1906                     return "UnknownTag"; //TBD
  1907             }
  1908         }
  1909 
  1910         /**
  1911          * Returns resolved java type name.
  1912          */
  1913         public String javaName(String name) {
  1914             if (name == null) {
  1915                 return "null";
  1916             }
  1917             int len = name.length();
  1918             if (len == 0) {
  1919                 return "\"\"";
  1920             }
  1921             int cc = '/';
  1922             fullname:
  1923             { // xxx/yyy/zzz
  1924                 int cp;
  1925                 for (int k = 0; k < len; k += Character.charCount(cp)) {
  1926                     cp = name.codePointAt(k);
  1927                     if (cc == '/') {
  1928                         if (!isJavaIdentifierStart(cp)) {
  1929                             break fullname;
  1930                         }
  1931                     } else if (cp != '/') {
  1932                         if (!isJavaIdentifierPart(cp)) {
  1933                             break fullname;
  1934                         }
  1935                     }
  1936                     cc = cp;
  1937                 }
  1938                 return name;
  1939             }
  1940             return "\"" + name + "\"";
  1941         }
  1942 
  1943         public String getName(int cpx) {
  1944             String res;
  1945             try {
  1946                 return javaName((String) cpool[cpx]); //.replace('/','.');
  1947             } catch (ArrayIndexOutOfBoundsException e) {
  1948                 return "<invalid constant pool index:" + cpx + ">";
  1949             } catch (ClassCastException e) {
  1950                 return "<invalid constant pool ref:" + cpx + ">";
  1951             }
  1952         }
  1953 
  1954         /**
  1955          * Returns unqualified class name.
  1956          */
  1957         public String getShortClassName(int cpx) {
  1958             String classname = javaName(getClassName(cpx));
  1959             pkgPrefixLen = classname.lastIndexOf("/") + 1;
  1960             if (pkgPrefixLen != 0) {
  1961                 pkgPrefix = classname.substring(0, pkgPrefixLen);
  1962                 if (classname.startsWith(pkgPrefix)) {
  1963                     return classname.substring(pkgPrefixLen);
  1964                 }
  1965             }
  1966             return classname;
  1967         }
  1968 
  1969         /**
  1970          * Returns source file name.
  1971          */
  1972         public String getSourceName() {
  1973             return getName(source_cpx);
  1974         }
  1975 
  1976         /**
  1977          * Returns package name.
  1978          */
  1979         public String getPkgName() {
  1980             String classname = getClassName(this_class);
  1981             pkgPrefixLen = classname.lastIndexOf("/") + 1;
  1982             if (pkgPrefixLen != 0) {
  1983                 pkgPrefix = classname.substring(0, pkgPrefixLen);
  1984                 return /* ("package  " + */ pkgPrefix.substring(0, pkgPrefixLen - 1) /* + ";\n") */;
  1985             } else {
  1986                 return null;
  1987             }
  1988         }
  1989 
  1990         /**
  1991          * Returns total constant pool entry count.
  1992          */
  1993         public int getCpoolCount() {
  1994             return cpool_count;
  1995         }
  1996 
  1997         /**
  1998          * Returns minor version of class file.
  1999          */
  2000         public int getMinor_version() {
  2001             return minor_version;
  2002         }
  2003 
  2004         /**
  2005          * Returns major version of class file.
  2006          */
  2007         public int getMajor_version() {
  2008             return major_version;
  2009         }
  2010 
  2011         private boolean isJavaIdentifierStart(int cp) {
  2012             return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z');
  2013         }
  2014 
  2015         private boolean isJavaIdentifierPart(int cp) {
  2016             return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9');
  2017         }
  2018 
  2019         public String[] getNameAndType(int indx) {
  2020             return getNameAndType(indx, 0, new String[2]);
  2021         }
  2022 
  2023         private String[] getNameAndType(int indx, int at, String[] arr) {
  2024             CPX2 c2 = getCpoolEntry(indx);
  2025             arr[at] = StringValue(c2.cpx1);
  2026             arr[at + 1] = StringValue(c2.cpx2);
  2027             return arr;
  2028         }
  2029 
  2030         public String[] getFieldInfoName(int indx) {
  2031             CPX2 c2 = getCpoolEntry(indx);
  2032             String[] arr = new String[3];
  2033             arr[0] = getClassName(c2.cpx1);
  2034             return getNameAndType(c2.cpx2, 1, arr);
  2035         }
  2036 
  2037         public MethodData findMethod(String name, String signature) {
  2038             for (MethodData md: methods) {
  2039                 if (md.getName().equals(name)
  2040                         && md.getInternalSig().equals(signature)) {
  2041                     return md;
  2042                 }
  2043             }
  2044 
  2045             // not found
  2046             return null;
  2047         }
  2048 
  2049         public FieldData findField(String name, String signature) {
  2050             for (FieldData fd: fields) {
  2051                 if (fd.getName().equals(name)
  2052                         && fd.getInternalSig().equals(signature)) {
  2053                     return fd;
  2054                 }
  2055             }
  2056 
  2057             // not found
  2058             return null;
  2059         }
  2060 
  2061         static byte[] findAttr(String n, AttrData[] attrs) {
  2062             for (AttrData ad : attrs) {
  2063                 if (n.equals(ad.getAttrName())) {
  2064                     return ad.getData();
  2065                 }
  2066             }
  2067             return null;
  2068         }
  2069     }
  2070 
  2071     /**
  2072      * Strores field data informastion.
  2073      *
  2074      * @author Sucheta Dambalkar (Adopted code from jdis)
  2075      */
  2076     static class FieldData {
  2077 
  2078         ClassData cls;
  2079         int access;
  2080         int name_index;
  2081         int descriptor_index;
  2082         int attributes_count;
  2083         int value_cpx = 0;
  2084         boolean isSynthetic = false;
  2085         boolean isDeprecated = false;
  2086         Vector attrs;
  2087 
  2088         public FieldData(ClassData cls) {
  2089             this.cls = cls;
  2090         }
  2091 
  2092         /**
  2093          * Read and store field info.
  2094          */
  2095         public void read(DataInputStream in) throws IOException {
  2096             access = in.readUnsignedShort();
  2097             name_index = in.readUnsignedShort();
  2098             descriptor_index = in.readUnsignedShort();
  2099             // Read the attributes
  2100             int attributes_count = in.readUnsignedShort();
  2101             attrs = new Vector(attributes_count);
  2102             for (int i = 0; i < attributes_count; i++) {
  2103                 int attr_name_index = in.readUnsignedShort();
  2104                 if (cls.getTag(attr_name_index) != CONSTANT_UTF8) {
  2105                     continue;
  2106                 }
  2107                 String attr_name = cls.getString(attr_name_index);
  2108                 if (attr_name.equals("ConstantValue")) {
  2109                     if (in.readInt() != 2) {
  2110                         throw new ClassFormatError("invalid ConstantValue attr length");
  2111                     }
  2112                     value_cpx = in.readUnsignedShort();
  2113                     AttrData attr = new AttrData(cls);
  2114                     attr.read(attr_name_index);
  2115                     attrs.addElement(attr);
  2116                 } else if (attr_name.equals("Synthetic")) {
  2117                     if (in.readInt() != 0) {
  2118                         throw new ClassFormatError("invalid Synthetic attr length");
  2119                     }
  2120                     isSynthetic = true;
  2121                     AttrData attr = new AttrData(cls);
  2122                     attr.read(attr_name_index);
  2123                     attrs.addElement(attr);
  2124                 } else if (attr_name.equals("Deprecated")) {
  2125                     if (in.readInt() != 0) {
  2126                         throw new ClassFormatError("invalid Synthetic attr length");
  2127                     }
  2128                     isDeprecated = true;
  2129                     AttrData attr = new AttrData(cls);
  2130                     attr.read(attr_name_index);
  2131                     attrs.addElement(attr);
  2132                 } else {
  2133                     AttrData attr = new AttrData(cls);
  2134                     attr.read(attr_name_index, in);
  2135                     attrs.addElement(attr);
  2136                 }
  2137             }
  2138 
  2139         }  // end read
  2140 
  2141         public boolean isStatic() {
  2142             return (access & ACC_STATIC) != 0;
  2143         }
  2144 
  2145         /**
  2146          * Returns access of a field.
  2147          */
  2148         public String[] getAccess() {
  2149             Vector v = new Vector();
  2150             if ((access & ACC_PUBLIC) != 0) {
  2151                 v.addElement("public");
  2152             }
  2153             if ((access & ACC_PRIVATE) != 0) {
  2154                 v.addElement("private");
  2155             }
  2156             if ((access & ACC_PROTECTED) != 0) {
  2157                 v.addElement("protected");
  2158             }
  2159             if ((access & ACC_STATIC) != 0) {
  2160                 v.addElement("static");
  2161             }
  2162             if ((access & ACC_FINAL) != 0) {
  2163                 v.addElement("final");
  2164             }
  2165             if ((access & ACC_VOLATILE) != 0) {
  2166                 v.addElement("volatile");
  2167             }
  2168             if ((access & ACC_TRANSIENT) != 0) {
  2169                 v.addElement("transient");
  2170             }
  2171             String[] accflags = new String[v.size()];
  2172             v.copyInto(accflags);
  2173             return accflags;
  2174         }
  2175 
  2176         /**
  2177          * Returns name of a field.
  2178          */
  2179         public String getName() {
  2180             return cls.getStringValue(name_index);
  2181         }
  2182 
  2183         /**
  2184          * Returns internal signature of a field
  2185          */
  2186         public String getInternalSig() {
  2187             return cls.getStringValue(descriptor_index);
  2188         }
  2189 
  2190         /**
  2191          * Returns true if field is synthetic.
  2192          */
  2193         public boolean isSynthetic() {
  2194             return isSynthetic;
  2195         }
  2196 
  2197         /**
  2198          * Returns true if field is deprecated.
  2199          */
  2200         public boolean isDeprecated() {
  2201             return isDeprecated;
  2202         }
  2203 
  2204         /**
  2205          * Returns index of constant value in cpool.
  2206          */
  2207         public int getConstantValueIndex() {
  2208             return (value_cpx);
  2209         }
  2210 
  2211         /**
  2212          * Returns list of attributes of field.
  2213          */
  2214         public Vector getAttributes() {
  2215             return attrs;
  2216         }
  2217 
  2218         public byte[] findAnnotationData(boolean classRetention) {
  2219             String n = classRetention
  2220                 ? "RuntimeInvisibleAnnotations" : // NOI18N
  2221                 "RuntimeVisibleAnnotations"; // NOI18N
  2222             AttrData[] arr = new AttrData[attrs.size()];
  2223             attrs.copyInto(arr);
  2224             return ClassData.findAttr(n, arr);
  2225         }
  2226     }
  2227 
  2228     /**
  2229      * A JavaScript optimized replacement for Hashtable.
  2230      *
  2231      * @author Jaroslav Tulach <jtulach@netbeans.org>
  2232      */
  2233     private static final class Hashtable {
  2234 
  2235         private Object[] keys;
  2236         private Object[] values;
  2237 
  2238         Hashtable(int i) {
  2239             this();
  2240         }
  2241 
  2242         Hashtable(int i, double d) {
  2243             this();
  2244         }
  2245 
  2246         Hashtable() {
  2247         }
  2248 
  2249         synchronized void put(Object key, Object val) {
  2250             int[] where = {-1, -1};
  2251             Object found = get(key, where);
  2252             if (where[0] != -1) {
  2253                 // key exists
  2254                 values[where[0]] = val;
  2255             } else {
  2256                 if (where[1] != -1) {
  2257                     // null found
  2258                     keys[where[1]] = key;
  2259                     values[where[1]] = val;
  2260                 } else {
  2261                     if (keys == null) {
  2262                         keys = new Object[11];
  2263                         values = new Object[11];
  2264                         keys[0] = key;
  2265                         values[0] = val;
  2266                     } else {
  2267                         Object[] newKeys = new Object[keys.length * 2];
  2268                         Object[] newValues = new Object[values.length * 2];
  2269                         for (int i = 0; i < keys.length; i++) {
  2270                             newKeys[i] = keys[i];
  2271                             newValues[i] = values[i];
  2272                         }
  2273                         newKeys[keys.length] = key;
  2274                         newValues[keys.length] = val;
  2275                         keys = newKeys;
  2276                         values = newValues;
  2277                     }
  2278                 }
  2279             }
  2280         }
  2281 
  2282         Object get(Object key) {
  2283             return get(key, null);
  2284         }
  2285 
  2286         private synchronized Object get(Object key, int[] foundAndNull) {
  2287             if (keys == null) {
  2288                 return null;
  2289             }
  2290             for (int i = 0; i < keys.length; i++) {
  2291                 if (keys[i] == null) {
  2292                     if (foundAndNull != null) {
  2293                         foundAndNull[1] = i;
  2294                     }
  2295                 } else if (keys[i].equals(key)) {
  2296                     if (foundAndNull != null) {
  2297                         foundAndNull[0] = i;
  2298                     }
  2299                     return values[i];
  2300                 }
  2301             }
  2302             return null;
  2303         }
  2304     }
  2305 
  2306     /**
  2307      * Strores InnerClass data informastion.
  2308      *
  2309      * @author Sucheta Dambalkar (Adopted code from jdis)
  2310      */
  2311     private static class InnerClassData {
  2312 
  2313         ClassData cls;
  2314         int inner_class_info_index, outer_class_info_index, inner_name_index, access;
  2315 
  2316         public InnerClassData(ClassData cls) {
  2317             this.cls = cls;
  2318 
  2319         }
  2320 
  2321         /**
  2322          * Read Innerclass attribute data.
  2323          */
  2324         public void read(DataInputStream in) throws IOException {
  2325             inner_class_info_index = in.readUnsignedShort();
  2326             outer_class_info_index = in.readUnsignedShort();
  2327             inner_name_index = in.readUnsignedShort();
  2328             access = in.readUnsignedShort();
  2329         }  // end read
  2330 
  2331         /**
  2332          * Returns the access of this class or interface.
  2333          */
  2334         public String[] getAccess() {
  2335             Vector v = new Vector();
  2336             if ((access & ACC_PUBLIC) != 0) {
  2337                 v.addElement("public");
  2338             }
  2339             if ((access & ACC_FINAL) != 0) {
  2340                 v.addElement("final");
  2341             }
  2342             if ((access & ACC_ABSTRACT) != 0) {
  2343                 v.addElement("abstract");
  2344             }
  2345             String[] accflags = new String[v.size()];
  2346             v.copyInto(accflags);
  2347             return accflags;
  2348         }
  2349     } // end InnerClassData
  2350 
  2351     /**
  2352      * Strores LineNumberTable data information.
  2353      *
  2354      * @author Sucheta Dambalkar (Adopted code from jdis)
  2355      */
  2356     private static class LineNumData {
  2357 
  2358         short start_pc, line_number;
  2359 
  2360         public LineNumData() {
  2361         }
  2362 
  2363         /**
  2364          * Read LineNumberTable attribute.
  2365          */
  2366         public LineNumData(DataInputStream in) throws IOException {
  2367             start_pc = in.readShort();
  2368             line_number = in.readShort();
  2369 
  2370         }
  2371     }
  2372 
  2373     /**
  2374      * Strores LocalVariableTable data information.
  2375      *
  2376      * @author Sucheta Dambalkar (Adopted code from jdis)
  2377      */
  2378     private static class LocVarData {
  2379 
  2380         short start_pc, length, name_cpx, sig_cpx, slot;
  2381 
  2382         public LocVarData() {
  2383         }
  2384 
  2385         /**
  2386          * Read LocalVariableTable attribute.
  2387          */
  2388         public LocVarData(DataInputStream in) throws IOException {
  2389             start_pc = in.readShort();
  2390             length = in.readShort();
  2391             name_cpx = in.readShort();
  2392             sig_cpx = in.readShort();
  2393             slot = in.readShort();
  2394 
  2395         }
  2396     }
  2397     /**
  2398      * Strores method data informastion.
  2399      *
  2400      * @author Sucheta Dambalkar (Adopted code from jdis)
  2401      */
  2402     static class MethodData {
  2403 
  2404         ClassData cls;
  2405         int access;
  2406         int name_index;
  2407         int descriptor_index;
  2408         int attributes_count;
  2409         byte[] code;
  2410         Vector exception_table = new Vector(0);
  2411         Vector lin_num_tb = new Vector(0);
  2412         Vector loc_var_tb = new Vector(0);
  2413         StackMapTableData[] stackMapTable;
  2414         StackMapData[] stackMap;
  2415         int[] exc_index_table = null;
  2416         Vector attrs = new Vector(0);
  2417         Vector code_attrs = new Vector(0);
  2418         int max_stack, max_locals;
  2419         boolean isSynthetic = false;
  2420         boolean isDeprecated = false;
  2421 
  2422         public MethodData(ClassData cls) {
  2423             this.cls = cls;
  2424         }
  2425 
  2426         /**
  2427          * Read method info.
  2428          */
  2429         public void read(DataInputStream in) throws IOException {
  2430             access = in.readUnsignedShort();
  2431             name_index = in.readUnsignedShort();
  2432             descriptor_index = in.readUnsignedShort();
  2433             int attributes_count = in.readUnsignedShort();
  2434             for (int i = 0; i < attributes_count; i++) {
  2435                 int attr_name_index = in.readUnsignedShort();
  2436 
  2437                 readAttr:
  2438                 {
  2439                     if (cls.getTag(attr_name_index) == CONSTANT_UTF8) {
  2440                         String attr_name = cls.getString(attr_name_index);
  2441                         if (attr_name.equals("Code")) {
  2442                             readCode(in);
  2443                             AttrData attr = new AttrData(cls);
  2444                             attr.read(attr_name_index);
  2445                             attrs.addElement(attr);
  2446                             break readAttr;
  2447                         } else if (attr_name.equals("Exceptions")) {
  2448                             readExceptions(in);
  2449                             AttrData attr = new AttrData(cls);
  2450                             attr.read(attr_name_index);
  2451                             attrs.addElement(attr);
  2452                             break readAttr;
  2453                         } else if (attr_name.equals("Synthetic")) {
  2454                             if (in.readInt() != 0) {
  2455                                 throw new ClassFormatError("invalid Synthetic attr length");
  2456                             }
  2457                             isSynthetic = true;
  2458                             AttrData attr = new AttrData(cls);
  2459                             attr.read(attr_name_index);
  2460                             attrs.addElement(attr);
  2461                             break readAttr;
  2462                         } else if (attr_name.equals("Deprecated")) {
  2463                             if (in.readInt() != 0) {
  2464                                 throw new ClassFormatError("invalid Synthetic attr length");
  2465                             }
  2466                             isDeprecated = true;
  2467                             AttrData attr = new AttrData(cls);
  2468                             attr.read(attr_name_index);
  2469                             attrs.addElement(attr);
  2470                             break readAttr;
  2471                         }
  2472                     }
  2473                     AttrData attr = new AttrData(cls);
  2474                     attr.read(attr_name_index, in);
  2475                     attrs.addElement(attr);
  2476                 }
  2477             }
  2478         }
  2479 
  2480         /**
  2481          * Read code attribute info.
  2482          */
  2483         public void readCode(DataInputStream in) throws IOException {
  2484 
  2485             int attr_length = in.readInt();
  2486             max_stack = in.readUnsignedShort();
  2487             max_locals = in.readUnsignedShort();
  2488             int codelen = in.readInt();
  2489 
  2490             code = new byte[codelen];
  2491             int totalread = 0;
  2492             while (totalread < codelen) {
  2493                 totalread += in.read(code, totalread, codelen - totalread);
  2494             }
  2495             //      in.read(code, 0, codelen);
  2496             int clen = 0;
  2497             readExceptionTable(in);
  2498             int code_attributes_count = in.readUnsignedShort();
  2499 
  2500             for (int k = 0; k < code_attributes_count; k++) {
  2501                 int table_name_index = in.readUnsignedShort();
  2502                 int table_name_tag = cls.getTag(table_name_index);
  2503                 AttrData attr = new AttrData(cls);
  2504                 if (table_name_tag == CONSTANT_UTF8) {
  2505                     String table_name_tstr = cls.getString(table_name_index);
  2506                     if (table_name_tstr.equals("LineNumberTable")) {
  2507                         readLineNumTable(in);
  2508                         attr.read(table_name_index);
  2509                     } else if (table_name_tstr.equals("LocalVariableTable")) {
  2510                         readLocVarTable(in);
  2511                         attr.read(table_name_index);
  2512                     } else if (table_name_tstr.equals("StackMapTable")) {
  2513                         readStackMapTable(in);
  2514                         attr.read(table_name_index);
  2515                     } else if (table_name_tstr.equals("StackMap")) {
  2516                         readStackMap(in);
  2517                         attr.read(table_name_index);
  2518                     } else {
  2519                         attr.read(table_name_index, in);
  2520                     }
  2521                     code_attrs.addElement(attr);
  2522                     continue;
  2523                 }
  2524 
  2525                 attr.read(table_name_index, in);
  2526                 code_attrs.addElement(attr);
  2527             }
  2528         }
  2529 
  2530         /**
  2531          * Read exception table info.
  2532          */
  2533         void readExceptionTable(DataInputStream in) throws IOException {
  2534             int exception_table_len = in.readUnsignedShort();
  2535             exception_table = new Vector(exception_table_len);
  2536             for (int l = 0; l < exception_table_len; l++) {
  2537                 exception_table.addElement(new TrapData(in, l));
  2538             }
  2539         }
  2540 
  2541         /**
  2542          * Read LineNumberTable attribute info.
  2543          */
  2544         void readLineNumTable(DataInputStream in) throws IOException {
  2545             int attr_len = in.readInt(); // attr_length
  2546             int lin_num_tb_len = in.readUnsignedShort();
  2547             lin_num_tb = new Vector(lin_num_tb_len);
  2548             for (int l = 0; l < lin_num_tb_len; l++) {
  2549                 lin_num_tb.addElement(new LineNumData(in));
  2550             }
  2551         }
  2552 
  2553         /**
  2554          * Read LocalVariableTable attribute info.
  2555          */
  2556         void readLocVarTable(DataInputStream in) throws IOException {
  2557             int attr_len = in.readInt(); // attr_length
  2558             int loc_var_tb_len = in.readUnsignedShort();
  2559             loc_var_tb = new Vector(loc_var_tb_len);
  2560             for (int l = 0; l < loc_var_tb_len; l++) {
  2561                 loc_var_tb.addElement(new LocVarData(in));
  2562             }
  2563         }
  2564 
  2565         /**
  2566          * Read Exception attribute info.
  2567          */
  2568         public void readExceptions(DataInputStream in) throws IOException {
  2569             int attr_len = in.readInt(); // attr_length in prog
  2570             int num_exceptions = in.readUnsignedShort();
  2571             exc_index_table = new int[num_exceptions];
  2572             for (int l = 0; l < num_exceptions; l++) {
  2573                 int exc = in.readShort();
  2574                 exc_index_table[l] = exc;
  2575             }
  2576         }
  2577 
  2578         /**
  2579          * Read StackMapTable attribute info.
  2580          */
  2581         void readStackMapTable(DataInputStream in) throws IOException {
  2582             int attr_len = in.readInt();  //attr_length
  2583             int stack_map_tb_len = in.readUnsignedShort();
  2584             stackMapTable = new StackMapTableData[stack_map_tb_len];
  2585             for (int i = 0; i < stack_map_tb_len; i++) {
  2586                 stackMapTable[i] = StackMapTableData.getInstance(in, this);
  2587             }
  2588         }
  2589 
  2590         /**
  2591          * Read StackMap attribute info.
  2592          */
  2593         void readStackMap(DataInputStream in) throws IOException {
  2594             int attr_len = in.readInt();  //attr_length
  2595             int stack_map_len = in.readUnsignedShort();
  2596             stackMap = new StackMapData[stack_map_len];
  2597             for (int i = 0; i < stack_map_len; i++) {
  2598                 stackMap[i] = new StackMapData(in, this);
  2599             }
  2600         }
  2601 
  2602         /**
  2603          * Return access of the method.
  2604          */
  2605         public int getAccess() {
  2606             return access;
  2607         }
  2608 
  2609         /**
  2610          * Return name of the method.
  2611          */
  2612         public String getName() {
  2613             return cls.getStringValue(name_index);
  2614         }
  2615 
  2616         /**
  2617          * Return internal siganature of the method.
  2618          */
  2619         public String getInternalSig() {
  2620             return cls.getStringValue(descriptor_index);
  2621         }
  2622 
  2623         /**
  2624          * Return code attribute data of a method.
  2625          */
  2626         public byte[] getCode() {
  2627             return code;
  2628         }
  2629 
  2630         /**
  2631          * Return LineNumberTable size.
  2632          */
  2633         public int getnumlines() {
  2634             return lin_num_tb.size();
  2635         }
  2636 
  2637         /**
  2638          * Return LineNumberTable
  2639          */
  2640         public Vector getlin_num_tb() {
  2641             return lin_num_tb;
  2642         }
  2643 
  2644         /**
  2645          * Return LocalVariableTable size.
  2646          */
  2647         public int getloc_var_tbsize() {
  2648             return loc_var_tb.size();
  2649         }
  2650 
  2651         /**
  2652          * Return LocalVariableTable.
  2653          */
  2654         public Vector getloc_var_tb() {
  2655             return loc_var_tb;
  2656         }
  2657 
  2658         /**
  2659          * Return StackMap.
  2660          */
  2661         public StackMapData[] getStackMap() {
  2662             return stackMap;
  2663         }
  2664 
  2665         /**
  2666          * Return StackMapTable.
  2667          */
  2668         public StackMapTableData[] getStackMapTable() {
  2669             return stackMapTable;
  2670         }
  2671 
  2672         public StackMapIterator createStackMapIterator() {
  2673             return new StackMapIterator(this);
  2674         }
  2675 
  2676         /**
  2677          * Return true if method is static
  2678          */
  2679         public boolean isStatic() {
  2680             if ((access & ACC_STATIC) != 0) {
  2681                 return true;
  2682             }
  2683             return false;
  2684         }
  2685 
  2686         /**
  2687          * Return max depth of operand stack.
  2688          */
  2689         public int getMaxStack() {
  2690             return max_stack;
  2691         }
  2692 
  2693         /**
  2694          * Return number of local variables.
  2695          */
  2696         public int getMaxLocals() {
  2697             return max_locals;
  2698         }
  2699 
  2700         /**
  2701          * Return exception index table in Exception attribute.
  2702          */
  2703         public int[] get_exc_index_table() {
  2704             return exc_index_table;
  2705         }
  2706 
  2707         /**
  2708          * Return exception table in code attributre.
  2709          */
  2710         public TrapDataIterator getTrapDataIterator() {
  2711             return new TrapDataIterator(exception_table);
  2712         }
  2713 
  2714         /**
  2715          * Return method attributes.
  2716          */
  2717         public Vector getAttributes() {
  2718             return attrs;
  2719         }
  2720 
  2721         /**
  2722          * Return code attributes.
  2723          */
  2724         public Vector getCodeAttributes() {
  2725             return code_attrs;
  2726         }
  2727 
  2728         /**
  2729          * Return true if method id synthetic.
  2730          */
  2731         public boolean isSynthetic() {
  2732             return isSynthetic;
  2733         }
  2734 
  2735         /**
  2736          * Return true if method is deprecated.
  2737          */
  2738         public boolean isDeprecated() {
  2739             return isDeprecated;
  2740         }
  2741 
  2742         public byte[] findAnnotationData(boolean classRetention) {
  2743             String n = classRetention
  2744                 ? "RuntimeInvisibleAnnotations" : // NOI18N
  2745                 "RuntimeVisibleAnnotations"; // NOI18N
  2746             AttrData[] arr = new AttrData[attrs.size()];
  2747             attrs.copyInto(arr);
  2748             return ClassData.findAttr(n, arr);
  2749         }
  2750 
  2751         public boolean isConstructor() {
  2752             return "<init>".equals(getName());
  2753         }
  2754     }
  2755 
  2756     /* represents one entry of StackMap attribute
  2757      */
  2758     private static class StackMapData {
  2759 
  2760         final int offset;
  2761         final int[] locals;
  2762         final int[] stack;
  2763 
  2764         StackMapData(int offset, int[] locals, int[] stack) {
  2765             this.offset = offset;
  2766             this.locals = locals;
  2767             this.stack = stack;
  2768         }
  2769 
  2770         StackMapData(DataInputStream in, MethodData method) throws IOException {
  2771             offset = in.readUnsignedShort();
  2772             int local_size = in.readUnsignedShort();
  2773             locals = readTypeArray(in, local_size, method);
  2774             int stack_size = in.readUnsignedShort();
  2775             stack = readTypeArray(in, stack_size, method);
  2776         }
  2777 
  2778         static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException {
  2779             int[] types = new int[length];
  2780             for (int i = 0; i < length; i++) {
  2781                 types[i] = readType(in, method);
  2782             }
  2783             return types;
  2784         }
  2785 
  2786         static final int readType(DataInputStream in, MethodData method) throws IOException {
  2787             int type = in.readUnsignedByte();
  2788             if (type == ITEM_Object || type == ITEM_NewObject) {
  2789                 type = type | (in.readUnsignedShort() << 8);
  2790             }
  2791             return type;
  2792         }
  2793     }
  2794 
  2795     static final class StackMapIterator {
  2796 
  2797         private final StackMapTableData[] stackMapTable;
  2798         private final TypeArray argTypes;
  2799         private final TypeArray localTypes;
  2800         private final TypeArray stackTypes;
  2801         private int nextFrameIndex;
  2802         private int lastFrameByteCodeOffset;
  2803         private int byteCodeOffset;
  2804 
  2805         StackMapIterator(final MethodData methodData) {
  2806             this(methodData.getStackMapTable(),
  2807                 methodData.getInternalSig(),
  2808                 methodData.isStatic());
  2809         }
  2810 
  2811         StackMapIterator(final StackMapTableData[] stackMapTable,
  2812             final String methodSignature,
  2813             final boolean isStaticMethod) {
  2814             this.stackMapTable = (stackMapTable != null)
  2815                 ? stackMapTable
  2816                 : new StackMapTableData[0];
  2817 
  2818             argTypes = getArgTypes(methodSignature, isStaticMethod);
  2819             localTypes = new TypeArray();
  2820             stackTypes = new TypeArray();
  2821 
  2822             localTypes.addAll(argTypes);
  2823 
  2824             lastFrameByteCodeOffset = -1;
  2825             advanceBy(0);
  2826         }
  2827 
  2828         public String getFrameAsString() {
  2829             return (nextFrameIndex == 0)
  2830                 ? StackMapTableData.toString("INITIAL", 0, null, null)
  2831                 : stackMapTable[nextFrameIndex - 1].toString();
  2832         }
  2833 
  2834         public int getFrameIndex() {
  2835             return nextFrameIndex;
  2836         }
  2837 
  2838         public TypeArray getFrameStack() {
  2839             return stackTypes;
  2840         }
  2841 
  2842         public TypeArray getFrameLocals() {
  2843             return localTypes;
  2844         }
  2845 
  2846         public TypeArray getArguments() {
  2847             return argTypes;
  2848         }
  2849 
  2850         public void advanceBy(final int numByteCodes) {
  2851             if (numByteCodes < 0) {
  2852                 throw new IllegalStateException("Forward only iterator");
  2853             }
  2854 
  2855             byteCodeOffset += numByteCodes;
  2856             while ((nextFrameIndex < stackMapTable.length)
  2857                 && ((byteCodeOffset - lastFrameByteCodeOffset)
  2858                 >= (stackMapTable[nextFrameIndex].offsetDelta
  2859                 + 1))) {
  2860                 final StackMapTableData nextFrame = stackMapTable[nextFrameIndex];
  2861 
  2862                 lastFrameByteCodeOffset += nextFrame.offsetDelta + 1;
  2863                 nextFrame.applyTo(localTypes, stackTypes);
  2864 
  2865                 ++nextFrameIndex;
  2866             }
  2867         }
  2868 
  2869         public void advanceTo(final int nextByteCodeOffset) {
  2870             advanceBy(nextByteCodeOffset - byteCodeOffset);
  2871         }
  2872 
  2873         private static TypeArray getArgTypes(final String methodSignature,
  2874             final boolean isStaticMethod) {
  2875             final TypeArray argTypes = new TypeArray();
  2876 
  2877             if (!isStaticMethod) {
  2878                 argTypes.add(ITEM_Object);
  2879             }
  2880 
  2881             if (methodSignature.charAt(0) != '(') {
  2882                 throw new IllegalArgumentException("Invalid method signature");
  2883             }
  2884 
  2885             final int length = methodSignature.length();
  2886             boolean skipType = false;
  2887             int argType;
  2888             for (int i = 1; i < length; ++i) {
  2889                 switch (methodSignature.charAt(i)) {
  2890                     case 'B':
  2891                     case 'C':
  2892                     case 'S':
  2893                     case 'Z':
  2894                     case 'I':
  2895                         argType = ITEM_Integer;
  2896                         break;
  2897                     case 'J':
  2898                         argType = ITEM_Long;
  2899                         break;
  2900                     case 'F':
  2901                         argType = ITEM_Float;
  2902                         break;
  2903                     case 'D':
  2904                         argType = ITEM_Double;
  2905                         break;
  2906                     case 'L': {
  2907                         i = methodSignature.indexOf(';', i + 1);
  2908                         if (i == -1) {
  2909                             throw new IllegalArgumentException(
  2910                                 "Invalid method signature");
  2911                         }
  2912                         argType = ITEM_Object;
  2913                         break;
  2914                     }
  2915                     case ')':
  2916                         // not interested in the return value type
  2917                         return argTypes;
  2918                     case '[':
  2919                         if (!skipType) {
  2920                             argTypes.add(ITEM_Object);
  2921                             skipType = true;
  2922                         }
  2923                         continue;
  2924 
  2925                     default:
  2926                         throw new IllegalArgumentException(
  2927                             "Invalid method signature");
  2928                 }
  2929 
  2930                 if (!skipType) {
  2931                     argTypes.add(argType);
  2932                 } else {
  2933                     skipType = false;
  2934                 }
  2935             }
  2936 
  2937             return argTypes;
  2938         }
  2939     }
  2940     /* represents one entry of StackMapTable attribute
  2941      */
  2942 
  2943     private static abstract class StackMapTableData {
  2944 
  2945         final int frameType;
  2946         int offsetDelta;
  2947 
  2948         StackMapTableData(int frameType) {
  2949             this.frameType = frameType;
  2950         }
  2951 
  2952         abstract void applyTo(TypeArray localTypes, TypeArray stackTypes);
  2953 
  2954         protected static String toString(
  2955             final String frameType,
  2956             final int offset,
  2957             final int[] localTypes,
  2958             final int[] stackTypes) {
  2959             final StringBuilder sb = new StringBuilder(frameType);
  2960 
  2961             sb.append("(off: +").append(offset);
  2962             if (localTypes != null) {
  2963                 sb.append(", locals: ");
  2964                 appendTypes(sb, localTypes);
  2965             }
  2966             if (stackTypes != null) {
  2967                 sb.append(", stack: ");
  2968                 appendTypes(sb, stackTypes);
  2969             }
  2970             sb.append(')');
  2971 
  2972             return sb.toString();
  2973         }
  2974 
  2975         private static void appendTypes(final StringBuilder sb, final int[] types) {
  2976             sb.append('[');
  2977             if (types.length > 0) {
  2978                 sb.append(TypeArray.typeString(types[0]));
  2979                 for (int i = 1; i < types.length; ++i) {
  2980                     sb.append(", ");
  2981                     sb.append(TypeArray.typeString(types[i]));
  2982                 }
  2983             }
  2984             sb.append(']');
  2985         }
  2986 
  2987         private static class SameFrame extends StackMapTableData {
  2988 
  2989             SameFrame(int frameType, int offsetDelta) {
  2990                 super(frameType);
  2991                 this.offsetDelta = offsetDelta;
  2992             }
  2993 
  2994             @Override
  2995             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  2996                 stackTypes.clear();
  2997             }
  2998 
  2999             @Override
  3000             public String toString() {
  3001                 return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED)
  3002                     ? "_FRAME_EXTENDED" : ""),
  3003                     offsetDelta,
  3004                     null, null);
  3005             }
  3006         }
  3007 
  3008         private static class SameLocals1StackItem extends StackMapTableData {
  3009 
  3010             final int[] stack;
  3011 
  3012             SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) {
  3013                 super(frameType);
  3014                 this.offsetDelta = offsetDelta;
  3015                 this.stack = stack;
  3016             }
  3017 
  3018             @Override
  3019             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  3020                 stackTypes.setAll(stack);
  3021             }
  3022 
  3023             @Override
  3024             public String toString() {
  3025                 return toString(
  3026                     "SAME_LOCALS_1_STACK_ITEM"
  3027                     + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED)
  3028                     ? "_EXTENDED" : ""),
  3029                     offsetDelta,
  3030                     null, stack);
  3031             }
  3032         }
  3033 
  3034         private static class ChopFrame extends StackMapTableData {
  3035 
  3036             ChopFrame(int frameType, int offsetDelta) {
  3037                 super(frameType);
  3038                 this.offsetDelta = offsetDelta;
  3039             }
  3040 
  3041             @Override
  3042             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  3043                 localTypes.setSize(localTypes.getSize()
  3044                     - (SAME_FRAME_EXTENDED - frameType));
  3045                 stackTypes.clear();
  3046             }
  3047 
  3048             @Override
  3049             public String toString() {
  3050                 return toString("CHOP", offsetDelta, null, null);
  3051             }
  3052         }
  3053 
  3054         private static class AppendFrame extends StackMapTableData {
  3055 
  3056             final int[] locals;
  3057 
  3058             AppendFrame(int frameType, int offsetDelta, int[] locals) {
  3059                 super(frameType);
  3060                 this.offsetDelta = offsetDelta;
  3061                 this.locals = locals;
  3062             }
  3063 
  3064             @Override
  3065             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  3066                 localTypes.addAll(locals);
  3067                 stackTypes.clear();
  3068             }
  3069 
  3070             @Override
  3071             public String toString() {
  3072                 return toString("APPEND", offsetDelta, locals, null);
  3073             }
  3074         }
  3075 
  3076         private static class FullFrame extends StackMapTableData {
  3077 
  3078             final int[] locals;
  3079             final int[] stack;
  3080 
  3081             FullFrame(int offsetDelta, int[] locals, int[] stack) {
  3082                 super(FULL_FRAME);
  3083                 this.offsetDelta = offsetDelta;
  3084                 this.locals = locals;
  3085                 this.stack = stack;
  3086             }
  3087 
  3088             @Override
  3089             void applyTo(TypeArray localTypes, TypeArray stackTypes) {
  3090                 localTypes.setAll(locals);
  3091                 stackTypes.setAll(stack);
  3092             }
  3093 
  3094             @Override
  3095             public String toString() {
  3096                 return toString("FULL", offsetDelta, locals, stack);
  3097             }
  3098         }
  3099 
  3100         static StackMapTableData getInstance(DataInputStream in, MethodData method)
  3101             throws IOException {
  3102             int frameType = in.readUnsignedByte();
  3103 
  3104             if (frameType < SAME_FRAME_BOUND) {
  3105                 // same_frame
  3106                 return new SameFrame(frameType, frameType);
  3107             } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) {
  3108                 // same_locals_1_stack_item_frame
  3109                 // read additional single stack element
  3110                 return new SameLocals1StackItem(frameType,
  3111                     (frameType - SAME_FRAME_BOUND),
  3112                     StackMapData.readTypeArray(in, 1, method));
  3113             } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
  3114                 // same_locals_1_stack_item_extended
  3115                 return new SameLocals1StackItem(frameType,
  3116                     in.readUnsignedShort(),
  3117                     StackMapData.readTypeArray(in, 1, method));
  3118             } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) {
  3119                 // chop_frame or same_frame_extended
  3120                 return new ChopFrame(frameType, in.readUnsignedShort());
  3121             } else if (frameType == SAME_FRAME_EXTENDED) {
  3122                 // chop_frame or same_frame_extended
  3123                 return new SameFrame(frameType, in.readUnsignedShort());
  3124             } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) {
  3125                 // append_frame
  3126                 return new AppendFrame(frameType, in.readUnsignedShort(),
  3127                     StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method));
  3128             } else if (frameType == FULL_FRAME) {
  3129                 // full_frame
  3130                 int offsetDelta = in.readUnsignedShort();
  3131                 int locals_size = in.readUnsignedShort();
  3132                 int[] locals = StackMapData.readTypeArray(in, locals_size, method);
  3133                 int stack_size = in.readUnsignedShort();
  3134                 int[] stack = StackMapData.readTypeArray(in, stack_size, method);
  3135                 return new FullFrame(offsetDelta, locals, stack);
  3136             } else {
  3137                 throw new ClassFormatError("unrecognized frame_type in StackMapTable");
  3138             }
  3139         }
  3140     }
  3141 
  3142     /**
  3143      * Stores exception table data in code attribute.
  3144      *
  3145      * @author Sucheta Dambalkar (Adopted code from jdis)
  3146      */
  3147     static final class TrapData {
  3148 
  3149         public final short start_pc;
  3150         public final short end_pc;
  3151         public final short handler_pc;
  3152         public final short catch_cpx;
  3153         final int num;
  3154 
  3155         /**
  3156          * Read and store exception table data in code attribute.
  3157          */
  3158         TrapData(DataInputStream in, int num) throws IOException {
  3159             this.num = num;
  3160             start_pc = in.readShort();
  3161             end_pc = in.readShort();
  3162             handler_pc = in.readShort();
  3163             catch_cpx = in.readShort();
  3164         }
  3165 
  3166         /**
  3167          * returns recommended identifier
  3168          */
  3169         public String ident() {
  3170             return "t" + num;
  3171         }
  3172     }
  3173     /**
  3174      *
  3175      * @author Jaroslav Tulach <jtulach@netbeans.org>
  3176      */
  3177     static final class TrapDataIterator {
  3178 
  3179         private final Hashtable exStart = new Hashtable();
  3180         private final Hashtable exStop = new Hashtable();
  3181         private TrapData[] current = new TrapData[10];
  3182         private int currentCount;
  3183 
  3184         TrapDataIterator(Vector exceptionTable) {
  3185             for (int i = 0; i < exceptionTable.size(); i++) {
  3186                 final TrapData td = (TrapData) exceptionTable.elementAt(i);
  3187                 put(exStart, td.start_pc, td);
  3188                 put(exStop, td.end_pc, td);
  3189             }
  3190         }
  3191 
  3192         private static void put(Hashtable h, short key, TrapData td) {
  3193             Short s = Short.valueOf((short) key);
  3194             Vector v = (Vector) h.get(s);
  3195             if (v == null) {
  3196                 v = new Vector(1);
  3197                 h.put(s, v);
  3198             }
  3199             v.add(td);
  3200         }
  3201 
  3202         private boolean processAll(Hashtable h, Short key, boolean add) {
  3203             boolean change = false;
  3204             Vector v = (Vector) h.get(key);
  3205             if (v != null) {
  3206                 int s = v.size();
  3207                 for (int i = 0; i < s; i++) {
  3208                     TrapData td = (TrapData) v.elementAt(i);
  3209                     if (add) {
  3210                         add(td);
  3211                         change = true;
  3212                     } else {
  3213                         remove(td);
  3214                         change = true;
  3215                     }
  3216                 }
  3217             }
  3218             return change;
  3219         }
  3220 
  3221         public boolean advanceTo(int i) {
  3222             Short s = Short.valueOf((short) i);
  3223             boolean ch1 = processAll(exStart, s, true);
  3224             boolean ch2 = processAll(exStop, s, false);
  3225             return ch1 || ch2;
  3226         }
  3227 
  3228         public boolean useTry() {
  3229             return currentCount > 0;
  3230         }
  3231 
  3232         public TrapData[] current() {
  3233             TrapData[] copy = new TrapData[currentCount];
  3234             for (int i = 0; i < currentCount; i++) {
  3235                 copy[i] = current[i];
  3236             }
  3237             return copy;
  3238         }
  3239 
  3240         private void add(TrapData e) {
  3241             if (currentCount == current.length) {
  3242                 TrapData[] data = new TrapData[currentCount * 2];
  3243                 for (int i = 0; i < currentCount; i++) {
  3244                     data[i] = current[i];
  3245                 }
  3246                 current = data;
  3247             }
  3248             current[currentCount++] = e;
  3249         }
  3250 
  3251         private void remove(TrapData e) {
  3252             if (currentCount == 0) {
  3253                 return;
  3254             }
  3255             int from = 0;
  3256             while (from < currentCount) {
  3257                 if (e == current[from++]) {
  3258                     break;
  3259                 }
  3260             }
  3261             while (from < currentCount) {
  3262                 current[from - 1] = current[from];
  3263                 current[from] = null;
  3264                 from++;
  3265             }
  3266             currentCount--;
  3267         }
  3268     }
  3269     static final class TypeArray {
  3270 
  3271         private static final int CAPACITY_INCREMENT = 16;
  3272         private int[] types;
  3273         private int size;
  3274 
  3275         public TypeArray() {
  3276         }
  3277 
  3278         public TypeArray(final TypeArray initialTypes) {
  3279             setAll(initialTypes);
  3280         }
  3281 
  3282         public void add(final int newType) {
  3283             ensureCapacity(size + 1);
  3284             types[size++] = newType;
  3285         }
  3286 
  3287         public void addAll(final TypeArray newTypes) {
  3288             addAll(newTypes.types, 0, newTypes.size);
  3289         }
  3290 
  3291         public void addAll(final int[] newTypes) {
  3292             addAll(newTypes, 0, newTypes.length);
  3293         }
  3294 
  3295         public void addAll(final int[] newTypes,
  3296             final int offset,
  3297             final int count) {
  3298             if (count > 0) {
  3299                 ensureCapacity(size + count);
  3300                 arraycopy(newTypes, offset, types, size, count);
  3301                 size += count;
  3302             }
  3303         }
  3304 
  3305         public void set(final int index, final int newType) {
  3306             types[index] = newType;
  3307         }
  3308 
  3309         public void setAll(final TypeArray newTypes) {
  3310             setAll(newTypes.types, 0, newTypes.size);
  3311         }
  3312 
  3313         public void setAll(final int[] newTypes) {
  3314             setAll(newTypes, 0, newTypes.length);
  3315         }
  3316 
  3317         public void setAll(final int[] newTypes,
  3318             final int offset,
  3319             final int count) {
  3320             if (count > 0) {
  3321                 ensureCapacity(count);
  3322                 arraycopy(newTypes, offset, types, 0, count);
  3323                 size = count;
  3324             } else {
  3325                 clear();
  3326             }
  3327         }
  3328 
  3329         public void setSize(final int newSize) {
  3330             if (size != newSize) {
  3331                 ensureCapacity(newSize);
  3332 
  3333                 for (int i = size; i < newSize; ++i) {
  3334                     types[i] = 0;
  3335                 }
  3336                 size = newSize;
  3337             }
  3338         }
  3339 
  3340         public void clear() {
  3341             size = 0;
  3342         }
  3343 
  3344         public int getSize() {
  3345             return size;
  3346         }
  3347 
  3348         public int get(final int index) {
  3349             return types[index];
  3350         }
  3351 
  3352         public static String typeString(final int type) {
  3353             switch (type & 0xff) {
  3354                 case ITEM_Bogus:
  3355                     return "_top_";
  3356                 case ITEM_Integer:
  3357                     return "_int_";
  3358                 case ITEM_Float:
  3359                     return "_float_";
  3360                 case ITEM_Double:
  3361                     return "_double_";
  3362                 case ITEM_Long:
  3363                     return "_long_";
  3364                 case ITEM_Null:
  3365                     return "_null_";
  3366                 case ITEM_InitObject: // UninitializedThis
  3367                     return "_init_";
  3368                 case ITEM_Object:
  3369                     return "_object_";
  3370                 case ITEM_NewObject: // Uninitialized
  3371                     return "_new_";
  3372                 default:
  3373                     throw new IllegalArgumentException("Unknown type");
  3374             }
  3375         }
  3376 
  3377         @Override
  3378         public String toString() {
  3379             final StringBuilder sb = new StringBuilder("[");
  3380             if (size > 0) {
  3381                 sb.append(typeString(types[0]));
  3382                 for (int i = 1; i < size; ++i) {
  3383                     sb.append(", ");
  3384                     sb.append(typeString(types[i]));
  3385                 }
  3386             }
  3387 
  3388             return sb.append(']').toString();
  3389         }
  3390 
  3391         private void ensureCapacity(final int minCapacity) {
  3392             if ((minCapacity == 0)
  3393                 || (types != null) && (minCapacity <= types.length)) {
  3394                 return;
  3395             }
  3396 
  3397             final int newCapacity =
  3398                 ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT)
  3399                 * CAPACITY_INCREMENT;
  3400             final int[] newTypes = new int[newCapacity];
  3401 
  3402             if (size > 0) {
  3403                 arraycopy(types, 0, newTypes, 0, size);
  3404             }
  3405 
  3406             types = newTypes;
  3407         }
  3408 
  3409         // no System.arraycopy
  3410         private void arraycopy(final int[] src, final int srcPos,
  3411             final int[] dest, final int destPos,
  3412             final int length) {
  3413             for (int i = 0; i < length; ++i) {
  3414                 dest[destPos + i] = src[srcPos + i];
  3415             }
  3416         }
  3417     }
  3418     /**
  3419      * A JavaScript ready replacement for java.util.Vector
  3420      *
  3421      * @author Jaroslav Tulach <jtulach@netbeans.org>
  3422      */
  3423     @JavaScriptPrototype(prototype = "new Array")
  3424     private static final class Vector {
  3425 
  3426         private Object[] arr;
  3427 
  3428         Vector() {
  3429         }
  3430 
  3431         Vector(int i) {
  3432         }
  3433 
  3434         void add(Object objectType) {
  3435             addElement(objectType);
  3436         }
  3437 
  3438         @JavaScriptBody(args = {"obj"}, body =
  3439             "this.push(obj);")
  3440         void addElement(Object obj) {
  3441             final int s = size();
  3442             setSize(s + 1);
  3443             setElementAt(obj, s);
  3444         }
  3445 
  3446         @JavaScriptBody(args = {}, body =
  3447             "return this.length;")
  3448         int size() {
  3449             return arr == null ? 0 : arr.length;
  3450         }
  3451 
  3452         @JavaScriptBody(args = {"newArr"}, body =
  3453             "for (var i = 0; i < this.length; i++) {\n"
  3454             + "  newArr[i] = this[i];\n"
  3455             + "}\n")
  3456         void copyInto(Object[] newArr) {
  3457             if (arr == null) {
  3458                 return;
  3459             }
  3460             int min = Math.min(newArr.length, arr.length);
  3461             for (int i = 0; i < min; i++) {
  3462                 newArr[i] = arr[i];
  3463             }
  3464         }
  3465 
  3466         @JavaScriptBody(args = {"index"}, body =
  3467             "return this[index];")
  3468         Object elementAt(int index) {
  3469             return arr[index];
  3470         }
  3471 
  3472         private void setSize(int len) {
  3473             Object[] newArr = new Object[len];
  3474             copyInto(newArr);
  3475             arr = newArr;
  3476         }
  3477 
  3478         @JavaScriptBody(args = {"val", "index"}, body =
  3479             "this[index] = val;")
  3480         void setElementAt(Object val, int index) {
  3481             arr[index] = val;
  3482         }
  3483     }
  3484     
  3485 }