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