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