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    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.lang.reflect;
040    
041    import gnu.java.lang.CPStringBuilder;
042    
043    import gnu.java.lang.reflect.TypeSignature;
044    
045    import java.io.Serializable;
046    import java.security.ProtectionDomain;
047    import java.util.Arrays;
048    import java.util.HashMap;
049    import java.util.HashSet;
050    import java.util.Iterator;
051    import java.util.Map;
052    import 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     */
163    public 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    }