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