| 1 | 14 | jlechner | /* Proxy.java -- build a proxy class that implements reflected interfaces
 | 
      
         | 2 |  |  |    Copyright (C) 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
 | 
      
         | 3 |  |  |  
 | 
      
         | 4 |  |  | This file is part of GNU Classpath.
 | 
      
         | 5 |  |  |  
 | 
      
         | 6 |  |  | GNU Classpath is free software; you can redistribute it and/or modify
 | 
      
         | 7 |  |  | it under the terms of the GNU General Public License as published by
 | 
      
         | 8 |  |  | the Free Software Foundation; either version 2, or (at your option)
 | 
      
         | 9 |  |  | any later version.
 | 
      
         | 10 |  |  |  
 | 
      
         | 11 |  |  | GNU Classpath is distributed in the hope that it will be useful, but
 | 
      
         | 12 |  |  | WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
      
         | 13 |  |  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
      
         | 14 |  |  | General Public License for more details.
 | 
      
         | 15 |  |  |  
 | 
      
         | 16 |  |  | You should have received a copy of the GNU General Public License
 | 
      
         | 17 |  |  | along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
      
         | 18 |  |  | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
      
         | 19 |  |  | 02110-1301 USA.
 | 
      
         | 20 |  |  |  
 | 
      
         | 21 |  |  | Linking this library statically or dynamically with other modules is
 | 
      
         | 22 |  |  | making a combined work based on this library.  Thus, the terms and
 | 
      
         | 23 |  |  | conditions of the GNU General Public License cover the whole
 | 
      
         | 24 |  |  | combination.
 | 
      
         | 25 |  |  |  
 | 
      
         | 26 |  |  | As a special exception, the copyright holders of this library give you
 | 
      
         | 27 |  |  | permission to link this library with independent modules to produce an
 | 
      
         | 28 |  |  | executable, regardless of the license terms of these independent
 | 
      
         | 29 |  |  | modules, and to copy and distribute the resulting executable under
 | 
      
         | 30 |  |  | terms of your choice, provided that you also meet, for each linked
 | 
      
         | 31 |  |  | independent module, the terms and conditions of the license of that
 | 
      
         | 32 |  |  | module.  An independent module is a module which is not derived from
 | 
      
         | 33 |  |  | or based on this library.  If you modify this library, you may extend
 | 
      
         | 34 |  |  | this exception to your version of the library, but you are not
 | 
      
         | 35 |  |  | obligated to do so.  If you do not wish to do so, delete this
 | 
      
         | 36 |  |  | exception statement from your version. */
 | 
      
         | 37 |  |  |  
 | 
      
         | 38 |  |  |  
 | 
      
         | 39 |  |  | package java.lang.reflect;
 | 
      
         | 40 |  |  |  
 | 
      
         | 41 |  |  | import gnu.java.lang.reflect.TypeSignature;
 | 
      
         | 42 |  |  |  
 | 
      
         | 43 |  |  | import java.io.Serializable;
 | 
      
         | 44 |  |  | import java.security.ProtectionDomain;
 | 
      
         | 45 |  |  | import java.util.HashMap;
 | 
      
         | 46 |  |  | import java.util.HashSet;
 | 
      
         | 47 |  |  | import java.util.Iterator;
 | 
      
         | 48 |  |  | import java.util.Map;
 | 
      
         | 49 |  |  | import java.util.Set;
 | 
      
         | 50 |  |  |  
 | 
      
         | 51 |  |  | /**
 | 
      
         | 52 |  |  |  * This class allows you to dynamically create an instance of any (or
 | 
      
         | 53 |  |  |  * even multiple) interfaces by reflection, and decide at runtime
 | 
      
         | 54 |  |  |  * how that instance will behave by giving it an appropriate
 | 
      
         | 55 |  |  |  * {@link InvocationHandler}.  Proxy classes serialize specially, so
 | 
      
         | 56 |  |  |  * that the proxy object can be reused between VMs, without requiring
 | 
      
         | 57 |  |  |  * a persistent copy of the generated class code.
 | 
      
         | 58 |  |  |  *
 | 
      
         | 59 |  |  |  * <h3>Creation</h3>
 | 
      
         | 60 |  |  |  * To create a proxy for some interface Foo:
 | 
      
         | 61 |  |  |  *
 | 
      
         | 62 |  |  |  * <pre>
 | 
      
         | 63 |  |  |  *   InvocationHandler handler = new MyInvocationHandler(...);
 | 
      
         | 64 |  |  |  *   Class proxyClass = Proxy.getProxyClass(
 | 
      
         | 65 |  |  |  *       Foo.class.getClassLoader(), new Class[] { Foo.class });
 | 
      
         | 66 |  |  |  *   Foo f = (Foo) proxyClass
 | 
      
         | 67 |  |  |  *       .getConstructor(new Class[] { InvocationHandler.class })
 | 
      
         | 68 |  |  |  *       .newInstance(new Object[] { handler });
 | 
      
         | 69 |  |  |  * </pre>
 | 
      
         | 70 |  |  |  * or more simply:
 | 
      
         | 71 |  |  |  * <pre>
 | 
      
         | 72 |  |  |  *   Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
 | 
      
         | 73 |  |  |  *                                        new Class[] { Foo.class },
 | 
      
         | 74 |  |  |  *                                        handler);
 | 
      
         | 75 |  |  |  * </pre>
 | 
      
         | 76 |  |  |  *
 | 
      
         | 77 |  |  |  * <h3>Dynamic Proxy Classes</h3>
 | 
      
         | 78 |  |  |  * A dynamic proxy class is created at runtime, and has the following
 | 
      
         | 79 |  |  |  * properties:
 | 
      
         | 80 |  |  |  * <ul>
 | 
      
         | 81 |  |  |  *  <li>The class is <code>public</code> and <code>final</code>,
 | 
      
         | 82 |  |  |  *      and is neither <code>abstract</code> nor an inner class.</li>
 | 
      
         | 83 |  |  |  *  <li>The class has no canonical name (there is no formula you can use
 | 
      
         | 84 |  |  |  *      to determine or generate its name), but begins with the
 | 
      
         | 85 |  |  |  *      sequence "$Proxy".  Abuse this knowledge at your own peril.
 | 
      
         | 86 |  |  |  *      (For now, '$' in user identifiers is legal, but it may not
 | 
      
         | 87 |  |  |  *      be that way forever. You weren't using '$' in your
 | 
      
         | 88 |  |  |  *      identifiers, were you?)</li>
 | 
      
         | 89 |  |  |  *  <li>The class extends Proxy, and explicitly implements all the
 | 
      
         | 90 |  |  |  *      interfaces specified at creation, in order (this is important
 | 
      
         | 91 |  |  |  *      for determining how method invocation is resolved).  Note that
 | 
      
         | 92 |  |  |  *      a proxy class implements {@link Serializable}, at least
 | 
      
         | 93 |  |  |  *      implicitly, since Proxy does, but true serial behavior
 | 
      
         | 94 |  |  |  *      depends on using a serializable invocation handler as well.</li>
 | 
      
         | 95 |  |  |  *  <li>If at least one interface is non-public, the proxy class
 | 
      
         | 96 |  |  |  *      will be in the same package.  Otherwise, the package is
 | 
      
         | 97 |  |  |  *      unspecified.  This will work even if the package is sealed
 | 
      
         | 98 |  |  |  *      from user-generated classes, because Proxy classes are
 | 
      
         | 99 |  |  |  *      generated by a trusted source.  Meanwhile, the proxy class
 | 
      
         | 100 |  |  |  *      belongs to the classloader you designated.</li>
 | 
      
         | 101 |  |  |  *  <li>Reflection works as expected: {@link Class#getInterfaces()} and
 | 
      
         | 102 |  |  |  *      {@link Class#getMethods()} work as they do on normal classes.</li>
 | 
      
         | 103 |  |  |  *  <li>The method {@link #isProxyClass(Class)} will distinguish between
 | 
      
         | 104 |  |  |  *      true proxy classes and user extensions of this class.  It only
 | 
      
         | 105 |  |  |  *      returns true for classes created by {@link #getProxyClass}.</li>
 | 
      
         | 106 |  |  |  *  <li>The {@link ProtectionDomain} of a proxy class is the same as for
 | 
      
         | 107 |  |  |  *      bootstrap classes, such as Object or Proxy, since it is created by
 | 
      
         | 108 |  |  |  *      a trusted source.  This protection domain will typically be granted
 | 
      
         | 109 |  |  |  *      {@link java.security.AllPermission}. But this is not a security
 | 
      
         | 110 |  |  |  *      risk, since there are adequate permissions on reflection, which is
 | 
      
         | 111 |  |  |  *      the only way to create an instance of the proxy class.</li>
 | 
      
         | 112 |  |  |  *  <li>The proxy class contains a single constructor, which takes as
 | 
      
         | 113 |  |  |  *      its only argument an {@link InvocationHandler}.  The method
 | 
      
         | 114 |  |  |  *      {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
 | 
      
         | 115 |  |  |  *      is shorthand to do the necessary reflection.</li>
 | 
      
         | 116 |  |  |  * </ul>
 | 
      
         | 117 |  |  |  *
 | 
      
         | 118 |  |  |  * <h3>Proxy Instances</h3>
 | 
      
         | 119 |  |  |  * A proxy instance is an instance of a proxy class.  It has the
 | 
      
         | 120 |  |  |  * following properties, many of which follow from the properties of a
 | 
      
         | 121 |  |  |  * proxy class listed above:
 | 
      
         | 122 |  |  |  * <ul>
 | 
      
         | 123 |  |  |  *  <li>For a proxy class with Foo listed as one of its interfaces, the
 | 
      
         | 124 |  |  |  *      expression <code>proxy instanceof Foo</code> will return true,
 | 
      
         | 125 |  |  |  *      and the expression <code>(Foo) proxy</code> will succeed without
 | 
      
         | 126 |  |  |  *      a {@link ClassCastException}.</li>
 | 
      
         | 127 |  |  |  *  <li>Each proxy instance has an invocation handler, which can be
 | 
      
         | 128 |  |  |  *      accessed by {@link #getInvocationHandler(Object)}.  Any call
 | 
      
         | 129 |  |  |  *      to an interface method, including {@link Object#hashCode()},
 | 
      
         | 130 |  |  |  *      {@link Object#equals(Object)}, or {@link Object#toString()},
 | 
      
         | 131 |  |  |  *      but excluding the public final methods of Object, will be
 | 
      
         | 132 |  |  |  *      encoded and passed to the {@link InvocationHandler#invoke}
 | 
      
         | 133 |  |  |  *      method of this handler.</li>
 | 
      
         | 134 |  |  |  * </ul>
 | 
      
         | 135 |  |  |  *
 | 
      
         | 136 |  |  |  * <h3>Inheritance Issues</h3>
 | 
      
         | 137 |  |  |  * A proxy class may inherit a method from more than one interface.
 | 
      
         | 138 |  |  |  * The order in which interfaces are listed matters, because it determines
 | 
      
         | 139 |  |  |  * which reflected {@link Method} object will be passed to the invocation
 | 
      
         | 140 |  |  |  * handler.  This means that the dynamically generated class cannot
 | 
      
         | 141 |  |  |  * determine through which interface a method is being invoked.<p>
 | 
      
         | 142 |  |  |  *
 | 
      
         | 143 |  |  |  * In short, if a method is declared in Object (namely, hashCode,
 | 
      
         | 144 |  |  |  * equals, or toString), then Object will be used; otherwise, the
 | 
      
         | 145 |  |  |  * leftmost interface that inherits or declares a method will be used,
 | 
      
         | 146 |  |  |  * even if it has a more permissive throws clause than what the proxy
 | 
      
         | 147 |  |  |  * class is allowed. Thus, in the invocation handler, it is not always
 | 
      
         | 148 |  |  |  * safe to assume that every class listed in the throws clause of the
 | 
      
         | 149 |  |  |  * passed Method object can safely be thrown; fortunately, the Proxy
 | 
      
         | 150 |  |  |  * instance is robust enough to wrap all illegal checked exceptions in
 | 
      
         | 151 |  |  |  * {@link UndeclaredThrowableException}.
 | 
      
         | 152 |  |  |  *
 | 
      
         | 153 |  |  |  * @see InvocationHandler
 | 
      
         | 154 |  |  |  * @see UndeclaredThrowableException
 | 
      
         | 155 |  |  |  * @see Class
 | 
      
         | 156 |  |  |  * @author Eric Blake (ebb9@email.byu.edu)
 | 
      
         | 157 |  |  |  * @since 1.3
 | 
      
         | 158 |  |  |  * @status updated to 1.4, except for the use of ProtectionDomain
 | 
      
         | 159 |  |  |  */
 | 
      
         | 160 |  |  | public class Proxy implements Serializable
 | 
      
         | 161 |  |  | {
 | 
      
         | 162 |  |  |   /**
 | 
      
         | 163 |  |  |    * Compatible with JDK 1.3+.
 | 
      
         | 164 |  |  |    */
 | 
      
         | 165 |  |  |   private static final long serialVersionUID = -2222568056686623797L;
 | 
      
         | 166 |  |  |  
 | 
      
         | 167 |  |  |   /**
 | 
      
         | 168 |  |  |    * Map of ProxyType to proxy class.
 | 
      
         | 169 |  |  |    *
 | 
      
         | 170 |  |  |    * @XXX This prevents proxy classes from being garbage collected.
 | 
      
         | 171 |  |  |    * java.util.WeakHashSet is not appropriate, because that collects the
 | 
      
         | 172 |  |  |    * keys, but we are interested in collecting the elements.
 | 
      
         | 173 |  |  |    */
 | 
      
         | 174 |  |  |   private static final Map proxyClasses = new HashMap();
 | 
      
         | 175 |  |  |  
 | 
      
         | 176 |  |  |   /**
 | 
      
         | 177 |  |  |    * The invocation handler for this proxy instance.  For Proxy, this
 | 
      
         | 178 |  |  |    * field is unused, but it appears here in order to be serialized in all
 | 
      
         | 179 |  |  |    * proxy classes.
 | 
      
         | 180 |  |  |    *
 | 
      
         | 181 |  |  |    * <em>NOTE</em>: This implementation is more secure for proxy classes
 | 
      
         | 182 |  |  |    * than what Sun specifies. Sun does not require h to be immutable, but
 | 
      
         | 183 |  |  |    * this means you could change h after the fact by reflection.  However,
 | 
      
         | 184 |  |  |    * by making h immutable, we may break non-proxy classes which extend
 | 
      
         | 185 |  |  |    * Proxy.
 | 
      
         | 186 |  |  |    * @serial invocation handler associated with this proxy instance
 | 
      
         | 187 |  |  |    */
 | 
      
         | 188 |  |  |   protected InvocationHandler h;
 | 
      
         | 189 |  |  |  
 | 
      
         | 190 |  |  |   /**
 | 
      
         | 191 |  |  |    * Constructs a new Proxy from a subclass (usually a proxy class),
 | 
      
         | 192 |  |  |    * with the specified invocation handler.
 | 
      
         | 193 |  |  |    *
 | 
      
         | 194 |  |  |    * <em>NOTE</em>: This throws a NullPointerException if you attempt
 | 
      
         | 195 |  |  |    * to create a proxy instance with a null handler using reflection.
 | 
      
         | 196 |  |  |    * This behavior is not yet specified by Sun; see Sun Bug 4487672.
 | 
      
         | 197 |  |  |    *
 | 
      
         | 198 |  |  |    * @param handler the invocation handler, may be null if the subclass
 | 
      
         | 199 |  |  |    *        is not a proxy class
 | 
      
         | 200 |  |  |    * @throws NullPointerException if handler is null and this is a proxy
 | 
      
         | 201 |  |  |    *         instance
 | 
      
         | 202 |  |  |    */
 | 
      
         | 203 |  |  |   protected Proxy(InvocationHandler handler)
 | 
      
         | 204 |  |  |   {
 | 
      
         | 205 |  |  |     if (handler == null && isProxyClass(getClass()))
 | 
      
         | 206 |  |  |       throw new NullPointerException("invalid handler");
 | 
      
         | 207 |  |  |     h = handler;
 | 
      
         | 208 |  |  |   }
 | 
      
         | 209 |  |  |  
 | 
      
         | 210 |  |  |   /**
 | 
      
         | 211 |  |  |    * Returns the proxy {@link Class} for the given ClassLoader and array
 | 
      
         | 212 |  |  |    * of interfaces, dynamically generating it if necessary.
 | 
      
         | 213 |  |  |    *
 | 
      
         | 214 |  |  |    * <p>There are several restrictions on this method, the violation of
 | 
      
         | 215 |  |  |    * which will result in an IllegalArgumentException or
 | 
      
         | 216 |  |  |    * NullPointerException:</p>
 | 
      
         | 217 |  |  |    *
 | 
      
         | 218 |  |  |    * <ul>
 | 
      
         | 219 |  |  |    * <li>All objects in `interfaces' must represent distinct interfaces.
 | 
      
         | 220 |  |  |    *     Classes, primitive types, null, and duplicates are forbidden.</li>
 | 
      
         | 221 |  |  |    * <li>The interfaces must be visible in the specified ClassLoader.
 | 
      
         | 222 |  |  |    *     In other words, for each interface i:
 | 
      
         | 223 |  |  |    *     <code>Class.forName(i.getName(), false, loader) == i</code>
 | 
      
         | 224 |  |  |    *     must be true.</li>
 | 
      
         | 225 |  |  |    * <li>All non-public interfaces (if any) must reside in the same
 | 
      
         | 226 |  |  |    *     package, or the proxy class would be non-instantiable.  If
 | 
      
         | 227 |  |  |    *     there are no non-public interfaces, the package of the proxy
 | 
      
         | 228 |  |  |    *     class is unspecified.</li>
 | 
      
         | 229 |  |  |    * <li>All interfaces must be compatible - if two declare a method
 | 
      
         | 230 |  |  |    *     with the same name and parameters, the return type must be
 | 
      
         | 231 |  |  |    *     the same and the throws clause of the proxy class will be
 | 
      
         | 232 |  |  |    *     the maximal subset of subclasses of the throws clauses for
 | 
      
         | 233 |  |  |    *     each method that is overridden.</li>
 | 
      
         | 234 |  |  |    * <li>VM constraints limit the number of interfaces a proxy class
 | 
      
         | 235 |  |  |    *     may directly implement (however, the indirect inheritance
 | 
      
         | 236 |  |  |    *     of {@link Serializable} does not count against this limit).
 | 
      
         | 237 |  |  |    *     Even though most VMs can theoretically have 65535
 | 
      
         | 238 |  |  |    *     superinterfaces for a class, the actual limit is smaller
 | 
      
         | 239 |  |  |    *     because a class's constant pool is limited to 65535 entries,
 | 
      
         | 240 |  |  |    *     and not all entries can be interfaces.</li>
 | 
      
         | 241 |  |  |    * </ul>
 | 
      
         | 242 |  |  |    *
 | 
      
         | 243 |  |  |    * <p>Note that different orders of interfaces produce distinct classes.</p>
 | 
      
         | 244 |  |  |    *
 | 
      
         | 245 |  |  |    * @param loader the class loader to define the proxy class in; null
 | 
      
         | 246 |  |  |    *        implies the bootstrap class loader
 | 
      
         | 247 |  |  |    * @param interfaces the array of interfaces the proxy class implements,
 | 
      
         | 248 |  |  |    *        may be empty, but not null
 | 
      
         | 249 |  |  |    * @return the Class object of the proxy class
 | 
      
         | 250 |  |  |    * @throws IllegalArgumentException if the constraints above were
 | 
      
         | 251 |  |  |    *         violated, except for problems with null
 | 
      
         | 252 |  |  |    * @throws NullPointerException if `interfaces' is null or contains
 | 
      
         | 253 |  |  |    *         a null entry
 | 
      
         | 254 |  |  |    */
 | 
      
         | 255 |  |  |   // synchronized so that we aren't trying to build the same class
 | 
      
         | 256 |  |  |   // simultaneously in two threads
 | 
      
         | 257 |  |  |   public static synchronized Class getProxyClass(ClassLoader loader,
 | 
      
         | 258 |  |  |                                                  Class[] interfaces)
 | 
      
         | 259 |  |  |   {
 | 
      
         | 260 |  |  |     interfaces = (Class[]) interfaces.clone();
 | 
      
         | 261 |  |  |     ProxyType pt = new ProxyType(loader, interfaces);
 | 
      
         | 262 |  |  |     Class clazz = (Class) proxyClasses.get(pt);
 | 
      
         | 263 |  |  |     if (clazz == null)
 | 
      
         | 264 |  |  |       {
 | 
      
         | 265 |  |  |         if (VMProxy.HAVE_NATIVE_GET_PROXY_CLASS)
 | 
      
         | 266 |  |  |           clazz = VMProxy.getProxyClass(loader, interfaces);
 | 
      
         | 267 |  |  |         else
 | 
      
         | 268 |  |  |           {
 | 
      
         | 269 |  |  |             ProxyData data = (VMProxy.HAVE_NATIVE_GET_PROXY_DATA
 | 
      
         | 270 |  |  |                               ? VMProxy.getProxyData(loader, interfaces)
 | 
      
         | 271 |  |  |                               : ProxyData.getProxyData(pt));
 | 
      
         | 272 |  |  |  
 | 
      
         | 273 |  |  |             clazz = (VMProxy.HAVE_NATIVE_GENERATE_PROXY_CLASS
 | 
      
         | 274 |  |  |                      ? VMProxy.generateProxyClass(loader, data)
 | 
      
         | 275 |  |  |                      : new ClassFactory(data).generate(loader));
 | 
      
         | 276 |  |  |           }
 | 
      
         | 277 |  |  |  
 | 
      
         | 278 |  |  |         Object check = proxyClasses.put(pt, clazz);
 | 
      
         | 279 |  |  |         // assert check == null && clazz != null;
 | 
      
         | 280 |  |  |         if (check != null || clazz == null)
 | 
      
         | 281 |  |  |           throw new InternalError(/*"Fatal flaw in getProxyClass"*/);
 | 
      
         | 282 |  |  |       }
 | 
      
         | 283 |  |  |     return clazz;
 | 
      
         | 284 |  |  |   }
 | 
      
         | 285 |  |  |  
 | 
      
         | 286 |  |  |   /**
 | 
      
         | 287 |  |  |    * Combines several methods into one.  This is equivalent to:
 | 
      
         | 288 |  |  |    * <pre>
 | 
      
         | 289 |  |  |    *   Proxy.getProxyClass(loader, interfaces)
 | 
      
         | 290 |  |  |    *       .getConstructor(new Class[] {InvocationHandler.class})
 | 
      
         | 291 |  |  |    *       .newInstance(new Object[] {handler});
 | 
      
         | 292 |  |  |    * </pre>
 | 
      
         | 293 |  |  |    * except that it will not fail with the normal problems caused
 | 
      
         | 294 |  |  |    * by reflection.  It can still fail for the same reasons documented
 | 
      
         | 295 |  |  |    * in getProxyClass, or if handler is null.
 | 
      
         | 296 |  |  |    *
 | 
      
         | 297 |  |  |    * @param loader the class loader to define the proxy class in; null
 | 
      
         | 298 |  |  |    *        implies the bootstrap class loader
 | 
      
         | 299 |  |  |    * @param interfaces the array of interfaces the proxy class implements,
 | 
      
         | 300 |  |  |    *        may be empty, but not null
 | 
      
         | 301 |  |  |    * @param handler the invocation handler, may not be null
 | 
      
         | 302 |  |  |    * @return a proxy instance implementing the specified interfaces
 | 
      
         | 303 |  |  |    * @throws IllegalArgumentException if the constraints for getProxyClass
 | 
      
         | 304 |  |  |    *         were violated, except for problems with null
 | 
      
         | 305 |  |  |    * @throws NullPointerException if `interfaces' is null or contains
 | 
      
         | 306 |  |  |    *         a null entry, or if handler is null
 | 
      
         | 307 |  |  |    * @see #getProxyClass(ClassLoader, Class[])
 | 
      
         | 308 |  |  |    * @see Class#getConstructor(Class[])
 | 
      
         | 309 |  |  |    * @see Constructor#newInstance(Object[])
 | 
      
         | 310 |  |  |    */
 | 
      
         | 311 |  |  |   public static Object newProxyInstance(ClassLoader loader,
 | 
      
         | 312 |  |  |                                         Class[] interfaces,
 | 
      
         | 313 |  |  |                                         InvocationHandler handler)
 | 
      
         | 314 |  |  |   {
 | 
      
         | 315 |  |  |     try
 | 
      
         | 316 |  |  |       {
 | 
      
         | 317 |  |  |         // getProxyClass() and Proxy() throw the necessary exceptions
 | 
      
         | 318 |  |  |         return getProxyClass(loader, interfaces)
 | 
      
         | 319 |  |  |           .getConstructor(new Class[] {InvocationHandler.class})
 | 
      
         | 320 |  |  |           .newInstance(new Object[] {handler});
 | 
      
         | 321 |  |  |       }
 | 
      
         | 322 |  |  |     catch (RuntimeException e)
 | 
      
         | 323 |  |  |       {
 | 
      
         | 324 |  |  |         // Let IllegalArgumentException, NullPointerException escape.
 | 
      
         | 325 |  |  |         // assert e instanceof IllegalArgumentException
 | 
      
         | 326 |  |  |         //   || e instanceof NullPointerException;
 | 
      
         | 327 |  |  |         throw e;
 | 
      
         | 328 |  |  |       }
 | 
      
         | 329 |  |  |     catch (InvocationTargetException e)
 | 
      
         | 330 |  |  |       {
 | 
      
         | 331 |  |  |         // Let wrapped NullPointerException escape.
 | 
      
         | 332 |  |  |         // assert e.getTargetException() instanceof NullPointerException
 | 
      
         | 333 |  |  |         throw (NullPointerException) e.getCause();
 | 
      
         | 334 |  |  |       }
 | 
      
         | 335 |  |  |     catch (Exception e)
 | 
      
         | 336 |  |  |       {
 | 
      
         | 337 |  |  |         // Covers InstantiationException, IllegalAccessException,
 | 
      
         | 338 |  |  |         // NoSuchMethodException, none of which should be generated
 | 
      
         | 339 |  |  |         // if the proxy class was generated correctly.
 | 
      
         | 340 |  |  |         // assert false;
 | 
      
         | 341 |  |  |         throw (Error) new InternalError("Unexpected: " + e).initCause(e);
 | 
      
         | 342 |  |  |       }
 | 
      
         | 343 |  |  |   }
 | 
      
         | 344 |  |  |  
 | 
      
         | 345 |  |  |   /**
 | 
      
         | 346 |  |  |    * Returns true if and only if the Class object is a dynamically created
 | 
      
         | 347 |  |  |    * proxy class (created by <code>getProxyClass</code> or by the
 | 
      
         | 348 |  |  |    * syntactic sugar of <code>newProxyInstance</code>).
 | 
      
         | 349 |  |  |    *
 | 
      
         | 350 |  |  |    * <p>This check is secure (in other words, it is not simply
 | 
      
         | 351 |  |  |    * <code>clazz.getSuperclass() == Proxy.class</code>), it will not
 | 
      
         | 352 |  |  |    * be spoofed by non-proxy classes that extend Proxy.
 | 
      
         | 353 |  |  |    *
 | 
      
         | 354 |  |  |    * @param clazz the class to check, must not be null
 | 
      
         | 355 |  |  |    * @return true if the class represents a proxy class
 | 
      
         | 356 |  |  |    * @throws NullPointerException if clazz is null
 | 
      
         | 357 |  |  |    */
 | 
      
         | 358 |  |  |   // This is synchronized on the off chance that another thread is
 | 
      
         | 359 |  |  |   // trying to add a class to the map at the same time we read it.
 | 
      
         | 360 |  |  |   public static synchronized boolean isProxyClass(Class clazz)
 | 
      
         | 361 |  |  |   {
 | 
      
         | 362 |  |  |     if (! Proxy.class.isAssignableFrom(clazz))
 | 
      
         | 363 |  |  |       return false;
 | 
      
         | 364 |  |  |     // This is a linear search, even though we could do an O(1) search
 | 
      
         | 365 |  |  |     // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()).
 | 
      
         | 366 |  |  |     return proxyClasses.containsValue(clazz);
 | 
      
         | 367 |  |  |   }
 | 
      
         | 368 |  |  |  
 | 
      
         | 369 |  |  |   /**
 | 
      
         | 370 |  |  |    * Returns the invocation handler for the given proxy instance.<p>
 | 
      
         | 371 |  |  |    *
 | 
      
         | 372 |  |  |    * <em>NOTE</em>: We guarantee a non-null result if successful,
 | 
      
         | 373 |  |  |    * but Sun allows the creation of a proxy instance with a null
 | 
      
         | 374 |  |  |    * handler.  See the comments for {@link #Proxy(InvocationHandler)}.
 | 
      
         | 375 |  |  |    *
 | 
      
         | 376 |  |  |    * @param proxy the proxy instance, must not be null
 | 
      
         | 377 |  |  |    * @return the invocation handler, guaranteed non-null.
 | 
      
         | 378 |  |  |    * @throws IllegalArgumentException if
 | 
      
         | 379 |  |  |    *         <code>Proxy.isProxyClass(proxy.getClass())</code> returns false.
 | 
      
         | 380 |  |  |    * @throws NullPointerException if proxy is null
 | 
      
         | 381 |  |  |    */
 | 
      
         | 382 |  |  |   public static InvocationHandler getInvocationHandler(Object proxy)
 | 
      
         | 383 |  |  |   {
 | 
      
         | 384 |  |  |     if (! isProxyClass(proxy.getClass()))
 | 
      
         | 385 |  |  |       throw new IllegalArgumentException("not a proxy instance");
 | 
      
         | 386 |  |  |     return ((Proxy) proxy).h;
 | 
      
         | 387 |  |  |   }
 | 
      
         | 388 |  |  |  
 | 
      
         | 389 |  |  |   /**
 | 
      
         | 390 |  |  |    * Helper class for mapping unique ClassLoader and interface combinations
 | 
      
         | 391 |  |  |    * to proxy classes.
 | 
      
         | 392 |  |  |    *
 | 
      
         | 393 |  |  |    * @author Eric Blake (ebb9@email.byu.edu)
 | 
      
         | 394 |  |  |    */
 | 
      
         | 395 |  |  |   private static final class ProxyType
 | 
      
         | 396 |  |  |   {
 | 
      
         | 397 |  |  |     /**
 | 
      
         | 398 |  |  |      * Store the class loader (may be null)
 | 
      
         | 399 |  |  |      */
 | 
      
         | 400 |  |  |     final ClassLoader loader;
 | 
      
         | 401 |  |  |  
 | 
      
         | 402 |  |  |     /**
 | 
      
         | 403 |  |  |      * Store the interfaces (never null, all elements are interfaces)
 | 
      
         | 404 |  |  |      */
 | 
      
         | 405 |  |  |     final Class[] interfaces;
 | 
      
         | 406 |  |  |  
 | 
      
         | 407 |  |  |     /**
 | 
      
         | 408 |  |  |      * Construct the helper object.
 | 
      
         | 409 |  |  |      *
 | 
      
         | 410 |  |  |      * @param loader the class loader to define the proxy class in; null
 | 
      
         | 411 |  |  |      *        implies the bootstrap class loader
 | 
      
         | 412 |  |  |      * @param interfaces an array of interfaces
 | 
      
         | 413 |  |  |      */
 | 
      
         | 414 |  |  |     ProxyType(ClassLoader loader, Class[] interfaces)
 | 
      
         | 415 |  |  |     {
 | 
      
         | 416 |  |  |       this.loader = loader;
 | 
      
         | 417 |  |  |       this.interfaces = interfaces;
 | 
      
         | 418 |  |  |     }
 | 
      
         | 419 |  |  |  
 | 
      
         | 420 |  |  |     /**
 | 
      
         | 421 |  |  |      * Calculates the hash code.
 | 
      
         | 422 |  |  |      *
 | 
      
         | 423 |  |  |      * @return a combination of the classloader and interfaces hashcodes.
 | 
      
         | 424 |  |  |      */
 | 
      
         | 425 |  |  |     public int hashCode()
 | 
      
         | 426 |  |  |     {
 | 
      
         | 427 |  |  |       int hash = loader == null ? 0 : loader.hashCode();
 | 
      
         | 428 |  |  |       for (int i = 0; i < interfaces.length; i++)
 | 
      
         | 429 |  |  |         hash = hash * 31 + interfaces[i].hashCode();
 | 
      
         | 430 |  |  |       return hash;
 | 
      
         | 431 |  |  |     }
 | 
      
         | 432 |  |  |  
 | 
      
         | 433 |  |  |     /**
 | 
      
         | 434 |  |  |      * Calculates equality.
 | 
      
         | 435 |  |  |      *
 | 
      
         | 436 |  |  |      * @param other object to compare to
 | 
      
         | 437 |  |  |      * @return true if it is a ProxyType with same data
 | 
      
         | 438 |  |  |      */
 | 
      
         | 439 |  |  |     public boolean equals(Object other)
 | 
      
         | 440 |  |  |     {
 | 
      
         | 441 |  |  |       ProxyType pt = (ProxyType) other;
 | 
      
         | 442 |  |  |       if (loader != pt.loader || interfaces.length != pt.interfaces.length)
 | 
      
         | 443 |  |  |         return false;
 | 
      
         | 444 |  |  |       for (int i = 0; i < interfaces.length; i++)
 | 
      
         | 445 |  |  |         if (interfaces[i] != pt.interfaces[i])
 | 
      
         | 446 |  |  |           return false;
 | 
      
         | 447 |  |  |       return true;
 | 
      
         | 448 |  |  |     }
 | 
      
         | 449 |  |  |   } // class ProxyType
 | 
      
         | 450 |  |  |  
 | 
      
         | 451 |  |  |   /**
 | 
      
         | 452 |  |  |    * Helper class which allows hashing of a method name and signature
 | 
      
         | 453 |  |  |    * without worrying about return type, declaring class, or throws clause,
 | 
      
         | 454 |  |  |    * and which reduces the maximally common throws clause between two methods
 | 
      
         | 455 |  |  |    *
 | 
      
         | 456 |  |  |    * @author Eric Blake (ebb9@email.byu.edu)
 | 
      
         | 457 |  |  |    */
 | 
      
         | 458 |  |  |   private static final class ProxySignature
 | 
      
         | 459 |  |  |   {
 | 
      
         | 460 |  |  |     /**
 | 
      
         | 461 |  |  |      * The core signatures which all Proxy instances handle.
 | 
      
         | 462 |  |  |      */
 | 
      
         | 463 |  |  |     static final HashMap coreMethods = new HashMap();
 | 
      
         | 464 |  |  |     static
 | 
      
         | 465 |  |  |     {
 | 
      
         | 466 |  |  |       try
 | 
      
         | 467 |  |  |         {
 | 
      
         | 468 |  |  |           ProxySignature sig
 | 
      
         | 469 |  |  |             = new ProxySignature(Object.class
 | 
      
         | 470 |  |  |                                  .getMethod("equals",
 | 
      
         | 471 |  |  |                                             new Class[] {Object.class}));
 | 
      
         | 472 |  |  |           coreMethods.put(sig, sig);
 | 
      
         | 473 |  |  |           sig = new ProxySignature(Object.class.getMethod("hashCode", null));
 | 
      
         | 474 |  |  |           coreMethods.put(sig, sig);
 | 
      
         | 475 |  |  |           sig = new ProxySignature(Object.class.getMethod("toString", null));
 | 
      
         | 476 |  |  |           coreMethods.put(sig, sig);
 | 
      
         | 477 |  |  |         }
 | 
      
         | 478 |  |  |       catch (Exception e)
 | 
      
         | 479 |  |  |         {
 | 
      
         | 480 |  |  |           // assert false;
 | 
      
         | 481 |  |  |           throw (Error) new InternalError("Unexpected: " + e).initCause(e);
 | 
      
         | 482 |  |  |         }
 | 
      
         | 483 |  |  |     }
 | 
      
         | 484 |  |  |  
 | 
      
         | 485 |  |  |     /**
 | 
      
         | 486 |  |  |      * The underlying Method object, never null
 | 
      
         | 487 |  |  |      */
 | 
      
         | 488 |  |  |     final Method method;
 | 
      
         | 489 |  |  |  
 | 
      
         | 490 |  |  |     /**
 | 
      
         | 491 |  |  |      * The set of compatible thrown exceptions, may be empty
 | 
      
         | 492 |  |  |      */
 | 
      
         | 493 |  |  |     final Set exceptions = new HashSet();
 | 
      
         | 494 |  |  |  
 | 
      
         | 495 |  |  |     /**
 | 
      
         | 496 |  |  |      * Construct a signature
 | 
      
         | 497 |  |  |      *
 | 
      
         | 498 |  |  |      * @param method the Method this signature is based on, never null
 | 
      
         | 499 |  |  |      */
 | 
      
         | 500 |  |  |     ProxySignature(Method method)
 | 
      
         | 501 |  |  |     {
 | 
      
         | 502 |  |  |       this.method = method;
 | 
      
         | 503 |  |  |       Class[] exc = method.getExceptionTypes();
 | 
      
         | 504 |  |  |       int i = exc.length;
 | 
      
         | 505 |  |  |       while (--i >= 0)
 | 
      
         | 506 |  |  |         {
 | 
      
         | 507 |  |  |           // discard unchecked exceptions
 | 
      
         | 508 |  |  |           if (Error.class.isAssignableFrom(exc[i])
 | 
      
         | 509 |  |  |               || RuntimeException.class.isAssignableFrom(exc[i]))
 | 
      
         | 510 |  |  |             continue;
 | 
      
         | 511 |  |  |           exceptions.add(exc[i]);
 | 
      
         | 512 |  |  |         }
 | 
      
         | 513 |  |  |     }
 | 
      
         | 514 |  |  |  
 | 
      
         | 515 |  |  |     /**
 | 
      
         | 516 |  |  |      * Given a method, make sure it's return type is identical
 | 
      
         | 517 |  |  |      * to this, and adjust this signature's throws clause appropriately
 | 
      
         | 518 |  |  |      *
 | 
      
         | 519 |  |  |      * @param other the signature to merge in
 | 
      
         | 520 |  |  |      * @throws IllegalArgumentException if the return types conflict
 | 
      
         | 521 |  |  |      */
 | 
      
         | 522 |  |  |     void checkCompatibility(ProxySignature other)
 | 
      
         | 523 |  |  |     {
 | 
      
         | 524 |  |  |       if (method.getReturnType() != other.method.getReturnType())
 | 
      
         | 525 |  |  |         throw new IllegalArgumentException("incompatible return types: "
 | 
      
         | 526 |  |  |                                            + method + ", " + other.method);
 | 
      
         | 527 |  |  |  
 | 
      
         | 528 |  |  |       // if you can think of a more efficient way than this O(n^2) search,
 | 
      
         | 529 |  |  |       // implement it!
 | 
      
         | 530 |  |  |       int size1 = exceptions.size();
 | 
      
         | 531 |  |  |       int size2 = other.exceptions.size();
 | 
      
         | 532 |  |  |       boolean[] valid1 = new boolean[size1];
 | 
      
         | 533 |  |  |       boolean[] valid2 = new boolean[size2];
 | 
      
         | 534 |  |  |       Iterator itr = exceptions.iterator();
 | 
      
         | 535 |  |  |       int pos = size1;
 | 
      
         | 536 |  |  |       while (--pos >= 0)
 | 
      
         | 537 |  |  |         {
 | 
      
         | 538 |  |  |           Class c1 = (Class) itr.next();
 | 
      
         | 539 |  |  |           Iterator itr2 = other.exceptions.iterator();
 | 
      
         | 540 |  |  |           int pos2 = size2;
 | 
      
         | 541 |  |  |           while (--pos2 >= 0)
 | 
      
         | 542 |  |  |             {
 | 
      
         | 543 |  |  |               Class c2 = (Class) itr2.next();
 | 
      
         | 544 |  |  |               if (c2.isAssignableFrom(c1))
 | 
      
         | 545 |  |  |                 valid1[pos] = true;
 | 
      
         | 546 |  |  |               if (c1.isAssignableFrom(c2))
 | 
      
         | 547 |  |  |                 valid2[pos2] = true;
 | 
      
         | 548 |  |  |             }
 | 
      
         | 549 |  |  |         }
 | 
      
         | 550 |  |  |       pos = size1;
 | 
      
         | 551 |  |  |       itr = exceptions.iterator();
 | 
      
         | 552 |  |  |       while (--pos >= 0)
 | 
      
         | 553 |  |  |         {
 | 
      
         | 554 |  |  |           itr.next();
 | 
      
         | 555 |  |  |           if (! valid1[pos])
 | 
      
         | 556 |  |  |             itr.remove();
 | 
      
         | 557 |  |  |         }
 | 
      
         | 558 |  |  |       pos = size2;
 | 
      
         | 559 |  |  |       itr = other.exceptions.iterator();
 | 
      
         | 560 |  |  |       while (--pos >= 0)
 | 
      
         | 561 |  |  |         {
 | 
      
         | 562 |  |  |           itr.next();
 | 
      
         | 563 |  |  |           if (! valid2[pos])
 | 
      
         | 564 |  |  |             itr.remove();
 | 
      
         | 565 |  |  |         }
 | 
      
         | 566 |  |  |       exceptions.addAll(other.exceptions);
 | 
      
         | 567 |  |  |     }
 | 
      
         | 568 |  |  |  
 | 
      
         | 569 |  |  |     /**
 | 
      
         | 570 |  |  |      * Calculates the hash code.
 | 
      
         | 571 |  |  |      *
 | 
      
         | 572 |  |  |      * @return a combination of name and parameter types
 | 
      
         | 573 |  |  |      */
 | 
      
         | 574 |  |  |     public int hashCode()
 | 
      
         | 575 |  |  |     {
 | 
      
         | 576 |  |  |       int hash = method.getName().hashCode();
 | 
      
         | 577 |  |  |       Class[] types = method.getParameterTypes();
 | 
      
         | 578 |  |  |       for (int i = 0; i < types.length; i++)
 | 
      
         | 579 |  |  |         hash = hash * 31 + types[i].hashCode();
 | 
      
         | 580 |  |  |       return hash;
 | 
      
         | 581 |  |  |     }
 | 
      
         | 582 |  |  |  
 | 
      
         | 583 |  |  |     /**
 | 
      
         | 584 |  |  |      * Calculates equality.
 | 
      
         | 585 |  |  |      *
 | 
      
         | 586 |  |  |      * @param other object to compare to
 | 
      
         | 587 |  |  |      * @return true if it is a ProxySignature with same data
 | 
      
         | 588 |  |  |      */
 | 
      
         | 589 |  |  |     public boolean equals(Object other)
 | 
      
         | 590 |  |  |     {
 | 
      
         | 591 |  |  |       ProxySignature ps = (ProxySignature) other;
 | 
      
         | 592 |  |  |       Class[] types1 = method.getParameterTypes();
 | 
      
         | 593 |  |  |       Class[] types2 = ps.method.getParameterTypes();
 | 
      
         | 594 |  |  |       if (! method.getName().equals(ps.method.getName())
 | 
      
         | 595 |  |  |           || types1.length != types2.length)
 | 
      
         | 596 |  |  |         return false;
 | 
      
         | 597 |  |  |       int i = types1.length;
 | 
      
         | 598 |  |  |       while (--i >= 0)
 | 
      
         | 599 |  |  |         if (types1[i] != types2[i])
 | 
      
         | 600 |  |  |           return false;
 | 
      
         | 601 |  |  |       return true;
 | 
      
         | 602 |  |  |     }
 | 
      
         | 603 |  |  |   } // class ProxySignature
 | 
      
         | 604 |  |  |  
 | 
      
         | 605 |  |  |   /**
 | 
      
         | 606 |  |  |    * A flat representation of all data needed to generate bytecode/instantiate
 | 
      
         | 607 |  |  |    * a proxy class.  This is basically a struct.
 | 
      
         | 608 |  |  |    *
 | 
      
         | 609 |  |  |    * @author Eric Blake (ebb9@email.byu.edu)
 | 
      
         | 610 |  |  |    */
 | 
      
         | 611 |  |  |   static final class ProxyData
 | 
      
         | 612 |  |  |   {
 | 
      
         | 613 |  |  |     /**
 | 
      
         | 614 |  |  |      * The package this class is in <b>including the trailing dot</b>
 | 
      
         | 615 |  |  |      * or an empty string for the unnamed (aka default) package.
 | 
      
         | 616 |  |  |      */
 | 
      
         | 617 |  |  |     String pack = "";
 | 
      
         | 618 |  |  |  
 | 
      
         | 619 |  |  |     /**
 | 
      
         | 620 |  |  |      * The interfaces this class implements.  Non-null, but possibly empty.
 | 
      
         | 621 |  |  |      */
 | 
      
         | 622 |  |  |     Class[] interfaces;
 | 
      
         | 623 |  |  |  
 | 
      
         | 624 |  |  |     /**
 | 
      
         | 625 |  |  |      * The Method objects this class must pass as the second argument to
 | 
      
         | 626 |  |  |      * invoke (also useful for determining what methods this class has).
 | 
      
         | 627 |  |  |      * Non-null, non-empty (includes at least Object.hashCode, Object.equals,
 | 
      
         | 628 |  |  |      * and Object.toString).
 | 
      
         | 629 |  |  |      */
 | 
      
         | 630 |  |  |     Method[] methods;
 | 
      
         | 631 |  |  |  
 | 
      
         | 632 |  |  |     /**
 | 
      
         | 633 |  |  |      * The exceptions that do not need to be wrapped in
 | 
      
         | 634 |  |  |      * UndeclaredThrowableException. exceptions[i] is the same as, or a
 | 
      
         | 635 |  |  |      * subset of subclasses, of methods[i].getExceptionTypes(), depending on
 | 
      
         | 636 |  |  |      * compatible throws clauses with multiple inheritance. It is unspecified
 | 
      
         | 637 |  |  |      * if these lists include or exclude subclasses of Error and
 | 
      
         | 638 |  |  |      * RuntimeException, but excluding them is harmless and generates a
 | 
      
         | 639 |  |  |      * smaller class.
 | 
      
         | 640 |  |  |      */
 | 
      
         | 641 |  |  |     Class[][] exceptions;
 | 
      
         | 642 |  |  |  
 | 
      
         | 643 |  |  |     /**
 | 
      
         | 644 |  |  |      * For unique id's
 | 
      
         | 645 |  |  |      */
 | 
      
         | 646 |  |  |     private static int count;
 | 
      
         | 647 |  |  |  
 | 
      
         | 648 |  |  |     /**
 | 
      
         | 649 |  |  |      * The id of this proxy class
 | 
      
         | 650 |  |  |      */
 | 
      
         | 651 |  |  |     final int id = count++;
 | 
      
         | 652 |  |  |  
 | 
      
         | 653 |  |  |     /**
 | 
      
         | 654 |  |  |      * Construct a ProxyData with uninitialized data members.
 | 
      
         | 655 |  |  |      */
 | 
      
         | 656 |  |  |     ProxyData()
 | 
      
         | 657 |  |  |     {
 | 
      
         | 658 |  |  |     }
 | 
      
         | 659 |  |  |  
 | 
      
         | 660 |  |  |     /**
 | 
      
         | 661 |  |  |      * Return the name of a package (including the trailing dot)
 | 
      
         | 662 |  |  |      * given the name of a class.
 | 
      
         | 663 |  |  |      * Returns an empty string if no package.  We use this in preference to
 | 
      
         | 664 |  |  |      * using Class.getPackage() to avoid problems with ClassLoaders
 | 
      
         | 665 |  |  |      * that don't set the package.
 | 
      
         | 666 |  |  |      */
 | 
      
         | 667 |  |  |     private static String getPackage(Class k)
 | 
      
         | 668 |  |  |     {
 | 
      
         | 669 |  |  |       String name = k.getName();
 | 
      
         | 670 |  |  |       int idx = name.lastIndexOf('.');
 | 
      
         | 671 |  |  |       return name.substring(0, idx + 1);
 | 
      
         | 672 |  |  |     }
 | 
      
         | 673 |  |  |  
 | 
      
         | 674 |  |  |     /**
 | 
      
         | 675 |  |  |      * Verifies that the arguments are legal, and sets up remaining data
 | 
      
         | 676 |  |  |      * This should only be called when a class must be generated, as
 | 
      
         | 677 |  |  |      * it is expensive.
 | 
      
         | 678 |  |  |      *
 | 
      
         | 679 |  |  |      * @param pt the ProxyType to convert to ProxyData
 | 
      
         | 680 |  |  |      * @return the flattened, verified ProxyData structure for use in
 | 
      
         | 681 |  |  |      *         class generation
 | 
      
         | 682 |  |  |      * @throws IllegalArgumentException if `interfaces' contains
 | 
      
         | 683 |  |  |      *         non-interfaces or incompatible combinations, and verify is true
 | 
      
         | 684 |  |  |      * @throws NullPointerException if interfaces is null or contains null
 | 
      
         | 685 |  |  |      */
 | 
      
         | 686 |  |  |     static ProxyData getProxyData(ProxyType pt)
 | 
      
         | 687 |  |  |     {
 | 
      
         | 688 |  |  |       Map method_set = (Map) ProxySignature.coreMethods.clone();
 | 
      
         | 689 |  |  |       boolean in_package = false; // true if we encounter non-public interface
 | 
      
         | 690 |  |  |  
 | 
      
         | 691 |  |  |       ProxyData data = new ProxyData();
 | 
      
         | 692 |  |  |       data.interfaces = pt.interfaces;
 | 
      
         | 693 |  |  |  
 | 
      
         | 694 |  |  |       // if interfaces is too large, we croak later on when the constant
 | 
      
         | 695 |  |  |       // pool overflows
 | 
      
         | 696 |  |  |       int i = data.interfaces.length;
 | 
      
         | 697 |  |  |       while (--i >= 0)
 | 
      
         | 698 |  |  |         {
 | 
      
         | 699 |  |  |           Class inter = data.interfaces[i];
 | 
      
         | 700 |  |  |           if (! inter.isInterface())
 | 
      
         | 701 |  |  |             throw new IllegalArgumentException("not an interface: " + inter);
 | 
      
         | 702 |  |  |           try
 | 
      
         | 703 |  |  |             {
 | 
      
         | 704 |  |  |               if (Class.forName(inter.getName(), false, pt.loader) != inter)
 | 
      
         | 705 |  |  |                 throw new IllegalArgumentException("not accessible in "
 | 
      
         | 706 |  |  |                                                    + "classloader: " + inter);
 | 
      
         | 707 |  |  |             }
 | 
      
         | 708 |  |  |           catch (ClassNotFoundException e)
 | 
      
         | 709 |  |  |             {
 | 
      
         | 710 |  |  |               throw new IllegalArgumentException("not accessible in "
 | 
      
         | 711 |  |  |                                                  + "classloader: " + inter);
 | 
      
         | 712 |  |  |             }
 | 
      
         | 713 |  |  |           if (! Modifier.isPublic(inter.getModifiers()))
 | 
      
         | 714 |  |  |             if (in_package)
 | 
      
         | 715 |  |  |               {
 | 
      
         | 716 |  |  |                 String p = getPackage(inter);
 | 
      
         | 717 |  |  |                 if (! data.pack.equals(p))
 | 
      
         | 718 |  |  |                   throw new IllegalArgumentException("non-public interfaces "
 | 
      
         | 719 |  |  |                                                      + "from different "
 | 
      
         | 720 |  |  |                                                      + "packages");
 | 
      
         | 721 |  |  |               }
 | 
      
         | 722 |  |  |             else
 | 
      
         | 723 |  |  |               {
 | 
      
         | 724 |  |  |                 in_package = true;
 | 
      
         | 725 |  |  |                 data.pack = getPackage(inter);
 | 
      
         | 726 |  |  |               }
 | 
      
         | 727 |  |  |           for (int j = i-1; j >= 0; j--)
 | 
      
         | 728 |  |  |             if (data.interfaces[j] == inter)
 | 
      
         | 729 |  |  |               throw new IllegalArgumentException("duplicate interface: "
 | 
      
         | 730 |  |  |                                                  + inter);
 | 
      
         | 731 |  |  |           Method[] methods = inter.getMethods();
 | 
      
         | 732 |  |  |           int j = methods.length;
 | 
      
         | 733 |  |  |           while (--j >= 0)
 | 
      
         | 734 |  |  |             {
 | 
      
         | 735 |  |  |               ProxySignature sig = new ProxySignature(methods[j]);
 | 
      
         | 736 |  |  |               ProxySignature old = (ProxySignature) method_set.put(sig, sig);
 | 
      
         | 737 |  |  |               if (old != null)
 | 
      
         | 738 |  |  |                 sig.checkCompatibility(old);
 | 
      
         | 739 |  |  |             }
 | 
      
         | 740 |  |  |         }
 | 
      
         | 741 |  |  |  
 | 
      
         | 742 |  |  |       i = method_set.size();
 | 
      
         | 743 |  |  |       data.methods = new Method[i];
 | 
      
         | 744 |  |  |       data.exceptions = new Class[i][];
 | 
      
         | 745 |  |  |       Iterator itr = method_set.values().iterator();
 | 
      
         | 746 |  |  |       while (--i >= 0)
 | 
      
         | 747 |  |  |         {
 | 
      
         | 748 |  |  |           ProxySignature sig = (ProxySignature) itr.next();
 | 
      
         | 749 |  |  |           data.methods[i] = sig.method;
 | 
      
         | 750 |  |  |           data.exceptions[i] = (Class[]) sig.exceptions
 | 
      
         | 751 |  |  |             .toArray(new Class[sig.exceptions.size()]);
 | 
      
         | 752 |  |  |         }
 | 
      
         | 753 |  |  |       return data;
 | 
      
         | 754 |  |  |     }
 | 
      
         | 755 |  |  |   } // class ProxyData
 | 
      
         | 756 |  |  |  
 | 
      
         | 757 |  |  |   /**
 | 
      
         | 758 |  |  |    * Does all the work of building a class. By making this a nested class,
 | 
      
         | 759 |  |  |    * this code is not loaded in memory if the VM has a native
 | 
      
         | 760 |  |  |    * implementation instead.
 | 
      
         | 761 |  |  |    *
 | 
      
         | 762 |  |  |    * @author Eric Blake (ebb9@email.byu.edu)
 | 
      
         | 763 |  |  |    */
 | 
      
         | 764 |  |  |   private static final class ClassFactory
 | 
      
         | 765 |  |  |   {
 | 
      
         | 766 |  |  |     /** Constants for assisting the compilation */
 | 
      
         | 767 |  |  |     private static final byte FIELD = 1;
 | 
      
         | 768 |  |  |     private static final byte METHOD = 2;
 | 
      
         | 769 |  |  |     private static final byte INTERFACE = 3;
 | 
      
         | 770 |  |  |     private static final String CTOR_SIG
 | 
      
         | 771 |  |  |       = "(Ljava/lang/reflect/InvocationHandler;)V";
 | 
      
         | 772 |  |  |     private static final String INVOKE_SIG = "(Ljava/lang/Object;"
 | 
      
         | 773 |  |  |       + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
 | 
      
         | 774 |  |  |  
 | 
      
         | 775 |  |  |     /** Bytecodes for insertion in the class definition byte[] */
 | 
      
         | 776 |  |  |     private static final char ACONST_NULL = 1;
 | 
      
         | 777 |  |  |     private static final char ICONST_0 = 3;
 | 
      
         | 778 |  |  |     private static final char BIPUSH = 16;
 | 
      
         | 779 |  |  |     private static final char SIPUSH = 17;
 | 
      
         | 780 |  |  |     private static final char ILOAD = 21;
 | 
      
         | 781 |  |  |     private static final char ILOAD_0 = 26;
 | 
      
         | 782 |  |  |     private static final char ALOAD_0 = 42;
 | 
      
         | 783 |  |  |     private static final char ALOAD_1 = 43;
 | 
      
         | 784 |  |  |     private static final char AALOAD = 50;
 | 
      
         | 785 |  |  |     private static final char AASTORE = 83;
 | 
      
         | 786 |  |  |     private static final char DUP = 89;
 | 
      
         | 787 |  |  |     private static final char DUP_X1 = 90;
 | 
      
         | 788 |  |  |     private static final char SWAP = 95;
 | 
      
         | 789 |  |  |     private static final char IRETURN = 172;
 | 
      
         | 790 |  |  |     private static final char LRETURN = 173;
 | 
      
         | 791 |  |  |     private static final char FRETURN = 174;
 | 
      
         | 792 |  |  |     private static final char DRETURN = 175;
 | 
      
         | 793 |  |  |     private static final char ARETURN = 176;
 | 
      
         | 794 |  |  |     private static final char RETURN = 177;
 | 
      
         | 795 |  |  |     private static final char GETSTATIC = 178;
 | 
      
         | 796 |  |  |     private static final char GETFIELD = 180;
 | 
      
         | 797 |  |  |     private static final char INVOKEVIRTUAL = 182;
 | 
      
         | 798 |  |  |     private static final char INVOKESPECIAL = 183;
 | 
      
         | 799 |  |  |     private static final char INVOKEINTERFACE = 185;
 | 
      
         | 800 |  |  |     private static final char NEW = 187;
 | 
      
         | 801 |  |  |     private static final char ANEWARRAY = 189;
 | 
      
         | 802 |  |  |     private static final char ATHROW = 191;
 | 
      
         | 803 |  |  |     private static final char CHECKCAST = 192;
 | 
      
         | 804 |  |  |  
 | 
      
         | 805 |  |  |     // Implementation note: we use StringBuffers to hold the byte data, since
 | 
      
         | 806 |  |  |     // they automatically grow.  However, we only use the low 8 bits of
 | 
      
         | 807 |  |  |     // every char in the array, so we are using twice the necessary memory
 | 
      
         | 808 |  |  |     // for the ease StringBuffer provides.
 | 
      
         | 809 |  |  |  
 | 
      
         | 810 |  |  |     /** The constant pool. */
 | 
      
         | 811 |  |  |     private final StringBuffer pool = new StringBuffer();
 | 
      
         | 812 |  |  |     /** The rest of the class data. */
 | 
      
         | 813 |  |  |     private final StringBuffer stream = new StringBuffer();
 | 
      
         | 814 |  |  |  
 | 
      
         | 815 |  |  |     /** Map of strings to byte sequences, to minimize size of pool. */
 | 
      
         | 816 |  |  |     private final Map poolEntries = new HashMap();
 | 
      
         | 817 |  |  |  
 | 
      
         | 818 |  |  |     /** The VM name of this proxy class. */
 | 
      
         | 819 |  |  |     private final String qualName;
 | 
      
         | 820 |  |  |  
 | 
      
         | 821 |  |  |     /**
 | 
      
         | 822 |  |  |      * The Method objects the proxy class refers to when calling the
 | 
      
         | 823 |  |  |      * invocation handler.
 | 
      
         | 824 |  |  |      */
 | 
      
         | 825 |  |  |     private final Method[] methods;
 | 
      
         | 826 |  |  |  
 | 
      
         | 827 |  |  |     /**
 | 
      
         | 828 |  |  |      * Initializes the buffers with the bytecode contents for a proxy class.
 | 
      
         | 829 |  |  |      *
 | 
      
         | 830 |  |  |      * @param data the remainder of the class data
 | 
      
         | 831 |  |  |      * @throws IllegalArgumentException if anything else goes wrong this
 | 
      
         | 832 |  |  |      *         late in the game; as far as I can tell, this will only happen
 | 
      
         | 833 |  |  |      *         if the constant pool overflows, which is possible even when
 | 
      
         | 834 |  |  |      *         the user doesn't exceed the 65535 interface limit
 | 
      
         | 835 |  |  |      */
 | 
      
         | 836 |  |  |     ClassFactory(ProxyData data)
 | 
      
         | 837 |  |  |     {
 | 
      
         | 838 |  |  |       methods = data.methods;
 | 
      
         | 839 |  |  |  
 | 
      
         | 840 |  |  |       // magic = 0xcafebabe
 | 
      
         | 841 |  |  |       // minor_version = 0
 | 
      
         | 842 |  |  |       // major_version = 46
 | 
      
         | 843 |  |  |       // constant_pool_count: place-holder for now
 | 
      
         | 844 |  |  |       pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0");
 | 
      
         | 845 |  |  |       // constant_pool[], filled in as we go
 | 
      
         | 846 |  |  |  
 | 
      
         | 847 |  |  |       // access_flags
 | 
      
         | 848 |  |  |       putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC);
 | 
      
         | 849 |  |  |       // this_class
 | 
      
         | 850 |  |  |       qualName = (data.pack + "$Proxy" + data.id);
 | 
      
         | 851 |  |  |       putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false)));
 | 
      
         | 852 |  |  |       // super_class
 | 
      
         | 853 |  |  |       putU2(classInfo("java/lang/reflect/Proxy"));
 | 
      
         | 854 |  |  |  
 | 
      
         | 855 |  |  |       // interfaces_count
 | 
      
         | 856 |  |  |       putU2(data.interfaces.length);
 | 
      
         | 857 |  |  |       // interfaces[]
 | 
      
         | 858 |  |  |       for (int i = 0; i < data.interfaces.length; i++)
 | 
      
         | 859 |  |  |         putU2(classInfo(data.interfaces[i]));
 | 
      
         | 860 |  |  |  
 | 
      
         | 861 |  |  |       // Recall that Proxy classes serialize specially, so we do not need
 | 
      
         | 862 |  |  |       // to worry about a <clinit> method for this field.  Instead, we
 | 
      
         | 863 |  |  |       // just assign it by reflection after the class is successfully loaded.
 | 
      
         | 864 |  |  |       // fields_count - private static Method[] m;
 | 
      
         | 865 |  |  |       putU2(1);
 | 
      
         | 866 |  |  |       // fields[]
 | 
      
         | 867 |  |  |       // m.access_flags
 | 
      
         | 868 |  |  |       putU2(Modifier.PRIVATE | Modifier.STATIC);
 | 
      
         | 869 |  |  |       // m.name_index
 | 
      
         | 870 |  |  |       putU2(utf8Info("m"));
 | 
      
         | 871 |  |  |       // m.descriptor_index
 | 
      
         | 872 |  |  |       putU2(utf8Info("[Ljava/lang/reflect/Method;"));
 | 
      
         | 873 |  |  |       // m.attributes_count
 | 
      
         | 874 |  |  |       putU2(0);
 | 
      
         | 875 |  |  |       // m.attributes[]
 | 
      
         | 876 |  |  |  
 | 
      
         | 877 |  |  |       // methods_count - # handler methods, plus <init>
 | 
      
         | 878 |  |  |       putU2(methods.length + 1);
 | 
      
         | 879 |  |  |       // methods[]
 | 
      
         | 880 |  |  |       // <init>.access_flags
 | 
      
         | 881 |  |  |       putU2(Modifier.PUBLIC);
 | 
      
         | 882 |  |  |       // <init>.name_index
 | 
      
         | 883 |  |  |       putU2(utf8Info("<init>"));
 | 
      
         | 884 |  |  |       // <init>.descriptor_index
 | 
      
         | 885 |  |  |       putU2(utf8Info(CTOR_SIG));
 | 
      
         | 886 |  |  |       // <init>.attributes_count - only Code is needed
 | 
      
         | 887 |  |  |       putU2(1);
 | 
      
         | 888 |  |  |       // <init>.Code.attribute_name_index
 | 
      
         | 889 |  |  |       putU2(utf8Info("Code"));
 | 
      
         | 890 |  |  |       // <init>.Code.attribute_length = 18
 | 
      
         | 891 |  |  |       // <init>.Code.info:
 | 
      
         | 892 |  |  |       //   $Proxynn(InvocationHandler h) { super(h); }
 | 
      
         | 893 |  |  |       // <init>.Code.max_stack = 2
 | 
      
         | 894 |  |  |       // <init>.Code.max_locals = 2
 | 
      
         | 895 |  |  |       // <init>.Code.code_length = 6
 | 
      
         | 896 |  |  |       // <init>.Code.code[]
 | 
      
         | 897 |  |  |       stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1
 | 
      
         | 898 |  |  |                     + INVOKESPECIAL);
 | 
      
         | 899 |  |  |       putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "<init>", CTOR_SIG));
 | 
      
         | 900 |  |  |       // <init>.Code.exception_table_length = 0
 | 
      
         | 901 |  |  |       // <init>.Code.exception_table[]
 | 
      
         | 902 |  |  |       // <init>.Code.attributes_count = 0
 | 
      
         | 903 |  |  |       // <init>.Code.attributes[]
 | 
      
         | 904 |  |  |       stream.append(RETURN + "\0\0\0\0");
 | 
      
         | 905 |  |  |  
 | 
      
         | 906 |  |  |       for (int i = methods.length - 1; i >= 0; i--)
 | 
      
         | 907 |  |  |         emitMethod(i, data.exceptions[i]);
 | 
      
         | 908 |  |  |  
 | 
      
         | 909 |  |  |       // attributes_count
 | 
      
         | 910 |  |  |       putU2(0);
 | 
      
         | 911 |  |  |       // attributes[] - empty; omit SourceFile attribute
 | 
      
         | 912 |  |  |       // XXX should we mark this with a Synthetic attribute?
 | 
      
         | 913 |  |  |     }
 | 
      
         | 914 |  |  |  
 | 
      
         | 915 |  |  |     /**
 | 
      
         | 916 |  |  |      * Produce the bytecode for a single method.
 | 
      
         | 917 |  |  |      *
 | 
      
         | 918 |  |  |      * @param i the index of the method we are building
 | 
      
         | 919 |  |  |      * @param e the exceptions possible for the method
 | 
      
         | 920 |  |  |      */
 | 
      
         | 921 |  |  |     private void emitMethod(int i, Class[] e)
 | 
      
         | 922 |  |  |     {
 | 
      
         | 923 |  |  |       // First, we precalculate the method length and other information.
 | 
      
         | 924 |  |  |  
 | 
      
         | 925 |  |  |       Method m = methods[i];
 | 
      
         | 926 |  |  |       Class[] paramtypes = m.getParameterTypes();
 | 
      
         | 927 |  |  |       int wrap_overhead = 0; // max words taken by wrapped primitive
 | 
      
         | 928 |  |  |       int param_count = 1; // 1 for this
 | 
      
         | 929 |  |  |       int code_length = 16; // aload_0, getfield, aload_0, getstatic, const,
 | 
      
         | 930 |  |  |       // aaload, const/aconst_null, invokeinterface
 | 
      
         | 931 |  |  |       if (i > 5)
 | 
      
         | 932 |  |  |         {
 | 
      
         | 933 |  |  |           if (i > Byte.MAX_VALUE)
 | 
      
         | 934 |  |  |             code_length += 2; // sipush
 | 
      
         | 935 |  |  |           else
 | 
      
         | 936 |  |  |             code_length++; // bipush
 | 
      
         | 937 |  |  |         }
 | 
      
         | 938 |  |  |       if (paramtypes.length > 0)
 | 
      
         | 939 |  |  |         {
 | 
      
         | 940 |  |  |           code_length += 3; // anewarray
 | 
      
         | 941 |  |  |           if (paramtypes.length > Byte.MAX_VALUE)
 | 
      
         | 942 |  |  |             code_length += 2; // sipush
 | 
      
         | 943 |  |  |           else if (paramtypes.length > 5)
 | 
      
         | 944 |  |  |             code_length++; // bipush
 | 
      
         | 945 |  |  |           for (int j = 0; j < paramtypes.length; j++)
 | 
      
         | 946 |  |  |             {
 | 
      
         | 947 |  |  |               code_length += 4; // dup, const, load, store
 | 
      
         | 948 |  |  |               Class type = paramtypes[j];
 | 
      
         | 949 |  |  |               if (j > 5)
 | 
      
         | 950 |  |  |                 {
 | 
      
         | 951 |  |  |                   if (j > Byte.MAX_VALUE)
 | 
      
         | 952 |  |  |                     code_length += 2; // sipush
 | 
      
         | 953 |  |  |                   else
 | 
      
         | 954 |  |  |                     code_length++; // bipush
 | 
      
         | 955 |  |  |                 }
 | 
      
         | 956 |  |  |               if (param_count >= 4)
 | 
      
         | 957 |  |  |                 code_length++; // 2-byte load
 | 
      
         | 958 |  |  |               param_count++;
 | 
      
         | 959 |  |  |               if (type.isPrimitive())
 | 
      
         | 960 |  |  |                 {
 | 
      
         | 961 |  |  |                   code_length += 7; // new, dup, invokespecial
 | 
      
         | 962 |  |  |                   if (type == long.class || type == double.class)
 | 
      
         | 963 |  |  |                     {
 | 
      
         | 964 |  |  |                       wrap_overhead = 3;
 | 
      
         | 965 |  |  |                       param_count++;
 | 
      
         | 966 |  |  |                     }
 | 
      
         | 967 |  |  |                   else if (wrap_overhead < 2)
 | 
      
         | 968 |  |  |                     wrap_overhead = 2;
 | 
      
         | 969 |  |  |                 }
 | 
      
         | 970 |  |  |             }
 | 
      
         | 971 |  |  |         }
 | 
      
         | 972 |  |  |       int end_pc = code_length;
 | 
      
         | 973 |  |  |       Class ret_type = m.getReturnType();
 | 
      
         | 974 |  |  |       if (ret_type == void.class)
 | 
      
         | 975 |  |  |         code_length++; // return
 | 
      
         | 976 |  |  |       else if (ret_type.isPrimitive())
 | 
      
         | 977 |  |  |         code_length += 7; // cast, invokevirtual, return
 | 
      
         | 978 |  |  |       else
 | 
      
         | 979 |  |  |         code_length += 4; // cast, return
 | 
      
         | 980 |  |  |       int exception_count = 0;
 | 
      
         | 981 |  |  |       boolean throws_throwable = false;
 | 
      
         | 982 |  |  |       for (int j = 0; j < e.length; j++)
 | 
      
         | 983 |  |  |         if (e[j] == Throwable.class)
 | 
      
         | 984 |  |  |           {
 | 
      
         | 985 |  |  |             throws_throwable = true;
 | 
      
         | 986 |  |  |             break;
 | 
      
         | 987 |  |  |           }
 | 
      
         | 988 |  |  |       if (! throws_throwable)
 | 
      
         | 989 |  |  |         {
 | 
      
         | 990 |  |  |           exception_count = e.length + 3; // Throwable, Error, RuntimeException
 | 
      
         | 991 |  |  |           code_length += 9; // new, dup_x1, swap, invokespecial, athrow
 | 
      
         | 992 |  |  |         }
 | 
      
         | 993 |  |  |       int handler_pc = code_length - 1;
 | 
      
         | 994 |  |  |       StringBuffer signature = new StringBuffer("(");
 | 
      
         | 995 |  |  |       for (int j = 0; j < paramtypes.length; j++)
 | 
      
         | 996 |  |  |         signature.append(TypeSignature.getEncodingOfClass(paramtypes[j]));
 | 
      
         | 997 |  |  |       signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type));
 | 
      
         | 998 |  |  |  
 | 
      
         | 999 |  |  |       // Now we have enough information to emit the method.
 | 
      
         | 1000 |  |  |  
 | 
      
         | 1001 |  |  |       // handler.access_flags
 | 
      
         | 1002 |  |  |       putU2(Modifier.PUBLIC | Modifier.FINAL);
 | 
      
         | 1003 |  |  |       // handler.name_index
 | 
      
         | 1004 |  |  |       putU2(utf8Info(m.getName()));
 | 
      
         | 1005 |  |  |       // handler.descriptor_index
 | 
      
         | 1006 |  |  |       putU2(utf8Info(signature.toString()));
 | 
      
         | 1007 |  |  |       // handler.attributes_count - Code is necessary, Exceptions possible
 | 
      
         | 1008 |  |  |       putU2(e.length > 0 ? 2 : 1);
 | 
      
         | 1009 |  |  |  
 | 
      
         | 1010 |  |  |       // handler.Code.info:
 | 
      
         | 1011 |  |  |       //   type name(args) {
 | 
      
         | 1012 |  |  |       //     try {
 | 
      
         | 1013 |  |  |       //       return (type) h.invoke(this, methods[i], new Object[] {args});
 | 
      
         | 1014 |  |  |       //     } catch (<declared Exceptions> e) {
 | 
      
         | 1015 |  |  |       //       throw e;
 | 
      
         | 1016 |  |  |       //     } catch (Throwable t) {
 | 
      
         | 1017 |  |  |       //       throw new UndeclaredThrowableException(t);
 | 
      
         | 1018 |  |  |       //     }
 | 
      
         | 1019 |  |  |       //   }
 | 
      
         | 1020 |  |  |       // Special cases:
 | 
      
         | 1021 |  |  |       //  if arg_n is primitive, wrap it
 | 
      
         | 1022 |  |  |       //  if method throws Throwable, try-catch is not needed
 | 
      
         | 1023 |  |  |       //  if method returns void, return statement not needed
 | 
      
         | 1024 |  |  |       //  if method returns primitive, unwrap it
 | 
      
         | 1025 |  |  |       //  save space by sharing code for all the declared handlers
 | 
      
         | 1026 |  |  |  
 | 
      
         | 1027 |  |  |       // handler.Code.attribute_name_index
 | 
      
         | 1028 |  |  |       putU2(utf8Info("Code"));
 | 
      
         | 1029 |  |  |       // handler.Code.attribute_length
 | 
      
         | 1030 |  |  |       putU4(12 + code_length + 8 * exception_count);
 | 
      
         | 1031 |  |  |       // handler.Code.max_stack
 | 
      
         | 1032 |  |  |       putU2(param_count == 1 ? 4 : 7 + wrap_overhead);
 | 
      
         | 1033 |  |  |       // handler.Code.max_locals
 | 
      
         | 1034 |  |  |       putU2(param_count);
 | 
      
         | 1035 |  |  |       // handler.Code.code_length
 | 
      
         | 1036 |  |  |       putU4(code_length);
 | 
      
         | 1037 |  |  |       // handler.Code.code[]
 | 
      
         | 1038 |  |  |       putU1(ALOAD_0);
 | 
      
         | 1039 |  |  |       putU1(GETFIELD);
 | 
      
         | 1040 |  |  |       putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h",
 | 
      
         | 1041 |  |  |                     "Ljava/lang/reflect/InvocationHandler;"));
 | 
      
         | 1042 |  |  |       putU1(ALOAD_0);
 | 
      
         | 1043 |  |  |       putU1(GETSTATIC);
 | 
      
         | 1044 |  |  |       putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false),
 | 
      
         | 1045 |  |  |                     "m", "[Ljava/lang/reflect/Method;"));
 | 
      
         | 1046 |  |  |       putConst(i);
 | 
      
         | 1047 |  |  |       putU1(AALOAD);
 | 
      
         | 1048 |  |  |       if (paramtypes.length > 0)
 | 
      
         | 1049 |  |  |         {
 | 
      
         | 1050 |  |  |           putConst(paramtypes.length);
 | 
      
         | 1051 |  |  |           putU1(ANEWARRAY);
 | 
      
         | 1052 |  |  |           putU2(classInfo("java/lang/Object"));
 | 
      
         | 1053 |  |  |           param_count = 1;
 | 
      
         | 1054 |  |  |           for (int j = 0; j < paramtypes.length; j++, param_count++)
 | 
      
         | 1055 |  |  |             {
 | 
      
         | 1056 |  |  |               putU1(DUP);
 | 
      
         | 1057 |  |  |               putConst(j);
 | 
      
         | 1058 |  |  |               if (paramtypes[j].isPrimitive())
 | 
      
         | 1059 |  |  |                 {
 | 
      
         | 1060 |  |  |                   putU1(NEW);
 | 
      
         | 1061 |  |  |                   putU2(classInfo(wrapper(paramtypes[j])));
 | 
      
         | 1062 |  |  |                   putU1(DUP);
 | 
      
         | 1063 |  |  |                 }
 | 
      
         | 1064 |  |  |               putLoad(param_count, paramtypes[j]);
 | 
      
         | 1065 |  |  |               if (paramtypes[j].isPrimitive())
 | 
      
         | 1066 |  |  |                 {
 | 
      
         | 1067 |  |  |                   putU1(INVOKESPECIAL);
 | 
      
         | 1068 |  |  |                   putU2(refInfo(METHOD, wrapper(paramtypes[j]), "<init>",
 | 
      
         | 1069 |  |  |                                 '(' + (TypeSignature
 | 
      
         | 1070 |  |  |                                        .getEncodingOfClass(paramtypes[j])
 | 
      
         | 1071 |  |  |                                        + ")V")));
 | 
      
         | 1072 |  |  |                   if (paramtypes[j] == long.class
 | 
      
         | 1073 |  |  |                       || paramtypes[j] == double.class)
 | 
      
         | 1074 |  |  |                     param_count++;
 | 
      
         | 1075 |  |  |                 }
 | 
      
         | 1076 |  |  |               putU1(AASTORE);
 | 
      
         | 1077 |  |  |             }
 | 
      
         | 1078 |  |  |         }
 | 
      
         | 1079 |  |  |       else
 | 
      
         | 1080 |  |  |         putU1(ACONST_NULL);
 | 
      
         | 1081 |  |  |       putU1(INVOKEINTERFACE);
 | 
      
         | 1082 |  |  |       putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler",
 | 
      
         | 1083 |  |  |                     "invoke", INVOKE_SIG));
 | 
      
         | 1084 |  |  |       putU1(4); // InvocationHandler, this, Method, Object[]
 | 
      
         | 1085 |  |  |       putU1(0);
 | 
      
         | 1086 |  |  |       if (ret_type == void.class)
 | 
      
         | 1087 |  |  |         putU1(RETURN);
 | 
      
         | 1088 |  |  |       else if (ret_type.isPrimitive())
 | 
      
         | 1089 |  |  |         {
 | 
      
         | 1090 |  |  |           putU1(CHECKCAST);
 | 
      
         | 1091 |  |  |           putU2(classInfo(wrapper(ret_type)));
 | 
      
         | 1092 |  |  |           putU1(INVOKEVIRTUAL);
 | 
      
         | 1093 |  |  |           putU2(refInfo(METHOD, wrapper(ret_type),
 | 
      
         | 1094 |  |  |                         ret_type.getName() + "Value",
 | 
      
         | 1095 |  |  |                         "()" + TypeSignature.getEncodingOfClass(ret_type)));
 | 
      
         | 1096 |  |  |           if (ret_type == long.class)
 | 
      
         | 1097 |  |  |             putU1(LRETURN);
 | 
      
         | 1098 |  |  |           else if (ret_type == float.class)
 | 
      
         | 1099 |  |  |             putU1(FRETURN);
 | 
      
         | 1100 |  |  |           else if (ret_type == double.class)
 | 
      
         | 1101 |  |  |             putU1(DRETURN);
 | 
      
         | 1102 |  |  |           else
 | 
      
         | 1103 |  |  |             putU1(IRETURN);
 | 
      
         | 1104 |  |  |         }
 | 
      
         | 1105 |  |  |       else
 | 
      
         | 1106 |  |  |         {
 | 
      
         | 1107 |  |  |           putU1(CHECKCAST);
 | 
      
         | 1108 |  |  |           putU2(classInfo(ret_type));
 | 
      
         | 1109 |  |  |           putU1(ARETURN);
 | 
      
         | 1110 |  |  |         }
 | 
      
         | 1111 |  |  |       if (! throws_throwable)
 | 
      
         | 1112 |  |  |         {
 | 
      
         | 1113 |  |  |           putU1(NEW);
 | 
      
         | 1114 |  |  |           putU2(classInfo("java/lang/reflect/UndeclaredThrowableException"));
 | 
      
         | 1115 |  |  |           putU1(DUP_X1);
 | 
      
         | 1116 |  |  |           putU1(SWAP);
 | 
      
         | 1117 |  |  |           putU1(INVOKESPECIAL);
 | 
      
         | 1118 |  |  |           putU2(refInfo(METHOD,
 | 
      
         | 1119 |  |  |                         "java/lang/reflect/UndeclaredThrowableException",
 | 
      
         | 1120 |  |  |                         "<init>", "(Ljava/lang/Throwable;)V"));
 | 
      
         | 1121 |  |  |           putU1(ATHROW);
 | 
      
         | 1122 |  |  |         }
 | 
      
         | 1123 |  |  |  
 | 
      
         | 1124 |  |  |       // handler.Code.exception_table_length
 | 
      
         | 1125 |  |  |       putU2(exception_count);
 | 
      
         | 1126 |  |  |       // handler.Code.exception_table[]
 | 
      
         | 1127 |  |  |       if (! throws_throwable)
 | 
      
         | 1128 |  |  |         {
 | 
      
         | 1129 |  |  |           // handler.Code.exception_table.start_pc
 | 
      
         | 1130 |  |  |           putU2(0);
 | 
      
         | 1131 |  |  |           // handler.Code.exception_table.end_pc
 | 
      
         | 1132 |  |  |           putU2(end_pc);
 | 
      
         | 1133 |  |  |           // handler.Code.exception_table.handler_pc
 | 
      
         | 1134 |  |  |           putU2(handler_pc);
 | 
      
         | 1135 |  |  |           // handler.Code.exception_table.catch_type
 | 
      
         | 1136 |  |  |           putU2(classInfo("java/lang/Error"));
 | 
      
         | 1137 |  |  |           // handler.Code.exception_table.start_pc
 | 
      
         | 1138 |  |  |           putU2(0);
 | 
      
         | 1139 |  |  |           // handler.Code.exception_table.end_pc
 | 
      
         | 1140 |  |  |           putU2(end_pc);
 | 
      
         | 1141 |  |  |           // handler.Code.exception_table.handler_pc
 | 
      
         | 1142 |  |  |           putU2(handler_pc);
 | 
      
         | 1143 |  |  |           // handler.Code.exception_table.catch_type
 | 
      
         | 1144 |  |  |           putU2(classInfo("java/lang/RuntimeException"));
 | 
      
         | 1145 |  |  |           for (int j = 0; j < e.length; j++)
 | 
      
         | 1146 |  |  |             {
 | 
      
         | 1147 |  |  |               // handler.Code.exception_table.start_pc
 | 
      
         | 1148 |  |  |               putU2(0);
 | 
      
         | 1149 |  |  |               // handler.Code.exception_table.end_pc
 | 
      
         | 1150 |  |  |               putU2(end_pc);
 | 
      
         | 1151 |  |  |               // handler.Code.exception_table.handler_pc
 | 
      
         | 1152 |  |  |               putU2(handler_pc);
 | 
      
         | 1153 |  |  |               // handler.Code.exception_table.catch_type
 | 
      
         | 1154 |  |  |               putU2(classInfo(e[j]));
 | 
      
         | 1155 |  |  |             }
 | 
      
         | 1156 |  |  |           // handler.Code.exception_table.start_pc
 | 
      
         | 1157 |  |  |           putU2(0);
 | 
      
         | 1158 |  |  |           // handler.Code.exception_table.end_pc
 | 
      
         | 1159 |  |  |           putU2(end_pc);
 | 
      
         | 1160 |  |  |           // handler.Code.exception_table.handler_pc -
 | 
      
         | 1161 |  |  |           //   -8 for undeclared handler, which falls thru to normal one
 | 
      
         | 1162 |  |  |           putU2(handler_pc - 8);
 | 
      
         | 1163 |  |  |           // handler.Code.exception_table.catch_type
 | 
      
         | 1164 |  |  |           putU2(0);
 | 
      
         | 1165 |  |  |         }
 | 
      
         | 1166 |  |  |       // handler.Code.attributes_count
 | 
      
         | 1167 |  |  |       putU2(0);
 | 
      
         | 1168 |  |  |       // handler.Code.attributes[]
 | 
      
         | 1169 |  |  |  
 | 
      
         | 1170 |  |  |       if (e.length > 0)
 | 
      
         | 1171 |  |  |         {
 | 
      
         | 1172 |  |  |           // handler.Exceptions.attribute_name_index
 | 
      
         | 1173 |  |  |           putU2(utf8Info("Exceptions"));
 | 
      
         | 1174 |  |  |           // handler.Exceptions.attribute_length
 | 
      
         | 1175 |  |  |           putU4(2 * e.length + 2);
 | 
      
         | 1176 |  |  |           // handler.Exceptions.number_of_exceptions
 | 
      
         | 1177 |  |  |           putU2(e.length);
 | 
      
         | 1178 |  |  |           // handler.Exceptions.exception_index_table[]
 | 
      
         | 1179 |  |  |           for (int j = 0; j < e.length; j++)
 | 
      
         | 1180 |  |  |             putU2(classInfo(e[j]));
 | 
      
         | 1181 |  |  |         }
 | 
      
         | 1182 |  |  |     }
 | 
      
         | 1183 |  |  |  
 | 
      
         | 1184 |  |  |     /**
 | 
      
         | 1185 |  |  |      * Creates the Class object that corresponds to the bytecode buffers
 | 
      
         | 1186 |  |  |      * built when this object was constructed.
 | 
      
         | 1187 |  |  |      *
 | 
      
         | 1188 |  |  |      * @param loader the class loader to define the proxy class in; null
 | 
      
         | 1189 |  |  |      *        implies the bootstrap class loader
 | 
      
         | 1190 |  |  |      * @return the proxy class Class object
 | 
      
         | 1191 |  |  |      */
 | 
      
         | 1192 |  |  |     Class generate(ClassLoader loader)
 | 
      
         | 1193 |  |  |     {
 | 
      
         | 1194 |  |  |       byte[] bytecode = new byte[pool.length() + stream.length()];
 | 
      
         | 1195 |  |  |       // More efficient to bypass calling charAt() repetitively.
 | 
      
         | 1196 |  |  |       char[] c = pool.toString().toCharArray();
 | 
      
         | 1197 |  |  |       int i = c.length;
 | 
      
         | 1198 |  |  |       while (--i >= 0)
 | 
      
         | 1199 |  |  |         bytecode[i] = (byte) c[i];
 | 
      
         | 1200 |  |  |       c = stream.toString().toCharArray();
 | 
      
         | 1201 |  |  |       i = c.length;
 | 
      
         | 1202 |  |  |       int j = bytecode.length;
 | 
      
         | 1203 |  |  |       while (i > 0)
 | 
      
         | 1204 |  |  |         bytecode[--j] = (byte) c[--i];
 | 
      
         | 1205 |  |  |  
 | 
      
         | 1206 |  |  |       // Patch the constant pool size, which we left at 0 earlier.
 | 
      
         | 1207 |  |  |       int count = poolEntries.size() + 1;
 | 
      
         | 1208 |  |  |       bytecode[8] = (byte) (count >> 8);
 | 
      
         | 1209 |  |  |       bytecode[9] = (byte) count;
 | 
      
         | 1210 |  |  |  
 | 
      
         | 1211 |  |  |       try
 | 
      
         | 1212 |  |  |         {
 | 
      
         | 1213 |  |  |           Class vmClassLoader = Class.forName("java.lang.VMClassLoader");
 | 
      
         | 1214 |  |  |           Class[] types = {ClassLoader.class, String.class,
 | 
      
         | 1215 |  |  |                            byte[].class, int.class, int.class,
 | 
      
         | 1216 |  |  |                            ProtectionDomain.class };
 | 
      
         | 1217 |  |  |           Method m = vmClassLoader.getDeclaredMethod("defineClass", types);
 | 
      
         | 1218 |  |  |           // We can bypass the security check of setAccessible(true), since
 | 
      
         | 1219 |  |  |           // we're in the same package.
 | 
      
         | 1220 |  |  |           m.flag = true;
 | 
      
         | 1221 |  |  |  
 | 
      
         | 1222 |  |  |           Object[] args = {loader, qualName, bytecode, new Integer(0),
 | 
      
         | 1223 |  |  |                            new Integer(bytecode.length),
 | 
      
         | 1224 |  |  |                            Object.class.getProtectionDomain() };
 | 
      
         | 1225 |  |  |           Class clazz = (Class) m.invoke(null, args);
 | 
      
         | 1226 |  |  |  
 | 
      
         | 1227 |  |  |           // Finally, initialize the m field of the proxy class, before
 | 
      
         | 1228 |  |  |           // returning it.
 | 
      
         | 1229 |  |  |           Field f = clazz.getDeclaredField("m");
 | 
      
         | 1230 |  |  |           f.flag = true;
 | 
      
         | 1231 |  |  |           // we can share the array, because it is not publicized
 | 
      
         | 1232 |  |  |           f.set(null, methods);
 | 
      
         | 1233 |  |  |  
 | 
      
         | 1234 |  |  |           return clazz;
 | 
      
         | 1235 |  |  |         }
 | 
      
         | 1236 |  |  |       catch (Exception e)
 | 
      
         | 1237 |  |  |         {
 | 
      
         | 1238 |  |  |           // assert false;
 | 
      
         | 1239 |  |  |           throw (Error) new InternalError("Unexpected: " + e).initCause(e);
 | 
      
         | 1240 |  |  |         }
 | 
      
         | 1241 |  |  |     }
 | 
      
         | 1242 |  |  |  
 | 
      
         | 1243 |  |  |     /**
 | 
      
         | 1244 |  |  |      * Put a single byte on the stream.
 | 
      
         | 1245 |  |  |      *
 | 
      
         | 1246 |  |  |      * @param i the information to add (only lowest 8 bits are used)
 | 
      
         | 1247 |  |  |      */
 | 
      
         | 1248 |  |  |     private void putU1(int i)
 | 
      
         | 1249 |  |  |     {
 | 
      
         | 1250 |  |  |       stream.append((char) i);
 | 
      
         | 1251 |  |  |     }
 | 
      
         | 1252 |  |  |  
 | 
      
         | 1253 |  |  |     /**
 | 
      
         | 1254 |  |  |      * Put two bytes on the stream.
 | 
      
         | 1255 |  |  |      *
 | 
      
         | 1256 |  |  |      * @param i the information to add (only lowest 16 bits are used)
 | 
      
         | 1257 |  |  |      */
 | 
      
         | 1258 |  |  |     private void putU2(int i)
 | 
      
         | 1259 |  |  |     {
 | 
      
         | 1260 |  |  |       stream.append((char) (i >> 8)).append((char) i);
 | 
      
         | 1261 |  |  |     }
 | 
      
         | 1262 |  |  |  
 | 
      
         | 1263 |  |  |     /**
 | 
      
         | 1264 |  |  |      * Put four bytes on the stream.
 | 
      
         | 1265 |  |  |      *
 | 
      
         | 1266 |  |  |      * @param i the information to add (treated as unsigned)
 | 
      
         | 1267 |  |  |      */
 | 
      
         | 1268 |  |  |     private void putU4(int i)
 | 
      
         | 1269 |  |  |     {
 | 
      
         | 1270 |  |  |       stream.append((char) (i >> 24)).append((char) (i >> 16));
 | 
      
         | 1271 |  |  |       stream.append((char) (i >> 8)).append((char) i);
 | 
      
         | 1272 |  |  |     }
 | 
      
         | 1273 |  |  |  
 | 
      
         | 1274 |  |  |     /**
 | 
      
         | 1275 |  |  |      * Put bytecode to load a constant integer on the stream. This only
 | 
      
         | 1276 |  |  |      * needs to work for values less than Short.MAX_VALUE.
 | 
      
         | 1277 |  |  |      *
 | 
      
         | 1278 |  |  |      * @param i the int to add
 | 
      
         | 1279 |  |  |      */
 | 
      
         | 1280 |  |  |     private void putConst(int i)
 | 
      
         | 1281 |  |  |     {
 | 
      
         | 1282 |  |  |       if (i >= -1 && i <= 5)
 | 
      
         | 1283 |  |  |         putU1(ICONST_0 + i);
 | 
      
         | 1284 |  |  |       else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE)
 | 
      
         | 1285 |  |  |         {
 | 
      
         | 1286 |  |  |           putU1(BIPUSH);
 | 
      
         | 1287 |  |  |           putU1(i);
 | 
      
         | 1288 |  |  |         }
 | 
      
         | 1289 |  |  |       else
 | 
      
         | 1290 |  |  |         {
 | 
      
         | 1291 |  |  |           putU1(SIPUSH);
 | 
      
         | 1292 |  |  |           putU2(i);
 | 
      
         | 1293 |  |  |         }
 | 
      
         | 1294 |  |  |     }
 | 
      
         | 1295 |  |  |  
 | 
      
         | 1296 |  |  |     /**
 | 
      
         | 1297 |  |  |      * Put bytecode to load a given local variable on the stream.
 | 
      
         | 1298 |  |  |      *
 | 
      
         | 1299 |  |  |      * @param i the slot to load
 | 
      
         | 1300 |  |  |      * @param type the base type of the load
 | 
      
         | 1301 |  |  |      */
 | 
      
         | 1302 |  |  |     private void putLoad(int i, Class type)
 | 
      
         | 1303 |  |  |     {
 | 
      
         | 1304 |  |  |       int offset = 0;
 | 
      
         | 1305 |  |  |       if (type == long.class)
 | 
      
         | 1306 |  |  |         offset = 1;
 | 
      
         | 1307 |  |  |       else if (type == float.class)
 | 
      
         | 1308 |  |  |         offset = 2;
 | 
      
         | 1309 |  |  |       else if (type == double.class)
 | 
      
         | 1310 |  |  |         offset = 3;
 | 
      
         | 1311 |  |  |       else if (! type.isPrimitive())
 | 
      
         | 1312 |  |  |         offset = 4;
 | 
      
         | 1313 |  |  |       if (i < 4)
 | 
      
         | 1314 |  |  |         putU1(ILOAD_0 + 4 * offset + i);
 | 
      
         | 1315 |  |  |       else
 | 
      
         | 1316 |  |  |         {
 | 
      
         | 1317 |  |  |           putU1(ILOAD + offset);
 | 
      
         | 1318 |  |  |           putU1(i);
 | 
      
         | 1319 |  |  |         }
 | 
      
         | 1320 |  |  |     }
 | 
      
         | 1321 |  |  |  
 | 
      
         | 1322 |  |  |     /**
 | 
      
         | 1323 |  |  |      * Given a primitive type, return its wrapper class name.
 | 
      
         | 1324 |  |  |      *
 | 
      
         | 1325 |  |  |      * @param clazz the primitive type (but not void.class)
 | 
      
         | 1326 |  |  |      * @return the internal form of the wrapper class name
 | 
      
         | 1327 |  |  |      */
 | 
      
         | 1328 |  |  |     private String wrapper(Class clazz)
 | 
      
         | 1329 |  |  |     {
 | 
      
         | 1330 |  |  |       if (clazz == boolean.class)
 | 
      
         | 1331 |  |  |         return "java/lang/Boolean";
 | 
      
         | 1332 |  |  |       if (clazz == byte.class)
 | 
      
         | 1333 |  |  |         return "java/lang/Byte";
 | 
      
         | 1334 |  |  |       if (clazz == short.class)
 | 
      
         | 1335 |  |  |         return "java/lang/Short";
 | 
      
         | 1336 |  |  |       if (clazz == char.class)
 | 
      
         | 1337 |  |  |         return "java/lang/Character";
 | 
      
         | 1338 |  |  |       if (clazz == int.class)
 | 
      
         | 1339 |  |  |         return "java/lang/Integer";
 | 
      
         | 1340 |  |  |       if (clazz == long.class)
 | 
      
         | 1341 |  |  |         return "java/lang/Long";
 | 
      
         | 1342 |  |  |       if (clazz == float.class)
 | 
      
         | 1343 |  |  |         return "java/lang/Float";
 | 
      
         | 1344 |  |  |       if (clazz == double.class)
 | 
      
         | 1345 |  |  |         return "java/lang/Double";
 | 
      
         | 1346 |  |  |       // assert false;
 | 
      
         | 1347 |  |  |       return null;
 | 
      
         | 1348 |  |  |     }
 | 
      
         | 1349 |  |  |  
 | 
      
         | 1350 |  |  |     /**
 | 
      
         | 1351 |  |  |      * Returns the entry of this String in the Constant pool, adding it
 | 
      
         | 1352 |  |  |      * if necessary.
 | 
      
         | 1353 |  |  |      *
 | 
      
         | 1354 |  |  |      * @param str the String to resolve
 | 
      
         | 1355 |  |  |      * @return the index of the String in the constant pool
 | 
      
         | 1356 |  |  |      */
 | 
      
         | 1357 |  |  |     private char utf8Info(String str)
 | 
      
         | 1358 |  |  |     {
 | 
      
         | 1359 |  |  |       String utf8 = toUtf8(str);
 | 
      
         | 1360 |  |  |       int len = utf8.length();
 | 
      
         | 1361 |  |  |       return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8);
 | 
      
         | 1362 |  |  |     }
 | 
      
         | 1363 |  |  |  
 | 
      
         | 1364 |  |  |     /**
 | 
      
         | 1365 |  |  |      * Returns the entry of the appropriate class info structure in the
 | 
      
         | 1366 |  |  |      * Constant pool, adding it if necessary.
 | 
      
         | 1367 |  |  |      *
 | 
      
         | 1368 |  |  |      * @param name the class name, in internal form
 | 
      
         | 1369 |  |  |      * @return the index of the ClassInfo in the constant pool
 | 
      
         | 1370 |  |  |      */
 | 
      
         | 1371 |  |  |     private char classInfo(String name)
 | 
      
         | 1372 |  |  |     {
 | 
      
         | 1373 |  |  |       char index = utf8Info(name);
 | 
      
         | 1374 |  |  |       char[] c = {7, (char) (index >> 8), (char) (index & 0xff)};
 | 
      
         | 1375 |  |  |       return poolIndex(new String(c));
 | 
      
         | 1376 |  |  |     }
 | 
      
         | 1377 |  |  |  
 | 
      
         | 1378 |  |  |     /**
 | 
      
         | 1379 |  |  |      * Returns the entry of the appropriate class info structure in the
 | 
      
         | 1380 |  |  |      * Constant pool, adding it if necessary.
 | 
      
         | 1381 |  |  |      *
 | 
      
         | 1382 |  |  |      * @param clazz the class type
 | 
      
         | 1383 |  |  |      * @return the index of the ClassInfo in the constant pool
 | 
      
         | 1384 |  |  |      */
 | 
      
         | 1385 |  |  |     private char classInfo(Class clazz)
 | 
      
         | 1386 |  |  |     {
 | 
      
         | 1387 |  |  |       return classInfo(TypeSignature.getEncodingOfClass(clazz.getName(),
 | 
      
         | 1388 |  |  |                                                         false));
 | 
      
         | 1389 |  |  |     }
 | 
      
         | 1390 |  |  |  
 | 
      
         | 1391 |  |  |     /**
 | 
      
         | 1392 |  |  |      * Returns the entry of the appropriate fieldref, methodref, or
 | 
      
         | 1393 |  |  |      * interfacemethodref info structure in the Constant pool, adding it
 | 
      
         | 1394 |  |  |      * if necessary.
 | 
      
         | 1395 |  |  |      *
 | 
      
         | 1396 |  |  |      * @param structure FIELD, METHOD, or INTERFACE
 | 
      
         | 1397 |  |  |      * @param clazz the class name, in internal form
 | 
      
         | 1398 |  |  |      * @param name the simple reference name
 | 
      
         | 1399 |  |  |      * @param type the type of the reference
 | 
      
         | 1400 |  |  |      * @return the index of the appropriate Info structure in the constant pool
 | 
      
         | 1401 |  |  |      */
 | 
      
         | 1402 |  |  |     private char refInfo(byte structure, String clazz, String name,
 | 
      
         | 1403 |  |  |                          String type)
 | 
      
         | 1404 |  |  |     {
 | 
      
         | 1405 |  |  |       char cindex = classInfo(clazz);
 | 
      
         | 1406 |  |  |       char ntindex = nameAndTypeInfo(name, type);
 | 
      
         | 1407 |  |  |       // relies on FIELD == 1, METHOD == 2, INTERFACE == 3
 | 
      
         | 1408 |  |  |       char[] c = {(char) (structure + 8),
 | 
      
         | 1409 |  |  |                   (char) (cindex >> 8), (char) (cindex & 0xff),
 | 
      
         | 1410 |  |  |                   (char) (ntindex >> 8), (char) (ntindex & 0xff)};
 | 
      
         | 1411 |  |  |       return poolIndex(new String(c));
 | 
      
         | 1412 |  |  |     }
 | 
      
         | 1413 |  |  |  
 | 
      
         | 1414 |  |  |     /**
 | 
      
         | 1415 |  |  |      * Returns the entry of the appropriate nameAndTyperef info structure
 | 
      
         | 1416 |  |  |      * in the Constant pool, adding it if necessary.
 | 
      
         | 1417 |  |  |      *
 | 
      
         | 1418 |  |  |      * @param name the simple name
 | 
      
         | 1419 |  |  |      * @param type the reference type
 | 
      
         | 1420 |  |  |      * @return the index of the NameAndTypeInfo structure in the constant pool
 | 
      
         | 1421 |  |  |      */
 | 
      
         | 1422 |  |  |     private char nameAndTypeInfo(String name, String type)
 | 
      
         | 1423 |  |  |     {
 | 
      
         | 1424 |  |  |       char nindex = utf8Info(name);
 | 
      
         | 1425 |  |  |       char tindex = utf8Info(type);
 | 
      
         | 1426 |  |  |       char[] c = {12, (char) (nindex >> 8), (char) (nindex & 0xff),
 | 
      
         | 1427 |  |  |                   (char) (tindex >> 8), (char) (tindex & 0xff)};
 | 
      
         | 1428 |  |  |       return poolIndex(new String(c));
 | 
      
         | 1429 |  |  |     }
 | 
      
         | 1430 |  |  |  
 | 
      
         | 1431 |  |  |     /**
 | 
      
         | 1432 |  |  |      * Converts a regular string to a UTF8 string, where the upper byte
 | 
      
         | 1433 |  |  |      * of every char is 0, and '\\u0000' is not in the string.  This is
 | 
      
         | 1434 |  |  |      * basically to use a String as a fancy byte[], and while it is less
 | 
      
         | 1435 |  |  |      * efficient in memory use, it is easier for hashing.
 | 
      
         | 1436 |  |  |      *
 | 
      
         | 1437 |  |  |      * @param str the original, in straight unicode
 | 
      
         | 1438 |  |  |      * @return a modified string, in UTF8 format in the low bytes
 | 
      
         | 1439 |  |  |      */
 | 
      
         | 1440 |  |  |     private String toUtf8(String str)
 | 
      
         | 1441 |  |  |     {
 | 
      
         | 1442 |  |  |       final char[] ca = str.toCharArray();
 | 
      
         | 1443 |  |  |       final int len = ca.length;
 | 
      
         | 1444 |  |  |  
 | 
      
         | 1445 |  |  |       // Avoid object creation, if str is already fits UTF8.
 | 
      
         | 1446 |  |  |       int i;
 | 
      
         | 1447 |  |  |       for (i = 0; i < len; i++)
 | 
      
         | 1448 |  |  |         if (ca[i] == 0 || ca[i] > '\u007f')
 | 
      
         | 1449 |  |  |           break;
 | 
      
         | 1450 |  |  |       if (i == len)
 | 
      
         | 1451 |  |  |         return str;
 | 
      
         | 1452 |  |  |  
 | 
      
         | 1453 |  |  |       final StringBuffer sb = new StringBuffer(str);
 | 
      
         | 1454 |  |  |       sb.setLength(i);
 | 
      
         | 1455 |  |  |       for ( ; i < len; i++)
 | 
      
         | 1456 |  |  |         {
 | 
      
         | 1457 |  |  |           final char c = ca[i];
 | 
      
         | 1458 |  |  |           if (c > 0 && c <= '\u007f')
 | 
      
         | 1459 |  |  |             sb.append(c);
 | 
      
         | 1460 |  |  |           else if (c <= '\u07ff') // includes '\0'
 | 
      
         | 1461 |  |  |             {
 | 
      
         | 1462 |  |  |               sb.append((char) (0xc0 | (c >> 6)));
 | 
      
         | 1463 |  |  |               sb.append((char) (0x80 | (c & 0x6f)));
 | 
      
         | 1464 |  |  |             }
 | 
      
         | 1465 |  |  |           else
 | 
      
         | 1466 |  |  |             {
 | 
      
         | 1467 |  |  |               sb.append((char) (0xe0 | (c >> 12)));
 | 
      
         | 1468 |  |  |               sb.append((char) (0x80 | ((c >> 6) & 0x6f)));
 | 
      
         | 1469 |  |  |               sb.append((char) (0x80 | (c & 0x6f)));
 | 
      
         | 1470 |  |  |             }
 | 
      
         | 1471 |  |  |         }
 | 
      
         | 1472 |  |  |       return sb.toString();
 | 
      
         | 1473 |  |  |     }
 | 
      
         | 1474 |  |  |  
 | 
      
         | 1475 |  |  |     /**
 | 
      
         | 1476 |  |  |      * Returns the location of a byte sequence (conveniently wrapped in
 | 
      
         | 1477 |  |  |      * a String with all characters between \u0001 and \u00ff inclusive)
 | 
      
         | 1478 |  |  |      * in the constant pool, adding it if necessary.
 | 
      
         | 1479 |  |  |      *
 | 
      
         | 1480 |  |  |      * @param sequence the byte sequence to look for
 | 
      
         | 1481 |  |  |      * @return the index of the sequence
 | 
      
         | 1482 |  |  |      * @throws IllegalArgumentException if this would make the constant
 | 
      
         | 1483 |  |  |      *         pool overflow
 | 
      
         | 1484 |  |  |      */
 | 
      
         | 1485 |  |  |     private char poolIndex(String sequence)
 | 
      
         | 1486 |  |  |     {
 | 
      
         | 1487 |  |  |       Integer i = (Integer) poolEntries.get(sequence);
 | 
      
         | 1488 |  |  |       if (i == null)
 | 
      
         | 1489 |  |  |         {
 | 
      
         | 1490 |  |  |           // pool starts at index 1
 | 
      
         | 1491 |  |  |           int size = poolEntries.size() + 1;
 | 
      
         | 1492 |  |  |           if (size >= 65535)
 | 
      
         | 1493 |  |  |             throw new IllegalArgumentException("exceeds VM limitations");
 | 
      
         | 1494 |  |  |           i = new Integer(size);
 | 
      
         | 1495 |  |  |           poolEntries.put(sequence, i);
 | 
      
         | 1496 |  |  |           pool.append(sequence);
 | 
      
         | 1497 |  |  |         }
 | 
      
         | 1498 |  |  |       return (char) i.intValue();
 | 
      
         | 1499 |  |  |     }
 | 
      
         | 1500 |  |  |   } // class ClassFactory
 | 
      
         | 1501 |  |  | }
 |