rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 21 Oct 2013 14:34:12 +0200
changeset 1378 9ee9b36adb53
parent 772 rt/emul/mini/src/main/java/java/lang/reflect/Proxy.java@d382dacfd73f
child 1529 9afa6856382c
permissions -rw-r--r--
Can create Proxy for an annotation
     1 /*
     2  * Copyright (c) 1999, 2010, 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 org.apidesign.bck2brwsr.emul.reflect;
    27 
    28 import java.io.ByteArrayOutputStream;
    29 import java.io.DataOutputStream;
    30 import java.io.IOException;
    31 import java.io.OutputStream;
    32 import java.lang.ref.Reference;
    33 import java.lang.ref.WeakReference;
    34 import java.lang.reflect.Array;
    35 import java.lang.reflect.Constructor;
    36 import java.lang.reflect.InvocationHandler;
    37 import java.lang.reflect.InvocationTargetException;
    38 import java.lang.reflect.Method;
    39 import java.lang.reflect.Modifier;
    40 import java.util.ArrayList;
    41 import java.util.Arrays;
    42 import java.util.Collections;
    43 import java.util.HashMap;
    44 import java.util.HashSet;
    45 import java.util.LinkedList;
    46 import java.util.Map;
    47 import java.util.Set;
    48 import java.util.List;
    49 import java.util.ListIterator;
    50 import java.util.WeakHashMap;
    51 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    52 import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
    53 
    54 /**
    55  * {@code Proxy} provides static methods for creating dynamic proxy
    56  * classes and instances, and it is also the superclass of all
    57  * dynamic proxy classes created by those methods.
    58  *
    59  * <p>To create a proxy for some interface {@code Foo}:
    60  * <pre>
    61  *     InvocationHandler handler = new MyInvocationHandler(...);
    62  *     Class proxyClass = Proxy.getProxyClass(
    63  *         Foo.class.getClassLoader(), new Class[] { Foo.class });
    64  *     Foo f = (Foo) proxyClass.
    65  *         getConstructor(new Class[] { InvocationHandler.class }).
    66  *         newInstance(new Object[] { handler });
    67  * </pre>
    68  * or more simply:
    69  * <pre>
    70  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
    71  *                                          new Class[] { Foo.class },
    72  *                                          handler);
    73  * </pre>
    74  *
    75  * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
    76  * class</i> below) is a class that implements a list of interfaces
    77  * specified at runtime when the class is created, with behavior as
    78  * described below.
    79  *
    80  * A <i>proxy interface</i> is such an interface that is implemented
    81  * by a proxy class.
    82  *
    83  * A <i>proxy instance</i> is an instance of a proxy class.
    84  *
    85  * Each proxy instance has an associated <i>invocation handler</i>
    86  * object, which implements the interface {@link InvocationHandler}.
    87  * A method invocation on a proxy instance through one of its proxy
    88  * interfaces will be dispatched to the {@link InvocationHandler#invoke
    89  * invoke} method of the instance's invocation handler, passing the proxy
    90  * instance, a {@code java.lang.reflect.Method} object identifying
    91  * the method that was invoked, and an array of type {@code Object}
    92  * containing the arguments.  The invocation handler processes the
    93  * encoded method invocation as appropriate and the result that it
    94  * returns will be returned as the result of the method invocation on
    95  * the proxy instance.
    96  *
    97  * <p>A proxy class has the following properties:
    98  *
    99  * <ul>
   100  * <li>Proxy classes are public, final, and not abstract.
   101  *
   102  * <li>The unqualified name of a proxy class is unspecified.  The space
   103  * of class names that begin with the string {@code "$Proxy"}
   104  * should be, however, reserved for proxy classes.
   105  *
   106  * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
   107  *
   108  * <li>A proxy class implements exactly the interfaces specified at its
   109  * creation, in the same order.
   110  *
   111  * <li>If a proxy class implements a non-public interface, then it will
   112  * be defined in the same package as that interface.  Otherwise, the
   113  * package of a proxy class is also unspecified.  Note that package
   114  * sealing will not prevent a proxy class from being successfully defined
   115  * in a particular package at runtime, and neither will classes already
   116  * defined by the same class loader and the same package with particular
   117  * signers.
   118  *
   119  * <li>Since a proxy class implements all of the interfaces specified at
   120  * its creation, invoking {@code getInterfaces} on its
   121  * {@code Class} object will return an array containing the same
   122  * list of interfaces (in the order specified at its creation), invoking
   123  * {@code getMethods} on its {@code Class} object will return
   124  * an array of {@code Method} objects that include all of the
   125  * methods in those interfaces, and invoking {@code getMethod} will
   126  * find methods in the proxy interfaces as would be expected.
   127  *
   128  * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
   129  * return true if it is passed a proxy class-- a class returned by
   130  * {@code Proxy.getProxyClass} or the class of an object returned by
   131  * {@code Proxy.newProxyInstance}-- and false otherwise.
   132  *
   133  * <li>The {@code java.security.ProtectionDomain} of a proxy class
   134  * is the same as that of system classes loaded by the bootstrap class
   135  * loader, such as {@code java.lang.Object}, because the code for a
   136  * proxy class is generated by trusted system code.  This protection
   137  * domain will typically be granted
   138  * {@code java.security.AllPermission}.
   139  *
   140  * <li>Each proxy class has one public constructor that takes one argument,
   141  * an implementation of the interface {@link InvocationHandler}, to set
   142  * the invocation handler for a proxy instance.  Rather than having to use
   143  * the reflection API to access the public constructor, a proxy instance
   144  * can be also be created by calling the {@link Proxy#newProxyInstance
   145  * Proxy.newProxyInstance} method, which combines the actions of calling
   146  * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
   147  * constructor with an invocation handler.
   148  * </ul>
   149  *
   150  * <p>A proxy instance has the following properties:
   151  *
   152  * <ul>
   153  * <li>Given a proxy instance {@code proxy} and one of the
   154  * interfaces implemented by its proxy class {@code Foo}, the
   155  * following expression will return true:
   156  * <pre>
   157  *     {@code proxy instanceof Foo}
   158  * </pre>
   159  * and the following cast operation will succeed (rather than throwing
   160  * a {@code ClassCastException}):
   161  * <pre>
   162  *     {@code (Foo) proxy}
   163  * </pre>
   164  *
   165  * <li>Each proxy instance has an associated invocation handler, the one
   166  * that was passed to its constructor.  The static
   167  * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method
   168  * will return the invocation handler associated with the proxy instance
   169  * passed as its argument.
   170  *
   171  * <li>An interface method invocation on a proxy instance will be
   172  * encoded and dispatched to the invocation handler's {@link
   173  * InvocationHandler#invoke invoke} method as described in the
   174  * documentation for that method.
   175  *
   176  * <li>An invocation of the {@code hashCode},
   177  * {@code equals}, or {@code toString} methods declared in
   178  * {@code java.lang.Object} on a proxy instance will be encoded and
   179  * dispatched to the invocation handler's {@code invoke} method in
   180  * the same manner as interface method invocations are encoded and
   181  * dispatched, as described above.  The declaring class of the
   182  * {@code Method} object passed to {@code invoke} will be
   183  * {@code java.lang.Object}.  Other public methods of a proxy
   184  * instance inherited from {@code java.lang.Object} are not
   185  * overridden by a proxy class, so invocations of those methods behave
   186  * like they do for instances of {@code java.lang.Object}.
   187  * </ul>
   188  *
   189  * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
   190  *
   191  * <p>When two or more interfaces of a proxy class contain a method with
   192  * the same name and parameter signature, the order of the proxy class's
   193  * interfaces becomes significant.  When such a <i>duplicate method</i>
   194  * is invoked on a proxy instance, the {@code Method} object passed
   195  * to the invocation handler will not necessarily be the one whose
   196  * declaring class is assignable from the reference type of the interface
   197  * that the proxy's method was invoked through.  This limitation exists
   198  * because the corresponding method implementation in the generated proxy
   199  * class cannot determine which interface it was invoked through.
   200  * Therefore, when a duplicate method is invoked on a proxy instance,
   201  * the {@code Method} object for the method in the foremost interface
   202  * that contains the method (either directly or inherited through a
   203  * superinterface) in the proxy class's list of interfaces is passed to
   204  * the invocation handler's {@code invoke} method, regardless of the
   205  * reference type through which the method invocation occurred.
   206  *
   207  * <p>If a proxy interface contains a method with the same name and
   208  * parameter signature as the {@code hashCode}, {@code equals},
   209  * or {@code toString} methods of {@code java.lang.Object},
   210  * when such a method is invoked on a proxy instance, the
   211  * {@code Method} object passed to the invocation handler will have
   212  * {@code java.lang.Object} as its declaring class.  In other words,
   213  * the public, non-final methods of {@code java.lang.Object}
   214  * logically precede all of the proxy interfaces for the determination of
   215  * which {@code Method} object to pass to the invocation handler.
   216  *
   217  * <p>Note also that when a duplicate method is dispatched to an
   218  * invocation handler, the {@code invoke} method may only throw
   219  * checked exception types that are assignable to one of the exception
   220  * types in the {@code throws} clause of the method in <i>all</i> of
   221  * the proxy interfaces that it can be invoked through.  If the
   222  * {@code invoke} method throws a checked exception that is not
   223  * assignable to any of the exception types declared by the method in one
   224  * of the proxy interfaces that it can be invoked through, then an
   225  * unchecked {@code UndeclaredThrowableException} will be thrown by
   226  * the invocation on the proxy instance.  This restriction means that not
   227  * all of the exception types returned by invoking
   228  * {@code getExceptionTypes} on the {@code Method} object
   229  * passed to the {@code invoke} method can necessarily be thrown
   230  * successfully by the {@code invoke} method.
   231  *
   232  * @author      Peter Jones
   233  * @see         InvocationHandler
   234  * @since       1.3
   235  */
   236 public final class ProxyImpl implements java.io.Serializable {
   237 
   238     private static final long serialVersionUID = -2222568056686623797L;
   239 
   240     /** prefix for all proxy class names */
   241     private final static String proxyClassNamePrefix = "$Proxy";
   242 
   243     /** parameter types of a proxy class constructor */
   244     private final static Class[] constructorParams =
   245         { InvocationHandler.class };
   246 
   247     /** maps a class loader to the proxy class cache for that loader */
   248     private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
   249         = new WeakHashMap<>();
   250 
   251     /** marks that a particular proxy class is currently being generated */
   252     private static Object pendingGenerationMarker = new Object();
   253 
   254     /** next number to use for generation of unique proxy class names */
   255     private static long nextUniqueNumber = 0;
   256     private static Object nextUniqueNumberLock = new Object();
   257 
   258     /** set of all generated proxy classes, for isProxyClass implementation */
   259     private static Map<Class<?>, Void> proxyClasses =
   260         Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
   261 
   262     /**
   263      * the invocation handler for this proxy instance.
   264      * @serial
   265      */
   266     protected InvocationHandler h;
   267 
   268     /**
   269      * Prohibits instantiation.
   270      */
   271     private ProxyImpl() {
   272     }
   273 
   274     /**
   275      * Constructs a new {@code Proxy} instance from a subclass
   276      * (typically, a dynamic proxy class) with the specified value
   277      * for its invocation handler.
   278      *
   279      * @param   h the invocation handler for this proxy instance
   280      */
   281     protected ProxyImpl(InvocationHandler h) {
   282         this.h = h;
   283     }
   284 
   285     /**
   286      * Returns the {@code java.lang.Class} object for a proxy class
   287      * given a class loader and an array of interfaces.  The proxy class
   288      * will be defined by the specified class loader and will implement
   289      * all of the supplied interfaces.  If a proxy class for the same
   290      * permutation of interfaces has already been defined by the class
   291      * loader, then the existing proxy class will be returned; otherwise,
   292      * a proxy class for those interfaces will be generated dynamically
   293      * and defined by the class loader.
   294      *
   295      * <p>There are several restrictions on the parameters that may be
   296      * passed to {@code Proxy.getProxyClass}:
   297      *
   298      * <ul>
   299      * <li>All of the {@code Class} objects in the
   300      * {@code interfaces} array must represent interfaces, not
   301      * classes or primitive types.
   302      *
   303      * <li>No two elements in the {@code interfaces} array may
   304      * refer to identical {@code Class} objects.
   305      *
   306      * <li>All of the interface types must be visible by name through the
   307      * specified class loader.  In other words, for class loader
   308      * {@code cl} and every interface {@code i}, the following
   309      * expression must be true:
   310      * <pre>
   311      *     Class.forName(i.getName(), false, cl) == i
   312      * </pre>
   313      *
   314      * <li>All non-public interfaces must be in the same package;
   315      * otherwise, it would not be possible for the proxy class to
   316      * implement all of the interfaces, regardless of what package it is
   317      * defined in.
   318      *
   319      * <li>For any set of member methods of the specified interfaces
   320      * that have the same signature:
   321      * <ul>
   322      * <li>If the return type of any of the methods is a primitive
   323      * type or void, then all of the methods must have that same
   324      * return type.
   325      * <li>Otherwise, one of the methods must have a return type that
   326      * is assignable to all of the return types of the rest of the
   327      * methods.
   328      * </ul>
   329      *
   330      * <li>The resulting proxy class must not exceed any limits imposed
   331      * on classes by the virtual machine.  For example, the VM may limit
   332      * the number of interfaces that a class may implement to 65535; in
   333      * that case, the size of the {@code interfaces} array must not
   334      * exceed 65535.
   335      * </ul>
   336      *
   337      * <p>If any of these restrictions are violated,
   338      * {@code Proxy.getProxyClass} will throw an
   339      * {@code IllegalArgumentException}.  If the {@code interfaces}
   340      * array argument or any of its elements are {@code null}, a
   341      * {@code NullPointerException} will be thrown.
   342      *
   343      * <p>Note that the order of the specified proxy interfaces is
   344      * significant: two requests for a proxy class with the same combination
   345      * of interfaces but in a different order will result in two distinct
   346      * proxy classes.
   347      *
   348      * @param   loader the class loader to define the proxy class
   349      * @param   interfaces the list of interfaces for the proxy class
   350      *          to implement
   351      * @return  a proxy class that is defined in the specified class loader
   352      *          and that implements the specified interfaces
   353      * @throws  IllegalArgumentException if any of the restrictions on the
   354      *          parameters that may be passed to {@code getProxyClass}
   355      *          are violated
   356      * @throws  NullPointerException if the {@code interfaces} array
   357      *          argument or any of its elements are {@code null}
   358      */
   359     public static Class<?> getProxyClass(ClassLoader loader,
   360                                          Class<?>... interfaces)
   361         throws IllegalArgumentException
   362     {
   363         if (interfaces.length > 65535) {
   364             throw new IllegalArgumentException("interface limit exceeded");
   365         }
   366 
   367         Class<?> proxyClass = null;
   368 
   369         /* collect interface names to use as key for proxy class cache */
   370         String[] interfaceNames = new String[interfaces.length];
   371 
   372         // for detecting duplicates
   373         Set<Class<?>> interfaceSet = new HashSet<>();
   374 
   375         for (int i = 0; i < interfaces.length; i++) {
   376             /*
   377              * Verify that the class loader resolves the name of this
   378              * interface to the same Class object.
   379              */
   380             String interfaceName = interfaces[i].getName();
   381             Class<?> interfaceClass = null;
   382             try {
   383                 interfaceClass = Class.forName(interfaceName, false, loader);
   384             } catch (ClassNotFoundException e) {
   385             }
   386             if (interfaceClass != interfaces[i]) {
   387                 throw new IllegalArgumentException(
   388                     interfaces[i] + " is not visible from class loader");
   389             }
   390 
   391             /*
   392              * Verify that the Class object actually represents an
   393              * interface.
   394              */
   395             if (!interfaceClass.isInterface()) {
   396                 throw new IllegalArgumentException(
   397                     interfaceClass.getName() + " is not an interface");
   398             }
   399 
   400             /*
   401              * Verify that this interface is not a duplicate.
   402              */
   403             if (interfaceSet.contains(interfaceClass)) {
   404                 throw new IllegalArgumentException(
   405                     "repeated interface: " + interfaceClass.getName());
   406             }
   407             interfaceSet.add(interfaceClass);
   408 
   409             interfaceNames[i] = interfaceName;
   410         }
   411 
   412         /*
   413          * Using string representations of the proxy interfaces as
   414          * keys in the proxy class cache (instead of their Class
   415          * objects) is sufficient because we require the proxy
   416          * interfaces to be resolvable by name through the supplied
   417          * class loader, and it has the advantage that using a string
   418          * representation of a class makes for an implicit weak
   419          * reference to the class.
   420          */
   421         List<String> key = Arrays.asList(interfaceNames);
   422 
   423         /*
   424          * Find or create the proxy class cache for the class loader.
   425          */
   426         Map<List<String>, Object> cache;
   427         synchronized (loaderToCache) {
   428             cache = loaderToCache.get(loader);
   429             if (cache == null) {
   430                 cache = new HashMap<>();
   431                 loaderToCache.put(loader, cache);
   432             }
   433             /*
   434              * This mapping will remain valid for the duration of this
   435              * method, without further synchronization, because the mapping
   436              * will only be removed if the class loader becomes unreachable.
   437              */
   438         }
   439 
   440         /*
   441          * Look up the list of interfaces in the proxy class cache using
   442          * the key.  This lookup will result in one of three possible
   443          * kinds of values:
   444          *     null, if there is currently no proxy class for the list of
   445          *         interfaces in the class loader,
   446          *     the pendingGenerationMarker object, if a proxy class for the
   447          *         list of interfaces is currently being generated,
   448          *     or a weak reference to a Class object, if a proxy class for
   449          *         the list of interfaces has already been generated.
   450          */
   451         synchronized (cache) {
   452             /*
   453              * Note that we need not worry about reaping the cache for
   454              * entries with cleared weak references because if a proxy class
   455              * has been garbage collected, its class loader will have been
   456              * garbage collected as well, so the entire cache will be reaped
   457              * from the loaderToCache map.
   458              */
   459             do {
   460                 Object value = cache.get(key);
   461                 if (value instanceof Reference) {
   462                     proxyClass = (Class<?>) ((Reference) value).get();
   463                 }
   464                 if (proxyClass != null) {
   465                     // proxy class already generated: return it
   466                     return proxyClass;
   467                 } else if (value == pendingGenerationMarker) {
   468                     // proxy class being generated: wait for it
   469                     try {
   470                         cache.wait();
   471                     } catch (InterruptedException e) {
   472                         /*
   473                          * The class generation that we are waiting for should
   474                          * take a small, bounded time, so we can safely ignore
   475                          * thread interrupts here.
   476                          */
   477                     }
   478                     continue;
   479                 } else {
   480                     /*
   481                      * No proxy class for this list of interfaces has been
   482                      * generated or is being generated, so we will go and
   483                      * generate it now.  Mark it as pending generation.
   484                      */
   485                     cache.put(key, pendingGenerationMarker);
   486                     break;
   487                 }
   488             } while (true);
   489         }
   490 
   491         try {
   492             String proxyPkg = null;     // package to define proxy class in
   493 
   494             /*
   495              * Record the package of a non-public proxy interface so that the
   496              * proxy class will be defined in the same package.  Verify that
   497              * all non-public proxy interfaces are in the same package.
   498              */
   499             for (int i = 0; i < interfaces.length; i++) {
   500                 int flags = interfaces[i].getModifiers();
   501                 if (!Modifier.isPublic(flags)) {
   502                     String name = interfaces[i].getName();
   503                     int n = name.lastIndexOf('.');
   504                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
   505                     if (proxyPkg == null) {
   506                         proxyPkg = pkg;
   507                     } else if (!pkg.equals(proxyPkg)) {
   508                         throw new IllegalArgumentException(
   509                             "non-public interfaces from different packages");
   510                     }
   511                 }
   512             }
   513 
   514             if (proxyPkg == null) {     // if no non-public proxy interfaces,
   515                 proxyPkg = "";          // use the unnamed package
   516             }
   517 
   518             {
   519                 /*
   520                  * Choose a name for the proxy class to generate.
   521                  */
   522                 long num;
   523                 synchronized (nextUniqueNumberLock) {
   524                     num = nextUniqueNumber++;
   525                 }
   526                 String proxyName = proxyPkg + proxyClassNamePrefix + num;
   527                 /*
   528                  * Verify that the class loader hasn't already
   529                  * defined a class with the chosen name.
   530                  */
   531 
   532                 /*
   533                  * Generate the specified proxy class.
   534                  */
   535                 Generator gen = new Generator(proxyName, interfaces);
   536                 final byte[] proxyClassFile = gen.generateClassFile();
   537                 try {
   538                     proxyClass = defineClass0(loader, proxyName,
   539                         proxyClassFile);
   540                 } catch (ClassFormatError e) {
   541                     /*
   542                      * A ClassFormatError here means that (barring bugs in the
   543                      * proxy class generation code) there was some other
   544                      * invalid aspect of the arguments supplied to the proxy
   545                      * class creation (such as virtual machine limitations
   546                      * exceeded).
   547                      */
   548                     throw new IllegalArgumentException(e.toString());
   549                 }
   550                 gen.fillInMethods(proxyClass);
   551             }
   552             // add to set of all generated proxy classes, for isProxyClass
   553             proxyClasses.put(proxyClass, null);
   554 
   555         } finally {
   556             /*
   557              * We must clean up the "pending generation" state of the proxy
   558              * class cache entry somehow.  If a proxy class was successfully
   559              * generated, store it in the cache (with a weak reference);
   560              * otherwise, remove the reserved entry.  In all cases, notify
   561              * all waiters on reserved entries in this cache.
   562              */
   563             synchronized (cache) {
   564                 if (proxyClass != null) {
   565                     cache.put(key, new WeakReference<Class<?>>(proxyClass));
   566                 } else {
   567                     cache.remove(key);
   568                 }
   569                 cache.notifyAll();
   570             }
   571         }
   572         return proxyClass;
   573     }
   574 
   575     /**
   576      * Returns an instance of a proxy class for the specified interfaces
   577      * that dispatches method invocations to the specified invocation
   578      * handler.  This method is equivalent to:
   579      * <pre>
   580      *     Proxy.getProxyClass(loader, interfaces).
   581      *         getConstructor(new Class[] { InvocationHandler.class }).
   582      *         newInstance(new Object[] { handler });
   583      * </pre>
   584      *
   585      * <p>{@code Proxy.newProxyInstance} throws
   586      * {@code IllegalArgumentException} for the same reasons that
   587      * {@code Proxy.getProxyClass} does.
   588      *
   589      * @param   loader the class loader to define the proxy class
   590      * @param   interfaces the list of interfaces for the proxy class
   591      *          to implement
   592      * @param   h the invocation handler to dispatch method invocations to
   593      * @return  a proxy instance with the specified invocation handler of a
   594      *          proxy class that is defined by the specified class loader
   595      *          and that implements the specified interfaces
   596      * @throws  IllegalArgumentException if any of the restrictions on the
   597      *          parameters that may be passed to {@code getProxyClass}
   598      *          are violated
   599      * @throws  NullPointerException if the {@code interfaces} array
   600      *          argument or any of its elements are {@code null}, or
   601      *          if the invocation handler, {@code h}, is
   602      *          {@code null}
   603      */
   604     public static Object newProxyInstance(ClassLoader loader,
   605                                           Class<?>[] interfaces,
   606                                           InvocationHandler h)
   607         throws IllegalArgumentException
   608     {
   609         if (h == null) {
   610             throw new NullPointerException();
   611         }
   612 
   613         /*
   614          * Look up or generate the designated proxy class.
   615          */
   616         Class<?> cl = getProxyClass(loader, interfaces);
   617 
   618         /*
   619          * Invoke its constructor with the designated invocation handler.
   620          */
   621         try {
   622             Constructor cons = cl.getConstructor(constructorParams);
   623             return cons.newInstance(new Object[] { h });
   624         } catch (NoSuchMethodException e) {
   625             throw new InternalError(e.toString());
   626         } catch (IllegalAccessException e) {
   627             throw new InternalError(e.toString());
   628         } catch (InstantiationException e) {
   629             throw new InternalError(e.toString());
   630         } catch (InvocationTargetException e) {
   631             throw new InternalError(e.toString());
   632         }
   633     }
   634 
   635     /**
   636      * Returns true if and only if the specified class was dynamically
   637      * generated to be a proxy class using the {@code getProxyClass}
   638      * method or the {@code newProxyInstance} method.
   639      *
   640      * <p>The reliability of this method is important for the ability
   641      * to use it to make security decisions, so its implementation should
   642      * not just test if the class in question extends {@code Proxy}.
   643      *
   644      * @param   cl the class to test
   645      * @return  {@code true} if the class is a proxy class and
   646      *          {@code false} otherwise
   647      * @throws  NullPointerException if {@code cl} is {@code null}
   648      */
   649     public static boolean isProxyClass(Class<?> cl) {
   650         if (cl == null) {
   651             throw new NullPointerException();
   652         }
   653 
   654         return proxyClasses.containsKey(cl);
   655     }
   656 
   657     /**
   658      * Returns the invocation handler for the specified proxy instance.
   659      *
   660      * @param   proxy the proxy instance to return the invocation handler for
   661      * @return  the invocation handler for the proxy instance
   662      * @throws  IllegalArgumentException if the argument is not a
   663      *          proxy instance
   664      */
   665     public static InvocationHandler getInvocationHandler(Object proxy)
   666         throws IllegalArgumentException
   667     {
   668         /*
   669          * Verify that the object is actually a proxy instance.
   670          */
   671         if (!isProxyClass(proxy.getClass())) {
   672             throw new IllegalArgumentException("not a proxy instance");
   673         }
   674 
   675         ProxyImpl p = (ProxyImpl) proxy;
   676         return p.h;
   677     }
   678 
   679     @JavaScriptBody(args = { "ignore", "name", "byteCode" }, 
   680         body = "return vm._reload(name, byteCode).constructor.$class;"
   681     )
   682     private static native Class defineClass0(
   683         ClassLoader loader, String name, byte[] b
   684     );
   685     
   686     private static class Generator {
   687         /*
   688          * In the comments below, "JVMS" refers to The Java Virtual Machine
   689          * Specification Second Edition and "JLS" refers to the original
   690          * version of The Java Language Specification, unless otherwise
   691          * specified.
   692          */
   693 
   694         /* need 1.6 bytecode */
   695         private static final int CLASSFILE_MAJOR_VERSION = 50;
   696         private static final int CLASSFILE_MINOR_VERSION = 0;
   697 
   698         /*
   699          * beginning of constants copied from
   700          * sun.tools.java.RuntimeConstants (which no longer exists):
   701          */
   702 
   703         /* constant pool tags */
   704         private static final int CONSTANT_UTF8 = 1;
   705         private static final int CONSTANT_UNICODE = 2;
   706         private static final int CONSTANT_INTEGER = 3;
   707         private static final int CONSTANT_FLOAT = 4;
   708         private static final int CONSTANT_LONG = 5;
   709         private static final int CONSTANT_DOUBLE = 6;
   710         private static final int CONSTANT_CLASS = 7;
   711         private static final int CONSTANT_STRING = 8;
   712         private static final int CONSTANT_FIELD = 9;
   713         private static final int CONSTANT_METHOD = 10;
   714         private static final int CONSTANT_INTERFACEMETHOD = 11;
   715         private static final int CONSTANT_NAMEANDTYPE = 12;
   716 
   717         /* access and modifier flags */
   718         private static final int ACC_PUBLIC = 0x00000001;
   719         private static final int ACC_FINAL = 0x00000010;
   720         private static final int ACC_SUPER = 0x00000020;
   721 
   722     // end of constants copied from sun.tools.java.RuntimeConstants
   723         /**
   724          * name of the superclass of proxy classes
   725          */
   726         private final static String superclassName = "java/lang/reflect/Proxy";
   727 
   728         /**
   729          * name of field for storing a proxy instance's invocation handler
   730          */
   731         private final static String handlerFieldName = "h";
   732 
   733         /* preloaded Method objects for methods in java.lang.Object */
   734         private static Method hashCodeMethod;
   735         private static Method equalsMethod;
   736         private static Method toStringMethod;
   737 
   738         static {
   739             try {
   740                 hashCodeMethod = Object.class.getMethod("hashCode");
   741                 equalsMethod
   742                     = Object.class.getMethod("equals", new Class[]{Object.class});
   743                 toStringMethod = Object.class.getMethod("toString");
   744             } catch (NoSuchMethodException e) {
   745                 throw new IllegalStateException(e.getMessage());
   746             }
   747         }
   748 
   749         /**
   750          * name of proxy class
   751          */
   752         private String className;
   753 
   754         /**
   755          * proxy interfaces
   756          */
   757         private Class[] interfaces;
   758 
   759         /**
   760          * constant pool of class being generated
   761          */
   762         private ConstantPool cp = new ConstantPool();
   763 
   764         /**
   765          * maps method signature string to list of ProxyMethod objects for proxy
   766          * methods with that signature
   767          */
   768         private Map<String, List<ProxyMethod>> proxyMethods
   769             = new HashMap<String, List<ProxyMethod>>();
   770 
   771         /**
   772          * count of ProxyMethod objects added to proxyMethods
   773          */
   774         private int proxyMethodCount = 0;
   775 
   776         /**
   777          * Construct a ProxyGenerator to generate a proxy class with the
   778          * specified name and for the given interfaces.
   779          *
   780          * A ProxyGenerator object contains the state for the ongoing generation
   781          * of a particular proxy class.
   782          */
   783         private Generator(String className, Class[] interfaces) {
   784             this.className = className;
   785             this.interfaces = interfaces;
   786         }
   787 
   788         /**
   789          * Generate a class file for the proxy class. This method drives the
   790          * class file generation process.
   791          */
   792         private byte[] generateClassFile() {
   793 
   794             /* ============================================================
   795              * Step 1: Assemble ProxyMethod objects for all methods to
   796              * generate proxy dispatching code for.
   797              */
   798 
   799             /*
   800              * Record that proxy methods are needed for the hashCode, equals,
   801              * and toString methods of java.lang.Object.  This is done before
   802              * the methods from the proxy interfaces so that the methods from
   803              * java.lang.Object take precedence over duplicate methods in the
   804              * proxy interfaces.
   805              */
   806             addProxyMethod(hashCodeMethod, Object.class);
   807             addProxyMethod(equalsMethod, Object.class);
   808             addProxyMethod(toStringMethod, Object.class);
   809 
   810             /*
   811              * Now record all of the methods from the proxy interfaces, giving
   812              * earlier interfaces precedence over later ones with duplicate
   813              * methods.
   814              */
   815             for (int i = 0; i < interfaces.length; i++) {
   816                 Method[] methods = interfaces[i].getMethods();
   817                 for (int j = 0; j < methods.length; j++) {
   818                     addProxyMethod(methods[j], interfaces[i]);
   819                 }
   820             }
   821 
   822             /*
   823              * For each set of proxy methods with the same signature,
   824              * verify that the methods' return types are compatible.
   825              */
   826             for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
   827                 checkReturnTypes(sigmethods);
   828             }
   829 
   830             /* ============================================================
   831              * Step 2: Assemble FieldInfo and MethodInfo structs for all of
   832              * fields and methods in the class we are generating.
   833              */
   834             
   835             // will be done in fillInMethods
   836 
   837             /* ============================================================
   838              * Step 3: Write the final class file.
   839              */
   840 
   841             /*
   842              * Make sure that constant pool indexes are reserved for the
   843              * following items before starting to write the final class file.
   844              */
   845             cp.getClass(dotToSlash(className));
   846             cp.getClass(superclassName);
   847             for (int i = 0; i < interfaces.length; i++) {
   848                 cp.getClass(dotToSlash(interfaces[i].getName()));
   849             }
   850 
   851             /*
   852              * Disallow new constant pool additions beyond this point, since
   853              * we are about to write the final constant pool table.
   854              */
   855             cp.setReadOnly();
   856 
   857             ByteArrayOutputStream bout = new ByteArrayOutputStream();
   858             DataOutputStream dout = new DataOutputStream(bout);
   859 
   860             try {
   861                 /*
   862                  * Write all the items of the "ClassFile" structure.
   863                  * See JVMS section 4.1.
   864                  */
   865                 // u4 magic;
   866                 dout.writeInt(0xCAFEBABE);
   867                 // u2 minor_version;
   868                 dout.writeShort(CLASSFILE_MINOR_VERSION);
   869                 // u2 major_version;
   870                 dout.writeShort(CLASSFILE_MAJOR_VERSION);
   871 
   872                 cp.write(dout);             // (write constant pool)
   873 
   874                 // u2 access_flags;
   875                 dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
   876                 // u2 this_class;
   877                 dout.writeShort(cp.getClass(dotToSlash(className)));
   878                 // u2 super_class;
   879                 dout.writeShort(cp.getClass(superclassName));
   880 
   881                 // u2 interfaces_count;
   882                 dout.writeShort(interfaces.length);
   883                 // u2 interfaces[interfaces_count];
   884                 for (int i = 0; i < interfaces.length; i++) {
   885                     dout.writeShort(cp.getClass(
   886                         dotToSlash(interfaces[i].getName())));
   887                 }
   888 
   889                 // u2 fields_count;
   890                 dout.writeShort(0);
   891 
   892                 // u2 methods_count;
   893                 dout.writeShort(0);
   894 
   895                 // u2 attributes_count;
   896                 dout.writeShort(0); // (no ClassFile attributes for proxy classes)
   897 
   898             } catch (IOException e) {
   899                 throw new InternalError("unexpected I/O Exception");
   900             }
   901 
   902             return bout.toByteArray();
   903         }
   904 
   905         @JavaScriptBody(args = { "c", "sig", "method", "primitive" }, body = 
   906             "var p = c.cnstr.prototype;\n" +
   907             "p[sig] = function() {\n" +
   908             "  var h = this._h();\n" +
   909             "  var res = h.invoke__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_reflect_Method_2_3Ljava_lang_Object_2(this, method, arguments);\n" +
   910             "  \n" +
   911             "  \n" +
   912             "  return res;\n" +
   913             "};"
   914         )
   915         private static native void defineMethod(Class<?> proxyClass, String sig, Method method, boolean primitive);
   916 
   917         @JavaScriptBody(args = "c", body = 
   918               "var h = c.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2 = function(h) {\n"
   919             + "  c.superclass.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2.call(this, h);\n"
   920             + "}\n"
   921             + "h.cls = c.cnstr;\n"
   922         )
   923         private static native void defineConstructor(Class<?> proxyClass);
   924         
   925         final void fillInMethods(Class<?> proxyClass) {
   926             for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
   927                 for (ProxyMethod pm : sigmethods) {
   928                     String sig = MethodImpl.toSignature(pm.method);
   929                     defineMethod(proxyClass, sig, pm.method, pm.method.getReturnType().isPrimitive());
   930                 }
   931             }
   932             defineConstructor(proxyClass);
   933         }
   934 
   935         /**
   936          * Add another method to be proxied, either by creating a new
   937          * ProxyMethod object or augmenting an old one for a duplicate method.
   938          *
   939          * "fromClass" indicates the proxy interface that the method was found
   940          * through, which may be different from (a subinterface of) the method's
   941          * "declaring class". Note that the first Method object passed for a
   942          * given name and descriptor identifies the Method object (and thus the
   943          * declaring class) that will be passed to the invocation handler's
   944          * "invoke" method for a given set of duplicate methods.
   945          */
   946         private void addProxyMethod(Method m, Class fromClass) {
   947             String name = m.getName();
   948             Class[] parameterTypes = m.getParameterTypes();
   949             Class returnType = m.getReturnType();
   950             Class[] exceptionTypes = m.getExceptionTypes();
   951 
   952             String sig = MethodImpl.toSignature(m);
   953             List<ProxyMethod> sigmethods = proxyMethods.get(sig);
   954             if (sigmethods != null) {
   955                 for (ProxyMethod pm : sigmethods) {
   956                     if (returnType == pm.returnType) {
   957                         /*
   958                          * Found a match: reduce exception types to the
   959                          * greatest set of exceptions that can thrown
   960                          * compatibly with the throws clauses of both
   961                          * overridden methods.
   962                          */
   963                         List<Class<?>> legalExceptions = new ArrayList<Class<?>>();
   964                         collectCompatibleTypes(
   965                             exceptionTypes, pm.exceptionTypes, legalExceptions);
   966                         collectCompatibleTypes(
   967                             pm.exceptionTypes, exceptionTypes, legalExceptions);
   968                         pm.exceptionTypes = new Class[legalExceptions.size()];
   969                         pm.exceptionTypes
   970                             = legalExceptions.toArray(pm.exceptionTypes);
   971                         return;
   972                     }
   973                 }
   974             } else {
   975                 sigmethods = new ArrayList<ProxyMethod>(3);
   976                 proxyMethods.put(sig, sigmethods);
   977             }
   978             sigmethods.add(new ProxyMethod(m, name, parameterTypes, returnType,
   979                 exceptionTypes, fromClass));
   980         }
   981 
   982         /**
   983          * For a given set of proxy methods with the same signature, check that
   984          * their return types are compatible according to the Proxy
   985          * specification.
   986          *
   987          * Specifically, if there is more than one such method, then all of the
   988          * return types must be reference types, and there must be one return
   989          * type that is assignable to each of the rest of them.
   990          */
   991         private static void checkReturnTypes(List<ProxyMethod> methods) {
   992             /*
   993              * If there is only one method with a given signature, there
   994              * cannot be a conflict.  This is the only case in which a
   995              * primitive (or void) return type is allowed.
   996              */
   997             if (methods.size() < 2) {
   998                 return;
   999             }
  1000 
  1001             /*
  1002              * List of return types that are not yet known to be
  1003              * assignable from ("covered" by) any of the others.
  1004              */
  1005             LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>();
  1006 
  1007             nextNewReturnType:
  1008             for (ProxyMethod pm : methods) {
  1009                 Class<?> newReturnType = pm.returnType;
  1010                 if (newReturnType.isPrimitive()) {
  1011                     throw new IllegalArgumentException(
  1012                         "methods with same signature "
  1013                         + getFriendlyMethodSignature(pm.methodName,
  1014                             pm.parameterTypes)
  1015                         + " but incompatible return types: "
  1016                         + newReturnType.getName() + " and others");
  1017                 }
  1018                 boolean added = false;
  1019 
  1020                 /*
  1021                  * Compare the new return type to the existing uncovered
  1022                  * return types.
  1023                  */
  1024                 ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
  1025                 while (liter.hasNext()) {
  1026                     Class<?> uncoveredReturnType = liter.next();
  1027 
  1028                     /*
  1029                      * If an existing uncovered return type is assignable
  1030                      * to this new one, then we can forget the new one.
  1031                      */
  1032                     if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
  1033                         assert !added;
  1034                         continue nextNewReturnType;
  1035                     }
  1036 
  1037                     /*
  1038                      * If the new return type is assignable to an existing
  1039                      * uncovered one, then should replace the existing one
  1040                      * with the new one (or just forget the existing one,
  1041                      * if the new one has already be put in the list).
  1042                      */
  1043                     if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
  1044                         // (we can assume that each return type is unique)
  1045                         if (!added) {
  1046                             liter.set(newReturnType);
  1047                             added = true;
  1048                         } else {
  1049                             liter.remove();
  1050                         }
  1051                     }
  1052                 }
  1053 
  1054                 /*
  1055                  * If we got through the list of existing uncovered return
  1056                  * types without an assignability relationship, then add
  1057                  * the new return type to the list of uncovered ones.
  1058                  */
  1059                 if (!added) {
  1060                     uncoveredReturnTypes.add(newReturnType);
  1061                 }
  1062             }
  1063 
  1064             /*
  1065              * We shouldn't end up with more than one return type that is
  1066              * not assignable from any of the others.
  1067              */
  1068             if (uncoveredReturnTypes.size() > 1) {
  1069                 ProxyMethod pm = methods.get(0);
  1070                 throw new IllegalArgumentException(
  1071                     "methods with same signature "
  1072                     + getFriendlyMethodSignature(pm.methodName, pm.parameterTypes)
  1073                     + " but incompatible return types: " + uncoveredReturnTypes);
  1074             }
  1075         }
  1076 
  1077 
  1078         /**
  1079          * A ProxyMethod object represents a proxy method in the proxy class
  1080          * being generated: a method whose implementation will encode and
  1081          * dispatch invocations to the proxy instance's invocation handler.
  1082          */
  1083         private class ProxyMethod {
  1084 
  1085             private final Method method;
  1086             public String methodName;
  1087             public Class[] parameterTypes;
  1088             public Class returnType;
  1089             public Class[] exceptionTypes;
  1090             public Class fromClass;
  1091             public String methodFieldName;
  1092 
  1093             private ProxyMethod(Method m, 
  1094                 String methodName, Class[] parameterTypes, 
  1095                 Class returnType, Class[] exceptionTypes, 
  1096                 Class fromClass
  1097             ) {
  1098                 this.method = m;
  1099                 this.methodName = methodName;
  1100                 this.parameterTypes = parameterTypes;
  1101                 this.returnType = returnType;
  1102                 this.exceptionTypes = exceptionTypes;
  1103                 this.fromClass = fromClass;
  1104                 this.methodFieldName = "m" + proxyMethodCount++;
  1105             }
  1106 
  1107         }
  1108 
  1109         /*
  1110          * ==================== General Utility Methods ====================
  1111          */
  1112         /**
  1113          * Convert a fully qualified class name that uses '.' as the package
  1114          * separator, the external representation used by the Java language and
  1115          * APIs, to a fully qualified class name that uses '/' as the package
  1116          * separator, the representation used in the class file format (see JVMS
  1117          * section 4.2).
  1118          */
  1119         private static String dotToSlash(String name) {
  1120             return name.replace('.', '/');
  1121         }
  1122 
  1123         /**
  1124          * Return the list of "parameter descriptor" strings enclosed in
  1125          * parentheses corresponding to the given parameter types (in other
  1126          * words, a method descriptor without a return descriptor). This string
  1127          * is useful for constructing string keys for methods without regard to
  1128          * their return type.
  1129          */
  1130         private static String getParameterDescriptors(Class[] parameterTypes) {
  1131             StringBuilder desc = new StringBuilder("(");
  1132             for (int i = 0; i < parameterTypes.length; i++) {
  1133                 desc.append(getFieldType(parameterTypes[i]));
  1134             }
  1135             desc.append(')');
  1136             return desc.toString();
  1137         }
  1138 
  1139         /**
  1140          * Return the "field type" string for the given type, appropriate for a
  1141          * field descriptor, a parameter descriptor, or a return descriptor
  1142          * other than "void". See JVMS section 4.3.2.
  1143          */
  1144         private static String getFieldType(Class type) {
  1145             if (type.isPrimitive()) {
  1146                 return PrimitiveTypeInfo.get(type).baseTypeString;
  1147             } else if (type.isArray()) {
  1148                 /*
  1149                  * According to JLS 20.3.2, the getName() method on Class does
  1150                  * return the VM type descriptor format for array classes (only);
  1151                  * using that should be quicker than the otherwise obvious code:
  1152                  *
  1153                  *     return "[" + getTypeDescriptor(type.getComponentType());
  1154                  */
  1155                 return type.getName().replace('.', '/');
  1156             } else {
  1157                 return "L" + dotToSlash(type.getName()) + ";";
  1158             }
  1159         }
  1160 
  1161         /**
  1162          * Returns a human-readable string representing the signature of a
  1163          * method with the given name and parameter types.
  1164          */
  1165         private static String getFriendlyMethodSignature(String name,
  1166             Class[] parameterTypes) {
  1167             StringBuilder sig = new StringBuilder(name);
  1168             sig.append('(');
  1169             for (int i = 0; i < parameterTypes.length; i++) {
  1170                 if (i > 0) {
  1171                     sig.append(',');
  1172                 }
  1173                 Class parameterType = parameterTypes[i];
  1174                 int dimensions = 0;
  1175                 while (parameterType.isArray()) {
  1176                     parameterType = parameterType.getComponentType();
  1177                     dimensions++;
  1178                 }
  1179                 sig.append(parameterType.getName());
  1180                 while (dimensions-- > 0) {
  1181                     sig.append("[]");
  1182                 }
  1183             }
  1184             sig.append(')');
  1185             return sig.toString();
  1186         }
  1187 
  1188         /**
  1189          * Add to the given list all of the types in the "from" array that are
  1190          * not already contained in the list and are assignable to at least one
  1191          * of the types in the "with" array.
  1192          *
  1193          * This method is useful for computing the greatest common set of
  1194          * declared exceptions from duplicate methods inherited from different
  1195          * interfaces.
  1196          */
  1197         private static void collectCompatibleTypes(Class<?>[] from,
  1198             Class<?>[] with,
  1199             List<Class<?>> list) {
  1200             for (int i = 0; i < from.length; i++) {
  1201                 if (!list.contains(from[i])) {
  1202                     for (int j = 0; j < with.length; j++) {
  1203                         if (with[j].isAssignableFrom(from[i])) {
  1204                             list.add(from[i]);
  1205                             break;
  1206                         }
  1207                     }
  1208                 }
  1209             }
  1210         }
  1211 
  1212 
  1213         /**
  1214          * A PrimitiveTypeInfo object contains assorted information about a
  1215          * primitive type in its public fields. The struct for a particular
  1216          * primitive type can be obtained using the static "get" method.
  1217          */
  1218         private static class PrimitiveTypeInfo {
  1219 
  1220             /**
  1221              * "base type" used in various descriptors (see JVMS section 4.3.2)
  1222              */
  1223             public String baseTypeString;
  1224 
  1225             /**
  1226              * name of corresponding wrapper class
  1227              */
  1228             public String wrapperClassName;
  1229 
  1230             /**
  1231              * method descriptor for wrapper class "valueOf" factory method
  1232              */
  1233             public String wrapperValueOfDesc;
  1234 
  1235             /**
  1236              * name of wrapper class method for retrieving primitive value
  1237              */
  1238             public String unwrapMethodName;
  1239 
  1240             /**
  1241              * descriptor of same method
  1242              */
  1243             public String unwrapMethodDesc;
  1244 
  1245             private static Map<Class, PrimitiveTypeInfo> table
  1246                 = new HashMap<Class, PrimitiveTypeInfo>();
  1247 
  1248             static {
  1249                 add(byte.class, Byte.class);
  1250                 add(char.class, Character.class);
  1251                 add(double.class, Double.class);
  1252                 add(float.class, Float.class);
  1253                 add(int.class, Integer.class);
  1254                 add(long.class, Long.class);
  1255                 add(short.class, Short.class);
  1256                 add(boolean.class, Boolean.class);
  1257             }
  1258 
  1259             private static void add(Class primitiveClass, Class wrapperClass) {
  1260                 table.put(primitiveClass,
  1261                     new PrimitiveTypeInfo(primitiveClass, wrapperClass));
  1262             }
  1263 
  1264             private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) {
  1265                 assert primitiveClass.isPrimitive();
  1266 
  1267                 baseTypeString
  1268                     = Array.newInstance(primitiveClass, 0)
  1269                     .getClass().getName().substring(1);
  1270                 wrapperClassName = dotToSlash(wrapperClass.getName());
  1271                 wrapperValueOfDesc
  1272                     = "(" + baseTypeString + ")L" + wrapperClassName + ";";
  1273                 unwrapMethodName = primitiveClass.getName() + "Value";
  1274                 unwrapMethodDesc = "()" + baseTypeString;
  1275             }
  1276 
  1277             public static PrimitiveTypeInfo get(Class cl) {
  1278                 return table.get(cl);
  1279             }
  1280         }
  1281 
  1282         /**
  1283          * A ConstantPool object represents the constant pool of a class file
  1284          * being generated. This representation of a constant pool is designed
  1285          * specifically for use by ProxyGenerator; in particular, it assumes
  1286          * that constant pool entries will not need to be resorted (for example,
  1287          * by their type, as the Java compiler does), so that the final index
  1288          * value can be assigned and used when an entry is first created.
  1289          *
  1290          * Note that new entries cannot be created after the constant pool has
  1291          * been written to a class file. To prevent such logic errors, a
  1292          * ConstantPool instance can be marked "read only", so that further
  1293          * attempts to add new entries will fail with a runtime exception.
  1294          *
  1295          * See JVMS section 4.4 for more information about the constant pool of
  1296          * a class file.
  1297          */
  1298         private static class ConstantPool {
  1299 
  1300             /**
  1301              * list of constant pool entries, in constant pool index order.
  1302              *
  1303              * This list is used when writing the constant pool to a stream and
  1304              * for assigning the next index value. Note that element 0 of this
  1305              * list corresponds to constant pool index 1.
  1306              */
  1307             private List<Entry> pool = new ArrayList<Entry>(32);
  1308 
  1309             /**
  1310              * maps constant pool data of all types to constant pool indexes.
  1311              *
  1312              * This map is used to look up the index of an existing entry for
  1313              * values of all types.
  1314              */
  1315             private Map<Object, Short> map = new HashMap<Object, Short>(16);
  1316 
  1317             /**
  1318              * true if no new constant pool entries may be added
  1319              */
  1320             private boolean readOnly = false;
  1321 
  1322             /**
  1323              * Get or assign the index for a CONSTANT_Utf8 entry.
  1324              */
  1325             public short getUtf8(String s) {
  1326                 if (s == null) {
  1327                     throw new NullPointerException();
  1328                 }
  1329                 return getValue(s);
  1330             }
  1331 
  1332             /**
  1333              * Get or assign the index for a CONSTANT_Integer entry.
  1334              */
  1335             public short getInteger(int i) {
  1336                 return getValue(new Integer(i));
  1337             }
  1338 
  1339             /**
  1340              * Get or assign the index for a CONSTANT_Float entry.
  1341              */
  1342             public short getFloat(float f) {
  1343                 return getValue(new Float(f));
  1344             }
  1345 
  1346             /**
  1347              * Get or assign the index for a CONSTANT_Class entry.
  1348              */
  1349             public short getClass(String name) {
  1350                 short utf8Index = getUtf8(name);
  1351                 return getIndirect(new IndirectEntry(
  1352                     CONSTANT_CLASS, utf8Index));
  1353             }
  1354 
  1355             /**
  1356              * Get or assign the index for a CONSTANT_String entry.
  1357              */
  1358             public short getString(String s) {
  1359                 short utf8Index = getUtf8(s);
  1360                 return getIndirect(new IndirectEntry(
  1361                     CONSTANT_STRING, utf8Index));
  1362             }
  1363 
  1364             /**
  1365              * Get or assign the index for a CONSTANT_FieldRef entry.
  1366              */
  1367             public short getFieldRef(String className,
  1368                 String name, String descriptor) {
  1369                 short classIndex = getClass(className);
  1370                 short nameAndTypeIndex = getNameAndType(name, descriptor);
  1371                 return getIndirect(new IndirectEntry(
  1372                     CONSTANT_FIELD, classIndex, nameAndTypeIndex));
  1373             }
  1374 
  1375             /**
  1376              * Get or assign the index for a CONSTANT_MethodRef entry.
  1377              */
  1378             public short getMethodRef(String className,
  1379                 String name, String descriptor) {
  1380                 short classIndex = getClass(className);
  1381                 short nameAndTypeIndex = getNameAndType(name, descriptor);
  1382                 return getIndirect(new IndirectEntry(
  1383                     CONSTANT_METHOD, classIndex, nameAndTypeIndex));
  1384             }
  1385 
  1386             /**
  1387              * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
  1388              */
  1389             public short getInterfaceMethodRef(String className, String name,
  1390                 String descriptor) {
  1391                 short classIndex = getClass(className);
  1392                 short nameAndTypeIndex = getNameAndType(name, descriptor);
  1393                 return getIndirect(new IndirectEntry(
  1394                     CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
  1395             }
  1396 
  1397             /**
  1398              * Get or assign the index for a CONSTANT_NameAndType entry.
  1399              */
  1400             public short getNameAndType(String name, String descriptor) {
  1401                 short nameIndex = getUtf8(name);
  1402                 short descriptorIndex = getUtf8(descriptor);
  1403                 return getIndirect(new IndirectEntry(
  1404                     CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
  1405             }
  1406 
  1407             /**
  1408              * Set this ConstantPool instance to be "read only".
  1409              *
  1410              * After this method has been called, further requests to get an
  1411              * index for a non-existent entry will cause an InternalError to be
  1412              * thrown instead of creating of the entry.
  1413              */
  1414             public void setReadOnly() {
  1415                 readOnly = true;
  1416             }
  1417 
  1418             /**
  1419              * Write this constant pool to a stream as part of the class file
  1420              * format.
  1421              *
  1422              * This consists of writing the "constant_pool_count" and
  1423              * "constant_pool[]" items of the "ClassFile" structure, as
  1424              * described in JVMS section 4.1.
  1425              */
  1426             public void write(OutputStream out) throws IOException {
  1427                 DataOutputStream dataOut = new DataOutputStream(out);
  1428 
  1429                 // constant_pool_count: number of entries plus one
  1430                 dataOut.writeShort(pool.size() + 1);
  1431 
  1432                 for (Entry e : pool) {
  1433                     e.write(dataOut);
  1434                 }
  1435             }
  1436 
  1437             /**
  1438              * Add a new constant pool entry and return its index.
  1439              */
  1440             private short addEntry(Entry entry) {
  1441                 pool.add(entry);
  1442                 /*
  1443                  * Note that this way of determining the index of the
  1444                  * added entry is wrong if this pool supports
  1445                  * CONSTANT_Long or CONSTANT_Double entries.
  1446                  */
  1447                 if (pool.size() >= 65535) {
  1448                     throw new IllegalArgumentException(
  1449                         "constant pool size limit exceeded");
  1450                 }
  1451                 return (short) pool.size();
  1452             }
  1453 
  1454             /**
  1455              * Get or assign the index for an entry of a type that contains a
  1456              * direct value. The type of the given object determines the type of
  1457              * the desired entry as follows:
  1458              *
  1459              * java.lang.String CONSTANT_Utf8 java.lang.Integer CONSTANT_Integer
  1460              * java.lang.Float CONSTANT_Float java.lang.Long CONSTANT_Long
  1461              * java.lang.Double CONSTANT_DOUBLE
  1462              */
  1463             private short getValue(Object key) {
  1464                 Short index = map.get(key);
  1465                 if (index != null) {
  1466                     return index.shortValue();
  1467                 } else {
  1468                     if (readOnly) {
  1469                         throw new InternalError(
  1470                             "late constant pool addition: " + key);
  1471                     }
  1472                     short i = addEntry(new ValueEntry(key));
  1473                     map.put(key, new Short(i));
  1474                     return i;
  1475                 }
  1476             }
  1477 
  1478             /**
  1479              * Get or assign the index for an entry of a type that contains
  1480              * references to other constant pool entries.
  1481              */
  1482             private short getIndirect(IndirectEntry e) {
  1483                 Short index = map.get(e);
  1484                 if (index != null) {
  1485                     return index.shortValue();
  1486                 } else {
  1487                     if (readOnly) {
  1488                         throw new InternalError("late constant pool addition");
  1489                     }
  1490                     short i = addEntry(e);
  1491                     map.put(e, new Short(i));
  1492                     return i;
  1493                 }
  1494             }
  1495 
  1496             /**
  1497              * Entry is the abstact superclass of all constant pool entry types
  1498              * that can be stored in the "pool" list; its purpose is to define a
  1499              * common method for writing constant pool entries to a class file.
  1500              */
  1501             private static abstract class Entry {
  1502 
  1503                 public abstract void write(DataOutputStream out)
  1504                     throws IOException;
  1505             }
  1506 
  1507             /**
  1508              * ValueEntry represents a constant pool entry of a type that
  1509              * contains a direct value (see the comments for the "getValue"
  1510              * method for a list of such types).
  1511              *
  1512              * ValueEntry objects are not used as keys for their entries in the
  1513              * Map "map", so no useful hashCode or equals methods are defined.
  1514              */
  1515             private static class ValueEntry extends Entry {
  1516 
  1517                 private Object value;
  1518 
  1519                 public ValueEntry(Object value) {
  1520                     this.value = value;
  1521                 }
  1522 
  1523                 public void write(DataOutputStream out) throws IOException {
  1524                     if (value instanceof String) {
  1525                         out.writeByte(CONSTANT_UTF8);
  1526                         out.writeUTF((String) value);
  1527                     } else if (value instanceof Integer) {
  1528                         out.writeByte(CONSTANT_INTEGER);
  1529                         out.writeInt(((Integer) value).intValue());
  1530                     } else if (value instanceof Float) {
  1531                         out.writeByte(CONSTANT_FLOAT);
  1532                         out.writeFloat(((Float) value).floatValue());
  1533                     } else if (value instanceof Long) {
  1534                         out.writeByte(CONSTANT_LONG);
  1535                         out.writeLong(((Long) value).longValue());
  1536                     } else if (value instanceof Double) {
  1537                         out.writeDouble(CONSTANT_DOUBLE);
  1538                         out.writeDouble(((Double) value).doubleValue());
  1539                     } else {
  1540                         throw new InternalError("bogus value entry: " + value);
  1541                     }
  1542                 }
  1543             }
  1544 
  1545             /**
  1546              * IndirectEntry represents a constant pool entry of a type that
  1547              * references other constant pool entries, i.e., the following
  1548              * types:
  1549              *
  1550              * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
  1551              * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
  1552              * CONSTANT_NameAndType.
  1553              *
  1554              * Each of these entry types contains either one or two indexes of
  1555              * other constant pool entries.
  1556              *
  1557              * IndirectEntry objects are used as the keys for their entries in
  1558              * the Map "map", so the hashCode and equals methods are overridden
  1559              * to allow matching.
  1560              */
  1561             private static class IndirectEntry extends Entry {
  1562 
  1563                 private int tag;
  1564                 private short index0;
  1565                 private short index1;
  1566 
  1567                 /**
  1568                  * Construct an IndirectEntry for a constant pool entry type
  1569                  * that contains one index of another entry.
  1570                  */
  1571                 public IndirectEntry(int tag, short index) {
  1572                     this.tag = tag;
  1573                     this.index0 = index;
  1574                     this.index1 = 0;
  1575                 }
  1576 
  1577                 /**
  1578                  * Construct an IndirectEntry for a constant pool entry type
  1579                  * that contains two indexes for other entries.
  1580                  */
  1581                 public IndirectEntry(int tag, short index0, short index1) {
  1582                     this.tag = tag;
  1583                     this.index0 = index0;
  1584                     this.index1 = index1;
  1585                 }
  1586 
  1587                 public void write(DataOutputStream out) throws IOException {
  1588                     out.writeByte(tag);
  1589                     out.writeShort(index0);
  1590                     /*
  1591                      * If this entry type contains two indexes, write
  1592                      * out the second, too.
  1593                      */
  1594                     if (tag == CONSTANT_FIELD
  1595                         || tag == CONSTANT_METHOD
  1596                         || tag == CONSTANT_INTERFACEMETHOD
  1597                         || tag == CONSTANT_NAMEANDTYPE) {
  1598                         out.writeShort(index1);
  1599                     }
  1600                 }
  1601 
  1602                 public int hashCode() {
  1603                     return tag + index0 + index1;
  1604                 }
  1605 
  1606                 public boolean equals(Object obj) {
  1607                     if (obj instanceof IndirectEntry) {
  1608                         IndirectEntry other = (IndirectEntry) obj;
  1609                         if (tag == other.tag
  1610                             && index0 == other.index0 && index1 == other.index1) {
  1611                             return true;
  1612                         }
  1613                     }
  1614                     return false;
  1615                 }
  1616             }
  1617         }
  1618     }
  1619     
  1620 }