libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / java / lang / reflect / Proxy.java
blobfb2004e790bdf4eda2e4a87583633cfc4eb63f3e
1 /* Proxy.java -- build a proxy class that implements reflected interfaces
2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
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.
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. */
39 package java.lang.reflect;
41 import gnu.java.lang.CPStringBuilder;
43 import gnu.java.lang.reflect.TypeSignature;
45 import java.io.Serializable;
46 import java.security.ProtectionDomain;
47 import java.util.Arrays;
48 import java.util.HashMap;
49 import java.util.HashSet;
50 import java.util.Iterator;
51 import java.util.Map;
52 import java.util.Set;
54 /**
55 * This class allows you to dynamically create an instance of any (or
56 * even multiple) interfaces by reflection, and decide at runtime
57 * how that instance will behave by giving it an appropriate
58 * {@link InvocationHandler}. Proxy classes serialize specially, so
59 * that the proxy object can be reused between VMs, without requiring
60 * a persistent copy of the generated class code.
62 * <h3>Creation</h3>
63 * To create a proxy for some interface Foo:
65 * <pre>
66 * InvocationHandler handler = new MyInvocationHandler(...);
67 * Class proxyClass = Proxy.getProxyClass(
68 * Foo.class.getClassLoader(), new Class[] { Foo.class });
69 * Foo f = (Foo) proxyClass
70 * .getConstructor(new Class[] { InvocationHandler.class })
71 * .newInstance(new Object[] { handler });
72 * </pre>
73 * or more simply:
74 * <pre>
75 * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
76 * new Class[] { Foo.class },
77 * handler);
78 * </pre>
80 * <h3>Dynamic Proxy Classes</h3>
81 * A dynamic proxy class is created at runtime, and has the following
82 * properties:
83 * <ul>
84 * <li>The class is <code>public</code> and <code>final</code>,
85 * and is neither <code>abstract</code> nor an inner class.</li>
86 * <li>The class has no canonical name (there is no formula you can use
87 * to determine or generate its name), but begins with the
88 * sequence "$Proxy". Abuse this knowledge at your own peril.
89 * (For now, '$' in user identifiers is legal, but it may not
90 * be that way forever. You weren't using '$' in your
91 * identifiers, were you?)</li>
92 * <li>The class extends Proxy, and explicitly implements all the
93 * interfaces specified at creation, in order (this is important
94 * for determining how method invocation is resolved). Note that
95 * a proxy class implements {@link Serializable}, at least
96 * implicitly, since Proxy does, but true serial behavior
97 * depends on using a serializable invocation handler as well.</li>
98 * <li>If at least one interface is non-public, the proxy class
99 * will be in the same package. Otherwise, the package is
100 * unspecified. This will work even if the package is sealed
101 * from user-generated classes, because Proxy classes are
102 * generated by a trusted source. Meanwhile, the proxy class
103 * belongs to the classloader you designated.</li>
104 * <li>Reflection works as expected: {@link Class#getInterfaces()} and
105 * {@link Class#getMethods()} work as they do on normal classes.</li>
106 * <li>The method {@link #isProxyClass(Class)} will distinguish between
107 * true proxy classes and user extensions of this class. It only
108 * returns true for classes created by {@link #getProxyClass}.</li>
109 * <li>The {@link ProtectionDomain} of a proxy class is the same as for
110 * bootstrap classes, such as Object or Proxy, since it is created by
111 * a trusted source. This protection domain will typically be granted
112 * {@link java.security.AllPermission}. But this is not a security
113 * risk, since there are adequate permissions on reflection, which is
114 * the only way to create an instance of the proxy class.</li>
115 * <li>The proxy class contains a single constructor, which takes as
116 * its only argument an {@link InvocationHandler}. The method
117 * {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
118 * is shorthand to do the necessary reflection.</li>
119 * </ul>
121 * <h3>Proxy Instances</h3>
122 * A proxy instance is an instance of a proxy class. It has the
123 * following properties, many of which follow from the properties of a
124 * proxy class listed above:
125 * <ul>
126 * <li>For a proxy class with Foo listed as one of its interfaces, the
127 * expression <code>proxy instanceof Foo</code> will return true,
128 * and the expression <code>(Foo) proxy</code> will succeed without
129 * a {@link ClassCastException}.</li>
130 * <li>Each proxy instance has an invocation handler, which can be
131 * accessed by {@link #getInvocationHandler(Object)}. Any call
132 * to an interface method, including {@link Object#hashCode()},
133 * {@link Object#equals(Object)}, or {@link Object#toString()},
134 * but excluding the public final methods of Object, will be
135 * encoded and passed to the {@link InvocationHandler#invoke}
136 * method of this handler.</li>
137 * </ul>
139 * <h3>Inheritance Issues</h3>
140 * A proxy class may inherit a method from more than one interface.
141 * The order in which interfaces are listed matters, because it determines
142 * which reflected {@link Method} object will be passed to the invocation
143 * handler. This means that the dynamically generated class cannot
144 * determine through which interface a method is being invoked.<p>
146 * In short, if a method is declared in Object (namely, hashCode,
147 * equals, or toString), then Object will be used; otherwise, the
148 * leftmost interface that inherits or declares a method will be used,
149 * even if it has a more permissive throws clause than what the proxy
150 * class is allowed. Thus, in the invocation handler, it is not always
151 * safe to assume that every class listed in the throws clause of the
152 * passed Method object can safely be thrown; fortunately, the Proxy
153 * instance is robust enough to wrap all illegal checked exceptions in
154 * {@link UndeclaredThrowableException}.
156 * @see InvocationHandler
157 * @see UndeclaredThrowableException
158 * @see Class
159 * @author Eric Blake (ebb9@email.byu.edu)
160 * @since 1.3
161 * @status updated to 1.5, except for the use of ProtectionDomain
163 public class Proxy implements Serializable
166 * Compatible with JDK 1.3+.
168 private static final long serialVersionUID = -2222568056686623797L;
171 * Map of ProxyType to proxy class.
173 * @XXX This prevents proxy classes from being garbage collected.
174 * java.util.WeakHashSet is not appropriate, because that collects the
175 * keys, but we are interested in collecting the elements.
177 private static final Map proxyClasses = new HashMap();
180 * The invocation handler for this proxy instance. For Proxy, this
181 * field is unused, but it appears here in order to be serialized in all
182 * proxy classes.
184 * <em>NOTE</em>: This implementation is more secure for proxy classes
185 * than what Sun specifies. Sun does not require h to be immutable, but
186 * this means you could change h after the fact by reflection. However,
187 * by making h immutable, we may break non-proxy classes which extend
188 * Proxy.
189 * @serial invocation handler associated with this proxy instance
191 protected InvocationHandler h;
194 * Constructs a new Proxy from a subclass (usually a proxy class),
195 * with the specified invocation handler.
197 * <em>NOTE</em>: This throws a NullPointerException if you attempt
198 * to create a proxy instance with a null handler using reflection.
199 * This behavior is not yet specified by Sun; see Sun Bug 4487672.
201 * @param handler the invocation handler, may be null if the subclass
202 * is not a proxy class
203 * @throws NullPointerException if handler is null and this is a proxy
204 * instance
206 protected Proxy(InvocationHandler handler)
208 if (handler == null && isProxyClass(getClass()))
209 throw new NullPointerException("invalid handler");
210 h = handler;
214 * Returns the proxy {@link Class} for the given ClassLoader and array
215 * of interfaces, dynamically generating it if necessary.
217 * <p>There are several restrictions on this method, the violation of
218 * which will result in an IllegalArgumentException or
219 * NullPointerException:</p>
221 * <ul>
222 * <li>All objects in `interfaces' must represent distinct interfaces.
223 * Classes, primitive types, null, and duplicates are forbidden.</li>
224 * <li>The interfaces must be visible in the specified ClassLoader.
225 * In other words, for each interface i:
226 * <code>Class.forName(i.getName(), false, loader) == i</code>
227 * must be true.</li>
228 * <li>All non-public interfaces (if any) must reside in the same
229 * package, or the proxy class would be non-instantiable. If
230 * there are no non-public interfaces, the package of the proxy
231 * class is unspecified.</li>
232 * <li>All interfaces must be compatible - if two declare a method
233 * with the same name and parameters, the return type must be
234 * the same and the throws clause of the proxy class will be
235 * the maximal subset of subclasses of the throws clauses for
236 * each method that is overridden.</li>
237 * <li>VM constraints limit the number of interfaces a proxy class
238 * may directly implement (however, the indirect inheritance
239 * of {@link Serializable} does not count against this limit).
240 * Even though most VMs can theoretically have 65535
241 * superinterfaces for a class, the actual limit is smaller
242 * because a class's constant pool is limited to 65535 entries,
243 * and not all entries can be interfaces.</li>
244 * </ul>
246 * <p>Note that different orders of interfaces produce distinct classes.</p>
248 * @param loader the class loader to define the proxy class in; null
249 * implies the bootstrap class loader
250 * @param interfaces the array of interfaces the proxy class implements,
251 * may be empty, but not null
252 * @return the Class object of the proxy class
253 * @throws IllegalArgumentException if the constraints above were
254 * violated, except for problems with null
255 * @throws NullPointerException if `interfaces' is null or contains
256 * a null entry
258 // synchronized so that we aren't trying to build the same class
259 // simultaneously in two threads
260 public static synchronized Class<?> getProxyClass(ClassLoader loader,
261 Class<?>... interfaces)
263 interfaces = (Class[]) interfaces.clone();
264 ProxyType pt = new ProxyType(loader, interfaces);
265 Class clazz = (Class) proxyClasses.get(pt);
266 if (clazz == null)
268 if (VMProxy.HAVE_NATIVE_GET_PROXY_CLASS)
269 clazz = VMProxy.getProxyClass(loader, interfaces);
270 else
272 ProxyData data = (VMProxy.HAVE_NATIVE_GET_PROXY_DATA
273 ? VMProxy.getProxyData(loader, interfaces)
274 : ProxyData.getProxyData(pt));
276 clazz = (VMProxy.HAVE_NATIVE_GENERATE_PROXY_CLASS
277 ? VMProxy.generateProxyClass(loader, data)
278 : new ClassFactory(data).generate(loader));
281 Object check = proxyClasses.put(pt, clazz);
282 // assert check == null && clazz != null;
283 if (check != null || clazz == null)
284 throw new InternalError(/*"Fatal flaw in getProxyClass"*/);
286 return clazz;
290 * Combines several methods into one. This is equivalent to:
291 * <pre>
292 * Proxy.getProxyClass(loader, interfaces)
293 * .getConstructor(new Class[] {InvocationHandler.class})
294 * .newInstance(new Object[] {handler});
295 * </pre>
296 * except that it will not fail with the normal problems caused
297 * by reflection. It can still fail for the same reasons documented
298 * in getProxyClass, or if handler is null.
300 * @param loader the class loader to define the proxy class in; null
301 * implies the bootstrap class loader
302 * @param interfaces the array of interfaces the proxy class implements,
303 * may be empty, but not null
304 * @param handler the invocation handler, may not be null
305 * @return a proxy instance implementing the specified interfaces
306 * @throws IllegalArgumentException if the constraints for getProxyClass
307 * were violated, except for problems with null
308 * @throws NullPointerException if `interfaces' is null or contains
309 * a null entry, or if handler is null
310 * @see #getProxyClass(ClassLoader, Class[])
311 * @see Class#getConstructor(Class[])
312 * @see Constructor#newInstance(Object[])
314 public static Object newProxyInstance(ClassLoader loader,
315 Class<?>[] interfaces,
316 InvocationHandler handler)
320 // getProxyClass() and Proxy() throw the necessary exceptions
321 return getProxyClass(loader, interfaces)
322 .getConstructor(new Class[] {InvocationHandler.class})
323 .newInstance(new Object[] {handler});
325 catch (RuntimeException e)
327 // Let IllegalArgumentException, NullPointerException escape.
328 // assert e instanceof IllegalArgumentException
329 // || e instanceof NullPointerException;
330 throw e;
332 catch (InvocationTargetException e)
334 // Let wrapped NullPointerException escape.
335 // assert e.getTargetException() instanceof NullPointerException
336 throw (NullPointerException) e.getCause();
338 catch (Exception e)
340 // Covers InstantiationException, IllegalAccessException,
341 // NoSuchMethodException, none of which should be generated
342 // if the proxy class was generated correctly.
343 // assert false;
344 throw (Error) new InternalError("Unexpected: " + e).initCause(e);
349 * Returns true if and only if the Class object is a dynamically created
350 * proxy class (created by <code>getProxyClass</code> or by the
351 * syntactic sugar of <code>newProxyInstance</code>).
353 * <p>This check is secure (in other words, it is not simply
354 * <code>clazz.getSuperclass() == Proxy.class</code>), it will not
355 * be spoofed by non-proxy classes that extend Proxy.
357 * @param clazz the class to check, must not be null
358 * @return true if the class represents a proxy class
359 * @throws NullPointerException if clazz is null
361 // This is synchronized on the off chance that another thread is
362 // trying to add a class to the map at the same time we read it.
363 public static synchronized boolean isProxyClass(Class<?> clazz)
365 if (! Proxy.class.isAssignableFrom(clazz))
366 return false;
367 // This is a linear search, even though we could do an O(1) search
368 // using new ProxyType(clazz.getClassLoader(), clazz.getInterfaces()).
369 return proxyClasses.containsValue(clazz);
373 * Returns the invocation handler for the given proxy instance.<p>
375 * <em>NOTE</em>: We guarantee a non-null result if successful,
376 * but Sun allows the creation of a proxy instance with a null
377 * handler. See the comments for {@link #Proxy(InvocationHandler)}.
379 * @param proxy the proxy instance, must not be null
380 * @return the invocation handler, guaranteed non-null.
381 * @throws IllegalArgumentException if
382 * <code>Proxy.isProxyClass(proxy.getClass())</code> returns false.
383 * @throws NullPointerException if proxy is null
385 public static InvocationHandler getInvocationHandler(Object proxy)
387 if (! isProxyClass(proxy.getClass()))
388 throw new IllegalArgumentException("not a proxy instance");
389 return ((Proxy) proxy).h;
393 * Helper class for mapping unique ClassLoader and interface combinations
394 * to proxy classes.
396 * @author Eric Blake (ebb9@email.byu.edu)
398 private static final class ProxyType
401 * Store the class loader (may be null)
403 final ClassLoader loader;
406 * Store the interfaces (never null, all elements are interfaces)
408 final Class[] interfaces;
411 * Construct the helper object.
413 * @param loader the class loader to define the proxy class in; null
414 * implies the bootstrap class loader
415 * @param interfaces an array of interfaces
417 ProxyType(ClassLoader loader, Class[] interfaces)
419 this.loader = loader;
420 this.interfaces = interfaces;
424 * Calculates the hash code.
426 * @return a combination of the classloader and interfaces hashcodes.
428 public int hashCode()
430 int hash = loader == null ? 0 : loader.hashCode();
431 for (int i = 0; i < interfaces.length; i++)
432 hash = hash * 31 + interfaces[i].hashCode();
433 return hash;
437 * Calculates equality.
439 * @param other object to compare to
440 * @return true if it is a ProxyType with same data
442 public boolean equals(Object other)
444 ProxyType pt = (ProxyType) other;
445 if (loader != pt.loader || interfaces.length != pt.interfaces.length)
446 return false;
447 for (int i = 0; i < interfaces.length; i++)
448 if (interfaces[i] != pt.interfaces[i])
449 return false;
450 return true;
452 } // class ProxyType
455 * Helper class which allows hashing of a method name and signature
456 * without worrying about return type, declaring class, or throws clause,
457 * and which reduces the maximally common throws clause between two methods
459 * @author Eric Blake (ebb9@email.byu.edu)
461 private static final class ProxySignature
464 * The core signatures which all Proxy instances handle.
466 static final HashMap coreMethods = new HashMap();
467 static
471 ProxySignature sig
472 = new ProxySignature(Object.class
473 .getMethod("equals",
474 new Class[] {Object.class}));
475 coreMethods.put(sig, sig);
476 sig = new ProxySignature(Object.class.getMethod("hashCode"));
477 coreMethods.put(sig, sig);
478 sig = new ProxySignature(Object.class.getMethod("toString"));
479 coreMethods.put(sig, sig);
481 catch (Exception e)
483 // assert false;
484 throw (Error) new InternalError("Unexpected: " + e).initCause(e);
489 * The underlying Method object, never null
491 final Method method;
494 * The set of compatible thrown exceptions, may be empty
496 final Set exceptions = new HashSet();
499 * Construct a signature
501 * @param method the Method this signature is based on, never null
503 ProxySignature(Method method)
505 this.method = method;
506 Class[] exc = method.getExceptionTypes();
507 int i = exc.length;
508 while (--i >= 0)
510 // discard unchecked exceptions
511 if (Error.class.isAssignableFrom(exc[i])
512 || RuntimeException.class.isAssignableFrom(exc[i]))
513 continue;
514 exceptions.add(exc[i]);
519 * Given a method, make sure it's return type is identical
520 * to this, and adjust this signature's throws clause appropriately
522 * @param other the signature to merge in
523 * @throws IllegalArgumentException if the return types conflict
525 void checkCompatibility(ProxySignature other)
527 if (method.getReturnType() != other.method.getReturnType())
528 throw new IllegalArgumentException("incompatible return types: "
529 + method + ", " + other.method);
531 // if you can think of a more efficient way than this O(n^2) search,
532 // implement it!
533 int size1 = exceptions.size();
534 int size2 = other.exceptions.size();
535 boolean[] valid1 = new boolean[size1];
536 boolean[] valid2 = new boolean[size2];
537 Iterator itr = exceptions.iterator();
538 int pos = size1;
539 while (--pos >= 0)
541 Class c1 = (Class) itr.next();
542 Iterator itr2 = other.exceptions.iterator();
543 int pos2 = size2;
544 while (--pos2 >= 0)
546 Class c2 = (Class) itr2.next();
547 if (c2.isAssignableFrom(c1))
548 valid1[pos] = true;
549 if (c1.isAssignableFrom(c2))
550 valid2[pos2] = true;
553 pos = size1;
554 itr = exceptions.iterator();
555 while (--pos >= 0)
557 itr.next();
558 if (! valid1[pos])
559 itr.remove();
561 pos = size2;
562 itr = other.exceptions.iterator();
563 while (--pos >= 0)
565 itr.next();
566 if (! valid2[pos])
567 itr.remove();
569 exceptions.addAll(other.exceptions);
573 * Calculates the hash code.
575 * @return a combination of name and parameter types
577 public int hashCode()
579 int hash = method.getName().hashCode();
580 Class[] types = method.getParameterTypes();
581 for (int i = 0; i < types.length; i++)
582 hash = hash * 31 + types[i].hashCode();
583 return hash;
587 * Calculates equality.
589 * @param other object to compare to
590 * @return true if it is a ProxySignature with same data
592 public boolean equals(Object other)
594 ProxySignature ps = (ProxySignature) other;
595 Class[] types1 = method.getParameterTypes();
596 Class[] types2 = ps.method.getParameterTypes();
597 if (! method.getName().equals(ps.method.getName())
598 || types1.length != types2.length)
599 return false;
600 int i = types1.length;
601 while (--i >= 0)
602 if (types1[i] != types2[i])
603 return false;
604 return true;
606 } // class ProxySignature
609 * A flat representation of all data needed to generate bytecode/instantiate
610 * a proxy class. This is basically a struct.
612 * @author Eric Blake (ebb9@email.byu.edu)
614 static final class ProxyData
617 * The package this class is in <b>including the trailing dot</b>
618 * or an empty string for the unnamed (aka default) package.
620 String pack = "";
623 * The interfaces this class implements. Non-null, but possibly empty.
625 Class[] interfaces;
628 * The Method objects this class must pass as the second argument to
629 * invoke (also useful for determining what methods this class has).
630 * Non-null, non-empty (includes at least Object.hashCode, Object.equals,
631 * and Object.toString).
633 Method[] methods;
636 * The exceptions that do not need to be wrapped in
637 * UndeclaredThrowableException. exceptions[i] is the same as, or a
638 * subset of subclasses, of methods[i].getExceptionTypes(), depending on
639 * compatible throws clauses with multiple inheritance. It is unspecified
640 * if these lists include or exclude subclasses of Error and
641 * RuntimeException, but excluding them is harmless and generates a
642 * smaller class.
644 Class[][] exceptions;
647 * For unique id's
649 private static int count;
652 * The id of this proxy class
654 final int id = count++;
657 * Construct a ProxyData with uninitialized data members.
659 ProxyData()
664 * Return the name of a package (including the trailing dot)
665 * given the name of a class.
666 * Returns an empty string if no package. We use this in preference to
667 * using Class.getPackage() to avoid problems with ClassLoaders
668 * that don't set the package.
670 private static String getPackage(Class k)
672 String name = k.getName();
673 int idx = name.lastIndexOf('.');
674 return name.substring(0, idx + 1);
678 * Verifies that the arguments are legal, and sets up remaining data
679 * This should only be called when a class must be generated, as
680 * it is expensive.
682 * @param pt the ProxyType to convert to ProxyData
683 * @return the flattened, verified ProxyData structure for use in
684 * class generation
685 * @throws IllegalArgumentException if `interfaces' contains
686 * non-interfaces or incompatible combinations, and verify is true
687 * @throws NullPointerException if interfaces is null or contains null
689 static ProxyData getProxyData(ProxyType pt)
691 Map method_set = (Map) ProxySignature.coreMethods.clone();
692 boolean in_package = false; // true if we encounter non-public interface
694 ProxyData data = new ProxyData();
695 data.interfaces = pt.interfaces;
697 // if interfaces is too large, we croak later on when the constant
698 // pool overflows
699 int i = data.interfaces.length;
700 while (--i >= 0)
702 Class inter = data.interfaces[i];
703 if (! inter.isInterface())
704 throw new IllegalArgumentException("not an interface: " + inter);
707 if (Class.forName(inter.getName(), false, pt.loader) != inter)
708 throw new IllegalArgumentException("not accessible in "
709 + "classloader: " + inter);
711 catch (ClassNotFoundException e)
713 throw new IllegalArgumentException("not accessible in "
714 + "classloader: " + inter);
716 if (! Modifier.isPublic(inter.getModifiers()))
717 if (in_package)
719 String p = getPackage(inter);
720 if (! data.pack.equals(p))
721 throw new IllegalArgumentException("non-public interfaces "
722 + "from different "
723 + "packages");
725 else
727 in_package = true;
728 data.pack = getPackage(inter);
730 for (int j = i-1; j >= 0; j--)
731 if (data.interfaces[j] == inter)
732 throw new IllegalArgumentException("duplicate interface: "
733 + inter);
734 Method[] methods = inter.getMethods();
735 int j = methods.length;
736 while (--j >= 0)
738 if (isCoreObjectMethod(methods[j]))
740 // In the case of an attempt to redefine a public non-final
741 // method of Object, we must skip it
742 continue;
744 ProxySignature sig = new ProxySignature(methods[j]);
745 ProxySignature old = (ProxySignature) method_set.put(sig, sig);
746 if (old != null)
747 sig.checkCompatibility(old);
751 i = method_set.size();
752 data.methods = new Method[i];
753 data.exceptions = new Class[i][];
754 Iterator itr = method_set.values().iterator();
755 while (--i >= 0)
757 ProxySignature sig = (ProxySignature) itr.next();
758 data.methods[i] = sig.method;
759 data.exceptions[i] = (Class[]) sig.exceptions
760 .toArray(new Class[sig.exceptions.size()]);
762 return data;
766 * Checks whether the method is similar to a public non-final method of
767 * Object or not (i.e. with the same name and parameter types). Note that we
768 * can't rely, directly or indirectly (via Collection.contains) on
769 * Method.equals as it would also check the declaring class, what we do not
770 * want. We only want to check that the given method have the same signature
771 * as a core method (same name and parameter types)
773 * @param method the method to check
774 * @return whether the method has the same name and parameter types as
775 * Object.equals, Object.hashCode or Object.toString
776 * @see java.lang.Object#equals(Object)
777 * @see java.lang.Object#hashCode()
778 * @see java.lang.Object#toString()
780 private static boolean isCoreObjectMethod(Method method)
782 String methodName = method.getName();
783 if (methodName.equals("equals"))
785 return Arrays.equals(method.getParameterTypes(),
786 new Class[] { Object.class });
788 if (methodName.equals("hashCode"))
790 return method.getParameterTypes().length == 0;
792 if (methodName.equals("toString"))
794 return method.getParameterTypes().length == 0;
796 return false;
799 } // class ProxyData
802 * Does all the work of building a class. By making this a nested class,
803 * this code is not loaded in memory if the VM has a native
804 * implementation instead.
806 * @author Eric Blake (ebb9@email.byu.edu)
808 private static final class ClassFactory
810 /** Constants for assisting the compilation */
811 private static final byte FIELD = 1;
812 private static final byte METHOD = 2;
813 private static final byte INTERFACE = 3;
814 private static final String CTOR_SIG
815 = "(Ljava/lang/reflect/InvocationHandler;)V";
816 private static final String INVOKE_SIG = "(Ljava/lang/Object;"
817 + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
819 /** Bytecodes for insertion in the class definition byte[] */
820 private static final char ACONST_NULL = 1;
821 private static final char ICONST_0 = 3;
822 private static final char BIPUSH = 16;
823 private static final char SIPUSH = 17;
824 private static final char ILOAD = 21;
825 private static final char ILOAD_0 = 26;
826 private static final char ALOAD_0 = 42;
827 private static final char ALOAD_1 = 43;
828 private static final char AALOAD = 50;
829 private static final char AASTORE = 83;
830 private static final char DUP = 89;
831 private static final char DUP_X1 = 90;
832 private static final char SWAP = 95;
833 private static final char IRETURN = 172;
834 private static final char LRETURN = 173;
835 private static final char FRETURN = 174;
836 private static final char DRETURN = 175;
837 private static final char ARETURN = 176;
838 private static final char RETURN = 177;
839 private static final char GETSTATIC = 178;
840 private static final char GETFIELD = 180;
841 private static final char INVOKEVIRTUAL = 182;
842 private static final char INVOKESPECIAL = 183;
843 private static final char INVOKEINTERFACE = 185;
844 private static final char NEW = 187;
845 private static final char ANEWARRAY = 189;
846 private static final char ATHROW = 191;
847 private static final char CHECKCAST = 192;
849 // Implementation note: we use StringBuffers to hold the byte data, since
850 // they automatically grow. However, we only use the low 8 bits of
851 // every char in the array, so we are using twice the necessary memory
852 // for the ease StringBuffer provides.
854 /** The constant pool. */
855 private final StringBuffer pool = new StringBuffer();
856 /** The rest of the class data. */
857 private final StringBuffer stream = new StringBuffer();
859 /** Map of strings to byte sequences, to minimize size of pool. */
860 private final Map poolEntries = new HashMap();
862 /** The VM name of this proxy class. */
863 private final String qualName;
866 * The Method objects the proxy class refers to when calling the
867 * invocation handler.
869 private final Method[] methods;
872 * Initializes the buffers with the bytecode contents for a proxy class.
874 * @param data the remainder of the class data
875 * @throws IllegalArgumentException if anything else goes wrong this
876 * late in the game; as far as I can tell, this will only happen
877 * if the constant pool overflows, which is possible even when
878 * the user doesn't exceed the 65535 interface limit
880 ClassFactory(ProxyData data)
882 methods = data.methods;
884 // magic = 0xcafebabe
885 // minor_version = 0
886 // major_version = 46
887 // constant_pool_count: place-holder for now
888 pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0");
889 // constant_pool[], filled in as we go
891 // access_flags
892 putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC);
893 // this_class
894 qualName = (data.pack + "$Proxy" + data.id);
895 putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false)));
896 // super_class
897 putU2(classInfo("java/lang/reflect/Proxy"));
899 // interfaces_count
900 putU2(data.interfaces.length);
901 // interfaces[]
902 for (int i = 0; i < data.interfaces.length; i++)
903 putU2(classInfo(data.interfaces[i]));
905 // Recall that Proxy classes serialize specially, so we do not need
906 // to worry about a <clinit> method for this field. Instead, we
907 // just assign it by reflection after the class is successfully loaded.
908 // fields_count - private static Method[] m;
909 putU2(1);
910 // fields[]
911 // m.access_flags
912 putU2(Modifier.PRIVATE | Modifier.STATIC);
913 // m.name_index
914 putU2(utf8Info("m"));
915 // m.descriptor_index
916 putU2(utf8Info("[Ljava/lang/reflect/Method;"));
917 // m.attributes_count
918 putU2(0);
919 // m.attributes[]
921 // methods_count - # handler methods, plus <init>
922 putU2(methods.length + 1);
923 // methods[]
924 // <init>.access_flags
925 putU2(Modifier.PUBLIC);
926 // <init>.name_index
927 putU2(utf8Info("<init>"));
928 // <init>.descriptor_index
929 putU2(utf8Info(CTOR_SIG));
930 // <init>.attributes_count - only Code is needed
931 putU2(1);
932 // <init>.Code.attribute_name_index
933 putU2(utf8Info("Code"));
934 // <init>.Code.attribute_length = 18
935 // <init>.Code.info:
936 // $Proxynn(InvocationHandler h) { super(h); }
937 // <init>.Code.max_stack = 2
938 // <init>.Code.max_locals = 2
939 // <init>.Code.code_length = 6
940 // <init>.Code.code[]
941 stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1
942 + INVOKESPECIAL);
943 putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "<init>", CTOR_SIG));
944 // <init>.Code.exception_table_length = 0
945 // <init>.Code.exception_table[]
946 // <init>.Code.attributes_count = 0
947 // <init>.Code.attributes[]
948 stream.append(RETURN + "\0\0\0\0");
950 for (int i = methods.length - 1; i >= 0; i--)
951 emitMethod(i, data.exceptions[i]);
953 // attributes_count
954 putU2(0);
955 // attributes[] - empty; omit SourceFile attribute
956 // XXX should we mark this with a Synthetic attribute?
960 * Produce the bytecode for a single method.
962 * @param i the index of the method we are building
963 * @param e the exceptions possible for the method
965 private void emitMethod(int i, Class[] e)
967 // First, we precalculate the method length and other information.
969 Method m = methods[i];
970 Class[] paramtypes = m.getParameterTypes();
971 int wrap_overhead = 0; // max words taken by wrapped primitive
972 int param_count = 1; // 1 for this
973 int code_length = 16; // aload_0, getfield, aload_0, getstatic, const,
974 // aaload, const/aconst_null, invokeinterface
975 if (i > 5)
977 if (i > Byte.MAX_VALUE)
978 code_length += 2; // sipush
979 else
980 code_length++; // bipush
982 if (paramtypes.length > 0)
984 code_length += 3; // anewarray
985 if (paramtypes.length > Byte.MAX_VALUE)
986 code_length += 2; // sipush
987 else if (paramtypes.length > 5)
988 code_length++; // bipush
989 for (int j = 0; j < paramtypes.length; j++)
991 code_length += 4; // dup, const, load, store
992 Class type = paramtypes[j];
993 if (j > 5)
995 if (j > Byte.MAX_VALUE)
996 code_length += 2; // sipush
997 else
998 code_length++; // bipush
1000 if (param_count >= 4)
1001 code_length++; // 2-byte load
1002 param_count++;
1003 if (type.isPrimitive())
1005 code_length += 7; // new, dup, invokespecial
1006 if (type == long.class || type == double.class)
1008 wrap_overhead = 3;
1009 param_count++;
1011 else if (wrap_overhead < 2)
1012 wrap_overhead = 2;
1016 int end_pc = code_length;
1017 Class ret_type = m.getReturnType();
1018 if (ret_type == void.class)
1019 code_length++; // return
1020 else if (ret_type.isPrimitive())
1021 code_length += 7; // cast, invokevirtual, return
1022 else
1023 code_length += 4; // cast, return
1024 int exception_count = 0;
1025 boolean throws_throwable = false;
1026 for (int j = 0; j < e.length; j++)
1027 if (e[j] == Throwable.class)
1029 throws_throwable = true;
1030 break;
1032 if (! throws_throwable)
1034 exception_count = e.length + 3; // Throwable, Error, RuntimeException
1035 code_length += 9; // new, dup_x1, swap, invokespecial, athrow
1037 int handler_pc = code_length - 1;
1038 CPStringBuilder signature = new CPStringBuilder("(");
1039 for (int j = 0; j < paramtypes.length; j++)
1040 signature.append(TypeSignature.getEncodingOfClass(paramtypes[j]));
1041 signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type));
1043 // Now we have enough information to emit the method.
1045 // handler.access_flags
1046 putU2(Modifier.PUBLIC | Modifier.FINAL);
1047 // handler.name_index
1048 putU2(utf8Info(m.getName()));
1049 // handler.descriptor_index
1050 putU2(utf8Info(signature.toString()));
1051 // handler.attributes_count - Code is necessary, Exceptions possible
1052 putU2(e.length > 0 ? 2 : 1);
1054 // handler.Code.info:
1055 // type name(args) {
1056 // try {
1057 // return (type) h.invoke(this, methods[i], new Object[] {args});
1058 // } catch (<declared Exceptions> e) {
1059 // throw e;
1060 // } catch (Throwable t) {
1061 // throw new UndeclaredThrowableException(t);
1062 // }
1063 // }
1064 // Special cases:
1065 // if arg_n is primitive, wrap it
1066 // if method throws Throwable, try-catch is not needed
1067 // if method returns void, return statement not needed
1068 // if method returns primitive, unwrap it
1069 // save space by sharing code for all the declared handlers
1071 // handler.Code.attribute_name_index
1072 putU2(utf8Info("Code"));
1073 // handler.Code.attribute_length
1074 putU4(12 + code_length + 8 * exception_count);
1075 // handler.Code.max_stack
1076 putU2(param_count == 1 ? 4 : 7 + wrap_overhead);
1077 // handler.Code.max_locals
1078 putU2(param_count);
1079 // handler.Code.code_length
1080 putU4(code_length);
1081 // handler.Code.code[]
1082 putU1(ALOAD_0);
1083 putU1(GETFIELD);
1084 putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h",
1085 "Ljava/lang/reflect/InvocationHandler;"));
1086 putU1(ALOAD_0);
1087 putU1(GETSTATIC);
1088 putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false),
1089 "m", "[Ljava/lang/reflect/Method;"));
1090 putConst(i);
1091 putU1(AALOAD);
1092 if (paramtypes.length > 0)
1094 putConst(paramtypes.length);
1095 putU1(ANEWARRAY);
1096 putU2(classInfo("java/lang/Object"));
1097 param_count = 1;
1098 for (int j = 0; j < paramtypes.length; j++, param_count++)
1100 putU1(DUP);
1101 putConst(j);
1102 if (paramtypes[j].isPrimitive())
1104 putU1(NEW);
1105 putU2(classInfo(wrapper(paramtypes[j])));
1106 putU1(DUP);
1108 putLoad(param_count, paramtypes[j]);
1109 if (paramtypes[j].isPrimitive())
1111 putU1(INVOKESPECIAL);
1112 putU2(refInfo(METHOD, wrapper(paramtypes[j]), "<init>",
1113 '(' + (TypeSignature
1114 .getEncodingOfClass(paramtypes[j])
1115 + ")V")));
1116 if (paramtypes[j] == long.class
1117 || paramtypes[j] == double.class)
1118 param_count++;
1120 putU1(AASTORE);
1123 else
1124 putU1(ACONST_NULL);
1125 putU1(INVOKEINTERFACE);
1126 putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler",
1127 "invoke", INVOKE_SIG));
1128 putU1(4); // InvocationHandler, this, Method, Object[]
1129 putU1(0);
1130 if (ret_type == void.class)
1131 putU1(RETURN);
1132 else if (ret_type.isPrimitive())
1134 putU1(CHECKCAST);
1135 putU2(classInfo(wrapper(ret_type)));
1136 putU1(INVOKEVIRTUAL);
1137 putU2(refInfo(METHOD, wrapper(ret_type),
1138 ret_type.getName() + "Value",
1139 "()" + TypeSignature.getEncodingOfClass(ret_type)));
1140 if (ret_type == long.class)
1141 putU1(LRETURN);
1142 else if (ret_type == float.class)
1143 putU1(FRETURN);
1144 else if (ret_type == double.class)
1145 putU1(DRETURN);
1146 else
1147 putU1(IRETURN);
1149 else
1151 putU1(CHECKCAST);
1152 putU2(classInfo(ret_type));
1153 putU1(ARETURN);
1155 if (! throws_throwable)
1157 putU1(NEW);
1158 putU2(classInfo("java/lang/reflect/UndeclaredThrowableException"));
1159 putU1(DUP_X1);
1160 putU1(SWAP);
1161 putU1(INVOKESPECIAL);
1162 putU2(refInfo(METHOD,
1163 "java/lang/reflect/UndeclaredThrowableException",
1164 "<init>", "(Ljava/lang/Throwable;)V"));
1165 putU1(ATHROW);
1168 // handler.Code.exception_table_length
1169 putU2(exception_count);
1170 // handler.Code.exception_table[]
1171 if (! throws_throwable)
1173 // handler.Code.exception_table.start_pc
1174 putU2(0);
1175 // handler.Code.exception_table.end_pc
1176 putU2(end_pc);
1177 // handler.Code.exception_table.handler_pc
1178 putU2(handler_pc);
1179 // handler.Code.exception_table.catch_type
1180 putU2(classInfo("java/lang/Error"));
1181 // handler.Code.exception_table.start_pc
1182 putU2(0);
1183 // handler.Code.exception_table.end_pc
1184 putU2(end_pc);
1185 // handler.Code.exception_table.handler_pc
1186 putU2(handler_pc);
1187 // handler.Code.exception_table.catch_type
1188 putU2(classInfo("java/lang/RuntimeException"));
1189 for (int j = 0; j < e.length; j++)
1191 // handler.Code.exception_table.start_pc
1192 putU2(0);
1193 // handler.Code.exception_table.end_pc
1194 putU2(end_pc);
1195 // handler.Code.exception_table.handler_pc
1196 putU2(handler_pc);
1197 // handler.Code.exception_table.catch_type
1198 putU2(classInfo(e[j]));
1200 // handler.Code.exception_table.start_pc
1201 putU2(0);
1202 // handler.Code.exception_table.end_pc
1203 putU2(end_pc);
1204 // handler.Code.exception_table.handler_pc -
1205 // -8 for undeclared handler, which falls thru to normal one
1206 putU2(handler_pc - 8);
1207 // handler.Code.exception_table.catch_type
1208 putU2(0);
1210 // handler.Code.attributes_count
1211 putU2(0);
1212 // handler.Code.attributes[]
1214 if (e.length > 0)
1216 // handler.Exceptions.attribute_name_index
1217 putU2(utf8Info("Exceptions"));
1218 // handler.Exceptions.attribute_length
1219 putU4(2 * e.length + 2);
1220 // handler.Exceptions.number_of_exceptions
1221 putU2(e.length);
1222 // handler.Exceptions.exception_index_table[]
1223 for (int j = 0; j < e.length; j++)
1224 putU2(classInfo(e[j]));
1229 * Creates the Class object that corresponds to the bytecode buffers
1230 * built when this object was constructed.
1232 * @param loader the class loader to define the proxy class in; null
1233 * implies the bootstrap class loader
1234 * @return the proxy class Class object
1236 Class generate(ClassLoader loader)
1238 byte[] bytecode = new byte[pool.length() + stream.length()];
1239 // More efficient to bypass calling charAt() repetitively.
1240 char[] c = pool.toString().toCharArray();
1241 int i = c.length;
1242 while (--i >= 0)
1243 bytecode[i] = (byte) c[i];
1244 c = stream.toString().toCharArray();
1245 i = c.length;
1246 int j = bytecode.length;
1247 while (i > 0)
1248 bytecode[--j] = (byte) c[--i];
1250 // Patch the constant pool size, which we left at 0 earlier.
1251 int count = poolEntries.size() + 1;
1252 bytecode[8] = (byte) (count >> 8);
1253 bytecode[9] = (byte) count;
1257 Class vmClassLoader = Class.forName("java.lang.VMClassLoader");
1258 Class[] types = {ClassLoader.class, String.class,
1259 byte[].class, int.class, int.class,
1260 ProtectionDomain.class };
1261 Method m = vmClassLoader.getDeclaredMethod("defineClass", types);
1262 // We can bypass the security check of setAccessible(true), since
1263 // we're in the same package.
1264 m.flag = true;
1266 Object[] args = {loader, qualName, bytecode, Integer.valueOf(0),
1267 Integer.valueOf(bytecode.length),
1268 Object.class.getProtectionDomain() };
1269 Class clazz = (Class) m.invoke(null, args);
1271 // Finally, initialize the m field of the proxy class, before
1272 // returning it.
1273 Field f = clazz.getDeclaredField("m");
1274 f.flag = true;
1275 // we can share the array, because it is not publicized
1276 f.set(null, methods);
1278 return clazz;
1280 catch (Exception e)
1282 // assert false;
1283 throw (Error) new InternalError("Unexpected: " + e).initCause(e);
1288 * Put a single byte on the stream.
1290 * @param i the information to add (only lowest 8 bits are used)
1292 private void putU1(int i)
1294 stream.append((char) i);
1298 * Put two bytes on the stream.
1300 * @param i the information to add (only lowest 16 bits are used)
1302 private void putU2(int i)
1304 stream.append((char) (i >> 8)).append((char) i);
1308 * Put four bytes on the stream.
1310 * @param i the information to add (treated as unsigned)
1312 private void putU4(int i)
1314 stream.append((char) (i >> 24)).append((char) (i >> 16));
1315 stream.append((char) (i >> 8)).append((char) i);
1319 * Put bytecode to load a constant integer on the stream. This only
1320 * needs to work for values less than Short.MAX_VALUE.
1322 * @param i the int to add
1324 private void putConst(int i)
1326 if (i >= -1 && i <= 5)
1327 putU1(ICONST_0 + i);
1328 else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE)
1330 putU1(BIPUSH);
1331 putU1(i);
1333 else
1335 putU1(SIPUSH);
1336 putU2(i);
1341 * Put bytecode to load a given local variable on the stream.
1343 * @param i the slot to load
1344 * @param type the base type of the load
1346 private void putLoad(int i, Class type)
1348 int offset = 0;
1349 if (type == long.class)
1350 offset = 1;
1351 else if (type == float.class)
1352 offset = 2;
1353 else if (type == double.class)
1354 offset = 3;
1355 else if (! type.isPrimitive())
1356 offset = 4;
1357 if (i < 4)
1358 putU1(ILOAD_0 + 4 * offset + i);
1359 else
1361 putU1(ILOAD + offset);
1362 putU1(i);
1367 * Given a primitive type, return its wrapper class name.
1369 * @param clazz the primitive type (but not void.class)
1370 * @return the internal form of the wrapper class name
1372 private String wrapper(Class clazz)
1374 if (clazz == boolean.class)
1375 return "java/lang/Boolean";
1376 if (clazz == byte.class)
1377 return "java/lang/Byte";
1378 if (clazz == short.class)
1379 return "java/lang/Short";
1380 if (clazz == char.class)
1381 return "java/lang/Character";
1382 if (clazz == int.class)
1383 return "java/lang/Integer";
1384 if (clazz == long.class)
1385 return "java/lang/Long";
1386 if (clazz == float.class)
1387 return "java/lang/Float";
1388 if (clazz == double.class)
1389 return "java/lang/Double";
1390 // assert false;
1391 return null;
1395 * Returns the entry of this String in the Constant pool, adding it
1396 * if necessary.
1398 * @param str the String to resolve
1399 * @return the index of the String in the constant pool
1401 private char utf8Info(String str)
1403 String utf8 = toUtf8(str);
1404 int len = utf8.length();
1405 return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8);
1409 * Returns the entry of the appropriate class info structure in the
1410 * Constant pool, adding it if necessary.
1412 * @param name the class name, in internal form
1413 * @return the index of the ClassInfo in the constant pool
1415 private char classInfo(String name)
1417 char index = utf8Info(name);
1418 char[] c = {7, (char) (index >> 8), (char) (index & 0xff)};
1419 return poolIndex(new String(c));
1423 * Returns the entry of the appropriate class info structure in the
1424 * Constant pool, adding it if necessary.
1426 * @param clazz the class type
1427 * @return the index of the ClassInfo in the constant pool
1429 private char classInfo(Class clazz)
1431 return classInfo(TypeSignature.getEncodingOfClass(clazz.getName(),
1432 false));
1436 * Returns the entry of the appropriate fieldref, methodref, or
1437 * interfacemethodref info structure in the Constant pool, adding it
1438 * if necessary.
1440 * @param structure FIELD, METHOD, or INTERFACE
1441 * @param clazz the class name, in internal form
1442 * @param name the simple reference name
1443 * @param type the type of the reference
1444 * @return the index of the appropriate Info structure in the constant pool
1446 private char refInfo(byte structure, String clazz, String name,
1447 String type)
1449 char cindex = classInfo(clazz);
1450 char ntindex = nameAndTypeInfo(name, type);
1451 // relies on FIELD == 1, METHOD == 2, INTERFACE == 3
1452 char[] c = {(char) (structure + 8),
1453 (char) (cindex >> 8), (char) (cindex & 0xff),
1454 (char) (ntindex >> 8), (char) (ntindex & 0xff)};
1455 return poolIndex(new String(c));
1459 * Returns the entry of the appropriate nameAndTyperef info structure
1460 * in the Constant pool, adding it if necessary.
1462 * @param name the simple name
1463 * @param type the reference type
1464 * @return the index of the NameAndTypeInfo structure in the constant pool
1466 private char nameAndTypeInfo(String name, String type)
1468 char nindex = utf8Info(name);
1469 char tindex = utf8Info(type);
1470 char[] c = {12, (char) (nindex >> 8), (char) (nindex & 0xff),
1471 (char) (tindex >> 8), (char) (tindex & 0xff)};
1472 return poolIndex(new String(c));
1476 * Converts a regular string to a UTF8 string, where the upper byte
1477 * of every char is 0, and '\\u0000' is not in the string. This is
1478 * basically to use a String as a fancy byte[], and while it is less
1479 * efficient in memory use, it is easier for hashing.
1481 * @param str the original, in straight unicode
1482 * @return a modified string, in UTF8 format in the low bytes
1484 private String toUtf8(String str)
1486 final char[] ca = str.toCharArray();
1487 final int len = ca.length;
1489 // Avoid object creation, if str is already fits UTF8.
1490 int i;
1491 for (i = 0; i < len; i++)
1492 if (ca[i] == 0 || ca[i] > '\u007f')
1493 break;
1494 if (i == len)
1495 return str;
1497 final CPStringBuilder sb = new CPStringBuilder(str);
1498 sb.setLength(i);
1499 for ( ; i < len; i++)
1501 final char c = ca[i];
1502 if (c > 0 && c <= '\u007f')
1503 sb.append(c);
1504 else if (c <= '\u07ff') // includes '\0'
1506 sb.append((char) (0xc0 | (c >> 6)));
1507 sb.append((char) (0x80 | (c & 0x6f)));
1509 else
1511 sb.append((char) (0xe0 | (c >> 12)));
1512 sb.append((char) (0x80 | ((c >> 6) & 0x6f)));
1513 sb.append((char) (0x80 | (c & 0x6f)));
1516 return sb.toString();
1520 * Returns the location of a byte sequence (conveniently wrapped in
1521 * a String with all characters between \u0001 and \u00ff inclusive)
1522 * in the constant pool, adding it if necessary.
1524 * @param sequence the byte sequence to look for
1525 * @return the index of the sequence
1526 * @throws IllegalArgumentException if this would make the constant
1527 * pool overflow
1529 private char poolIndex(String sequence)
1531 Integer i = (Integer) poolEntries.get(sequence);
1532 if (i == null)
1534 // pool starts at index 1
1535 int size = poolEntries.size() + 1;
1536 if (size >= 65535)
1537 throw new IllegalArgumentException("exceeds VM limitations");
1538 i = Integer.valueOf(size);
1539 poolEntries.put(sequence, i);
1540 pool.append(sequence);
1542 return (char) i.intValue();
1544 } // class ClassFactory