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