rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java
changeset 1378 9ee9b36adb53
parent 772 d382dacfd73f
child 1529 9afa6856382c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java	Mon Oct 21 14:34:12 2013 +0200
     1.3 @@ -0,0 +1,1620 @@
     1.4 +/*
     1.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package org.apidesign.bck2brwsr.emul.reflect;
    1.30 +
    1.31 +import java.io.ByteArrayOutputStream;
    1.32 +import java.io.DataOutputStream;
    1.33 +import java.io.IOException;
    1.34 +import java.io.OutputStream;
    1.35 +import java.lang.ref.Reference;
    1.36 +import java.lang.ref.WeakReference;
    1.37 +import java.lang.reflect.Array;
    1.38 +import java.lang.reflect.Constructor;
    1.39 +import java.lang.reflect.InvocationHandler;
    1.40 +import java.lang.reflect.InvocationTargetException;
    1.41 +import java.lang.reflect.Method;
    1.42 +import java.lang.reflect.Modifier;
    1.43 +import java.util.ArrayList;
    1.44 +import java.util.Arrays;
    1.45 +import java.util.Collections;
    1.46 +import java.util.HashMap;
    1.47 +import java.util.HashSet;
    1.48 +import java.util.LinkedList;
    1.49 +import java.util.Map;
    1.50 +import java.util.Set;
    1.51 +import java.util.List;
    1.52 +import java.util.ListIterator;
    1.53 +import java.util.WeakHashMap;
    1.54 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    1.55 +import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
    1.56 +
    1.57 +/**
    1.58 + * {@code Proxy} provides static methods for creating dynamic proxy
    1.59 + * classes and instances, and it is also the superclass of all
    1.60 + * dynamic proxy classes created by those methods.
    1.61 + *
    1.62 + * <p>To create a proxy for some interface {@code Foo}:
    1.63 + * <pre>
    1.64 + *     InvocationHandler handler = new MyInvocationHandler(...);
    1.65 + *     Class proxyClass = Proxy.getProxyClass(
    1.66 + *         Foo.class.getClassLoader(), new Class[] { Foo.class });
    1.67 + *     Foo f = (Foo) proxyClass.
    1.68 + *         getConstructor(new Class[] { InvocationHandler.class }).
    1.69 + *         newInstance(new Object[] { handler });
    1.70 + * </pre>
    1.71 + * or more simply:
    1.72 + * <pre>
    1.73 + *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
    1.74 + *                                          new Class[] { Foo.class },
    1.75 + *                                          handler);
    1.76 + * </pre>
    1.77 + *
    1.78 + * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
    1.79 + * class</i> below) is a class that implements a list of interfaces
    1.80 + * specified at runtime when the class is created, with behavior as
    1.81 + * described below.
    1.82 + *
    1.83 + * A <i>proxy interface</i> is such an interface that is implemented
    1.84 + * by a proxy class.
    1.85 + *
    1.86 + * A <i>proxy instance</i> is an instance of a proxy class.
    1.87 + *
    1.88 + * Each proxy instance has an associated <i>invocation handler</i>
    1.89 + * object, which implements the interface {@link InvocationHandler}.
    1.90 + * A method invocation on a proxy instance through one of its proxy
    1.91 + * interfaces will be dispatched to the {@link InvocationHandler#invoke
    1.92 + * invoke} method of the instance's invocation handler, passing the proxy
    1.93 + * instance, a {@code java.lang.reflect.Method} object identifying
    1.94 + * the method that was invoked, and an array of type {@code Object}
    1.95 + * containing the arguments.  The invocation handler processes the
    1.96 + * encoded method invocation as appropriate and the result that it
    1.97 + * returns will be returned as the result of the method invocation on
    1.98 + * the proxy instance.
    1.99 + *
   1.100 + * <p>A proxy class has the following properties:
   1.101 + *
   1.102 + * <ul>
   1.103 + * <li>Proxy classes are public, final, and not abstract.
   1.104 + *
   1.105 + * <li>The unqualified name of a proxy class is unspecified.  The space
   1.106 + * of class names that begin with the string {@code "$Proxy"}
   1.107 + * should be, however, reserved for proxy classes.
   1.108 + *
   1.109 + * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
   1.110 + *
   1.111 + * <li>A proxy class implements exactly the interfaces specified at its
   1.112 + * creation, in the same order.
   1.113 + *
   1.114 + * <li>If a proxy class implements a non-public interface, then it will
   1.115 + * be defined in the same package as that interface.  Otherwise, the
   1.116 + * package of a proxy class is also unspecified.  Note that package
   1.117 + * sealing will not prevent a proxy class from being successfully defined
   1.118 + * in a particular package at runtime, and neither will classes already
   1.119 + * defined by the same class loader and the same package with particular
   1.120 + * signers.
   1.121 + *
   1.122 + * <li>Since a proxy class implements all of the interfaces specified at
   1.123 + * its creation, invoking {@code getInterfaces} on its
   1.124 + * {@code Class} object will return an array containing the same
   1.125 + * list of interfaces (in the order specified at its creation), invoking
   1.126 + * {@code getMethods} on its {@code Class} object will return
   1.127 + * an array of {@code Method} objects that include all of the
   1.128 + * methods in those interfaces, and invoking {@code getMethod} will
   1.129 + * find methods in the proxy interfaces as would be expected.
   1.130 + *
   1.131 + * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
   1.132 + * return true if it is passed a proxy class-- a class returned by
   1.133 + * {@code Proxy.getProxyClass} or the class of an object returned by
   1.134 + * {@code Proxy.newProxyInstance}-- and false otherwise.
   1.135 + *
   1.136 + * <li>The {@code java.security.ProtectionDomain} of a proxy class
   1.137 + * is the same as that of system classes loaded by the bootstrap class
   1.138 + * loader, such as {@code java.lang.Object}, because the code for a
   1.139 + * proxy class is generated by trusted system code.  This protection
   1.140 + * domain will typically be granted
   1.141 + * {@code java.security.AllPermission}.
   1.142 + *
   1.143 + * <li>Each proxy class has one public constructor that takes one argument,
   1.144 + * an implementation of the interface {@link InvocationHandler}, to set
   1.145 + * the invocation handler for a proxy instance.  Rather than having to use
   1.146 + * the reflection API to access the public constructor, a proxy instance
   1.147 + * can be also be created by calling the {@link Proxy#newProxyInstance
   1.148 + * Proxy.newProxyInstance} method, which combines the actions of calling
   1.149 + * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
   1.150 + * constructor with an invocation handler.
   1.151 + * </ul>
   1.152 + *
   1.153 + * <p>A proxy instance has the following properties:
   1.154 + *
   1.155 + * <ul>
   1.156 + * <li>Given a proxy instance {@code proxy} and one of the
   1.157 + * interfaces implemented by its proxy class {@code Foo}, the
   1.158 + * following expression will return true:
   1.159 + * <pre>
   1.160 + *     {@code proxy instanceof Foo}
   1.161 + * </pre>
   1.162 + * and the following cast operation will succeed (rather than throwing
   1.163 + * a {@code ClassCastException}):
   1.164 + * <pre>
   1.165 + *     {@code (Foo) proxy}
   1.166 + * </pre>
   1.167 + *
   1.168 + * <li>Each proxy instance has an associated invocation handler, the one
   1.169 + * that was passed to its constructor.  The static
   1.170 + * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method
   1.171 + * will return the invocation handler associated with the proxy instance
   1.172 + * passed as its argument.
   1.173 + *
   1.174 + * <li>An interface method invocation on a proxy instance will be
   1.175 + * encoded and dispatched to the invocation handler's {@link
   1.176 + * InvocationHandler#invoke invoke} method as described in the
   1.177 + * documentation for that method.
   1.178 + *
   1.179 + * <li>An invocation of the {@code hashCode},
   1.180 + * {@code equals}, or {@code toString} methods declared in
   1.181 + * {@code java.lang.Object} on a proxy instance will be encoded and
   1.182 + * dispatched to the invocation handler's {@code invoke} method in
   1.183 + * the same manner as interface method invocations are encoded and
   1.184 + * dispatched, as described above.  The declaring class of the
   1.185 + * {@code Method} object passed to {@code invoke} will be
   1.186 + * {@code java.lang.Object}.  Other public methods of a proxy
   1.187 + * instance inherited from {@code java.lang.Object} are not
   1.188 + * overridden by a proxy class, so invocations of those methods behave
   1.189 + * like they do for instances of {@code java.lang.Object}.
   1.190 + * </ul>
   1.191 + *
   1.192 + * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
   1.193 + *
   1.194 + * <p>When two or more interfaces of a proxy class contain a method with
   1.195 + * the same name and parameter signature, the order of the proxy class's
   1.196 + * interfaces becomes significant.  When such a <i>duplicate method</i>
   1.197 + * is invoked on a proxy instance, the {@code Method} object passed
   1.198 + * to the invocation handler will not necessarily be the one whose
   1.199 + * declaring class is assignable from the reference type of the interface
   1.200 + * that the proxy's method was invoked through.  This limitation exists
   1.201 + * because the corresponding method implementation in the generated proxy
   1.202 + * class cannot determine which interface it was invoked through.
   1.203 + * Therefore, when a duplicate method is invoked on a proxy instance,
   1.204 + * the {@code Method} object for the method in the foremost interface
   1.205 + * that contains the method (either directly or inherited through a
   1.206 + * superinterface) in the proxy class's list of interfaces is passed to
   1.207 + * the invocation handler's {@code invoke} method, regardless of the
   1.208 + * reference type through which the method invocation occurred.
   1.209 + *
   1.210 + * <p>If a proxy interface contains a method with the same name and
   1.211 + * parameter signature as the {@code hashCode}, {@code equals},
   1.212 + * or {@code toString} methods of {@code java.lang.Object},
   1.213 + * when such a method is invoked on a proxy instance, the
   1.214 + * {@code Method} object passed to the invocation handler will have
   1.215 + * {@code java.lang.Object} as its declaring class.  In other words,
   1.216 + * the public, non-final methods of {@code java.lang.Object}
   1.217 + * logically precede all of the proxy interfaces for the determination of
   1.218 + * which {@code Method} object to pass to the invocation handler.
   1.219 + *
   1.220 + * <p>Note also that when a duplicate method is dispatched to an
   1.221 + * invocation handler, the {@code invoke} method may only throw
   1.222 + * checked exception types that are assignable to one of the exception
   1.223 + * types in the {@code throws} clause of the method in <i>all</i> of
   1.224 + * the proxy interfaces that it can be invoked through.  If the
   1.225 + * {@code invoke} method throws a checked exception that is not
   1.226 + * assignable to any of the exception types declared by the method in one
   1.227 + * of the proxy interfaces that it can be invoked through, then an
   1.228 + * unchecked {@code UndeclaredThrowableException} will be thrown by
   1.229 + * the invocation on the proxy instance.  This restriction means that not
   1.230 + * all of the exception types returned by invoking
   1.231 + * {@code getExceptionTypes} on the {@code Method} object
   1.232 + * passed to the {@code invoke} method can necessarily be thrown
   1.233 + * successfully by the {@code invoke} method.
   1.234 + *
   1.235 + * @author      Peter Jones
   1.236 + * @see         InvocationHandler
   1.237 + * @since       1.3
   1.238 + */
   1.239 +public final class ProxyImpl implements java.io.Serializable {
   1.240 +
   1.241 +    private static final long serialVersionUID = -2222568056686623797L;
   1.242 +
   1.243 +    /** prefix for all proxy class names */
   1.244 +    private final static String proxyClassNamePrefix = "$Proxy";
   1.245 +
   1.246 +    /** parameter types of a proxy class constructor */
   1.247 +    private final static Class[] constructorParams =
   1.248 +        { InvocationHandler.class };
   1.249 +
   1.250 +    /** maps a class loader to the proxy class cache for that loader */
   1.251 +    private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
   1.252 +        = new WeakHashMap<>();
   1.253 +
   1.254 +    /** marks that a particular proxy class is currently being generated */
   1.255 +    private static Object pendingGenerationMarker = new Object();
   1.256 +
   1.257 +    /** next number to use for generation of unique proxy class names */
   1.258 +    private static long nextUniqueNumber = 0;
   1.259 +    private static Object nextUniqueNumberLock = new Object();
   1.260 +
   1.261 +    /** set of all generated proxy classes, for isProxyClass implementation */
   1.262 +    private static Map<Class<?>, Void> proxyClasses =
   1.263 +        Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
   1.264 +
   1.265 +    /**
   1.266 +     * the invocation handler for this proxy instance.
   1.267 +     * @serial
   1.268 +     */
   1.269 +    protected InvocationHandler h;
   1.270 +
   1.271 +    /**
   1.272 +     * Prohibits instantiation.
   1.273 +     */
   1.274 +    private ProxyImpl() {
   1.275 +    }
   1.276 +
   1.277 +    /**
   1.278 +     * Constructs a new {@code Proxy} instance from a subclass
   1.279 +     * (typically, a dynamic proxy class) with the specified value
   1.280 +     * for its invocation handler.
   1.281 +     *
   1.282 +     * @param   h the invocation handler for this proxy instance
   1.283 +     */
   1.284 +    protected ProxyImpl(InvocationHandler h) {
   1.285 +        this.h = h;
   1.286 +    }
   1.287 +
   1.288 +    /**
   1.289 +     * Returns the {@code java.lang.Class} object for a proxy class
   1.290 +     * given a class loader and an array of interfaces.  The proxy class
   1.291 +     * will be defined by the specified class loader and will implement
   1.292 +     * all of the supplied interfaces.  If a proxy class for the same
   1.293 +     * permutation of interfaces has already been defined by the class
   1.294 +     * loader, then the existing proxy class will be returned; otherwise,
   1.295 +     * a proxy class for those interfaces will be generated dynamically
   1.296 +     * and defined by the class loader.
   1.297 +     *
   1.298 +     * <p>There are several restrictions on the parameters that may be
   1.299 +     * passed to {@code Proxy.getProxyClass}:
   1.300 +     *
   1.301 +     * <ul>
   1.302 +     * <li>All of the {@code Class} objects in the
   1.303 +     * {@code interfaces} array must represent interfaces, not
   1.304 +     * classes or primitive types.
   1.305 +     *
   1.306 +     * <li>No two elements in the {@code interfaces} array may
   1.307 +     * refer to identical {@code Class} objects.
   1.308 +     *
   1.309 +     * <li>All of the interface types must be visible by name through the
   1.310 +     * specified class loader.  In other words, for class loader
   1.311 +     * {@code cl} and every interface {@code i}, the following
   1.312 +     * expression must be true:
   1.313 +     * <pre>
   1.314 +     *     Class.forName(i.getName(), false, cl) == i
   1.315 +     * </pre>
   1.316 +     *
   1.317 +     * <li>All non-public interfaces must be in the same package;
   1.318 +     * otherwise, it would not be possible for the proxy class to
   1.319 +     * implement all of the interfaces, regardless of what package it is
   1.320 +     * defined in.
   1.321 +     *
   1.322 +     * <li>For any set of member methods of the specified interfaces
   1.323 +     * that have the same signature:
   1.324 +     * <ul>
   1.325 +     * <li>If the return type of any of the methods is a primitive
   1.326 +     * type or void, then all of the methods must have that same
   1.327 +     * return type.
   1.328 +     * <li>Otherwise, one of the methods must have a return type that
   1.329 +     * is assignable to all of the return types of the rest of the
   1.330 +     * methods.
   1.331 +     * </ul>
   1.332 +     *
   1.333 +     * <li>The resulting proxy class must not exceed any limits imposed
   1.334 +     * on classes by the virtual machine.  For example, the VM may limit
   1.335 +     * the number of interfaces that a class may implement to 65535; in
   1.336 +     * that case, the size of the {@code interfaces} array must not
   1.337 +     * exceed 65535.
   1.338 +     * </ul>
   1.339 +     *
   1.340 +     * <p>If any of these restrictions are violated,
   1.341 +     * {@code Proxy.getProxyClass} will throw an
   1.342 +     * {@code IllegalArgumentException}.  If the {@code interfaces}
   1.343 +     * array argument or any of its elements are {@code null}, a
   1.344 +     * {@code NullPointerException} will be thrown.
   1.345 +     *
   1.346 +     * <p>Note that the order of the specified proxy interfaces is
   1.347 +     * significant: two requests for a proxy class with the same combination
   1.348 +     * of interfaces but in a different order will result in two distinct
   1.349 +     * proxy classes.
   1.350 +     *
   1.351 +     * @param   loader the class loader to define the proxy class
   1.352 +     * @param   interfaces the list of interfaces for the proxy class
   1.353 +     *          to implement
   1.354 +     * @return  a proxy class that is defined in the specified class loader
   1.355 +     *          and that implements the specified interfaces
   1.356 +     * @throws  IllegalArgumentException if any of the restrictions on the
   1.357 +     *          parameters that may be passed to {@code getProxyClass}
   1.358 +     *          are violated
   1.359 +     * @throws  NullPointerException if the {@code interfaces} array
   1.360 +     *          argument or any of its elements are {@code null}
   1.361 +     */
   1.362 +    public static Class<?> getProxyClass(ClassLoader loader,
   1.363 +                                         Class<?>... interfaces)
   1.364 +        throws IllegalArgumentException
   1.365 +    {
   1.366 +        if (interfaces.length > 65535) {
   1.367 +            throw new IllegalArgumentException("interface limit exceeded");
   1.368 +        }
   1.369 +
   1.370 +        Class<?> proxyClass = null;
   1.371 +
   1.372 +        /* collect interface names to use as key for proxy class cache */
   1.373 +        String[] interfaceNames = new String[interfaces.length];
   1.374 +
   1.375 +        // for detecting duplicates
   1.376 +        Set<Class<?>> interfaceSet = new HashSet<>();
   1.377 +
   1.378 +        for (int i = 0; i < interfaces.length; i++) {
   1.379 +            /*
   1.380 +             * Verify that the class loader resolves the name of this
   1.381 +             * interface to the same Class object.
   1.382 +             */
   1.383 +            String interfaceName = interfaces[i].getName();
   1.384 +            Class<?> interfaceClass = null;
   1.385 +            try {
   1.386 +                interfaceClass = Class.forName(interfaceName, false, loader);
   1.387 +            } catch (ClassNotFoundException e) {
   1.388 +            }
   1.389 +            if (interfaceClass != interfaces[i]) {
   1.390 +                throw new IllegalArgumentException(
   1.391 +                    interfaces[i] + " is not visible from class loader");
   1.392 +            }
   1.393 +
   1.394 +            /*
   1.395 +             * Verify that the Class object actually represents an
   1.396 +             * interface.
   1.397 +             */
   1.398 +            if (!interfaceClass.isInterface()) {
   1.399 +                throw new IllegalArgumentException(
   1.400 +                    interfaceClass.getName() + " is not an interface");
   1.401 +            }
   1.402 +
   1.403 +            /*
   1.404 +             * Verify that this interface is not a duplicate.
   1.405 +             */
   1.406 +            if (interfaceSet.contains(interfaceClass)) {
   1.407 +                throw new IllegalArgumentException(
   1.408 +                    "repeated interface: " + interfaceClass.getName());
   1.409 +            }
   1.410 +            interfaceSet.add(interfaceClass);
   1.411 +
   1.412 +            interfaceNames[i] = interfaceName;
   1.413 +        }
   1.414 +
   1.415 +        /*
   1.416 +         * Using string representations of the proxy interfaces as
   1.417 +         * keys in the proxy class cache (instead of their Class
   1.418 +         * objects) is sufficient because we require the proxy
   1.419 +         * interfaces to be resolvable by name through the supplied
   1.420 +         * class loader, and it has the advantage that using a string
   1.421 +         * representation of a class makes for an implicit weak
   1.422 +         * reference to the class.
   1.423 +         */
   1.424 +        List<String> key = Arrays.asList(interfaceNames);
   1.425 +
   1.426 +        /*
   1.427 +         * Find or create the proxy class cache for the class loader.
   1.428 +         */
   1.429 +        Map<List<String>, Object> cache;
   1.430 +        synchronized (loaderToCache) {
   1.431 +            cache = loaderToCache.get(loader);
   1.432 +            if (cache == null) {
   1.433 +                cache = new HashMap<>();
   1.434 +                loaderToCache.put(loader, cache);
   1.435 +            }
   1.436 +            /*
   1.437 +             * This mapping will remain valid for the duration of this
   1.438 +             * method, without further synchronization, because the mapping
   1.439 +             * will only be removed if the class loader becomes unreachable.
   1.440 +             */
   1.441 +        }
   1.442 +
   1.443 +        /*
   1.444 +         * Look up the list of interfaces in the proxy class cache using
   1.445 +         * the key.  This lookup will result in one of three possible
   1.446 +         * kinds of values:
   1.447 +         *     null, if there is currently no proxy class for the list of
   1.448 +         *         interfaces in the class loader,
   1.449 +         *     the pendingGenerationMarker object, if a proxy class for the
   1.450 +         *         list of interfaces is currently being generated,
   1.451 +         *     or a weak reference to a Class object, if a proxy class for
   1.452 +         *         the list of interfaces has already been generated.
   1.453 +         */
   1.454 +        synchronized (cache) {
   1.455 +            /*
   1.456 +             * Note that we need not worry about reaping the cache for
   1.457 +             * entries with cleared weak references because if a proxy class
   1.458 +             * has been garbage collected, its class loader will have been
   1.459 +             * garbage collected as well, so the entire cache will be reaped
   1.460 +             * from the loaderToCache map.
   1.461 +             */
   1.462 +            do {
   1.463 +                Object value = cache.get(key);
   1.464 +                if (value instanceof Reference) {
   1.465 +                    proxyClass = (Class<?>) ((Reference) value).get();
   1.466 +                }
   1.467 +                if (proxyClass != null) {
   1.468 +                    // proxy class already generated: return it
   1.469 +                    return proxyClass;
   1.470 +                } else if (value == pendingGenerationMarker) {
   1.471 +                    // proxy class being generated: wait for it
   1.472 +                    try {
   1.473 +                        cache.wait();
   1.474 +                    } catch (InterruptedException e) {
   1.475 +                        /*
   1.476 +                         * The class generation that we are waiting for should
   1.477 +                         * take a small, bounded time, so we can safely ignore
   1.478 +                         * thread interrupts here.
   1.479 +                         */
   1.480 +                    }
   1.481 +                    continue;
   1.482 +                } else {
   1.483 +                    /*
   1.484 +                     * No proxy class for this list of interfaces has been
   1.485 +                     * generated or is being generated, so we will go and
   1.486 +                     * generate it now.  Mark it as pending generation.
   1.487 +                     */
   1.488 +                    cache.put(key, pendingGenerationMarker);
   1.489 +                    break;
   1.490 +                }
   1.491 +            } while (true);
   1.492 +        }
   1.493 +
   1.494 +        try {
   1.495 +            String proxyPkg = null;     // package to define proxy class in
   1.496 +
   1.497 +            /*
   1.498 +             * Record the package of a non-public proxy interface so that the
   1.499 +             * proxy class will be defined in the same package.  Verify that
   1.500 +             * all non-public proxy interfaces are in the same package.
   1.501 +             */
   1.502 +            for (int i = 0; i < interfaces.length; i++) {
   1.503 +                int flags = interfaces[i].getModifiers();
   1.504 +                if (!Modifier.isPublic(flags)) {
   1.505 +                    String name = interfaces[i].getName();
   1.506 +                    int n = name.lastIndexOf('.');
   1.507 +                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
   1.508 +                    if (proxyPkg == null) {
   1.509 +                        proxyPkg = pkg;
   1.510 +                    } else if (!pkg.equals(proxyPkg)) {
   1.511 +                        throw new IllegalArgumentException(
   1.512 +                            "non-public interfaces from different packages");
   1.513 +                    }
   1.514 +                }
   1.515 +            }
   1.516 +
   1.517 +            if (proxyPkg == null) {     // if no non-public proxy interfaces,
   1.518 +                proxyPkg = "";          // use the unnamed package
   1.519 +            }
   1.520 +
   1.521 +            {
   1.522 +                /*
   1.523 +                 * Choose a name for the proxy class to generate.
   1.524 +                 */
   1.525 +                long num;
   1.526 +                synchronized (nextUniqueNumberLock) {
   1.527 +                    num = nextUniqueNumber++;
   1.528 +                }
   1.529 +                String proxyName = proxyPkg + proxyClassNamePrefix + num;
   1.530 +                /*
   1.531 +                 * Verify that the class loader hasn't already
   1.532 +                 * defined a class with the chosen name.
   1.533 +                 */
   1.534 +
   1.535 +                /*
   1.536 +                 * Generate the specified proxy class.
   1.537 +                 */
   1.538 +                Generator gen = new Generator(proxyName, interfaces);
   1.539 +                final byte[] proxyClassFile = gen.generateClassFile();
   1.540 +                try {
   1.541 +                    proxyClass = defineClass0(loader, proxyName,
   1.542 +                        proxyClassFile);
   1.543 +                } catch (ClassFormatError e) {
   1.544 +                    /*
   1.545 +                     * A ClassFormatError here means that (barring bugs in the
   1.546 +                     * proxy class generation code) there was some other
   1.547 +                     * invalid aspect of the arguments supplied to the proxy
   1.548 +                     * class creation (such as virtual machine limitations
   1.549 +                     * exceeded).
   1.550 +                     */
   1.551 +                    throw new IllegalArgumentException(e.toString());
   1.552 +                }
   1.553 +                gen.fillInMethods(proxyClass);
   1.554 +            }
   1.555 +            // add to set of all generated proxy classes, for isProxyClass
   1.556 +            proxyClasses.put(proxyClass, null);
   1.557 +
   1.558 +        } finally {
   1.559 +            /*
   1.560 +             * We must clean up the "pending generation" state of the proxy
   1.561 +             * class cache entry somehow.  If a proxy class was successfully
   1.562 +             * generated, store it in the cache (with a weak reference);
   1.563 +             * otherwise, remove the reserved entry.  In all cases, notify
   1.564 +             * all waiters on reserved entries in this cache.
   1.565 +             */
   1.566 +            synchronized (cache) {
   1.567 +                if (proxyClass != null) {
   1.568 +                    cache.put(key, new WeakReference<Class<?>>(proxyClass));
   1.569 +                } else {
   1.570 +                    cache.remove(key);
   1.571 +                }
   1.572 +                cache.notifyAll();
   1.573 +            }
   1.574 +        }
   1.575 +        return proxyClass;
   1.576 +    }
   1.577 +
   1.578 +    /**
   1.579 +     * Returns an instance of a proxy class for the specified interfaces
   1.580 +     * that dispatches method invocations to the specified invocation
   1.581 +     * handler.  This method is equivalent to:
   1.582 +     * <pre>
   1.583 +     *     Proxy.getProxyClass(loader, interfaces).
   1.584 +     *         getConstructor(new Class[] { InvocationHandler.class }).
   1.585 +     *         newInstance(new Object[] { handler });
   1.586 +     * </pre>
   1.587 +     *
   1.588 +     * <p>{@code Proxy.newProxyInstance} throws
   1.589 +     * {@code IllegalArgumentException} for the same reasons that
   1.590 +     * {@code Proxy.getProxyClass} does.
   1.591 +     *
   1.592 +     * @param   loader the class loader to define the proxy class
   1.593 +     * @param   interfaces the list of interfaces for the proxy class
   1.594 +     *          to implement
   1.595 +     * @param   h the invocation handler to dispatch method invocations to
   1.596 +     * @return  a proxy instance with the specified invocation handler of a
   1.597 +     *          proxy class that is defined by the specified class loader
   1.598 +     *          and that implements the specified interfaces
   1.599 +     * @throws  IllegalArgumentException if any of the restrictions on the
   1.600 +     *          parameters that may be passed to {@code getProxyClass}
   1.601 +     *          are violated
   1.602 +     * @throws  NullPointerException if the {@code interfaces} array
   1.603 +     *          argument or any of its elements are {@code null}, or
   1.604 +     *          if the invocation handler, {@code h}, is
   1.605 +     *          {@code null}
   1.606 +     */
   1.607 +    public static Object newProxyInstance(ClassLoader loader,
   1.608 +                                          Class<?>[] interfaces,
   1.609 +                                          InvocationHandler h)
   1.610 +        throws IllegalArgumentException
   1.611 +    {
   1.612 +        if (h == null) {
   1.613 +            throw new NullPointerException();
   1.614 +        }
   1.615 +
   1.616 +        /*
   1.617 +         * Look up or generate the designated proxy class.
   1.618 +         */
   1.619 +        Class<?> cl = getProxyClass(loader, interfaces);
   1.620 +
   1.621 +        /*
   1.622 +         * Invoke its constructor with the designated invocation handler.
   1.623 +         */
   1.624 +        try {
   1.625 +            Constructor cons = cl.getConstructor(constructorParams);
   1.626 +            return cons.newInstance(new Object[] { h });
   1.627 +        } catch (NoSuchMethodException e) {
   1.628 +            throw new InternalError(e.toString());
   1.629 +        } catch (IllegalAccessException e) {
   1.630 +            throw new InternalError(e.toString());
   1.631 +        } catch (InstantiationException e) {
   1.632 +            throw new InternalError(e.toString());
   1.633 +        } catch (InvocationTargetException e) {
   1.634 +            throw new InternalError(e.toString());
   1.635 +        }
   1.636 +    }
   1.637 +
   1.638 +    /**
   1.639 +     * Returns true if and only if the specified class was dynamically
   1.640 +     * generated to be a proxy class using the {@code getProxyClass}
   1.641 +     * method or the {@code newProxyInstance} method.
   1.642 +     *
   1.643 +     * <p>The reliability of this method is important for the ability
   1.644 +     * to use it to make security decisions, so its implementation should
   1.645 +     * not just test if the class in question extends {@code Proxy}.
   1.646 +     *
   1.647 +     * @param   cl the class to test
   1.648 +     * @return  {@code true} if the class is a proxy class and
   1.649 +     *          {@code false} otherwise
   1.650 +     * @throws  NullPointerException if {@code cl} is {@code null}
   1.651 +     */
   1.652 +    public static boolean isProxyClass(Class<?> cl) {
   1.653 +        if (cl == null) {
   1.654 +            throw new NullPointerException();
   1.655 +        }
   1.656 +
   1.657 +        return proxyClasses.containsKey(cl);
   1.658 +    }
   1.659 +
   1.660 +    /**
   1.661 +     * Returns the invocation handler for the specified proxy instance.
   1.662 +     *
   1.663 +     * @param   proxy the proxy instance to return the invocation handler for
   1.664 +     * @return  the invocation handler for the proxy instance
   1.665 +     * @throws  IllegalArgumentException if the argument is not a
   1.666 +     *          proxy instance
   1.667 +     */
   1.668 +    public static InvocationHandler getInvocationHandler(Object proxy)
   1.669 +        throws IllegalArgumentException
   1.670 +    {
   1.671 +        /*
   1.672 +         * Verify that the object is actually a proxy instance.
   1.673 +         */
   1.674 +        if (!isProxyClass(proxy.getClass())) {
   1.675 +            throw new IllegalArgumentException("not a proxy instance");
   1.676 +        }
   1.677 +
   1.678 +        ProxyImpl p = (ProxyImpl) proxy;
   1.679 +        return p.h;
   1.680 +    }
   1.681 +
   1.682 +    @JavaScriptBody(args = { "ignore", "name", "byteCode" }, 
   1.683 +        body = "return vm._reload(name, byteCode).constructor.$class;"
   1.684 +    )
   1.685 +    private static native Class defineClass0(
   1.686 +        ClassLoader loader, String name, byte[] b
   1.687 +    );
   1.688 +    
   1.689 +    private static class Generator {
   1.690 +        /*
   1.691 +         * In the comments below, "JVMS" refers to The Java Virtual Machine
   1.692 +         * Specification Second Edition and "JLS" refers to the original
   1.693 +         * version of The Java Language Specification, unless otherwise
   1.694 +         * specified.
   1.695 +         */
   1.696 +
   1.697 +        /* need 1.6 bytecode */
   1.698 +        private static final int CLASSFILE_MAJOR_VERSION = 50;
   1.699 +        private static final int CLASSFILE_MINOR_VERSION = 0;
   1.700 +
   1.701 +        /*
   1.702 +         * beginning of constants copied from
   1.703 +         * sun.tools.java.RuntimeConstants (which no longer exists):
   1.704 +         */
   1.705 +
   1.706 +        /* constant pool tags */
   1.707 +        private static final int CONSTANT_UTF8 = 1;
   1.708 +        private static final int CONSTANT_UNICODE = 2;
   1.709 +        private static final int CONSTANT_INTEGER = 3;
   1.710 +        private static final int CONSTANT_FLOAT = 4;
   1.711 +        private static final int CONSTANT_LONG = 5;
   1.712 +        private static final int CONSTANT_DOUBLE = 6;
   1.713 +        private static final int CONSTANT_CLASS = 7;
   1.714 +        private static final int CONSTANT_STRING = 8;
   1.715 +        private static final int CONSTANT_FIELD = 9;
   1.716 +        private static final int CONSTANT_METHOD = 10;
   1.717 +        private static final int CONSTANT_INTERFACEMETHOD = 11;
   1.718 +        private static final int CONSTANT_NAMEANDTYPE = 12;
   1.719 +
   1.720 +        /* access and modifier flags */
   1.721 +        private static final int ACC_PUBLIC = 0x00000001;
   1.722 +        private static final int ACC_FINAL = 0x00000010;
   1.723 +        private static final int ACC_SUPER = 0x00000020;
   1.724 +
   1.725 +    // end of constants copied from sun.tools.java.RuntimeConstants
   1.726 +        /**
   1.727 +         * name of the superclass of proxy classes
   1.728 +         */
   1.729 +        private final static String superclassName = "java/lang/reflect/Proxy";
   1.730 +
   1.731 +        /**
   1.732 +         * name of field for storing a proxy instance's invocation handler
   1.733 +         */
   1.734 +        private final static String handlerFieldName = "h";
   1.735 +
   1.736 +        /* preloaded Method objects for methods in java.lang.Object */
   1.737 +        private static Method hashCodeMethod;
   1.738 +        private static Method equalsMethod;
   1.739 +        private static Method toStringMethod;
   1.740 +
   1.741 +        static {
   1.742 +            try {
   1.743 +                hashCodeMethod = Object.class.getMethod("hashCode");
   1.744 +                equalsMethod
   1.745 +                    = Object.class.getMethod("equals", new Class[]{Object.class});
   1.746 +                toStringMethod = Object.class.getMethod("toString");
   1.747 +            } catch (NoSuchMethodException e) {
   1.748 +                throw new IllegalStateException(e.getMessage());
   1.749 +            }
   1.750 +        }
   1.751 +
   1.752 +        /**
   1.753 +         * name of proxy class
   1.754 +         */
   1.755 +        private String className;
   1.756 +
   1.757 +        /**
   1.758 +         * proxy interfaces
   1.759 +         */
   1.760 +        private Class[] interfaces;
   1.761 +
   1.762 +        /**
   1.763 +         * constant pool of class being generated
   1.764 +         */
   1.765 +        private ConstantPool cp = new ConstantPool();
   1.766 +
   1.767 +        /**
   1.768 +         * maps method signature string to list of ProxyMethod objects for proxy
   1.769 +         * methods with that signature
   1.770 +         */
   1.771 +        private Map<String, List<ProxyMethod>> proxyMethods
   1.772 +            = new HashMap<String, List<ProxyMethod>>();
   1.773 +
   1.774 +        /**
   1.775 +         * count of ProxyMethod objects added to proxyMethods
   1.776 +         */
   1.777 +        private int proxyMethodCount = 0;
   1.778 +
   1.779 +        /**
   1.780 +         * Construct a ProxyGenerator to generate a proxy class with the
   1.781 +         * specified name and for the given interfaces.
   1.782 +         *
   1.783 +         * A ProxyGenerator object contains the state for the ongoing generation
   1.784 +         * of a particular proxy class.
   1.785 +         */
   1.786 +        private Generator(String className, Class[] interfaces) {
   1.787 +            this.className = className;
   1.788 +            this.interfaces = interfaces;
   1.789 +        }
   1.790 +
   1.791 +        /**
   1.792 +         * Generate a class file for the proxy class. This method drives the
   1.793 +         * class file generation process.
   1.794 +         */
   1.795 +        private byte[] generateClassFile() {
   1.796 +
   1.797 +            /* ============================================================
   1.798 +             * Step 1: Assemble ProxyMethod objects for all methods to
   1.799 +             * generate proxy dispatching code for.
   1.800 +             */
   1.801 +
   1.802 +            /*
   1.803 +             * Record that proxy methods are needed for the hashCode, equals,
   1.804 +             * and toString methods of java.lang.Object.  This is done before
   1.805 +             * the methods from the proxy interfaces so that the methods from
   1.806 +             * java.lang.Object take precedence over duplicate methods in the
   1.807 +             * proxy interfaces.
   1.808 +             */
   1.809 +            addProxyMethod(hashCodeMethod, Object.class);
   1.810 +            addProxyMethod(equalsMethod, Object.class);
   1.811 +            addProxyMethod(toStringMethod, Object.class);
   1.812 +
   1.813 +            /*
   1.814 +             * Now record all of the methods from the proxy interfaces, giving
   1.815 +             * earlier interfaces precedence over later ones with duplicate
   1.816 +             * methods.
   1.817 +             */
   1.818 +            for (int i = 0; i < interfaces.length; i++) {
   1.819 +                Method[] methods = interfaces[i].getMethods();
   1.820 +                for (int j = 0; j < methods.length; j++) {
   1.821 +                    addProxyMethod(methods[j], interfaces[i]);
   1.822 +                }
   1.823 +            }
   1.824 +
   1.825 +            /*
   1.826 +             * For each set of proxy methods with the same signature,
   1.827 +             * verify that the methods' return types are compatible.
   1.828 +             */
   1.829 +            for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
   1.830 +                checkReturnTypes(sigmethods);
   1.831 +            }
   1.832 +
   1.833 +            /* ============================================================
   1.834 +             * Step 2: Assemble FieldInfo and MethodInfo structs for all of
   1.835 +             * fields and methods in the class we are generating.
   1.836 +             */
   1.837 +            
   1.838 +            // will be done in fillInMethods
   1.839 +
   1.840 +            /* ============================================================
   1.841 +             * Step 3: Write the final class file.
   1.842 +             */
   1.843 +
   1.844 +            /*
   1.845 +             * Make sure that constant pool indexes are reserved for the
   1.846 +             * following items before starting to write the final class file.
   1.847 +             */
   1.848 +            cp.getClass(dotToSlash(className));
   1.849 +            cp.getClass(superclassName);
   1.850 +            for (int i = 0; i < interfaces.length; i++) {
   1.851 +                cp.getClass(dotToSlash(interfaces[i].getName()));
   1.852 +            }
   1.853 +
   1.854 +            /*
   1.855 +             * Disallow new constant pool additions beyond this point, since
   1.856 +             * we are about to write the final constant pool table.
   1.857 +             */
   1.858 +            cp.setReadOnly();
   1.859 +
   1.860 +            ByteArrayOutputStream bout = new ByteArrayOutputStream();
   1.861 +            DataOutputStream dout = new DataOutputStream(bout);
   1.862 +
   1.863 +            try {
   1.864 +                /*
   1.865 +                 * Write all the items of the "ClassFile" structure.
   1.866 +                 * See JVMS section 4.1.
   1.867 +                 */
   1.868 +                // u4 magic;
   1.869 +                dout.writeInt(0xCAFEBABE);
   1.870 +                // u2 minor_version;
   1.871 +                dout.writeShort(CLASSFILE_MINOR_VERSION);
   1.872 +                // u2 major_version;
   1.873 +                dout.writeShort(CLASSFILE_MAJOR_VERSION);
   1.874 +
   1.875 +                cp.write(dout);             // (write constant pool)
   1.876 +
   1.877 +                // u2 access_flags;
   1.878 +                dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
   1.879 +                // u2 this_class;
   1.880 +                dout.writeShort(cp.getClass(dotToSlash(className)));
   1.881 +                // u2 super_class;
   1.882 +                dout.writeShort(cp.getClass(superclassName));
   1.883 +
   1.884 +                // u2 interfaces_count;
   1.885 +                dout.writeShort(interfaces.length);
   1.886 +                // u2 interfaces[interfaces_count];
   1.887 +                for (int i = 0; i < interfaces.length; i++) {
   1.888 +                    dout.writeShort(cp.getClass(
   1.889 +                        dotToSlash(interfaces[i].getName())));
   1.890 +                }
   1.891 +
   1.892 +                // u2 fields_count;
   1.893 +                dout.writeShort(0);
   1.894 +
   1.895 +                // u2 methods_count;
   1.896 +                dout.writeShort(0);
   1.897 +
   1.898 +                // u2 attributes_count;
   1.899 +                dout.writeShort(0); // (no ClassFile attributes for proxy classes)
   1.900 +
   1.901 +            } catch (IOException e) {
   1.902 +                throw new InternalError("unexpected I/O Exception");
   1.903 +            }
   1.904 +
   1.905 +            return bout.toByteArray();
   1.906 +        }
   1.907 +
   1.908 +        @JavaScriptBody(args = { "c", "sig", "method", "primitive" }, body = 
   1.909 +            "var p = c.cnstr.prototype;\n" +
   1.910 +            "p[sig] = function() {\n" +
   1.911 +            "  var h = this._h();\n" +
   1.912 +            "  var res = h.invoke__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_reflect_Method_2_3Ljava_lang_Object_2(this, method, arguments);\n" +
   1.913 +            "  \n" +
   1.914 +            "  \n" +
   1.915 +            "  return res;\n" +
   1.916 +            "};"
   1.917 +        )
   1.918 +        private static native void defineMethod(Class<?> proxyClass, String sig, Method method, boolean primitive);
   1.919 +
   1.920 +        @JavaScriptBody(args = "c", body = 
   1.921 +              "var h = c.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2 = function(h) {\n"
   1.922 +            + "  c.superclass.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2.call(this, h);\n"
   1.923 +            + "}\n"
   1.924 +            + "h.cls = c.cnstr;\n"
   1.925 +        )
   1.926 +        private static native void defineConstructor(Class<?> proxyClass);
   1.927 +        
   1.928 +        final void fillInMethods(Class<?> proxyClass) {
   1.929 +            for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
   1.930 +                for (ProxyMethod pm : sigmethods) {
   1.931 +                    String sig = MethodImpl.toSignature(pm.method);
   1.932 +                    defineMethod(proxyClass, sig, pm.method, pm.method.getReturnType().isPrimitive());
   1.933 +                }
   1.934 +            }
   1.935 +            defineConstructor(proxyClass);
   1.936 +        }
   1.937 +
   1.938 +        /**
   1.939 +         * Add another method to be proxied, either by creating a new
   1.940 +         * ProxyMethod object or augmenting an old one for a duplicate method.
   1.941 +         *
   1.942 +         * "fromClass" indicates the proxy interface that the method was found
   1.943 +         * through, which may be different from (a subinterface of) the method's
   1.944 +         * "declaring class". Note that the first Method object passed for a
   1.945 +         * given name and descriptor identifies the Method object (and thus the
   1.946 +         * declaring class) that will be passed to the invocation handler's
   1.947 +         * "invoke" method for a given set of duplicate methods.
   1.948 +         */
   1.949 +        private void addProxyMethod(Method m, Class fromClass) {
   1.950 +            String name = m.getName();
   1.951 +            Class[] parameterTypes = m.getParameterTypes();
   1.952 +            Class returnType = m.getReturnType();
   1.953 +            Class[] exceptionTypes = m.getExceptionTypes();
   1.954 +
   1.955 +            String sig = MethodImpl.toSignature(m);
   1.956 +            List<ProxyMethod> sigmethods = proxyMethods.get(sig);
   1.957 +            if (sigmethods != null) {
   1.958 +                for (ProxyMethod pm : sigmethods) {
   1.959 +                    if (returnType == pm.returnType) {
   1.960 +                        /*
   1.961 +                         * Found a match: reduce exception types to the
   1.962 +                         * greatest set of exceptions that can thrown
   1.963 +                         * compatibly with the throws clauses of both
   1.964 +                         * overridden methods.
   1.965 +                         */
   1.966 +                        List<Class<?>> legalExceptions = new ArrayList<Class<?>>();
   1.967 +                        collectCompatibleTypes(
   1.968 +                            exceptionTypes, pm.exceptionTypes, legalExceptions);
   1.969 +                        collectCompatibleTypes(
   1.970 +                            pm.exceptionTypes, exceptionTypes, legalExceptions);
   1.971 +                        pm.exceptionTypes = new Class[legalExceptions.size()];
   1.972 +                        pm.exceptionTypes
   1.973 +                            = legalExceptions.toArray(pm.exceptionTypes);
   1.974 +                        return;
   1.975 +                    }
   1.976 +                }
   1.977 +            } else {
   1.978 +                sigmethods = new ArrayList<ProxyMethod>(3);
   1.979 +                proxyMethods.put(sig, sigmethods);
   1.980 +            }
   1.981 +            sigmethods.add(new ProxyMethod(m, name, parameterTypes, returnType,
   1.982 +                exceptionTypes, fromClass));
   1.983 +        }
   1.984 +
   1.985 +        /**
   1.986 +         * For a given set of proxy methods with the same signature, check that
   1.987 +         * their return types are compatible according to the Proxy
   1.988 +         * specification.
   1.989 +         *
   1.990 +         * Specifically, if there is more than one such method, then all of the
   1.991 +         * return types must be reference types, and there must be one return
   1.992 +         * type that is assignable to each of the rest of them.
   1.993 +         */
   1.994 +        private static void checkReturnTypes(List<ProxyMethod> methods) {
   1.995 +            /*
   1.996 +             * If there is only one method with a given signature, there
   1.997 +             * cannot be a conflict.  This is the only case in which a
   1.998 +             * primitive (or void) return type is allowed.
   1.999 +             */
  1.1000 +            if (methods.size() < 2) {
  1.1001 +                return;
  1.1002 +            }
  1.1003 +
  1.1004 +            /*
  1.1005 +             * List of return types that are not yet known to be
  1.1006 +             * assignable from ("covered" by) any of the others.
  1.1007 +             */
  1.1008 +            LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>();
  1.1009 +
  1.1010 +            nextNewReturnType:
  1.1011 +            for (ProxyMethod pm : methods) {
  1.1012 +                Class<?> newReturnType = pm.returnType;
  1.1013 +                if (newReturnType.isPrimitive()) {
  1.1014 +                    throw new IllegalArgumentException(
  1.1015 +                        "methods with same signature "
  1.1016 +                        + getFriendlyMethodSignature(pm.methodName,
  1.1017 +                            pm.parameterTypes)
  1.1018 +                        + " but incompatible return types: "
  1.1019 +                        + newReturnType.getName() + " and others");
  1.1020 +                }
  1.1021 +                boolean added = false;
  1.1022 +
  1.1023 +                /*
  1.1024 +                 * Compare the new return type to the existing uncovered
  1.1025 +                 * return types.
  1.1026 +                 */
  1.1027 +                ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
  1.1028 +                while (liter.hasNext()) {
  1.1029 +                    Class<?> uncoveredReturnType = liter.next();
  1.1030 +
  1.1031 +                    /*
  1.1032 +                     * If an existing uncovered return type is assignable
  1.1033 +                     * to this new one, then we can forget the new one.
  1.1034 +                     */
  1.1035 +                    if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
  1.1036 +                        assert !added;
  1.1037 +                        continue nextNewReturnType;
  1.1038 +                    }
  1.1039 +
  1.1040 +                    /*
  1.1041 +                     * If the new return type is assignable to an existing
  1.1042 +                     * uncovered one, then should replace the existing one
  1.1043 +                     * with the new one (or just forget the existing one,
  1.1044 +                     * if the new one has already be put in the list).
  1.1045 +                     */
  1.1046 +                    if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
  1.1047 +                        // (we can assume that each return type is unique)
  1.1048 +                        if (!added) {
  1.1049 +                            liter.set(newReturnType);
  1.1050 +                            added = true;
  1.1051 +                        } else {
  1.1052 +                            liter.remove();
  1.1053 +                        }
  1.1054 +                    }
  1.1055 +                }
  1.1056 +
  1.1057 +                /*
  1.1058 +                 * If we got through the list of existing uncovered return
  1.1059 +                 * types without an assignability relationship, then add
  1.1060 +                 * the new return type to the list of uncovered ones.
  1.1061 +                 */
  1.1062 +                if (!added) {
  1.1063 +                    uncoveredReturnTypes.add(newReturnType);
  1.1064 +                }
  1.1065 +            }
  1.1066 +
  1.1067 +            /*
  1.1068 +             * We shouldn't end up with more than one return type that is
  1.1069 +             * not assignable from any of the others.
  1.1070 +             */
  1.1071 +            if (uncoveredReturnTypes.size() > 1) {
  1.1072 +                ProxyMethod pm = methods.get(0);
  1.1073 +                throw new IllegalArgumentException(
  1.1074 +                    "methods with same signature "
  1.1075 +                    + getFriendlyMethodSignature(pm.methodName, pm.parameterTypes)
  1.1076 +                    + " but incompatible return types: " + uncoveredReturnTypes);
  1.1077 +            }
  1.1078 +        }
  1.1079 +
  1.1080 +
  1.1081 +        /**
  1.1082 +         * A ProxyMethod object represents a proxy method in the proxy class
  1.1083 +         * being generated: a method whose implementation will encode and
  1.1084 +         * dispatch invocations to the proxy instance's invocation handler.
  1.1085 +         */
  1.1086 +        private class ProxyMethod {
  1.1087 +
  1.1088 +            private final Method method;
  1.1089 +            public String methodName;
  1.1090 +            public Class[] parameterTypes;
  1.1091 +            public Class returnType;
  1.1092 +            public Class[] exceptionTypes;
  1.1093 +            public Class fromClass;
  1.1094 +            public String methodFieldName;
  1.1095 +
  1.1096 +            private ProxyMethod(Method m, 
  1.1097 +                String methodName, Class[] parameterTypes, 
  1.1098 +                Class returnType, Class[] exceptionTypes, 
  1.1099 +                Class fromClass
  1.1100 +            ) {
  1.1101 +                this.method = m;
  1.1102 +                this.methodName = methodName;
  1.1103 +                this.parameterTypes = parameterTypes;
  1.1104 +                this.returnType = returnType;
  1.1105 +                this.exceptionTypes = exceptionTypes;
  1.1106 +                this.fromClass = fromClass;
  1.1107 +                this.methodFieldName = "m" + proxyMethodCount++;
  1.1108 +            }
  1.1109 +
  1.1110 +        }
  1.1111 +
  1.1112 +        /*
  1.1113 +         * ==================== General Utility Methods ====================
  1.1114 +         */
  1.1115 +        /**
  1.1116 +         * Convert a fully qualified class name that uses '.' as the package
  1.1117 +         * separator, the external representation used by the Java language and
  1.1118 +         * APIs, to a fully qualified class name that uses '/' as the package
  1.1119 +         * separator, the representation used in the class file format (see JVMS
  1.1120 +         * section 4.2).
  1.1121 +         */
  1.1122 +        private static String dotToSlash(String name) {
  1.1123 +            return name.replace('.', '/');
  1.1124 +        }
  1.1125 +
  1.1126 +        /**
  1.1127 +         * Return the list of "parameter descriptor" strings enclosed in
  1.1128 +         * parentheses corresponding to the given parameter types (in other
  1.1129 +         * words, a method descriptor without a return descriptor). This string
  1.1130 +         * is useful for constructing string keys for methods without regard to
  1.1131 +         * their return type.
  1.1132 +         */
  1.1133 +        private static String getParameterDescriptors(Class[] parameterTypes) {
  1.1134 +            StringBuilder desc = new StringBuilder("(");
  1.1135 +            for (int i = 0; i < parameterTypes.length; i++) {
  1.1136 +                desc.append(getFieldType(parameterTypes[i]));
  1.1137 +            }
  1.1138 +            desc.append(')');
  1.1139 +            return desc.toString();
  1.1140 +        }
  1.1141 +
  1.1142 +        /**
  1.1143 +         * Return the "field type" string for the given type, appropriate for a
  1.1144 +         * field descriptor, a parameter descriptor, or a return descriptor
  1.1145 +         * other than "void". See JVMS section 4.3.2.
  1.1146 +         */
  1.1147 +        private static String getFieldType(Class type) {
  1.1148 +            if (type.isPrimitive()) {
  1.1149 +                return PrimitiveTypeInfo.get(type).baseTypeString;
  1.1150 +            } else if (type.isArray()) {
  1.1151 +                /*
  1.1152 +                 * According to JLS 20.3.2, the getName() method on Class does
  1.1153 +                 * return the VM type descriptor format for array classes (only);
  1.1154 +                 * using that should be quicker than the otherwise obvious code:
  1.1155 +                 *
  1.1156 +                 *     return "[" + getTypeDescriptor(type.getComponentType());
  1.1157 +                 */
  1.1158 +                return type.getName().replace('.', '/');
  1.1159 +            } else {
  1.1160 +                return "L" + dotToSlash(type.getName()) + ";";
  1.1161 +            }
  1.1162 +        }
  1.1163 +
  1.1164 +        /**
  1.1165 +         * Returns a human-readable string representing the signature of a
  1.1166 +         * method with the given name and parameter types.
  1.1167 +         */
  1.1168 +        private static String getFriendlyMethodSignature(String name,
  1.1169 +            Class[] parameterTypes) {
  1.1170 +            StringBuilder sig = new StringBuilder(name);
  1.1171 +            sig.append('(');
  1.1172 +            for (int i = 0; i < parameterTypes.length; i++) {
  1.1173 +                if (i > 0) {
  1.1174 +                    sig.append(',');
  1.1175 +                }
  1.1176 +                Class parameterType = parameterTypes[i];
  1.1177 +                int dimensions = 0;
  1.1178 +                while (parameterType.isArray()) {
  1.1179 +                    parameterType = parameterType.getComponentType();
  1.1180 +                    dimensions++;
  1.1181 +                }
  1.1182 +                sig.append(parameterType.getName());
  1.1183 +                while (dimensions-- > 0) {
  1.1184 +                    sig.append("[]");
  1.1185 +                }
  1.1186 +            }
  1.1187 +            sig.append(')');
  1.1188 +            return sig.toString();
  1.1189 +        }
  1.1190 +
  1.1191 +        /**
  1.1192 +         * Add to the given list all of the types in the "from" array that are
  1.1193 +         * not already contained in the list and are assignable to at least one
  1.1194 +         * of the types in the "with" array.
  1.1195 +         *
  1.1196 +         * This method is useful for computing the greatest common set of
  1.1197 +         * declared exceptions from duplicate methods inherited from different
  1.1198 +         * interfaces.
  1.1199 +         */
  1.1200 +        private static void collectCompatibleTypes(Class<?>[] from,
  1.1201 +            Class<?>[] with,
  1.1202 +            List<Class<?>> list) {
  1.1203 +            for (int i = 0; i < from.length; i++) {
  1.1204 +                if (!list.contains(from[i])) {
  1.1205 +                    for (int j = 0; j < with.length; j++) {
  1.1206 +                        if (with[j].isAssignableFrom(from[i])) {
  1.1207 +                            list.add(from[i]);
  1.1208 +                            break;
  1.1209 +                        }
  1.1210 +                    }
  1.1211 +                }
  1.1212 +            }
  1.1213 +        }
  1.1214 +
  1.1215 +
  1.1216 +        /**
  1.1217 +         * A PrimitiveTypeInfo object contains assorted information about a
  1.1218 +         * primitive type in its public fields. The struct for a particular
  1.1219 +         * primitive type can be obtained using the static "get" method.
  1.1220 +         */
  1.1221 +        private static class PrimitiveTypeInfo {
  1.1222 +
  1.1223 +            /**
  1.1224 +             * "base type" used in various descriptors (see JVMS section 4.3.2)
  1.1225 +             */
  1.1226 +            public String baseTypeString;
  1.1227 +
  1.1228 +            /**
  1.1229 +             * name of corresponding wrapper class
  1.1230 +             */
  1.1231 +            public String wrapperClassName;
  1.1232 +
  1.1233 +            /**
  1.1234 +             * method descriptor for wrapper class "valueOf" factory method
  1.1235 +             */
  1.1236 +            public String wrapperValueOfDesc;
  1.1237 +
  1.1238 +            /**
  1.1239 +             * name of wrapper class method for retrieving primitive value
  1.1240 +             */
  1.1241 +            public String unwrapMethodName;
  1.1242 +
  1.1243 +            /**
  1.1244 +             * descriptor of same method
  1.1245 +             */
  1.1246 +            public String unwrapMethodDesc;
  1.1247 +
  1.1248 +            private static Map<Class, PrimitiveTypeInfo> table
  1.1249 +                = new HashMap<Class, PrimitiveTypeInfo>();
  1.1250 +
  1.1251 +            static {
  1.1252 +                add(byte.class, Byte.class);
  1.1253 +                add(char.class, Character.class);
  1.1254 +                add(double.class, Double.class);
  1.1255 +                add(float.class, Float.class);
  1.1256 +                add(int.class, Integer.class);
  1.1257 +                add(long.class, Long.class);
  1.1258 +                add(short.class, Short.class);
  1.1259 +                add(boolean.class, Boolean.class);
  1.1260 +            }
  1.1261 +
  1.1262 +            private static void add(Class primitiveClass, Class wrapperClass) {
  1.1263 +                table.put(primitiveClass,
  1.1264 +                    new PrimitiveTypeInfo(primitiveClass, wrapperClass));
  1.1265 +            }
  1.1266 +
  1.1267 +            private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) {
  1.1268 +                assert primitiveClass.isPrimitive();
  1.1269 +
  1.1270 +                baseTypeString
  1.1271 +                    = Array.newInstance(primitiveClass, 0)
  1.1272 +                    .getClass().getName().substring(1);
  1.1273 +                wrapperClassName = dotToSlash(wrapperClass.getName());
  1.1274 +                wrapperValueOfDesc
  1.1275 +                    = "(" + baseTypeString + ")L" + wrapperClassName + ";";
  1.1276 +                unwrapMethodName = primitiveClass.getName() + "Value";
  1.1277 +                unwrapMethodDesc = "()" + baseTypeString;
  1.1278 +            }
  1.1279 +
  1.1280 +            public static PrimitiveTypeInfo get(Class cl) {
  1.1281 +                return table.get(cl);
  1.1282 +            }
  1.1283 +        }
  1.1284 +
  1.1285 +        /**
  1.1286 +         * A ConstantPool object represents the constant pool of a class file
  1.1287 +         * being generated. This representation of a constant pool is designed
  1.1288 +         * specifically for use by ProxyGenerator; in particular, it assumes
  1.1289 +         * that constant pool entries will not need to be resorted (for example,
  1.1290 +         * by their type, as the Java compiler does), so that the final index
  1.1291 +         * value can be assigned and used when an entry is first created.
  1.1292 +         *
  1.1293 +         * Note that new entries cannot be created after the constant pool has
  1.1294 +         * been written to a class file. To prevent such logic errors, a
  1.1295 +         * ConstantPool instance can be marked "read only", so that further
  1.1296 +         * attempts to add new entries will fail with a runtime exception.
  1.1297 +         *
  1.1298 +         * See JVMS section 4.4 for more information about the constant pool of
  1.1299 +         * a class file.
  1.1300 +         */
  1.1301 +        private static class ConstantPool {
  1.1302 +
  1.1303 +            /**
  1.1304 +             * list of constant pool entries, in constant pool index order.
  1.1305 +             *
  1.1306 +             * This list is used when writing the constant pool to a stream and
  1.1307 +             * for assigning the next index value. Note that element 0 of this
  1.1308 +             * list corresponds to constant pool index 1.
  1.1309 +             */
  1.1310 +            private List<Entry> pool = new ArrayList<Entry>(32);
  1.1311 +
  1.1312 +            /**
  1.1313 +             * maps constant pool data of all types to constant pool indexes.
  1.1314 +             *
  1.1315 +             * This map is used to look up the index of an existing entry for
  1.1316 +             * values of all types.
  1.1317 +             */
  1.1318 +            private Map<Object, Short> map = new HashMap<Object, Short>(16);
  1.1319 +
  1.1320 +            /**
  1.1321 +             * true if no new constant pool entries may be added
  1.1322 +             */
  1.1323 +            private boolean readOnly = false;
  1.1324 +
  1.1325 +            /**
  1.1326 +             * Get or assign the index for a CONSTANT_Utf8 entry.
  1.1327 +             */
  1.1328 +            public short getUtf8(String s) {
  1.1329 +                if (s == null) {
  1.1330 +                    throw new NullPointerException();
  1.1331 +                }
  1.1332 +                return getValue(s);
  1.1333 +            }
  1.1334 +
  1.1335 +            /**
  1.1336 +             * Get or assign the index for a CONSTANT_Integer entry.
  1.1337 +             */
  1.1338 +            public short getInteger(int i) {
  1.1339 +                return getValue(new Integer(i));
  1.1340 +            }
  1.1341 +
  1.1342 +            /**
  1.1343 +             * Get or assign the index for a CONSTANT_Float entry.
  1.1344 +             */
  1.1345 +            public short getFloat(float f) {
  1.1346 +                return getValue(new Float(f));
  1.1347 +            }
  1.1348 +
  1.1349 +            /**
  1.1350 +             * Get or assign the index for a CONSTANT_Class entry.
  1.1351 +             */
  1.1352 +            public short getClass(String name) {
  1.1353 +                short utf8Index = getUtf8(name);
  1.1354 +                return getIndirect(new IndirectEntry(
  1.1355 +                    CONSTANT_CLASS, utf8Index));
  1.1356 +            }
  1.1357 +
  1.1358 +            /**
  1.1359 +             * Get or assign the index for a CONSTANT_String entry.
  1.1360 +             */
  1.1361 +            public short getString(String s) {
  1.1362 +                short utf8Index = getUtf8(s);
  1.1363 +                return getIndirect(new IndirectEntry(
  1.1364 +                    CONSTANT_STRING, utf8Index));
  1.1365 +            }
  1.1366 +
  1.1367 +            /**
  1.1368 +             * Get or assign the index for a CONSTANT_FieldRef entry.
  1.1369 +             */
  1.1370 +            public short getFieldRef(String className,
  1.1371 +                String name, String descriptor) {
  1.1372 +                short classIndex = getClass(className);
  1.1373 +                short nameAndTypeIndex = getNameAndType(name, descriptor);
  1.1374 +                return getIndirect(new IndirectEntry(
  1.1375 +                    CONSTANT_FIELD, classIndex, nameAndTypeIndex));
  1.1376 +            }
  1.1377 +
  1.1378 +            /**
  1.1379 +             * Get or assign the index for a CONSTANT_MethodRef entry.
  1.1380 +             */
  1.1381 +            public short getMethodRef(String className,
  1.1382 +                String name, String descriptor) {
  1.1383 +                short classIndex = getClass(className);
  1.1384 +                short nameAndTypeIndex = getNameAndType(name, descriptor);
  1.1385 +                return getIndirect(new IndirectEntry(
  1.1386 +                    CONSTANT_METHOD, classIndex, nameAndTypeIndex));
  1.1387 +            }
  1.1388 +
  1.1389 +            /**
  1.1390 +             * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
  1.1391 +             */
  1.1392 +            public short getInterfaceMethodRef(String className, String name,
  1.1393 +                String descriptor) {
  1.1394 +                short classIndex = getClass(className);
  1.1395 +                short nameAndTypeIndex = getNameAndType(name, descriptor);
  1.1396 +                return getIndirect(new IndirectEntry(
  1.1397 +                    CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
  1.1398 +            }
  1.1399 +
  1.1400 +            /**
  1.1401 +             * Get or assign the index for a CONSTANT_NameAndType entry.
  1.1402 +             */
  1.1403 +            public short getNameAndType(String name, String descriptor) {
  1.1404 +                short nameIndex = getUtf8(name);
  1.1405 +                short descriptorIndex = getUtf8(descriptor);
  1.1406 +                return getIndirect(new IndirectEntry(
  1.1407 +                    CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
  1.1408 +            }
  1.1409 +
  1.1410 +            /**
  1.1411 +             * Set this ConstantPool instance to be "read only".
  1.1412 +             *
  1.1413 +             * After this method has been called, further requests to get an
  1.1414 +             * index for a non-existent entry will cause an InternalError to be
  1.1415 +             * thrown instead of creating of the entry.
  1.1416 +             */
  1.1417 +            public void setReadOnly() {
  1.1418 +                readOnly = true;
  1.1419 +            }
  1.1420 +
  1.1421 +            /**
  1.1422 +             * Write this constant pool to a stream as part of the class file
  1.1423 +             * format.
  1.1424 +             *
  1.1425 +             * This consists of writing the "constant_pool_count" and
  1.1426 +             * "constant_pool[]" items of the "ClassFile" structure, as
  1.1427 +             * described in JVMS section 4.1.
  1.1428 +             */
  1.1429 +            public void write(OutputStream out) throws IOException {
  1.1430 +                DataOutputStream dataOut = new DataOutputStream(out);
  1.1431 +
  1.1432 +                // constant_pool_count: number of entries plus one
  1.1433 +                dataOut.writeShort(pool.size() + 1);
  1.1434 +
  1.1435 +                for (Entry e : pool) {
  1.1436 +                    e.write(dataOut);
  1.1437 +                }
  1.1438 +            }
  1.1439 +
  1.1440 +            /**
  1.1441 +             * Add a new constant pool entry and return its index.
  1.1442 +             */
  1.1443 +            private short addEntry(Entry entry) {
  1.1444 +                pool.add(entry);
  1.1445 +                /*
  1.1446 +                 * Note that this way of determining the index of the
  1.1447 +                 * added entry is wrong if this pool supports
  1.1448 +                 * CONSTANT_Long or CONSTANT_Double entries.
  1.1449 +                 */
  1.1450 +                if (pool.size() >= 65535) {
  1.1451 +                    throw new IllegalArgumentException(
  1.1452 +                        "constant pool size limit exceeded");
  1.1453 +                }
  1.1454 +                return (short) pool.size();
  1.1455 +            }
  1.1456 +
  1.1457 +            /**
  1.1458 +             * Get or assign the index for an entry of a type that contains a
  1.1459 +             * direct value. The type of the given object determines the type of
  1.1460 +             * the desired entry as follows:
  1.1461 +             *
  1.1462 +             * java.lang.String CONSTANT_Utf8 java.lang.Integer CONSTANT_Integer
  1.1463 +             * java.lang.Float CONSTANT_Float java.lang.Long CONSTANT_Long
  1.1464 +             * java.lang.Double CONSTANT_DOUBLE
  1.1465 +             */
  1.1466 +            private short getValue(Object key) {
  1.1467 +                Short index = map.get(key);
  1.1468 +                if (index != null) {
  1.1469 +                    return index.shortValue();
  1.1470 +                } else {
  1.1471 +                    if (readOnly) {
  1.1472 +                        throw new InternalError(
  1.1473 +                            "late constant pool addition: " + key);
  1.1474 +                    }
  1.1475 +                    short i = addEntry(new ValueEntry(key));
  1.1476 +                    map.put(key, new Short(i));
  1.1477 +                    return i;
  1.1478 +                }
  1.1479 +            }
  1.1480 +
  1.1481 +            /**
  1.1482 +             * Get or assign the index for an entry of a type that contains
  1.1483 +             * references to other constant pool entries.
  1.1484 +             */
  1.1485 +            private short getIndirect(IndirectEntry e) {
  1.1486 +                Short index = map.get(e);
  1.1487 +                if (index != null) {
  1.1488 +                    return index.shortValue();
  1.1489 +                } else {
  1.1490 +                    if (readOnly) {
  1.1491 +                        throw new InternalError("late constant pool addition");
  1.1492 +                    }
  1.1493 +                    short i = addEntry(e);
  1.1494 +                    map.put(e, new Short(i));
  1.1495 +                    return i;
  1.1496 +                }
  1.1497 +            }
  1.1498 +
  1.1499 +            /**
  1.1500 +             * Entry is the abstact superclass of all constant pool entry types
  1.1501 +             * that can be stored in the "pool" list; its purpose is to define a
  1.1502 +             * common method for writing constant pool entries to a class file.
  1.1503 +             */
  1.1504 +            private static abstract class Entry {
  1.1505 +
  1.1506 +                public abstract void write(DataOutputStream out)
  1.1507 +                    throws IOException;
  1.1508 +            }
  1.1509 +
  1.1510 +            /**
  1.1511 +             * ValueEntry represents a constant pool entry of a type that
  1.1512 +             * contains a direct value (see the comments for the "getValue"
  1.1513 +             * method for a list of such types).
  1.1514 +             *
  1.1515 +             * ValueEntry objects are not used as keys for their entries in the
  1.1516 +             * Map "map", so no useful hashCode or equals methods are defined.
  1.1517 +             */
  1.1518 +            private static class ValueEntry extends Entry {
  1.1519 +
  1.1520 +                private Object value;
  1.1521 +
  1.1522 +                public ValueEntry(Object value) {
  1.1523 +                    this.value = value;
  1.1524 +                }
  1.1525 +
  1.1526 +                public void write(DataOutputStream out) throws IOException {
  1.1527 +                    if (value instanceof String) {
  1.1528 +                        out.writeByte(CONSTANT_UTF8);
  1.1529 +                        out.writeUTF((String) value);
  1.1530 +                    } else if (value instanceof Integer) {
  1.1531 +                        out.writeByte(CONSTANT_INTEGER);
  1.1532 +                        out.writeInt(((Integer) value).intValue());
  1.1533 +                    } else if (value instanceof Float) {
  1.1534 +                        out.writeByte(CONSTANT_FLOAT);
  1.1535 +                        out.writeFloat(((Float) value).floatValue());
  1.1536 +                    } else if (value instanceof Long) {
  1.1537 +                        out.writeByte(CONSTANT_LONG);
  1.1538 +                        out.writeLong(((Long) value).longValue());
  1.1539 +                    } else if (value instanceof Double) {
  1.1540 +                        out.writeDouble(CONSTANT_DOUBLE);
  1.1541 +                        out.writeDouble(((Double) value).doubleValue());
  1.1542 +                    } else {
  1.1543 +                        throw new InternalError("bogus value entry: " + value);
  1.1544 +                    }
  1.1545 +                }
  1.1546 +            }
  1.1547 +
  1.1548 +            /**
  1.1549 +             * IndirectEntry represents a constant pool entry of a type that
  1.1550 +             * references other constant pool entries, i.e., the following
  1.1551 +             * types:
  1.1552 +             *
  1.1553 +             * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
  1.1554 +             * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
  1.1555 +             * CONSTANT_NameAndType.
  1.1556 +             *
  1.1557 +             * Each of these entry types contains either one or two indexes of
  1.1558 +             * other constant pool entries.
  1.1559 +             *
  1.1560 +             * IndirectEntry objects are used as the keys for their entries in
  1.1561 +             * the Map "map", so the hashCode and equals methods are overridden
  1.1562 +             * to allow matching.
  1.1563 +             */
  1.1564 +            private static class IndirectEntry extends Entry {
  1.1565 +
  1.1566 +                private int tag;
  1.1567 +                private short index0;
  1.1568 +                private short index1;
  1.1569 +
  1.1570 +                /**
  1.1571 +                 * Construct an IndirectEntry for a constant pool entry type
  1.1572 +                 * that contains one index of another entry.
  1.1573 +                 */
  1.1574 +                public IndirectEntry(int tag, short index) {
  1.1575 +                    this.tag = tag;
  1.1576 +                    this.index0 = index;
  1.1577 +                    this.index1 = 0;
  1.1578 +                }
  1.1579 +
  1.1580 +                /**
  1.1581 +                 * Construct an IndirectEntry for a constant pool entry type
  1.1582 +                 * that contains two indexes for other entries.
  1.1583 +                 */
  1.1584 +                public IndirectEntry(int tag, short index0, short index1) {
  1.1585 +                    this.tag = tag;
  1.1586 +                    this.index0 = index0;
  1.1587 +                    this.index1 = index1;
  1.1588 +                }
  1.1589 +
  1.1590 +                public void write(DataOutputStream out) throws IOException {
  1.1591 +                    out.writeByte(tag);
  1.1592 +                    out.writeShort(index0);
  1.1593 +                    /*
  1.1594 +                     * If this entry type contains two indexes, write
  1.1595 +                     * out the second, too.
  1.1596 +                     */
  1.1597 +                    if (tag == CONSTANT_FIELD
  1.1598 +                        || tag == CONSTANT_METHOD
  1.1599 +                        || tag == CONSTANT_INTERFACEMETHOD
  1.1600 +                        || tag == CONSTANT_NAMEANDTYPE) {
  1.1601 +                        out.writeShort(index1);
  1.1602 +                    }
  1.1603 +                }
  1.1604 +
  1.1605 +                public int hashCode() {
  1.1606 +                    return tag + index0 + index1;
  1.1607 +                }
  1.1608 +
  1.1609 +                public boolean equals(Object obj) {
  1.1610 +                    if (obj instanceof IndirectEntry) {
  1.1611 +                        IndirectEntry other = (IndirectEntry) obj;
  1.1612 +                        if (tag == other.tag
  1.1613 +                            && index0 == other.index0 && index1 == other.index1) {
  1.1614 +                            return true;
  1.1615 +                        }
  1.1616 +                    }
  1.1617 +                    return false;
  1.1618 +                }
  1.1619 +            }
  1.1620 +        }
  1.1621 +    }
  1.1622 +    
  1.1623 +}