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