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