source: trunk/gcc/libjava/java/lang/reflect/Proxy.java

Last change on this file was 1389, checked in by bird, 21 years ago

Initial revision

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