1 /* Proxy.java -- build a proxy class that implements reflected interfaces
2    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package java.lang.reflect;
40 
41 import gnu.java.lang.CPStringBuilder;
42 
43 import gnu.java.lang.reflect.TypeSignature;
44 
45 import java.io.Serializable;
46 import java.security.ProtectionDomain;
47 import java.util.Arrays;
48 import java.util.HashMap;
49 import java.util.HashSet;
50 import java.util.Iterator;
51 import java.util.Map;
52 import java.util.Set;
53 
54 /**
55  * This class allows you to dynamically create an instance of any (or
56  * even multiple) interfaces by reflection, and decide at runtime
57  * how that instance will behave by giving it an appropriate
58  * {@link InvocationHandler}.  Proxy classes serialize specially, so
59  * that the proxy object can be reused between VMs, without requiring
60  * a persistent copy of the generated class code.
61  *
62  * <h3>Creation</h3>
63  * To create a proxy for some interface Foo:
64  *
65  * <pre>
66  *   InvocationHandler handler = new MyInvocationHandler(...);
67  *   Class proxyClass = Proxy.getProxyClass(
68  *       Foo.class.getClassLoader(), new Class[] { Foo.class });
69  *   Foo f = (Foo) proxyClass
70  *       .getConstructor(new Class[] { InvocationHandler.class })
71  *       .newInstance(new Object[] { handler });
72  * </pre>
73  * or more simply:
74  * <pre>
75  *   Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
76  *                                        new Class[] { Foo.class },
77  *                                        handler);
78  * </pre>
79  *
80  * <h3>Dynamic Proxy Classes</h3>
81  * A dynamic proxy class is created at runtime, and has the following
82  * properties:
83  * <ul>
84  *  <li>The class is <code>public</code> and <code>final</code>,
85  *      and is neither <code>abstract</code> nor an inner class.</li>
86  *  <li>The class has no canonical name (there is no formula you can use
87  *      to determine or generate its name), but begins with the
88  *      sequence "$Proxy".  Abuse this knowledge at your own peril.
89  *      (For now, '$' in user identifiers is legal, but it may not
90  *      be that way forever. You weren't using '$' in your
91  *      identifiers, were you?)</li>
92  *  <li>The class extends Proxy, and explicitly implements all the
93  *      interfaces specified at creation, in order (this is important
94  *      for determining how method invocation is resolved).  Note that
95  *      a proxy class implements {@link Serializable}, at least
96  *      implicitly, since Proxy does, but true serial behavior
97  *      depends on using a serializable invocation handler as well.</li>
98  *  <li>If at least one interface is non-public, the proxy class
99  *      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    */
Proxy(InvocationHandler handler)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
getProxyClass(ClassLoader loader, Class<?>... interfaces)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    */
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler)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.
isProxyClass(Class<?> clazz)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    */
getInvocationHandler(Object proxy)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      */
ProxyType(ClassLoader loader, Class[] interfaces)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      */
hashCode()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      */
equals(Object other)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}));
coreMethods.put(sig, sig)475           coreMethods.put(sig, sig);
476           sig = new ProxySignature(Object.class.getMethod("hashCode"));
coreMethods.put(sig, sig)477           coreMethods.put(sig, sig);
478           sig = new ProxySignature(Object.class.getMethod("toString"));
coreMethods.put(sig, sig)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      */
ProxySignature(Method method)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      */
checkCompatibility(ProxySignature other)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      */
hashCode()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      */
equals(Object other)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      */
ProxyData()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      */
getPackage(Class k)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      */
getProxyData(ProxyType pt)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      */
isCoreObjectMethod(Method method)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      */
ClassFactory(ProxyData data)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      */
emitMethod(int i, Class[] e)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      */
generate(ClassLoader loader)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      */
putU1(int i)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      */
putU2(int i)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      */
putU4(int i)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      */
putConst(int i)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      */
putLoad(int i, Class type)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      */
wrapper(Class clazz)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      */
utf8Info(String str)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      */
classInfo(String name)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      */
classInfo(Class clazz)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      */
refInfo(byte structure, String clazz, String name, String type)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      */
nameAndTypeInfo(String name, String type)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      */
toUtf8(String str)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      */
poolIndex(String sequence)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 }
1546