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