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