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