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