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

Save This Page
Home » openjdk-7 » sun » misc » [javadoc | source]