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