rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 13 May 2014 15:39:26 +0200
branchclosure
changeset 1566 bc1e4dacbde9
parent 1563 31bd01cfe50d
child 1567 58f2b09668d3
permissions -rw-r--r--
Prevent obfuscation when defining proxy constructor and methods
     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             "console.log('defineMethod: ' + sig.toString() + ' m: ' + method.toString().toString());\n" +
   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 }