1 /*
   2  * Copyright (c) 1999, 2008, 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 
  26 package sun.misc;
  27 
  28 import java.io.ByteArrayOutputStream;
  29 import java.io.DataOutputStream;
  30 import java.io.FileOutputStream;
  31 import java.io.IOException;
  32 import java.io.OutputStream;
  33 import java.lang.reflect.Array;
  34 import java.lang.reflect.Method;
  35 import java.util.ArrayList;
  36 import java.util.HashMap;
  37 import java.util.LinkedList;
  38 import java.util.List;
  39 import java.util.ListIterator;
  40 import java.util.Map;
  41 import sun.security.action.GetBooleanAction;
  42 
  43 /**
  44  * ProxyGenerator contains the code to generate a dynamic proxy class
  45  * for the java.lang.reflect.Proxy API.
  46  *
  47  * The external interfaces to ProxyGenerator is the static
  48  * "generateProxyClass" method.
  49  *
  50  * @author      Peter Jones
  51  * @since       1.3
  52  */
  53 public class ProxyGenerator {
  54     /*
  55      * In the comments below, "JVMS" refers to The Java Virtual Machine
  56      * Specification Second Edition and "JLS" refers to the original
  57      * version of The Java Language Specification, unless otherwise
  58      * specified.
  59      */
  60 
  61     /* generate 1.5-era class file version */
  62     private static final int CLASSFILE_MAJOR_VERSION = 49;
  63     private static final int CLASSFILE_MINOR_VERSION = 0;
  64 
  65     /*
  66      * beginning of constants copied from
  67      * sun.tools.java.RuntimeConstants (which no longer exists):
  68      */
  69 
  70     /* constant pool tags */
  71     private static final int CONSTANT_UTF8              = 1;
  72     private static final int CONSTANT_UNICODE           = 2;
  73     private static final int CONSTANT_INTEGER           = 3;
  74     private static final int CONSTANT_FLOAT             = 4;
  75     private static final int CONSTANT_LONG              = 5;
  76     private static final int CONSTANT_DOUBLE            = 6;
  77     private static final int CONSTANT_CLASS             = 7;
  78     private static final int CONSTANT_STRING            = 8;
  79     private static final int CONSTANT_FIELD             = 9;
  80     private static final int CONSTANT_METHOD            = 10;
  81     private static final int CONSTANT_INTERFACEMETHOD   = 11;
  82     private static final int CONSTANT_NAMEANDTYPE       = 12;
  83 
  84     /* access and modifier flags */
  85     private static final int ACC_PUBLIC                 = 0x00000001;
  86     private static final int ACC_PRIVATE                = 0x00000002;
  87 //  private static final int ACC_PROTECTED              = 0x00000004;
  88     private static final int ACC_STATIC                 = 0x00000008;
  89     private static final int ACC_FINAL                  = 0x00000010;
  90 //  private static final int ACC_SYNCHRONIZED           = 0x00000020;
  91 //  private static final int ACC_VOLATILE               = 0x00000040;
  92 //  private static final int ACC_TRANSIENT              = 0x00000080;
  93 //  private static final int ACC_NATIVE                 = 0x00000100;
  94 //  private static final int ACC_INTERFACE              = 0x00000200;
  95 //  private static final int ACC_ABSTRACT               = 0x00000400;
  96     private static final int ACC_SUPER                  = 0x00000020;
  97 //  private static final int ACC_STRICT                 = 0x00000800;
  98 
  99     /* opcodes */
 100 //  private static final int opc_nop                    = 0;
 101     private static final int opc_aconst_null            = 1;
 102 //  private static final int opc_iconst_m1              = 2;
 103     private static final int opc_iconst_0               = 3;
 104 //  private static final int opc_iconst_1               = 4;
 105 //  private static final int opc_iconst_2               = 5;
 106 //  private static final int opc_iconst_3               = 6;
 107 //  private static final int opc_iconst_4               = 7;
 108 //  private static final int opc_iconst_5               = 8;
 109 //  private static final int opc_lconst_0               = 9;
 110 //  private static final int opc_lconst_1               = 10;
 111 //  private static final int opc_fconst_0               = 11;
 112 //  private static final int opc_fconst_1               = 12;
 113 //  private static final int opc_fconst_2               = 13;
 114 //  private static final int opc_dconst_0               = 14;
 115 //  private static final int opc_dconst_1               = 15;
 116     private static final int opc_bipush                 = 16;
 117     private static final int opc_sipush                 = 17;
 118     private static final int opc_ldc                    = 18;
 119     private static final int opc_ldc_w                  = 19;
 120 //  private static final int opc_ldc2_w                 = 20;
 121     private static final int opc_iload                  = 21;
 122     private static final int opc_lload                  = 22;
 123     private static final int opc_fload                  = 23;
 124     private static final int opc_dload                  = 24;
 125     private static final int opc_aload                  = 25;
 126     private static final int opc_iload_0                = 26;
 127 //  private static final int opc_iload_1                = 27;
 128 //  private static final int opc_iload_2                = 28;
 129 //  private static final int opc_iload_3                = 29;
 130     private static final int opc_lload_0                = 30;
 131 //  private static final int opc_lload_1                = 31;
 132 //  private static final int opc_lload_2                = 32;
 133 //  private static final int opc_lload_3                = 33;
 134     private static final int opc_fload_0                = 34;
 135 //  private static final int opc_fload_1                = 35;
 136 //  private static final int opc_fload_2                = 36;
 137 //  private static final int opc_fload_3                = 37;
 138     private static final int opc_dload_0                = 38;
 139 //  private static final int opc_dload_1                = 39;
 140 //  private static final int opc_dload_2                = 40;
 141 //  private static final int opc_dload_3                = 41;
 142     private static final int opc_aload_0                = 42;
 143 //  private static final int opc_aload_1                = 43;
 144 //  private static final int opc_aload_2                = 44;
 145 //  private static final int opc_aload_3                = 45;
 146 //  private static final int opc_iaload                 = 46;
 147 //  private static final int opc_laload                 = 47;
 148 //  private static final int opc_faload                 = 48;
 149 //  private static final int opc_daload                 = 49;
 150 //  private static final int opc_aaload                 = 50;
 151 //  private static final int opc_baload                 = 51;
 152 //  private static final int opc_caload                 = 52;
 153 //  private static final int opc_saload                 = 53;
 154 //  private static final int opc_istore                 = 54;
 155 //  private static final int opc_lstore                 = 55;
 156 //  private static final int opc_fstore                 = 56;
 157 //  private static final int opc_dstore                 = 57;
 158     private static final int opc_astore                 = 58;
 159 //  private static final int opc_istore_0               = 59;
 160 //  private static final int opc_istore_1               = 60;
 161 //  private static final int opc_istore_2               = 61;
 162 //  private static final int opc_istore_3               = 62;
 163 //  private static final int opc_lstore_0               = 63;
 164 //  private static final int opc_lstore_1               = 64;
 165 //  private static final int opc_lstore_2               = 65;
 166 //  private static final int opc_lstore_3               = 66;
 167 //  private static final int opc_fstore_0               = 67;
 168 //  private static final int opc_fstore_1               = 68;
 169 //  private static final int opc_fstore_2               = 69;
 170 //  private static final int opc_fstore_3               = 70;
 171 //  private static final int opc_dstore_0               = 71;
 172 //  private static final int opc_dstore_1               = 72;
 173 //  private static final int opc_dstore_2               = 73;
 174 //  private static final int opc_dstore_3               = 74;
 175     private static final int opc_astore_0               = 75;
 176 //  private static final int opc_astore_1               = 76;
 177 //  private static final int opc_astore_2               = 77;
 178 //  private static final int opc_astore_3               = 78;
 179 //  private static final int opc_iastore                = 79;
 180 //  private static final int opc_lastore                = 80;
 181 //  private static final int opc_fastore                = 81;
 182 //  private static final int opc_dastore                = 82;
 183     private static final int opc_aastore                = 83;
 184 //  private static final int opc_bastore                = 84;
 185 //  private static final int opc_castore                = 85;
 186 //  private static final int opc_sastore                = 86;
 187     private static final int opc_pop                    = 87;
 188 //  private static final int opc_pop2                   = 88;
 189     private static final int opc_dup                    = 89;
 190 //  private static final int opc_dup_x1                 = 90;
 191 //  private static final int opc_dup_x2                 = 91;
 192 //  private static final int opc_dup2                   = 92;
 193 //  private static final int opc_dup2_x1                = 93;
 194 //  private static final int opc_dup2_x2                = 94;
 195 //  private static final int opc_swap                   = 95;
 196 //  private static final int opc_iadd                   = 96;
 197 //  private static final int opc_ladd                   = 97;
 198 //  private static final int opc_fadd                   = 98;
 199 //  private static final int opc_dadd                   = 99;
 200 //  private static final int opc_isub                   = 100;
 201 //  private static final int opc_lsub                   = 101;
 202 //  private static final int opc_fsub                   = 102;
 203 //  private static final int opc_dsub                   = 103;
 204 //  private static final int opc_imul                   = 104;
 205 //  private static final int opc_lmul                   = 105;
 206 //  private static final int opc_fmul                   = 106;
 207 //  private static final int opc_dmul                   = 107;
 208 //  private static final int opc_idiv                   = 108;
 209 //  private static final int opc_ldiv                   = 109;
 210 //  private static final int opc_fdiv                   = 110;
 211 //  private static final int opc_ddiv                   = 111;
 212 //  private static final int opc_irem                   = 112;
 213 //  private static final int opc_lrem                   = 113;
 214 //  private static final int opc_frem                   = 114;
 215 //  private static final int opc_drem                   = 115;
 216 //  private static final int opc_ineg                   = 116;
 217 //  private static final int opc_lneg                   = 117;
 218 //  private static final int opc_fneg                   = 118;
 219 //  private static final int opc_dneg                   = 119;
 220 //  private static final int opc_ishl                   = 120;
 221 //  private static final int opc_lshl                   = 121;
 222 //  private static final int opc_ishr                   = 122;
 223 //  private static final int opc_lshr                   = 123;
 224 //  private static final int opc_iushr                  = 124;
 225 //  private static final int opc_lushr                  = 125;
 226 //  private static final int opc_iand                   = 126;
 227 //  private static final int opc_land                   = 127;
 228 //  private static final int opc_ior                    = 128;
 229 //  private static final int opc_lor                    = 129;
 230 //  private static final int opc_ixor                   = 130;
 231 //  private static final int opc_lxor                   = 131;
 232 //  private static final int opc_iinc                   = 132;
 233 //  private static final int opc_i2l                    = 133;
 234 //  private static final int opc_i2f                    = 134;
 235 //  private static final int opc_i2d                    = 135;
 236 //  private static final int opc_l2i                    = 136;
 237 //  private static final int opc_l2f                    = 137;
 238 //  private static final int opc_l2d                    = 138;
 239 //  private static final int opc_f2i                    = 139;
 240 //  private static final int opc_f2l                    = 140;
 241 //  private static final int opc_f2d                    = 141;
 242 //  private static final int opc_d2i                    = 142;
 243 //  private static final int opc_d2l                    = 143;
 244 //  private static final int opc_d2f                    = 144;
 245 //  private static final int opc_i2b                    = 145;
 246 //  private static final int opc_i2c                    = 146;
 247 //  private static final int opc_i2s                    = 147;
 248 //  private static final int opc_lcmp                   = 148;
 249 //  private static final int opc_fcmpl                  = 149;
 250 //  private static final int opc_fcmpg                  = 150;
 251 //  private static final int opc_dcmpl                  = 151;
 252 //  private static final int opc_dcmpg                  = 152;
 253 //  private static final int opc_ifeq                   = 153;
 254 //  private static final int opc_ifne                   = 154;
 255 //  private static final int opc_iflt                   = 155;
 256 //  private static final int opc_ifge                   = 156;
 257 //  private static final int opc_ifgt                   = 157;
 258 //  private static final int opc_ifle                   = 158;
 259 //  private static final int opc_if_icmpeq              = 159;
 260 //  private static final int opc_if_icmpne              = 160;
 261 //  private static final int opc_if_icmplt              = 161;
 262 //  private static final int opc_if_icmpge              = 162;
 263 //  private static final int opc_if_icmpgt              = 163;
 264 //  private static final int opc_if_icmple              = 164;
 265 //  private static final int opc_if_acmpeq              = 165;
 266 //  private static final int opc_if_acmpne              = 166;
 267 //  private static final int opc_goto                   = 167;
 268 //  private static final int opc_jsr                    = 168;
 269 //  private static final int opc_ret                    = 169;
 270 //  private static final int opc_tableswitch            = 170;
 271 //  private static final int opc_lookupswitch           = 171;
 272     private static final int opc_ireturn                = 172;
 273     private static final int opc_lreturn                = 173;
 274     private static final int opc_freturn                = 174;
 275     private static final int opc_dreturn                = 175;
 276     private static final int opc_areturn                = 176;
 277     private static final int opc_return                 = 177;
 278     private static final int opc_getstatic              = 178;
 279     private static final int opc_putstatic              = 179;
 280     private static final int opc_getfield               = 180;
 281 //  private static final int opc_putfield               = 181;
 282     private static final int opc_invokevirtual          = 182;
 283     private static final int opc_invokespecial          = 183;
 284     private static final int opc_invokestatic           = 184;
 285     private static final int opc_invokeinterface        = 185;
 286     private static final int opc_new                    = 187;
 287 //  private static final int opc_newarray               = 188;
 288     private static final int opc_anewarray              = 189;
 289 //  private static final int opc_arraylength            = 190;
 290     private static final int opc_athrow                 = 191;
 291     private static final int opc_checkcast              = 192;
 292 //  private static final int opc_instanceof             = 193;
 293 //  private static final int opc_monitorenter           = 194;
 294 //  private static final int opc_monitorexit            = 195;
 295     private static final int opc_wide                   = 196;
 296 //  private static final int opc_multianewarray         = 197;
 297 //  private static final int opc_ifnull                 = 198;
 298 //  private static final int opc_ifnonnull              = 199;
 299 //  private static final int opc_goto_w                 = 200;
 300 //  private static final int opc_jsr_w                  = 201;
 301 
 302     // end of constants copied from sun.tools.java.RuntimeConstants
 303 
 304     /** name of the superclass of proxy classes */
 305     private final static String superclassName = "java/lang/reflect/Proxy";
 306 
 307     /** name of field for storing a proxy instance's invocation handler */
 308     private final static String handlerFieldName = "h";
 309 
 310     /** debugging flag for saving generated class files */
 311     private final static boolean saveGeneratedFiles =
 312         java.security.AccessController.doPrivileged(
 313             new GetBooleanAction(
 314                 "sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue();
 315 
 316     /**
 317      * Generate a proxy class given a name and a list of proxy interfaces.
 318      */
 319     public static byte[] generateProxyClass(final String name,
 320                                             Class[] interfaces)
 321     {
 322         ProxyGenerator gen = new ProxyGenerator(name, interfaces);
 323         final byte[] classFile = gen.generateClassFile();
 324 
 325         if (saveGeneratedFiles) {
 326             java.security.AccessController.doPrivileged(
 327             new java.security.PrivilegedAction<Void>() {
 328                 public Void run() {
 329                     try {
 330                         FileOutputStream file =
 331                             new FileOutputStream(dotToSlash(name) + ".class");
 332                         file.write(classFile);
 333                         file.close();
 334                         return null;
 335                     } catch (IOException e) {
 336                         throw new InternalError(
 337                             "I/O exception saving generated file: " + e);
 338                     }
 339                 }
 340             });
 341         }
 342 
 343         return classFile;
 344     }
 345 
 346     /* preloaded Method objects for methods in java.lang.Object */
 347     private static Method hashCodeMethod;
 348     private static Method equalsMethod;
 349     private static Method toStringMethod;
 350     static {
 351         try {
 352             hashCodeMethod = Object.class.getMethod("hashCode");
 353             equalsMethod =
 354                 Object.class.getMethod("equals", new Class[] { Object.class });
 355             toStringMethod = Object.class.getMethod("toString");
 356         } catch (NoSuchMethodException e) {
 357             throw new NoSuchMethodError(e.getMessage());
 358         }
 359     }
 360 
 361     /** name of proxy class */
 362     private String className;
 363 
 364     /** proxy interfaces */
 365     private Class[] interfaces;
 366 
 367     /** constant pool of class being generated */
 368     private ConstantPool cp = new ConstantPool();
 369 
 370     /** FieldInfo struct for each field of generated class */
 371     private List<FieldInfo> fields = new ArrayList<FieldInfo>();
 372 
 373     /** MethodInfo struct for each method of generated class */
 374     private List<MethodInfo> methods = new ArrayList<MethodInfo>();
 375 
 376     /**
 377      * maps method signature string to list of ProxyMethod objects for
 378      * proxy methods with that signature
 379      */
 380     private Map<String, List<ProxyMethod>> proxyMethods =
 381         new HashMap<String,List<ProxyMethod>>();
 382 
 383     /** count of ProxyMethod objects added to proxyMethods */
 384     private int proxyMethodCount = 0;
 385 
 386     /**
 387      * Construct a ProxyGenerator to generate a proxy class with the
 388      * specified name and for the given interfaces.
 389      *
 390      * A ProxyGenerator object contains the state for the ongoing
 391      * generation of a particular proxy class.
 392      */
 393     private ProxyGenerator(String className, Class[] interfaces) {
 394         this.className = className;
 395         this.interfaces = interfaces;
 396     }
 397 
 398     /**
 399      * Generate a class file for the proxy class.  This method drives the
 400      * class file generation process.
 401      */
 402     private byte[] generateClassFile() {
 403 
 404         /* ============================================================
 405          * Step 1: Assemble ProxyMethod objects for all methods to
 406          * generate proxy dispatching code for.
 407          */
 408 
 409         /*
 410          * Record that proxy methods are needed for the hashCode, equals,
 411          * and toString methods of java.lang.Object.  This is done before
 412          * the methods from the proxy interfaces so that the methods from
 413          * java.lang.Object take precedence over duplicate methods in the
 414          * proxy interfaces.
 415          */
 416         addProxyMethod(hashCodeMethod, Object.class);
 417         addProxyMethod(equalsMethod, Object.class);
 418         addProxyMethod(toStringMethod, Object.class);
 419 
 420         /*
 421          * Now record all of the methods from the proxy interfaces, giving
 422          * earlier interfaces precedence over later ones with duplicate
 423          * methods.
 424          */
 425         for (int i = 0; i < interfaces.length; i++) {
 426             Method[] methods = interfaces[i].getMethods();
 427             for (int j = 0; j < methods.length; j++) {
 428                 addProxyMethod(methods[j], interfaces[i]);
 429             }
 430         }
 431 
 432         /*
 433          * For each set of proxy methods with the same signature,
 434          * verify that the methods' return types are compatible.
 435          */
 436         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 437             checkReturnTypes(sigmethods);
 438         }
 439 
 440         /* ============================================================
 441          * Step 2: Assemble FieldInfo and MethodInfo structs for all of
 442          * fields and methods in the class we are generating.
 443          */
 444         try {
 445             methods.add(generateConstructor());
 446 
 447             for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 448                 for (ProxyMethod pm : sigmethods) {
 449 
 450                     // add static field for method's Method object
 451                     fields.add(new FieldInfo(pm.methodFieldName,
 452                         "Ljava/lang/reflect/Method;",
 453                          ACC_PRIVATE | ACC_STATIC));
 454 
 455                     // generate code for proxy method and add it
 456                     methods.add(pm.generateMethod());
 457                 }
 458             }
 459 
 460             methods.add(generateStaticInitializer());
 461 
 462         } catch (IOException e) {
 463             throw new InternalError("unexpected I/O Exception");
 464         }
 465 
 466         if (methods.size() > 65535) {
 467             throw new IllegalArgumentException("method limit exceeded");
 468         }
 469         if (fields.size() > 65535) {
 470             throw new IllegalArgumentException("field limit exceeded");
 471         }
 472 
 473         /* ============================================================
 474          * Step 3: Write the final class file.
 475          */
 476 
 477         /*
 478          * Make sure that constant pool indexes are reserved for the
 479          * following items before starting to write the final class file.
 480          */
 481         cp.getClass(dotToSlash(className));
 482         cp.getClass(superclassName);
 483         for (int i = 0; i < interfaces.length; i++) {
 484             cp.getClass(dotToSlash(interfaces[i].getName()));
 485         }
 486 
 487         /*
 488          * Disallow new constant pool additions beyond this point, since
 489          * we are about to write the final constant pool table.
 490          */
 491         cp.setReadOnly();
 492 
 493         ByteArrayOutputStream bout = new ByteArrayOutputStream();
 494         DataOutputStream dout = new DataOutputStream(bout);
 495 
 496         try {
 497             /*
 498              * Write all the items of the "ClassFile" structure.
 499              * See JVMS section 4.1.
 500              */
 501                                         // u4 magic;
 502             dout.writeInt(0xCAFEBABE);
 503                                         // u2 minor_version;
 504             dout.writeShort(CLASSFILE_MINOR_VERSION);
 505                                         // u2 major_version;
 506             dout.writeShort(CLASSFILE_MAJOR_VERSION);
 507 
 508             cp.write(dout);             // (write constant pool)
 509 
 510                                         // u2 access_flags;
 511             dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
 512                                         // u2 this_class;
 513             dout.writeShort(cp.getClass(dotToSlash(className)));
 514                                         // u2 super_class;
 515             dout.writeShort(cp.getClass(superclassName));
 516 
 517                                         // u2 interfaces_count;
 518             dout.writeShort(interfaces.length);
 519                                         // u2 interfaces[interfaces_count];
 520             for (int i = 0; i < interfaces.length; i++) {
 521                 dout.writeShort(cp.getClass(
 522                     dotToSlash(interfaces[i].getName())));
 523             }
 524 
 525                                         // u2 fields_count;
 526             dout.writeShort(fields.size());
 527                                         // field_info fields[fields_count];
 528             for (FieldInfo f : fields) {
 529                 f.write(dout);
 530             }
 531 
 532                                         // u2 methods_count;
 533             dout.writeShort(methods.size());
 534                                         // method_info methods[methods_count];
 535             for (MethodInfo m : methods) {
 536                 m.write(dout);
 537             }
 538 
 539                                          // u2 attributes_count;
 540             dout.writeShort(0); // (no ClassFile attributes for proxy classes)
 541 
 542         } catch (IOException e) {
 543             throw new InternalError("unexpected I/O Exception");
 544         }
 545 
 546         return bout.toByteArray();
 547     }
 548 
 549     /**
 550      * Add another method to be proxied, either by creating a new
 551      * ProxyMethod object or augmenting an old one for a duplicate
 552      * method.
 553      *
 554      * "fromClass" indicates the proxy interface that the method was
 555      * found through, which may be different from (a subinterface of)
 556      * the method's "declaring class".  Note that the first Method
 557      * object passed for a given name and descriptor identifies the
 558      * Method object (and thus the declaring class) that will be
 559      * passed to the invocation handler's "invoke" method for a given
 560      * set of duplicate methods.
 561      */
 562     private void addProxyMethod(Method m, Class fromClass) {
 563         String name = m.getName();
 564         Class[] parameterTypes = m.getParameterTypes();
 565         Class returnType = m.getReturnType();
 566         Class[] exceptionTypes = m.getExceptionTypes();
 567 
 568         String sig = name + getParameterDescriptors(parameterTypes);
 569         List<ProxyMethod> sigmethods = proxyMethods.get(sig);
 570         if (sigmethods != null) {
 571             for (ProxyMethod pm : sigmethods) {
 572                 if (returnType == pm.returnType) {
 573                     /*
 574                      * Found a match: reduce exception types to the
 575                      * greatest set of exceptions that can thrown
 576                      * compatibly with the throws clauses of both
 577                      * overridden methods.
 578                      */
 579                     List<Class<?>> legalExceptions = new ArrayList<Class<?>>();
 580                     collectCompatibleTypes(
 581                         exceptionTypes, pm.exceptionTypes, legalExceptions);
 582                     collectCompatibleTypes(
 583                         pm.exceptionTypes, exceptionTypes, legalExceptions);
 584                     pm.exceptionTypes = new Class[legalExceptions.size()];
 585                     pm.exceptionTypes =
 586                         legalExceptions.toArray(pm.exceptionTypes);
 587                     return;
 588                 }
 589             }
 590         } else {
 591             sigmethods = new ArrayList<ProxyMethod>(3);
 592             proxyMethods.put(sig, sigmethods);
 593         }
 594         sigmethods.add(new ProxyMethod(name, parameterTypes, returnType,
 595                                        exceptionTypes, fromClass));
 596     }
 597 
 598     /**
 599      * For a given set of proxy methods with the same signature, check
 600      * that their return types are compatible according to the Proxy
 601      * specification.
 602      *
 603      * Specifically, if there is more than one such method, then all
 604      * of the return types must be reference types, and there must be
 605      * one return type that is assignable to each of the rest of them.
 606      */
 607     private static void checkReturnTypes(List<ProxyMethod> methods) {
 608         /*
 609          * If there is only one method with a given signature, there
 610          * cannot be a conflict.  This is the only case in which a
 611          * primitive (or void) return type is allowed.
 612          */
 613         if (methods.size() < 2) {
 614             return;
 615         }
 616 
 617         /*
 618          * List of return types that are not yet known to be
 619          * assignable from ("covered" by) any of the others.
 620          */
 621         LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>();
 622 
 623     nextNewReturnType:
 624         for (ProxyMethod pm : methods) {
 625             Class<?> newReturnType = pm.returnType;
 626             if (newReturnType.isPrimitive()) {
 627                 throw new IllegalArgumentException(
 628                     "methods with same signature " +
 629                     getFriendlyMethodSignature(pm.methodName,
 630                                                pm.parameterTypes) +
 631                     " but incompatible return types: " +
 632                     newReturnType.getName() + " and others");
 633             }
 634             boolean added = false;
 635 
 636             /*
 637              * Compare the new return type to the existing uncovered
 638              * return types.
 639              */
 640             ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
 641             while (liter.hasNext()) {
 642                 Class<?> uncoveredReturnType = liter.next();
 643 
 644                 /*
 645                  * If an existing uncovered return type is assignable
 646                  * to this new one, then we can forget the new one.
 647                  */
 648                 if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
 649                     assert !added;
 650                     continue nextNewReturnType;
 651                 }
 652 
 653                 /*
 654                  * If the new return type is assignable to an existing
 655                  * uncovered one, then should replace the existing one
 656                  * with the new one (or just forget the existing one,
 657                  * if the new one has already be put in the list).
 658                  */
 659                 if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
 660                     // (we can assume that each return type is unique)
 661                     if (!added) {
 662                         liter.set(newReturnType);
 663                         added = true;
 664                     } else {
 665                         liter.remove();
 666                     }
 667                 }
 668             }
 669 
 670             /*
 671              * If we got through the list of existing uncovered return
 672              * types without an assignability relationship, then add
 673              * the new return type to the list of uncovered ones.
 674              */
 675             if (!added) {
 676                 uncoveredReturnTypes.add(newReturnType);
 677             }
 678         }
 679 
 680         /*
 681          * We shouldn't end up with more than one return type that is
 682          * not assignable from any of the others.
 683          */
 684         if (uncoveredReturnTypes.size() > 1) {
 685             ProxyMethod pm = methods.get(0);
 686             throw new IllegalArgumentException(
 687                 "methods with same signature " +
 688                 getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) +
 689                 " but incompatible return types: " + uncoveredReturnTypes);
 690         }
 691     }
 692 
 693     /**
 694      * A FieldInfo object contains information about a particular field
 695      * in the class being generated.  The class mirrors the data items of
 696      * the "field_info" structure of the class file format (see JVMS 4.5).
 697      */
 698     private class FieldInfo {
 699         public int accessFlags;
 700         public String name;
 701         public String descriptor;
 702 
 703         public FieldInfo(String name, String descriptor, int accessFlags) {
 704             this.name = name;
 705             this.descriptor = descriptor;
 706             this.accessFlags = accessFlags;
 707 
 708             /*
 709              * Make sure that constant pool indexes are reserved for the
 710              * following items before starting to write the final class file.
 711              */
 712             cp.getUtf8(name);
 713             cp.getUtf8(descriptor);
 714         }
 715 
 716         public void write(DataOutputStream out) throws IOException {
 717             /*
 718              * Write all the items of the "field_info" structure.
 719              * See JVMS section 4.5.
 720              */
 721                                         // u2 access_flags;
 722             out.writeShort(accessFlags);
 723                                         // u2 name_index;
 724             out.writeShort(cp.getUtf8(name));
 725                                         // u2 descriptor_index;
 726             out.writeShort(cp.getUtf8(descriptor));
 727                                         // u2 attributes_count;
 728             out.writeShort(0);  // (no field_info attributes for proxy classes)
 729         }
 730     }
 731 
 732     /**
 733      * An ExceptionTableEntry object holds values for the data items of
 734      * an entry in the "exception_table" item of the "Code" attribute of
 735      * "method_info" structures (see JVMS 4.7.3).
 736      */
 737     private static class ExceptionTableEntry {
 738         public short startPc;
 739         public short endPc;
 740         public short handlerPc;
 741         public short catchType;
 742 
 743         public ExceptionTableEntry(short startPc, short endPc,
 744                                    short handlerPc, short catchType)
 745         {
 746             this.startPc = startPc;
 747             this.endPc = endPc;
 748             this.handlerPc = handlerPc;
 749             this.catchType = catchType;
 750         }
 751     };
 752 
 753     /**
 754      * A MethodInfo object contains information about a particular method
 755      * in the class being generated.  This class mirrors the data items of
 756      * the "method_info" structure of the class file format (see JVMS 4.6).
 757      */
 758     private class MethodInfo {
 759         public int accessFlags;
 760         public String name;
 761         public String descriptor;
 762         public short maxStack;
 763         public short maxLocals;
 764         public ByteArrayOutputStream code = new ByteArrayOutputStream();
 765         public List<ExceptionTableEntry> exceptionTable =
 766             new ArrayList<ExceptionTableEntry>();
 767         public short[] declaredExceptions;
 768 
 769         public MethodInfo(String name, String descriptor, int accessFlags) {
 770             this.name = name;
 771             this.descriptor = descriptor;
 772             this.accessFlags = accessFlags;
 773 
 774             /*
 775              * Make sure that constant pool indexes are reserved for the
 776              * following items before starting to write the final class file.
 777              */
 778             cp.getUtf8(name);
 779             cp.getUtf8(descriptor);
 780             cp.getUtf8("Code");
 781             cp.getUtf8("Exceptions");
 782         }
 783 
 784         public void write(DataOutputStream out) throws IOException {
 785             /*
 786              * Write all the items of the "method_info" structure.
 787              * See JVMS section 4.6.
 788              */
 789                                         // u2 access_flags;
 790             out.writeShort(accessFlags);
 791                                         // u2 name_index;
 792             out.writeShort(cp.getUtf8(name));
 793                                         // u2 descriptor_index;
 794             out.writeShort(cp.getUtf8(descriptor));
 795                                         // u2 attributes_count;
 796             out.writeShort(2);  // (two method_info attributes:)
 797 
 798             // Write "Code" attribute. See JVMS section 4.7.3.
 799 
 800                                         // u2 attribute_name_index;
 801             out.writeShort(cp.getUtf8("Code"));
 802                                         // u4 attribute_length;
 803             out.writeInt(12 + code.size() + 8 * exceptionTable.size());
 804                                         // u2 max_stack;
 805             out.writeShort(maxStack);
 806                                         // u2 max_locals;
 807             out.writeShort(maxLocals);
 808                                         // u2 code_length;
 809             out.writeInt(code.size());
 810                                         // u1 code[code_length];
 811             code.writeTo(out);
 812                                         // u2 exception_table_length;
 813             out.writeShort(exceptionTable.size());
 814             for (ExceptionTableEntry e : exceptionTable) {
 815                                         // u2 start_pc;
 816                 out.writeShort(e.startPc);
 817                                         // u2 end_pc;
 818                 out.writeShort(e.endPc);
 819                                         // u2 handler_pc;
 820                 out.writeShort(e.handlerPc);
 821                                         // u2 catch_type;
 822                 out.writeShort(e.catchType);
 823             }
 824                                         // u2 attributes_count;
 825             out.writeShort(0);
 826 
 827             // write "Exceptions" attribute.  See JVMS section 4.7.4.
 828 
 829                                         // u2 attribute_name_index;
 830             out.writeShort(cp.getUtf8("Exceptions"));
 831                                         // u4 attributes_length;
 832             out.writeInt(2 + 2 * declaredExceptions.length);
 833                                         // u2 number_of_exceptions;
 834             out.writeShort(declaredExceptions.length);
 835                         // u2 exception_index_table[number_of_exceptions];
 836             for (int i = 0; i < declaredExceptions.length; i++) {
 837                 out.writeShort(declaredExceptions[i]);
 838             }
 839         }
 840 
 841     }
 842 
 843     /**
 844      * A ProxyMethod object represents a proxy method in the proxy class
 845      * being generated: a method whose implementation will encode and
 846      * dispatch invocations to the proxy instance's invocation handler.
 847      */
 848     private class ProxyMethod {
 849 
 850         public String methodName;
 851         public Class[] parameterTypes;
 852         public Class returnType;
 853         public Class[] exceptionTypes;
 854         public Class fromClass;
 855         public String methodFieldName;
 856 
 857         private ProxyMethod(String methodName, Class[] parameterTypes,
 858                             Class returnType, Class[] exceptionTypes,
 859                             Class fromClass)
 860         {
 861             this.methodName = methodName;
 862             this.parameterTypes = parameterTypes;
 863             this.returnType = returnType;
 864             this.exceptionTypes = exceptionTypes;
 865             this.fromClass = fromClass;
 866             this.methodFieldName = "m" + proxyMethodCount++;
 867         }
 868 
 869         /**
 870          * Return a MethodInfo object for this method, including generating
 871          * the code and exception table entry.
 872          */
 873         private MethodInfo generateMethod() throws IOException {
 874             String desc = getMethodDescriptor(parameterTypes, returnType);
 875             MethodInfo minfo = new MethodInfo(methodName, desc,
 876                 ACC_PUBLIC | ACC_FINAL);
 877 
 878             int[] parameterSlot = new int[parameterTypes.length];
 879             int nextSlot = 1;
 880             for (int i = 0; i < parameterSlot.length; i++) {
 881                 parameterSlot[i] = nextSlot;
 882                 nextSlot += getWordsPerType(parameterTypes[i]);
 883             }
 884             int localSlot0 = nextSlot;
 885             short pc, tryBegin = 0, tryEnd;
 886 
 887             DataOutputStream out = new DataOutputStream(minfo.code);
 888 
 889             code_aload(0, out);
 890 
 891             out.writeByte(opc_getfield);
 892             out.writeShort(cp.getFieldRef(
 893                 superclassName,
 894                 handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));
 895 
 896             code_aload(0, out);
 897 
 898             out.writeByte(opc_getstatic);
 899             out.writeShort(cp.getFieldRef(
 900                 dotToSlash(className),
 901                 methodFieldName, "Ljava/lang/reflect/Method;"));
 902 
 903             if (parameterTypes.length > 0) {
 904 
 905                 code_ipush(parameterTypes.length, out);
 906 
 907                 out.writeByte(opc_anewarray);
 908                 out.writeShort(cp.getClass("java/lang/Object"));
 909 
 910                 for (int i = 0; i < parameterTypes.length; i++) {
 911 
 912                     out.writeByte(opc_dup);
 913 
 914                     code_ipush(i, out);
 915 
 916                     codeWrapArgument(parameterTypes[i], parameterSlot[i], out);
 917 
 918                     out.writeByte(opc_aastore);
 919                 }
 920             } else {
 921 
 922                 out.writeByte(opc_aconst_null);
 923             }
 924 
 925             out.writeByte(opc_invokeinterface);
 926             out.writeShort(cp.getInterfaceMethodRef(
 927                 "java/lang/reflect/InvocationHandler",
 928                 "invoke",
 929                 "(Ljava/lang/Object;Ljava/lang/reflect/Method;" +
 930                     "[Ljava/lang/Object;)Ljava/lang/Object;"));
 931             out.writeByte(4);
 932             out.writeByte(0);
 933 
 934             if (returnType == void.class) {
 935 
 936                 out.writeByte(opc_pop);
 937 
 938                 out.writeByte(opc_return);
 939 
 940             } else {
 941 
 942                 codeUnwrapReturnValue(returnType, out);
 943             }
 944 
 945             tryEnd = pc = (short) minfo.code.size();
 946 
 947             List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes);
 948             if (catchList.size() > 0) {
 949 
 950                 for (Class<?> ex : catchList) {
 951                     minfo.exceptionTable.add(new ExceptionTableEntry(
 952                         tryBegin, tryEnd, pc,
 953                         cp.getClass(dotToSlash(ex.getName()))));
 954                 }
 955 
 956                 out.writeByte(opc_athrow);
 957 
 958                 pc = (short) minfo.code.size();
 959 
 960                 minfo.exceptionTable.add(new ExceptionTableEntry(
 961                     tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable")));
 962 
 963                 code_astore(localSlot0, out);
 964 
 965                 out.writeByte(opc_new);
 966                 out.writeShort(cp.getClass(
 967                     "java/lang/reflect/UndeclaredThrowableException"));
 968 
 969                 out.writeByte(opc_dup);
 970 
 971                 code_aload(localSlot0, out);
 972 
 973                 out.writeByte(opc_invokespecial);
 974 
 975                 out.writeShort(cp.getMethodRef(
 976                     "java/lang/reflect/UndeclaredThrowableException",
 977                     "<init>", "(Ljava/lang/Throwable;)V"));
 978 
 979                 out.writeByte(opc_athrow);
 980             }
 981 
 982             if (minfo.code.size() > 65535) {
 983                 throw new IllegalArgumentException("code size limit exceeded");
 984             }
 985 
 986             minfo.maxStack = 10;
 987             minfo.maxLocals = (short) (localSlot0 + 1);
 988             minfo.declaredExceptions = new short[exceptionTypes.length];
 989             for (int i = 0; i < exceptionTypes.length; i++) {
 990                 minfo.declaredExceptions[i] = cp.getClass(
 991                     dotToSlash(exceptionTypes[i].getName()));
 992             }
 993 
 994             return minfo;
 995         }
 996 
 997         /**
 998          * Generate code for wrapping an argument of the given type
 999          * whose value can be found at the specified local variable
1000          * index, in order for it to be passed (as an Object) to the
1001          * invocation handler's "invoke" method.  The code is written
1002          * to the supplied stream.
1003          */
1004         private void codeWrapArgument(Class type, int slot,
1005                                       DataOutputStream out)
1006             throws IOException
1007         {
1008             if (type.isPrimitive()) {
1009                 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
1010 
1011                 if (type == int.class ||
1012                     type == boolean.class ||
1013                     type == byte.class ||
1014                     type == char.class ||
1015                     type == short.class)
1016                 {
1017                     code_iload(slot, out);
1018                 } else if (type == long.class) {
1019                     code_lload(slot, out);
1020                 } else if (type == float.class) {
1021                     code_fload(slot, out);
1022                 } else if (type == double.class) {
1023                     code_dload(slot, out);
1024                 } else {
1025                     throw new AssertionError();
1026                 }
1027 
1028                 out.writeByte(opc_invokestatic);
1029                 out.writeShort(cp.getMethodRef(
1030                     prim.wrapperClassName,
1031                     "valueOf", prim.wrapperValueOfDesc));
1032 
1033             } else {
1034 
1035                 code_aload(slot, out);
1036             }
1037         }
1038 
1039         /**
1040          * Generate code for unwrapping a return value of the given
1041          * type from the invocation handler's "invoke" method (as type
1042          * Object) to its correct type.  The code is written to the
1043          * supplied stream.
1044          */
1045         private void codeUnwrapReturnValue(Class type, DataOutputStream out)
1046             throws IOException
1047         {
1048             if (type.isPrimitive()) {
1049                 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
1050 
1051                 out.writeByte(opc_checkcast);
1052                 out.writeShort(cp.getClass(prim.wrapperClassName));
1053 
1054                 out.writeByte(opc_invokevirtual);
1055                 out.writeShort(cp.getMethodRef(
1056                     prim.wrapperClassName,
1057                     prim.unwrapMethodName, prim.unwrapMethodDesc));
1058 
1059                 if (type == int.class ||
1060                     type == boolean.class ||
1061                     type == byte.class ||
1062                     type == char.class ||
1063                     type == short.class)
1064                 {
1065                     out.writeByte(opc_ireturn);
1066                 } else if (type == long.class) {
1067                     out.writeByte(opc_lreturn);
1068                 } else if (type == float.class) {
1069                     out.writeByte(opc_freturn);
1070                 } else if (type == double.class) {
1071                     out.writeByte(opc_dreturn);
1072                 } else {
1073                     throw new AssertionError();
1074                 }
1075 
1076             } else {
1077 
1078                 out.writeByte(opc_checkcast);
1079                 out.writeShort(cp.getClass(dotToSlash(type.getName())));
1080 
1081                 out.writeByte(opc_areturn);
1082             }
1083         }
1084 
1085         /**
1086          * Generate code for initializing the static field that stores
1087          * the Method object for this proxy method.  The code is written
1088          * to the supplied stream.
1089          */
1090         private void codeFieldInitialization(DataOutputStream out)
1091             throws IOException
1092         {
1093             codeClassForName(fromClass, out);
1094 
1095             code_ldc(cp.getString(methodName), out);
1096 
1097             code_ipush(parameterTypes.length, out);
1098 
1099             out.writeByte(opc_anewarray);
1100             out.writeShort(cp.getClass("java/lang/Class"));
1101 
1102             for (int i = 0; i < parameterTypes.length; i++) {
1103 
1104                 out.writeByte(opc_dup);
1105 
1106                 code_ipush(i, out);
1107 
1108                 if (parameterTypes[i].isPrimitive()) {
1109                     PrimitiveTypeInfo prim =
1110                         PrimitiveTypeInfo.get(parameterTypes[i]);
1111 
1112                     out.writeByte(opc_getstatic);
1113                     out.writeShort(cp.getFieldRef(
1114                         prim.wrapperClassName, "TYPE", "Ljava/lang/Class;"));
1115 
1116                 } else {
1117                     codeClassForName(parameterTypes[i], out);
1118                 }
1119 
1120                 out.writeByte(opc_aastore);
1121             }
1122 
1123             out.writeByte(opc_invokevirtual);
1124             out.writeShort(cp.getMethodRef(
1125                 "java/lang/Class",
1126                 "getMethod",
1127                 "(Ljava/lang/String;[Ljava/lang/Class;)" +
1128                 "Ljava/lang/reflect/Method;"));
1129 
1130             out.writeByte(opc_putstatic);
1131             out.writeShort(cp.getFieldRef(
1132                 dotToSlash(className),
1133                 methodFieldName, "Ljava/lang/reflect/Method;"));
1134         }
1135     }
1136 
1137     /**
1138      * Generate the constructor method for the proxy class.
1139      */
1140     private MethodInfo generateConstructor() throws IOException {
1141         MethodInfo minfo = new MethodInfo(
1142             "<init>", "(Ljava/lang/reflect/InvocationHandler;)V",
1143             ACC_PUBLIC);
1144 
1145         DataOutputStream out = new DataOutputStream(minfo.code);
1146 
1147         code_aload(0, out);
1148 
1149         code_aload(1, out);
1150 
1151         out.writeByte(opc_invokespecial);
1152         out.writeShort(cp.getMethodRef(
1153             superclassName,
1154             "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
1155 
1156         out.writeByte(opc_return);
1157 
1158         minfo.maxStack = 10;
1159         minfo.maxLocals = 2;
1160         minfo.declaredExceptions = new short[0];
1161 
1162         return minfo;
1163     }
1164 
1165     /**
1166      * Generate the static initializer method for the proxy class.
1167      */
1168     private MethodInfo generateStaticInitializer() throws IOException {
1169         MethodInfo minfo = new MethodInfo(
1170             "<clinit>", "()V", ACC_STATIC);
1171 
1172         int localSlot0 = 1;
1173         short pc, tryBegin = 0, tryEnd;
1174 
1175         DataOutputStream out = new DataOutputStream(minfo.code);
1176 
1177         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
1178             for (ProxyMethod pm : sigmethods) {
1179                 pm.codeFieldInitialization(out);
1180             }
1181         }
1182 
1183         out.writeByte(opc_return);
1184 
1185         tryEnd = pc = (short) minfo.code.size();
1186 
1187         minfo.exceptionTable.add(new ExceptionTableEntry(
1188             tryBegin, tryEnd, pc,
1189             cp.getClass("java/lang/NoSuchMethodException")));
1190 
1191         code_astore(localSlot0, out);
1192 
1193         out.writeByte(opc_new);
1194         out.writeShort(cp.getClass("java/lang/NoSuchMethodError"));
1195 
1196         out.writeByte(opc_dup);
1197 
1198         code_aload(localSlot0, out);
1199 
1200         out.writeByte(opc_invokevirtual);
1201         out.writeShort(cp.getMethodRef(
1202             "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
1203 
1204         out.writeByte(opc_invokespecial);
1205         out.writeShort(cp.getMethodRef(
1206             "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V"));
1207 
1208         out.writeByte(opc_athrow);
1209 
1210         pc = (short) minfo.code.size();
1211 
1212         minfo.exceptionTable.add(new ExceptionTableEntry(
1213             tryBegin, tryEnd, pc,
1214             cp.getClass("java/lang/ClassNotFoundException")));
1215 
1216         code_astore(localSlot0, out);
1217 
1218         out.writeByte(opc_new);
1219         out.writeShort(cp.getClass("java/lang/NoClassDefFoundError"));
1220 
1221         out.writeByte(opc_dup);
1222 
1223         code_aload(localSlot0, out);
1224 
1225         out.writeByte(opc_invokevirtual);
1226         out.writeShort(cp.getMethodRef(
1227             "java/lang/Throwable", "getMessage", "()Ljava/lang/String;"));
1228 
1229         out.writeByte(opc_invokespecial);
1230         out.writeShort(cp.getMethodRef(
1231             "java/lang/NoClassDefFoundError",
1232             "<init>", "(Ljava/lang/String;)V"));
1233 
1234         out.writeByte(opc_athrow);
1235 
1236         if (minfo.code.size() > 65535) {
1237             throw new IllegalArgumentException("code size limit exceeded");
1238         }
1239 
1240         minfo.maxStack = 10;
1241         minfo.maxLocals = (short) (localSlot0 + 1);
1242         minfo.declaredExceptions = new short[0];
1243 
1244         return minfo;
1245     }
1246 
1247 
1248     /*
1249      * =============== Code Generation Utility Methods ===============
1250      */
1251 
1252     /*
1253      * The following methods generate code for the load or store operation
1254      * indicated by their name for the given local variable.  The code is
1255      * written to the supplied stream.
1256      */
1257 
1258     private void code_iload(int lvar, DataOutputStream out)
1259         throws IOException
1260     {
1261         codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out);
1262     }
1263 
1264     private void code_lload(int lvar, DataOutputStream out)
1265         throws IOException
1266     {
1267         codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out);
1268     }
1269 
1270     private void code_fload(int lvar, DataOutputStream out)
1271         throws IOException
1272     {
1273         codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out);
1274     }
1275 
1276     private void code_dload(int lvar, DataOutputStream out)
1277         throws IOException
1278     {
1279         codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out);
1280     }
1281 
1282     private void code_aload(int lvar, DataOutputStream out)
1283         throws IOException
1284     {
1285         codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out);
1286     }
1287 
1288 //  private void code_istore(int lvar, DataOutputStream out)
1289 //      throws IOException
1290 //  {
1291 //      codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out);
1292 //  }
1293 
1294 //  private void code_lstore(int lvar, DataOutputStream out)
1295 //      throws IOException
1296 //  {
1297 //      codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out);
1298 //  }
1299 
1300 //  private void code_fstore(int lvar, DataOutputStream out)
1301 //      throws IOException
1302 //  {
1303 //      codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out);
1304 //  }
1305 
1306 //  private void code_dstore(int lvar, DataOutputStream out)
1307 //      throws IOException
1308 //  {
1309 //      codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out);
1310 //  }
1311 
1312     private void code_astore(int lvar, DataOutputStream out)
1313         throws IOException
1314     {
1315         codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out);
1316     }
1317 
1318     /**
1319      * Generate code for a load or store instruction for the given local
1320      * variable.  The code is written to the supplied stream.
1321      *
1322      * "opcode" indicates the opcode form of the desired load or store
1323      * instruction that takes an explicit local variable index, and
1324      * "opcode_0" indicates the corresponding form of the instruction
1325      * with the implicit index 0.
1326      */
1327     private void codeLocalLoadStore(int lvar, int opcode, int opcode_0,
1328                                     DataOutputStream out)
1329         throws IOException
1330     {
1331         assert lvar >= 0 && lvar <= 0xFFFF;
1332         if (lvar <= 3) {
1333             out.writeByte(opcode_0 + lvar);
1334         } else if (lvar <= 0xFF) {
1335             out.writeByte(opcode);
1336             out.writeByte(lvar & 0xFF);
1337         } else {
1338             /*
1339              * Use the "wide" instruction modifier for local variable
1340              * indexes that do not fit into an unsigned byte.
1341              */
1342             out.writeByte(opc_wide);
1343             out.writeByte(opcode);
1344             out.writeShort(lvar & 0xFFFF);
1345         }
1346     }
1347 
1348     /**
1349      * Generate code for an "ldc" instruction for the given constant pool
1350      * index (the "ldc_w" instruction is used if the index does not fit
1351      * into an unsigned byte).  The code is written to the supplied stream.
1352      */
1353     private void code_ldc(int index, DataOutputStream out)
1354         throws IOException
1355     {
1356         assert index >= 0 && index <= 0xFFFF;
1357         if (index <= 0xFF) {
1358             out.writeByte(opc_ldc);
1359             out.writeByte(index & 0xFF);
1360         } else {
1361             out.writeByte(opc_ldc_w);
1362             out.writeShort(index & 0xFFFF);
1363         }
1364     }
1365 
1366     /**
1367      * Generate code to push a constant integer value on to the operand
1368      * stack, using the "iconst_<i>", "bipush", or "sipush" instructions
1369      * depending on the size of the value.  The code is written to the
1370      * supplied stream.
1371      */
1372     private void code_ipush(int value, DataOutputStream out)
1373         throws IOException
1374     {
1375         if (value >= -1 && value <= 5) {
1376             out.writeByte(opc_iconst_0 + value);
1377         } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
1378             out.writeByte(opc_bipush);
1379             out.writeByte(value & 0xFF);
1380         } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
1381             out.writeByte(opc_sipush);
1382             out.writeShort(value & 0xFFFF);
1383         } else {
1384             throw new AssertionError();
1385         }
1386     }
1387 
1388     /**
1389      * Generate code to invoke the Class.forName with the name of the given
1390      * class to get its Class object at runtime.  The code is written to
1391      * the supplied stream.  Note that the code generated by this method
1392      * may caused the checked ClassNotFoundException to be thrown.
1393      */
1394     private void codeClassForName(Class cl, DataOutputStream out)
1395         throws IOException
1396     {
1397         code_ldc(cp.getString(cl.getName()), out);
1398 
1399         out.writeByte(opc_invokestatic);
1400         out.writeShort(cp.getMethodRef(
1401             "java/lang/Class",
1402             "forName", "(Ljava/lang/String;)Ljava/lang/Class;"));
1403     }
1404 
1405 
1406     /*
1407      * ==================== General Utility Methods ====================
1408      */
1409 
1410     /**
1411      * Convert a fully qualified class name that uses '.' as the package
1412      * separator, the external representation used by the Java language
1413      * and APIs, to a fully qualified class name that uses '/' as the
1414      * package separator, the representation used in the class file
1415      * format (see JVMS section 4.2).
1416      */
1417     private static String dotToSlash(String name) {
1418         return name.replace('.', '/');
1419     }
1420 
1421     /**
1422      * Return the "method descriptor" string for a method with the given
1423      * parameter types and return type.  See JVMS section 4.3.3.
1424      */
1425     private static String getMethodDescriptor(Class[] parameterTypes,
1426                                               Class returnType)
1427     {
1428         return getParameterDescriptors(parameterTypes) +
1429             ((returnType == void.class) ? "V" : getFieldType(returnType));
1430     }
1431 
1432     /**
1433      * Return the list of "parameter descriptor" strings enclosed in
1434      * parentheses corresponding to the given parameter types (in other
1435      * words, a method descriptor without a return descriptor).  This
1436      * string is useful for constructing string keys for methods without
1437      * regard to their return type.
1438      */
1439     private static String getParameterDescriptors(Class[] parameterTypes) {
1440         StringBuilder desc = new StringBuilder("(");
1441         for (int i = 0; i < parameterTypes.length; i++) {
1442             desc.append(getFieldType(parameterTypes[i]));
1443         }
1444         desc.append(')');
1445         return desc.toString();
1446     }
1447 
1448     /**
1449      * Return the "field type" string for the given type, appropriate for
1450      * a field descriptor, a parameter descriptor, or a return descriptor
1451      * other than "void".  See JVMS section 4.3.2.
1452      */
1453     private static String getFieldType(Class type) {
1454         if (type.isPrimitive()) {
1455             return PrimitiveTypeInfo.get(type).baseTypeString;
1456         } else if (type.isArray()) {
1457             /*
1458              * According to JLS 20.3.2, the getName() method on Class does
1459              * return the VM type descriptor format for array classes (only);
1460              * using that should be quicker than the otherwise obvious code:
1461              *
1462              *     return "[" + getTypeDescriptor(type.getComponentType());
1463              */
1464             return type.getName().replace('.', '/');
1465         } else {
1466             return "L" + dotToSlash(type.getName()) + ";";
1467         }
1468     }
1469 
1470     /**
1471      * Returns a human-readable string representing the signature of a
1472      * method with the given name and parameter types.
1473      */
1474     private static String getFriendlyMethodSignature(String name,
1475                                                      Class[] parameterTypes)
1476     {
1477         StringBuilder sig = new StringBuilder(name);
1478         sig.append('(');
1479         for (int i = 0; i < parameterTypes.length; i++) {
1480             if (i > 0) {
1481                 sig.append(',');
1482             }
1483             Class parameterType = parameterTypes[i];
1484             int dimensions = 0;
1485             while (parameterType.isArray()) {
1486                 parameterType = parameterType.getComponentType();
1487                 dimensions++;
1488             }
1489             sig.append(parameterType.getName());
1490             while (dimensions-- > 0) {
1491                 sig.append("[]");
1492             }
1493         }
1494         sig.append(')');
1495         return sig.toString();
1496     }
1497 
1498     /**
1499      * Return the number of abstract "words", or consecutive local variable
1500      * indexes, required to contain a value of the given type.  See JVMS
1501      * section 3.6.1.
1502      *
1503      * Note that the original version of the JVMS contained a definition of
1504      * this abstract notion of a "word" in section 3.4, but that definition
1505      * was removed for the second edition.
1506      */
1507     private static int getWordsPerType(Class type) {
1508         if (type == long.class || type == double.class) {
1509             return 2;
1510         } else {
1511             return 1;
1512         }
1513     }
1514 
1515     /**
1516      * Add to the given list all of the types in the "from" array that
1517      * are not already contained in the list and are assignable to at
1518      * least one of the types in the "with" array.
1519      *
1520      * This method is useful for computing the greatest common set of
1521      * declared exceptions from duplicate methods inherited from
1522      * different interfaces.
1523      */
1524     private static void collectCompatibleTypes(Class<?>[] from,
1525                                                Class<?>[] with,
1526                                                List<Class<?>> list)
1527     {
1528         for (int i = 0; i < from.length; i++) {
1529             if (!list.contains(from[i])) {
1530                 for (int j = 0; j < with.length; j++) {
1531                     if (with[j].isAssignableFrom(from[i])) {
1532                         list.add(from[i]);
1533                         break;
1534                     }
1535                 }
1536             }
1537         }
1538     }
1539 
1540     /**
1541      * Given the exceptions declared in the throws clause of a proxy method,
1542      * compute the exceptions that need to be caught from the invocation
1543      * handler's invoke method and rethrown intact in the method's
1544      * implementation before catching other Throwables and wrapping them
1545      * in UndeclaredThrowableExceptions.
1546      *
1547      * The exceptions to be caught are returned in a List object.  Each
1548      * exception in the returned list is guaranteed to not be a subclass of
1549      * any of the other exceptions in the list, so the catch blocks for
1550      * these exceptions may be generated in any order relative to each other.
1551      *
1552      * Error and RuntimeException are each always contained by the returned
1553      * list (if none of their superclasses are contained), since those
1554      * unchecked exceptions should always be rethrown intact, and thus their
1555      * subclasses will never appear in the returned list.
1556      *
1557      * The returned List will be empty if java.lang.Throwable is in the
1558      * given list of declared exceptions, indicating that no exceptions
1559      * need to be caught.
1560      */
1561     private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) {
1562         List<Class<?>> uniqueList = new ArrayList<Class<?>>();
1563                                                 // unique exceptions to catch
1564 
1565         uniqueList.add(Error.class);            // always catch/rethrow these
1566         uniqueList.add(RuntimeException.class);
1567 
1568     nextException:
1569         for (int i = 0; i < exceptions.length; i++) {
1570             Class<?> ex = exceptions[i];
1571             if (ex.isAssignableFrom(Throwable.class)) {
1572                 /*
1573                  * If Throwable is declared to be thrown by the proxy method,
1574                  * then no catch blocks are necessary, because the invoke
1575                  * can, at most, throw Throwable anyway.
1576                  */
1577                 uniqueList.clear();
1578                 break;
1579             } else if (!Throwable.class.isAssignableFrom(ex)) {
1580                 /*
1581                  * Ignore types that cannot be thrown by the invoke method.
1582                  */
1583                 continue;
1584             }
1585             /*
1586              * Compare this exception against the current list of
1587              * exceptions that need to be caught:
1588              */
1589             for (int j = 0; j < uniqueList.size();) {
1590                 Class<?> ex2 = uniqueList.get(j);
1591                 if (ex2.isAssignableFrom(ex)) {
1592                     /*
1593                      * if a superclass of this exception is already on
1594                      * the list to catch, then ignore this one and continue;
1595                      */
1596                     continue nextException;
1597                 } else if (ex.isAssignableFrom(ex2)) {
1598                     /*
1599                      * if a subclass of this exception is on the list
1600                      * to catch, then remove it;
1601                      */
1602                     uniqueList.remove(j);
1603                 } else {
1604                     j++;        // else continue comparing.
1605                 }
1606             }
1607             // This exception is unique (so far): add it to the list to catch.
1608             uniqueList.add(ex);
1609         }
1610         return uniqueList;
1611     }
1612 
1613     /**
1614      * A PrimitiveTypeInfo object contains assorted information about
1615      * a primitive type in its public fields.  The struct for a particular
1616      * primitive type can be obtained using the static "get" method.
1617      */
1618     private static class PrimitiveTypeInfo {
1619 
1620         /** "base type" used in various descriptors (see JVMS section 4.3.2) */
1621         public String baseTypeString;
1622 
1623         /** name of corresponding wrapper class */
1624         public String wrapperClassName;
1625 
1626         /** method descriptor for wrapper class "valueOf" factory method */
1627         public String wrapperValueOfDesc;
1628 
1629         /** name of wrapper class method for retrieving primitive value */
1630         public String unwrapMethodName;
1631 
1632         /** descriptor of same method */
1633         public String unwrapMethodDesc;
1634 
1635         private static Map<Class,PrimitiveTypeInfo> table =
1636             new HashMap<Class,PrimitiveTypeInfo>();
1637         static {
1638             add(byte.class, Byte.class);
1639             add(char.class, Character.class);
1640             add(double.class, Double.class);
1641             add(float.class, Float.class);
1642             add(int.class, Integer.class);
1643             add(long.class, Long.class);
1644             add(short.class, Short.class);
1645             add(boolean.class, Boolean.class);
1646         }
1647 
1648         private static void add(Class primitiveClass, Class wrapperClass) {
1649             table.put(primitiveClass,
1650                       new PrimitiveTypeInfo(primitiveClass, wrapperClass));
1651         }
1652 
1653         private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) {
1654             assert primitiveClass.isPrimitive();
1655 
1656             baseTypeString =
1657                 Array.newInstance(primitiveClass, 0)
1658                 .getClass().getName().substring(1);
1659             wrapperClassName = dotToSlash(wrapperClass.getName());
1660             wrapperValueOfDesc =
1661                 "(" + baseTypeString + ")L" + wrapperClassName + ";";
1662             unwrapMethodName = primitiveClass.getName() + "Value";
1663             unwrapMethodDesc = "()" + baseTypeString;
1664         }
1665 
1666         public static PrimitiveTypeInfo get(Class cl) {
1667             return table.get(cl);
1668         }
1669     }
1670 
1671 
1672     /**
1673      * A ConstantPool object represents the constant pool of a class file
1674      * being generated.  This representation of a constant pool is designed
1675      * specifically for use by ProxyGenerator; in particular, it assumes
1676      * that constant pool entries will not need to be resorted (for example,
1677      * by their type, as the Java compiler does), so that the final index
1678      * value can be assigned and used when an entry is first created.
1679      *
1680      * Note that new entries cannot be created after the constant pool has
1681      * been written to a class file.  To prevent such logic errors, a
1682      * ConstantPool instance can be marked "read only", so that further
1683      * attempts to add new entries will fail with a runtime exception.
1684      *
1685      * See JVMS section 4.4 for more information about the constant pool
1686      * of a class file.
1687      */
1688     private static class ConstantPool {
1689 
1690         /**
1691          * list of constant pool entries, in constant pool index order.
1692          *
1693          * This list is used when writing the constant pool to a stream
1694          * and for assigning the next index value.  Note that element 0
1695          * of this list corresponds to constant pool index 1.
1696          */
1697         private List<Entry> pool = new ArrayList<Entry>(32);
1698 
1699         /**
1700          * maps constant pool data of all types to constant pool indexes.
1701          *
1702          * This map is used to look up the index of an existing entry for
1703          * values of all types.
1704          */
1705         private Map<Object,Short> map = new HashMap<Object,Short>(16);
1706 
1707         /** true if no new constant pool entries may be added */
1708         private boolean readOnly = false;
1709 
1710         /**
1711          * Get or assign the index for a CONSTANT_Utf8 entry.
1712          */
1713         public short getUtf8(String s) {
1714             if (s == null) {
1715                 throw new NullPointerException();
1716             }
1717             return getValue(s);
1718         }
1719 
1720         /**
1721          * Get or assign the index for a CONSTANT_Integer entry.
1722          */
1723         public short getInteger(int i) {
1724             return getValue(new Integer(i));
1725         }
1726 
1727         /**
1728          * Get or assign the index for a CONSTANT_Float entry.
1729          */
1730         public short getFloat(float f) {
1731             return getValue(new Float(f));
1732         }
1733 
1734         /**
1735          * Get or assign the index for a CONSTANT_Class entry.
1736          */
1737         public short getClass(String name) {
1738             short utf8Index = getUtf8(name);
1739             return getIndirect(new IndirectEntry(
1740                 CONSTANT_CLASS, utf8Index));
1741         }
1742 
1743         /**
1744          * Get or assign the index for a CONSTANT_String entry.
1745          */
1746         public short getString(String s) {
1747             short utf8Index = getUtf8(s);
1748             return getIndirect(new IndirectEntry(
1749                 CONSTANT_STRING, utf8Index));
1750         }
1751 
1752         /**
1753          * Get or assign the index for a CONSTANT_FieldRef entry.
1754          */
1755         public short getFieldRef(String className,
1756                                  String name, String descriptor)
1757         {
1758             short classIndex = getClass(className);
1759             short nameAndTypeIndex = getNameAndType(name, descriptor);
1760             return getIndirect(new IndirectEntry(
1761                 CONSTANT_FIELD, classIndex, nameAndTypeIndex));
1762         }
1763 
1764         /**
1765          * Get or assign the index for a CONSTANT_MethodRef entry.
1766          */
1767         public short getMethodRef(String className,
1768                                   String name, String descriptor)
1769         {
1770             short classIndex = getClass(className);
1771             short nameAndTypeIndex = getNameAndType(name, descriptor);
1772             return getIndirect(new IndirectEntry(
1773                 CONSTANT_METHOD, classIndex, nameAndTypeIndex));
1774         }
1775 
1776         /**
1777          * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
1778          */
1779         public short getInterfaceMethodRef(String className, String name,
1780                                            String descriptor)
1781         {
1782             short classIndex = getClass(className);
1783             short nameAndTypeIndex = getNameAndType(name, descriptor);
1784             return getIndirect(new IndirectEntry(
1785                 CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
1786         }
1787 
1788         /**
1789          * Get or assign the index for a CONSTANT_NameAndType entry.
1790          */
1791         public short getNameAndType(String name, String descriptor) {
1792             short nameIndex = getUtf8(name);
1793             short descriptorIndex = getUtf8(descriptor);
1794             return getIndirect(new IndirectEntry(
1795                 CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
1796         }
1797 
1798         /**
1799          * Set this ConstantPool instance to be "read only".
1800          *
1801          * After this method has been called, further requests to get
1802          * an index for a non-existent entry will cause an InternalError
1803          * to be thrown instead of creating of the entry.
1804          */
1805         public void setReadOnly() {
1806             readOnly = true;
1807         }
1808 
1809         /**
1810          * Write this constant pool to a stream as part of
1811          * the class file format.
1812          *
1813          * This consists of writing the "constant_pool_count" and
1814          * "constant_pool[]" items of the "ClassFile" structure, as
1815          * described in JVMS section 4.1.
1816          */
1817         public void write(OutputStream out) throws IOException {
1818             DataOutputStream dataOut = new DataOutputStream(out);
1819 
1820             // constant_pool_count: number of entries plus one
1821             dataOut.writeShort(pool.size() + 1);
1822 
1823             for (Entry e : pool) {
1824                 e.write(dataOut);
1825             }
1826         }
1827 
1828         /**
1829          * Add a new constant pool entry and return its index.
1830          */
1831         private short addEntry(Entry entry) {
1832             pool.add(entry);
1833             /*
1834              * Note that this way of determining the index of the
1835              * added entry is wrong if this pool supports
1836              * CONSTANT_Long or CONSTANT_Double entries.
1837              */
1838             if (pool.size() >= 65535) {
1839                 throw new IllegalArgumentException(
1840                     "constant pool size limit exceeded");
1841             }
1842             return (short) pool.size();
1843         }
1844 
1845         /**
1846          * Get or assign the index for an entry of a type that contains
1847          * a direct value.  The type of the given object determines the
1848          * type of the desired entry as follows:
1849          *
1850          *      java.lang.String        CONSTANT_Utf8
1851          *      java.lang.Integer       CONSTANT_Integer
1852          *      java.lang.Float         CONSTANT_Float
1853          *      java.lang.Long          CONSTANT_Long
1854          *      java.lang.Double        CONSTANT_DOUBLE
1855          */
1856         private short getValue(Object key) {
1857             Short index = map.get(key);
1858             if (index != null) {
1859                 return index.shortValue();
1860             } else {
1861                 if (readOnly) {
1862                     throw new InternalError(
1863                         "late constant pool addition: " + key);
1864                 }
1865                 short i = addEntry(new ValueEntry(key));
1866                 map.put(key, new Short(i));
1867                 return i;
1868             }
1869         }
1870 
1871         /**
1872          * Get or assign the index for an entry of a type that contains
1873          * references to other constant pool entries.
1874          */
1875         private short getIndirect(IndirectEntry e) {
1876             Short index = map.get(e);
1877             if (index != null) {
1878                 return index.shortValue();
1879             } else {
1880                 if (readOnly) {
1881                     throw new InternalError("late constant pool addition");
1882                 }
1883                 short i = addEntry(e);
1884                 map.put(e, new Short(i));
1885                 return i;
1886             }
1887         }
1888 
1889         /**
1890          * Entry is the abstact superclass of all constant pool entry types
1891          * that can be stored in the "pool" list; its purpose is to define a
1892          * common method for writing constant pool entries to a class file.
1893          */
1894         private static abstract class Entry {
1895             public abstract void write(DataOutputStream out)
1896                 throws IOException;
1897         }
1898 
1899         /**
1900          * ValueEntry represents a constant pool entry of a type that
1901          * contains a direct value (see the comments for the "getValue"
1902          * method for a list of such types).
1903          *
1904          * ValueEntry objects are not used as keys for their entries in the
1905          * Map "map", so no useful hashCode or equals methods are defined.
1906          */
1907         private static class ValueEntry extends Entry {
1908             private Object value;
1909 
1910             public ValueEntry(Object value) {
1911                 this.value = value;
1912             }
1913 
1914             public void write(DataOutputStream out) throws IOException {
1915                 if (value instanceof String) {
1916                     out.writeByte(CONSTANT_UTF8);
1917                     out.writeUTF((String) value);
1918                 } else if (value instanceof Integer) {
1919                     out.writeByte(CONSTANT_INTEGER);
1920                     out.writeInt(((Integer) value).intValue());
1921                 } else if (value instanceof Float) {
1922                     out.writeByte(CONSTANT_FLOAT);
1923                     out.writeFloat(((Float) value).floatValue());
1924                 } else if (value instanceof Long) {
1925                     out.writeByte(CONSTANT_LONG);
1926                     out.writeLong(((Long) value).longValue());
1927                 } else if (value instanceof Double) {
1928                     out.writeDouble(CONSTANT_DOUBLE);
1929                     out.writeDouble(((Double) value).doubleValue());
1930                 } else {
1931                     throw new InternalError("bogus value entry: " + value);
1932                 }
1933             }
1934         }
1935 
1936         /**
1937          * IndirectEntry represents a constant pool entry of a type that
1938          * references other constant pool entries, i.e., the following types:
1939          *
1940          *      CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
1941          *      CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
1942          *      CONSTANT_NameAndType.
1943          *
1944          * Each of these entry types contains either one or two indexes of
1945          * other constant pool entries.
1946          *
1947          * IndirectEntry objects are used as the keys for their entries in
1948          * the Map "map", so the hashCode and equals methods are overridden
1949          * to allow matching.
1950          */
1951         private static class IndirectEntry extends Entry {
1952             private int tag;
1953             private short index0;
1954             private short index1;
1955 
1956             /**
1957              * Construct an IndirectEntry for a constant pool entry type
1958              * that contains one index of another entry.
1959              */
1960             public IndirectEntry(int tag, short index) {
1961                 this.tag = tag;
1962                 this.index0 = index;
1963                 this.index1 = 0;
1964             }
1965 
1966             /**
1967              * Construct an IndirectEntry for a constant pool entry type
1968              * that contains two indexes for other entries.
1969              */
1970             public IndirectEntry(int tag, short index0, short index1) {
1971                 this.tag = tag;
1972                 this.index0 = index0;
1973                 this.index1 = index1;
1974             }
1975 
1976             public void write(DataOutputStream out) throws IOException {
1977                 out.writeByte(tag);
1978                 out.writeShort(index0);
1979                 /*
1980                  * If this entry type contains two indexes, write
1981                  * out the second, too.
1982                  */
1983                 if (tag == CONSTANT_FIELD ||
1984                     tag == CONSTANT_METHOD ||
1985                     tag == CONSTANT_INTERFACEMETHOD ||
1986                     tag == CONSTANT_NAMEANDTYPE)
1987                 {
1988                     out.writeShort(index1);
1989                 }
1990             }
1991 
1992             public int hashCode() {
1993                 return tag + index0 + index1;
1994             }
1995 
1996             public boolean equals(Object obj) {
1997                 if (obj instanceof IndirectEntry) {
1998                     IndirectEntry other = (IndirectEntry) obj;
1999                     if (tag == other.tag &&
2000                         index0 == other.index0 && index1 == other.index1)
2001                     {
2002                         return true;
2003                     }
2004                 }
2005                 return false;
2006             }
2007         }
2008     }
2009 }