GNU Classpath (0.20) | |
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(Class)} 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 #newProxyInstance(ClassLoader, Class[], InvocationHandler)} 115: * is shorthand to do the necessary 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: this.loader = loader; 417: this.interfaces = interfaces; 418: } 419: 420: /** 421: * Calculates the hash code. 422: * 423: * @return a combination of the classloader and interfaces hashcodes. 424: */ 425: public int hashCode() 426: { 427: int hash = loader == null ? 0 : loader.hashCode(); 428: for (int i = 0; i < interfaces.length; i++) 429: hash = hash * 31 + interfaces[i].hashCode(); 430: return hash; 431: } 432: 433: /** 434: * Calculates equality. 435: * 436: * @param other object to compare to 437: * @return true if it is a ProxyType with same data 438: */ 439: public boolean equals(Object other) 440: { 441: ProxyType pt = (ProxyType) other; 442: if (loader != pt.loader || interfaces.length != pt.interfaces.length) 443: return false; 444: for (int i = 0; i < interfaces.length; i++) 445: if (interfaces[i] != pt.interfaces[i]) 446: return false; 447: return true; 448: } 449: } // class ProxyType 450: 451: /** 452: * Helper class which allows hashing of a method name and signature 453: * without worrying about return type, declaring class, or throws clause, 454: * and which reduces the maximally common throws clause between two methods 455: * 456: * @author Eric Blake (ebb9@email.byu.edu) 457: */ 458: private static final class ProxySignature 459: { 460: /** 461: * The core signatures which all Proxy instances handle. 462: */ 463: static final HashMap coreMethods = new HashMap(); 464: static 465: { 466: try 467: { 468: ProxySignature sig 469: = new ProxySignature(Object.class 470: .getMethod("equals", 471: new Class[] {Object.class})); 472: coreMethods.put(sig, sig); 473: sig = new ProxySignature(Object.class.getMethod("hashCode", null)); 474: coreMethods.put(sig, sig); 475: sig = new ProxySignature(Object.class.getMethod("toString", null)); 476: coreMethods.put(sig, sig); 477: } 478: catch (Exception e) 479: { 480: // assert false; 481: throw (Error) new InternalError("Unexpected: " + e).initCause(e); 482: } 483: } 484: 485: /** 486: * The underlying Method object, never null 487: */ 488: final Method method; 489: 490: /** 491: * The set of compatible thrown exceptions, may be empty 492: */ 493: final Set exceptions = new HashSet(); 494: 495: /** 496: * Construct a signature 497: * 498: * @param method the Method this signature is based on, never null 499: */ 500: ProxySignature(Method method) 501: { 502: this.method = method; 503: Class[] exc = method.getExceptionTypes(); 504: int i = exc.length; 505: while (--i >= 0) 506: { 507: // discard unchecked exceptions 508: if (Error.class.isAssignableFrom(exc[i]) 509: || RuntimeException.class.isAssignableFrom(exc[i])) 510: continue; 511: exceptions.add(exc[i]); 512: } 513: } 514: 515: /** 516: * Given a method, make sure it's return type is identical 517: * to this, and adjust this signature's throws clause appropriately 518: * 519: * @param other the signature to merge in 520: * @throws IllegalArgumentException if the return types conflict 521: */ 522: void checkCompatibility(ProxySignature other) 523: { 524: if (method.getReturnType() != other.method.getReturnType()) 525: throw new IllegalArgumentException("incompatible return types: " 526: + method + ", " + other.method); 527: 528: // if you can think of a more efficient way than this O(n^2) search, 529: // implement it! 530: int size1 = exceptions.size(); 531: int size2 = other.exceptions.size(); 532: boolean[] valid1 = new boolean[size1]; 533: boolean[] valid2 = new boolean[size2]; 534: Iterator itr = exceptions.iterator(); 535: int pos = size1; 536: while (--pos >= 0) 537: { 538: Class c1 = (Class) itr.next(); 539: Iterator itr2 = other.exceptions.iterator(); 540: int pos2 = size2; 541: while (--pos2 >= 0) 542: { 543: Class c2 = (Class) itr2.next(); 544: if (c2.isAssignableFrom(c1)) 545: valid1[pos] = true; 546: if (c1.isAssignableFrom(c2)) 547: valid2[pos2] = true; 548: } 549: } 550: pos = size1; 551: itr = exceptions.iterator(); 552: while (--pos >= 0) 553: { 554: itr.next(); 555: if (! valid1[pos]) 556: itr.remove(); 557: } 558: pos = size2; 559: itr = other.exceptions.iterator(); 560: while (--pos >= 0) 561: { 562: itr.next(); 563: if (! valid2[pos]) 564: itr.remove(); 565: } 566: exceptions.addAll(other.exceptions); 567: } 568: 569: /** 570: * Calculates the hash code. 571: * 572: * @return a combination of name and parameter types 573: */ 574: public int hashCode() 575: { 576: int hash = method.getName().hashCode(); 577: Class[] types = method.getParameterTypes(); 578: for (int i = 0; i < types.length; i++) 579: hash = hash * 31 + types[i].hashCode(); 580: return hash; 581: } 582: 583: /** 584: * Calculates equality. 585: * 586: * @param other object to compare to 587: * @return true if it is a ProxySignature with same data 588: */ 589: public boolean equals(Object other) 590: { 591: ProxySignature ps = (ProxySignature) other; 592: Class[] types1 = method.getParameterTypes(); 593: Class[] types2 = ps.method.getParameterTypes(); 594: if (! method.getName().equals(ps.method.getName()) 595: || types1.length != types2.length) 596: return false; 597: int i = types1.length; 598: while (--i >= 0) 599: if (types1[i] != types2[i]) 600: return false; 601: return true; 602: } 603: } // class ProxySignature 604: 605: /** 606: * A flat representation of all data needed to generate bytecode/instantiate 607: * a proxy class. This is basically a struct. 608: * 609: * @author Eric Blake (ebb9@email.byu.edu) 610: */ 611: static final class ProxyData 612: { 613: /** 614: * The package this class is in <b>including the trailing dot</b> 615: * or an empty string for the unnamed (aka default) package. 616: */ 617: String pack = ""; 618: 619: /** 620: * The interfaces this class implements. Non-null, but possibly empty. 621: */ 622: Class[] interfaces; 623: 624: /** 625: * The Method objects this class must pass as the second argument to 626: * invoke (also useful for determining what methods this class has). 627: * Non-null, non-empty (includes at least Object.hashCode, Object.equals, 628: * and Object.toString). 629: */ 630: Method[] methods; 631: 632: /** 633: * The exceptions that do not need to be wrapped in 634: * UndeclaredThrowableException. exceptions[i] is the same as, or a 635: * subset of subclasses, of methods[i].getExceptionTypes(), depending on 636: * compatible throws clauses with multiple inheritance. It is unspecified 637: * if these lists include or exclude subclasses of Error and 638: * RuntimeException, but excluding them is harmless and generates a 639: * smaller class. 640: */ 641: Class[][] exceptions; 642: 643: /** 644: * For unique id's 645: */ 646: private static int count; 647: 648: /** 649: * The id of this proxy class 650: */ 651: final int id = count++; 652: 653: /** 654: * Construct a ProxyData with uninitialized data members. 655: */ 656: ProxyData() 657: { 658: } 659: 660: /** 661: * Return the name of a package (including the trailing dot) 662: * given the name of a class. 663: * Returns an empty string if no package. We use this in preference to 664: * using Class.getPackage() to avoid problems with ClassLoaders 665: * that don't set the package. 666: */ 667: private static String getPackage(Class k) 668: { 669: String name = k.getName(); 670: int idx = name.lastIndexOf('.'); 671: return name.substring(0, idx + 1); 672: } 673: 674: /** 675: * Verifies that the arguments are legal, and sets up remaining data 676: * This should only be called when a class must be generated, as 677: * it is expensive. 678: * 679: * @param pt the ProxyType to convert to ProxyData 680: * @return the flattened, verified ProxyData structure for use in 681: * class generation 682: * @throws IllegalArgumentException if `interfaces' contains 683: * non-interfaces or incompatible combinations, and verify is true 684: * @throws NullPointerException if interfaces is null or contains null 685: */ 686: static ProxyData getProxyData(ProxyType pt) 687: { 688: Map method_set = (Map) ProxySignature.coreMethods.clone(); 689: boolean in_package = false; // true if we encounter non-public interface 690: 691: ProxyData data = new ProxyData(); 692: data.interfaces = pt.interfaces; 693: 694: // if interfaces is too large, we croak later on when the constant 695: // pool overflows 696: int i = data.interfaces.length; 697: while (--i >= 0) 698: { 699: Class inter = data.interfaces[i]; 700: if (! inter.isInterface()) 701: throw new IllegalArgumentException("not an interface: " + inter); 702: try 703: { 704: if (Class.forName(inter.getName(), false, pt.loader) != inter) 705: throw new IllegalArgumentException("not accessible in " 706: + "classloader: " + inter); 707: } 708: catch (ClassNotFoundException e) 709: { 710: throw new IllegalArgumentException("not accessible in " 711: + "classloader: " + inter); 712: } 713: if (! Modifier.isPublic(inter.getModifiers())) 714: if (in_package) 715: { 716: String p = getPackage(inter); 717: if (! data.pack.equals(p)) 718: throw new IllegalArgumentException("non-public interfaces " 719: + "from different " 720: + "packages"); 721: } 722: else 723: { 724: in_package = true; 725: data.pack = getPackage(inter); 726: } 727: for (int j = i-1; j >= 0; j--) 728: if (data.interfaces[j] == inter) 729: throw new IllegalArgumentException("duplicate interface: " 730: + inter); 731: Method[] methods = inter.getMethods(); 732: int j = methods.length; 733: while (--j >= 0) 734: { 735: ProxySignature sig = new ProxySignature(methods[j]); 736: ProxySignature old = (ProxySignature) method_set.put(sig, sig); 737: if (old != null) 738: sig.checkCompatibility(old); 739: } 740: } 741: 742: i = method_set.size(); 743: data.methods = new Method[i]; 744: data.exceptions = new Class[i][]; 745: Iterator itr = method_set.values().iterator(); 746: while (--i >= 0) 747: { 748: ProxySignature sig = (ProxySignature) itr.next(); 749: data.methods[i] = sig.method; 750: data.exceptions[i] = (Class[]) sig.exceptions 751: .toArray(new Class[sig.exceptions.size()]); 752: } 753: return data; 754: } 755: } // class ProxyData 756: 757: /** 758: * Does all the work of building a class. By making this a nested class, 759: * this code is not loaded in memory if the VM has a native 760: * implementation instead. 761: * 762: * @author Eric Blake (ebb9@email.byu.edu) 763: */ 764: private static final class ClassFactory 765: { 766: /** Constants for assisting the compilation */ 767: private static final byte FIELD = 1; 768: private static final byte METHOD = 2; 769: private static final byte INTERFACE = 3; 770: private static final String CTOR_SIG 771: = "(Ljava/lang/reflect/InvocationHandler;)V"; 772: private static final String INVOKE_SIG = "(Ljava/lang/Object;" 773: + "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"; 774: 775: /** Bytecodes for insertion in the class definition byte[] */ 776: private static final char ACONST_NULL = 1; 777: private static final char ICONST_0 = 3; 778: private static final char BIPUSH = 16; 779: private static final char SIPUSH = 17; 780: private static final char ILOAD = 21; 781: private static final char ILOAD_0 = 26; 782: private static final char ALOAD_0 = 42; 783: private static final char ALOAD_1 = 43; 784: private static final char AALOAD = 50; 785: private static final char AASTORE = 83; 786: private static final char DUP = 89; 787: private static final char DUP_X1 = 90; 788: private static final char SWAP = 95; 789: private static final char IRETURN = 172; 790: private static final char LRETURN = 173; 791: private static final char FRETURN = 174; 792: private static final char DRETURN = 175; 793: private static final char ARETURN = 176; 794: private static final char RETURN = 177; 795: private static final char GETSTATIC = 178; 796: private static final char GETFIELD = 180; 797: private static final char INVOKEVIRTUAL = 182; 798: private static final char INVOKESPECIAL = 183; 799: private static final char INVOKEINTERFACE = 185; 800: private static final char NEW = 187; 801: private static final char ANEWARRAY = 189; 802: private static final char ATHROW = 191; 803: private static final char CHECKCAST = 192; 804: 805: // Implementation note: we use StringBuffers to hold the byte data, since 806: // they automatically grow. However, we only use the low 8 bits of 807: // every char in the array, so we are using twice the necessary memory 808: // for the ease StringBuffer provides. 809: 810: /** The constant pool. */ 811: private final StringBuffer pool = new StringBuffer(); 812: /** The rest of the class data. */ 813: private final StringBuffer stream = new StringBuffer(); 814: 815: /** Map of strings to byte sequences, to minimize size of pool. */ 816: private final Map poolEntries = new HashMap(); 817: 818: /** The VM name of this proxy class. */ 819: private final String qualName; 820: 821: /** 822: * The Method objects the proxy class refers to when calling the 823: * invocation handler. 824: */ 825: private final Method[] methods; 826: 827: /** 828: * Initializes the buffers with the bytecode contents for a proxy class. 829: * 830: * @param data the remainder of the class data 831: * @throws IllegalArgumentException if anything else goes wrong this 832: * late in the game; as far as I can tell, this will only happen 833: * if the constant pool overflows, which is possible even when 834: * the user doesn't exceed the 65535 interface limit 835: */ 836: ClassFactory(ProxyData data) 837: { 838: methods = data.methods; 839: 840: // magic = 0xcafebabe 841: // minor_version = 0 842: // major_version = 46 843: // constant_pool_count: place-holder for now 844: pool.append("\u00ca\u00fe\u00ba\u00be\0\0\0\56\0\0"); 845: // constant_pool[], filled in as we go 846: 847: // access_flags 848: putU2(Modifier.SUPER | Modifier.FINAL | Modifier.PUBLIC); 849: // this_class 850: qualName = (data.pack + "$Proxy" + data.id); 851: putU2(classInfo(TypeSignature.getEncodingOfClass(qualName, false))); 852: // super_class 853: putU2(classInfo("java/lang/reflect/Proxy")); 854: 855: // interfaces_count 856: putU2(data.interfaces.length); 857: // interfaces[] 858: for (int i = 0; i < data.interfaces.length; i++) 859: putU2(classInfo(data.interfaces[i])); 860: 861: // Recall that Proxy classes serialize specially, so we do not need 862: // to worry about a <clinit> method for this field. Instead, we 863: // just assign it by reflection after the class is successfully loaded. 864: // fields_count - private static Method[] m; 865: putU2(1); 866: // fields[] 867: // m.access_flags 868: putU2(Modifier.PRIVATE | Modifier.STATIC); 869: // m.name_index 870: putU2(utf8Info("m")); 871: // m.descriptor_index 872: putU2(utf8Info("[Ljava/lang/reflect/Method;")); 873: // m.attributes_count 874: putU2(0); 875: // m.attributes[] 876: 877: // methods_count - # handler methods, plus <init> 878: putU2(methods.length + 1); 879: // methods[] 880: // <init>.access_flags 881: putU2(Modifier.PUBLIC); 882: // <init>.name_index 883: putU2(utf8Info("<init>")); 884: // <init>.descriptor_index 885: putU2(utf8Info(CTOR_SIG)); 886: // <init>.attributes_count - only Code is needed 887: putU2(1); 888: // <init>.Code.attribute_name_index 889: putU2(utf8Info("Code")); 890: // <init>.Code.attribute_length = 18 891: // <init>.Code.info: 892: // $Proxynn(InvocationHandler h) { super(h); } 893: // <init>.Code.max_stack = 2 894: // <init>.Code.max_locals = 2 895: // <init>.Code.code_length = 6 896: // <init>.Code.code[] 897: stream.append("\0\0\0\22\0\2\0\2\0\0\0\6" + ALOAD_0 + ALOAD_1 898: + INVOKESPECIAL); 899: putU2(refInfo(METHOD, "java/lang/reflect/Proxy", "<init>", CTOR_SIG)); 900: // <init>.Code.exception_table_length = 0 901: // <init>.Code.exception_table[] 902: // <init>.Code.attributes_count = 0 903: // <init>.Code.attributes[] 904: stream.append(RETURN + "\0\0\0\0"); 905: 906: for (int i = methods.length - 1; i >= 0; i--) 907: emitMethod(i, data.exceptions[i]); 908: 909: // attributes_count 910: putU2(0); 911: // attributes[] - empty; omit SourceFile attribute 912: // XXX should we mark this with a Synthetic attribute? 913: } 914: 915: /** 916: * Produce the bytecode for a single method. 917: * 918: * @param i the index of the method we are building 919: * @param e the exceptions possible for the method 920: */ 921: private void emitMethod(int i, Class[] e) 922: { 923: // First, we precalculate the method length and other information. 924: 925: Method m = methods[i]; 926: Class[] paramtypes = m.getParameterTypes(); 927: int wrap_overhead = 0; // max words taken by wrapped primitive 928: int param_count = 1; // 1 for this 929: int code_length = 16; // aload_0, getfield, aload_0, getstatic, const, 930: // aaload, const/aconst_null, invokeinterface 931: if (i > 5) 932: { 933: if (i > Byte.MAX_VALUE) 934: code_length += 2; // sipush 935: else 936: code_length++; // bipush 937: } 938: if (paramtypes.length > 0) 939: { 940: code_length += 3; // anewarray 941: if (paramtypes.length > Byte.MAX_VALUE) 942: code_length += 2; // sipush 943: else if (paramtypes.length > 5) 944: code_length++; // bipush 945: for (int j = 0; j < paramtypes.length; j++) 946: { 947: code_length += 4; // dup, const, load, store 948: Class type = paramtypes[j]; 949: if (j > 5) 950: { 951: if (j > Byte.MAX_VALUE) 952: code_length += 2; // sipush 953: else 954: code_length++; // bipush 955: } 956: if (param_count >= 4) 957: code_length++; // 2-byte load 958: param_count++; 959: if (type.isPrimitive()) 960: { 961: code_length += 7; // new, dup, invokespecial 962: if (type == long.class || type == double.class) 963: { 964: wrap_overhead = 3; 965: param_count++; 966: } 967: else if (wrap_overhead < 2) 968: wrap_overhead = 2; 969: } 970: } 971: } 972: int end_pc = code_length; 973: Class ret_type = m.getReturnType(); 974: if (ret_type == void.class) 975: code_length++; // return 976: else if (ret_type.isPrimitive()) 977: code_length += 7; // cast, invokevirtual, return 978: else 979: code_length += 4; // cast, return 980: int exception_count = 0; 981: boolean throws_throwable = false; 982: for (int j = 0; j < e.length; j++) 983: if (e[j] == Throwable.class) 984: { 985: throws_throwable = true; 986: break; 987: } 988: if (! throws_throwable) 989: { 990: exception_count = e.length + 3; // Throwable, Error, RuntimeException 991: code_length += 9; // new, dup_x1, swap, invokespecial, athrow 992: } 993: int handler_pc = code_length - 1; 994: StringBuffer signature = new StringBuffer("("); 995: for (int j = 0; j < paramtypes.length; j++) 996: signature.append(TypeSignature.getEncodingOfClass(paramtypes[j])); 997: signature.append(")").append(TypeSignature.getEncodingOfClass(ret_type)); 998: 999: // Now we have enough information to emit the method. 1000: 1001: // handler.access_flags 1002: putU2(Modifier.PUBLIC | Modifier.FINAL); 1003: // handler.name_index 1004: putU2(utf8Info(m.getName())); 1005: // handler.descriptor_index 1006: putU2(utf8Info(signature.toString())); 1007: // handler.attributes_count - Code is necessary, Exceptions possible 1008: putU2(e.length > 0 ? 2 : 1); 1009: 1010: // handler.Code.info: 1011: // type name(args) { 1012: // try { 1013: // return (type) h.invoke(this, methods[i], new Object[] {args}); 1014: // } catch (<declared Exceptions> e) { 1015: // throw e; 1016: // } catch (Throwable t) { 1017: // throw new UndeclaredThrowableException(t); 1018: // } 1019: // } 1020: // Special cases: 1021: // if arg_n is primitive, wrap it 1022: // if method throws Throwable, try-catch is not needed 1023: // if method returns void, return statement not needed 1024: // if method returns primitive, unwrap it 1025: // save space by sharing code for all the declared handlers 1026: 1027: // handler.Code.attribute_name_index 1028: putU2(utf8Info("Code")); 1029: // handler.Code.attribute_length 1030: putU4(12 + code_length + 8 * exception_count); 1031: // handler.Code.max_stack 1032: putU2(param_count == 1 ? 4 : 7 + wrap_overhead); 1033: // handler.Code.max_locals 1034: putU2(param_count); 1035: // handler.Code.code_length 1036: putU4(code_length); 1037: // handler.Code.code[] 1038: putU1(ALOAD_0); 1039: putU1(GETFIELD); 1040: putU2(refInfo(FIELD, "java/lang/reflect/Proxy", "h", 1041: "Ljava/lang/reflect/InvocationHandler;")); 1042: putU1(ALOAD_0); 1043: putU1(GETSTATIC); 1044: putU2(refInfo(FIELD, TypeSignature.getEncodingOfClass(qualName, false), 1045: "m", "[Ljava/lang/reflect/Method;")); 1046: putConst(i); 1047: putU1(AALOAD); 1048: if (paramtypes.length > 0) 1049: { 1050: putConst(paramtypes.length); 1051: putU1(ANEWARRAY); 1052: putU2(classInfo("java/lang/Object")); 1053: param_count = 1; 1054: for (int j = 0; j < paramtypes.length; j++, param_count++) 1055: { 1056: putU1(DUP); 1057: putConst(j); 1058: if (paramtypes[j].isPrimitive()) 1059: { 1060: putU1(NEW); 1061: putU2(classInfo(wrapper(paramtypes[j]))); 1062: putU1(DUP); 1063: } 1064: putLoad(param_count, paramtypes[j]); 1065: if (paramtypes[j].isPrimitive()) 1066: { 1067: putU1(INVOKESPECIAL); 1068: putU2(refInfo(METHOD, wrapper(paramtypes[j]), "<init>", 1069: '(' + (TypeSignature 1070: .getEncodingOfClass(paramtypes[j]) 1071: + ")V"))); 1072: if (paramtypes[j] == long.class 1073: || paramtypes[j] == double.class) 1074: param_count++; 1075: } 1076: putU1(AASTORE); 1077: } 1078: } 1079: else 1080: putU1(ACONST_NULL); 1081: putU1(INVOKEINTERFACE); 1082: putU2(refInfo(INTERFACE, "java/lang/reflect/InvocationHandler", 1083: "invoke", INVOKE_SIG)); 1084: putU1(4); // InvocationHandler, this, Method, Object[] 1085: putU1(0); 1086: if (ret_type == void.class) 1087: putU1(RETURN); 1088: else if (ret_type.isPrimitive()) 1089: { 1090: putU1(CHECKCAST); 1091: putU2(classInfo(wrapper(ret_type))); 1092: putU1(INVOKEVIRTUAL); 1093: putU2(refInfo(METHOD, wrapper(ret_type), 1094: ret_type.getName() + "Value", 1095: "()" + TypeSignature.getEncodingOfClass(ret_type))); 1096: if (ret_type == long.class) 1097: putU1(LRETURN); 1098: else if (ret_type == float.class) 1099: putU1(FRETURN); 1100: else if (ret_type == double.class) 1101: putU1(DRETURN); 1102: else 1103: putU1(IRETURN); 1104: } 1105: else 1106: { 1107: putU1(CHECKCAST); 1108: putU2(classInfo(ret_type)); 1109: putU1(ARETURN); 1110: } 1111: if (! throws_throwable) 1112: { 1113: putU1(NEW); 1114: putU2(classInfo("java/lang/reflect/UndeclaredThrowableException")); 1115: putU1(DUP_X1); 1116: putU1(SWAP); 1117: putU1(INVOKESPECIAL); 1118: putU2(refInfo(METHOD, 1119: "java/lang/reflect/UndeclaredThrowableException", 1120: "<init>", "(Ljava/lang/Throwable;)V")); 1121: putU1(ATHROW); 1122: } 1123: 1124: // handler.Code.exception_table_length 1125: putU2(exception_count); 1126: // handler.Code.exception_table[] 1127: if (! throws_throwable) 1128: { 1129: // handler.Code.exception_table.start_pc 1130: putU2(0); 1131: // handler.Code.exception_table.end_pc 1132: putU2(end_pc); 1133: // handler.Code.exception_table.handler_pc 1134: putU2(handler_pc); 1135: // handler.Code.exception_table.catch_type 1136: putU2(classInfo("java/lang/Error")); 1137: // handler.Code.exception_table.start_pc 1138: putU2(0); 1139: // handler.Code.exception_table.end_pc 1140: putU2(end_pc); 1141: // handler.Code.exception_table.handler_pc 1142: putU2(handler_pc); 1143: // handler.Code.exception_table.catch_type 1144: putU2(classInfo("java/lang/RuntimeException")); 1145: for (int j = 0; j < e.length; j++) 1146: { 1147: // handler.Code.exception_table.start_pc 1148: putU2(0); 1149: // handler.Code.exception_table.end_pc 1150: putU2(end_pc); 1151: // handler.Code.exception_table.handler_pc 1152: putU2(handler_pc); 1153: // handler.Code.exception_table.catch_type 1154: putU2(classInfo(e[j])); 1155: } 1156: // handler.Code.exception_table.start_pc 1157: putU2(0); 1158: // handler.Code.exception_table.end_pc 1159: putU2(end_pc); 1160: // handler.Code.exception_table.handler_pc - 1161: // -8 for undeclared handler, which falls thru to normal one 1162: putU2(handler_pc - 8); 1163: // handler.Code.exception_table.catch_type 1164: putU2(0); 1165: } 1166: // handler.Code.attributes_count 1167: putU2(0); 1168: // handler.Code.attributes[] 1169: 1170: if (e.length > 0) 1171: { 1172: // handler.Exceptions.attribute_name_index 1173: putU2(utf8Info("Exceptions")); 1174: // handler.Exceptions.attribute_length 1175: putU4(2 * e.length + 2); 1176: // handler.Exceptions.number_of_exceptions 1177: putU2(e.length); 1178: // handler.Exceptions.exception_index_table[] 1179: for (int j = 0; j < e.length; j++) 1180: putU2(classInfo(e[j])); 1181: } 1182: } 1183: 1184: /** 1185: * Creates the Class object that corresponds to the bytecode buffers 1186: * built when this object was constructed. 1187: * 1188: * @param loader the class loader to define the proxy class in; null 1189: * implies the bootstrap class loader 1190: * @return the proxy class Class object 1191: */ 1192: Class generate(ClassLoader loader) 1193: { 1194: byte[] bytecode = new byte[pool.length() + stream.length()]; 1195: // More efficient to bypass calling charAt() repetitively. 1196: char[] c = pool.toString().toCharArray(); 1197: int i = c.length; 1198: while (--i >= 0) 1199: bytecode[i] = (byte) c[i]; 1200: c = stream.toString().toCharArray(); 1201: i = c.length; 1202: int j = bytecode.length; 1203: while (i > 0) 1204: bytecode[--j] = (byte) c[--i]; 1205: 1206: // Patch the constant pool size, which we left at 0 earlier. 1207: int count = poolEntries.size() + 1; 1208: bytecode[8] = (byte) (count >> 8); 1209: bytecode[9] = (byte) count; 1210: 1211: try 1212: { 1213: Class vmClassLoader = Class.forName("java.lang.VMClassLoader"); 1214: Class[] types = {ClassLoader.class, String.class, 1215: byte[].class, int.class, int.class, 1216: ProtectionDomain.class }; 1217: Method m = vmClassLoader.getDeclaredMethod("defineClass", types); 1218: // We can bypass the security check of setAccessible(true), since 1219: // we're in the same package. 1220: m.flag = true; 1221: 1222: Object[] args = {loader, qualName, bytecode, new Integer(0), 1223: new Integer(bytecode.length), 1224: Object.class.getProtectionDomain() }; 1225: Class clazz = (Class) m.invoke(null, args); 1226: 1227: // Finally, initialize the m field of the proxy class, before 1228: // returning it. 1229: Field f = clazz.getDeclaredField("m"); 1230: f.flag = true; 1231: // we can share the array, because it is not publicized 1232: f.set(null, methods); 1233: 1234: return clazz; 1235: } 1236: catch (Exception e) 1237: { 1238: // assert false; 1239: throw (Error) new InternalError("Unexpected: " + e).initCause(e); 1240: } 1241: } 1242: 1243: /** 1244: * Put a single byte on the stream. 1245: * 1246: * @param i the information to add (only lowest 8 bits are used) 1247: */ 1248: private void putU1(int i) 1249: { 1250: stream.append((char) i); 1251: } 1252: 1253: /** 1254: * Put two bytes on the stream. 1255: * 1256: * @param i the information to add (only lowest 16 bits are used) 1257: */ 1258: private void putU2(int i) 1259: { 1260: stream.append((char) (i >> 8)).append((char) i); 1261: } 1262: 1263: /** 1264: * Put four bytes on the stream. 1265: * 1266: * @param i the information to add (treated as unsigned) 1267: */ 1268: private void putU4(int i) 1269: { 1270: stream.append((char) (i >> 24)).append((char) (i >> 16)); 1271: stream.append((char) (i >> 8)).append((char) i); 1272: } 1273: 1274: /** 1275: * Put bytecode to load a constant integer on the stream. This only 1276: * needs to work for values less than Short.MAX_VALUE. 1277: * 1278: * @param i the int to add 1279: */ 1280: private void putConst(int i) 1281: { 1282: if (i >= -1 && i <= 5) 1283: putU1(ICONST_0 + i); 1284: else if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) 1285: { 1286: putU1(BIPUSH); 1287: putU1(i); 1288: } 1289: else 1290: { 1291: putU1(SIPUSH); 1292: putU2(i); 1293: } 1294: } 1295: 1296: /** 1297: * Put bytecode to load a given local variable on the stream. 1298: * 1299: * @param i the slot to load 1300: * @param type the base type of the load 1301: */ 1302: private void putLoad(int i, Class type) 1303: { 1304: int offset = 0; 1305: if (type == long.class) 1306: offset = 1; 1307: else if (type == float.class) 1308: offset = 2; 1309: else if (type == double.class) 1310: offset = 3; 1311: else if (! type.isPrimitive()) 1312: offset = 4; 1313: if (i < 4) 1314: putU1(ILOAD_0 + 4 * offset + i); 1315: else 1316: { 1317: putU1(ILOAD + offset); 1318: putU1(i); 1319: } 1320: } 1321: 1322: /** 1323: * Given a primitive type, return its wrapper class name. 1324: * 1325: * @param clazz the primitive type (but not void.class) 1326: * @return the internal form of the wrapper class name 1327: */ 1328: private String wrapper(Class clazz) 1329: { 1330: if (clazz == boolean.class) 1331: return "java/lang/Boolean"; 1332: if (clazz == byte.class) 1333: return "java/lang/Byte"; 1334: if (clazz == short.class) 1335: return "java/lang/Short"; 1336: if (clazz == char.class) 1337: return "java/lang/Character"; 1338: if (clazz == int.class) 1339: return "java/lang/Integer"; 1340: if (clazz == long.class) 1341: return "java/lang/Long"; 1342: if (clazz == float.class) 1343: return "java/lang/Float"; 1344: if (clazz == double.class) 1345: return "java/lang/Double"; 1346: // assert false; 1347: return null; 1348: } 1349: 1350: /** 1351: * Returns the entry of this String in the Constant pool, adding it 1352: * if necessary. 1353: * 1354: * @param str the String to resolve 1355: * @return the index of the String in the constant pool 1356: */ 1357: private char utf8Info(String str) 1358: { 1359: String utf8 = toUtf8(str); 1360: int len = utf8.length(); 1361: return poolIndex("\1" + (char) (len >> 8) + (char) (len & 0xff) + utf8); 1362: } 1363: 1364: /** 1365: * Returns the entry of the appropriate class info structure in the 1366: * Constant pool, adding it if necessary. 1367: * 1368: * @param name the class name, in internal form 1369: * @return the index of the ClassInfo in the constant pool 1370: */ 1371: private char classInfo(String name) 1372: { 1373: char index = utf8Info(name); 1374: char[] c = {7, (char) (index >> 8), (char) (index & 0xff)}; 1375: return poolIndex(new String(c)); 1376: } 1377: 1378: /** 1379: * Returns the entry of the appropriate class info structure in the 1380: * Constant pool, adding it if necessary. 1381: * 1382: * @param clazz the class type 1383: * @return the index of the ClassInfo in the constant pool 1384: */ 1385: private char classInfo(Class clazz) 1386: { 1387: return classInfo(TypeSignature.getEncodingOfClass(clazz.getName(), 1388: false)); 1389: } 1390: 1391: /** 1392: * Returns the entry of the appropriate fieldref, methodref, or 1393: * interfacemethodref info structure in the Constant pool, adding it 1394: * if necessary. 1395: * 1396: * @param structure FIELD, METHOD, or INTERFACE 1397: * @param clazz the class name, in internal form 1398: * @param name the simple reference name 1399: * @param type the type of the reference 1400: * @return the index of the appropriate Info structure in the constant pool 1401: */ 1402: private char refInfo(byte structure, String clazz, String name, 1403: String type) 1404: { 1405: char cindex = classInfo(clazz); 1406: char ntindex = nameAndTypeInfo(name, type); 1407: // relies on FIELD == 1, METHOD == 2, INTERFACE == 3 1408: char[] c = {(char) (structure + 8), 1409: (char) (cindex >> 8), (char) (cindex & 0xff), 1410: (char) (ntindex >> 8), (char) (ntindex & 0xff)}; 1411: return poolIndex(new String(c)); 1412: } 1413: 1414: /** 1415: * Returns the entry of the appropriate nameAndTyperef info structure 1416: * in the Constant pool, adding it if necessary. 1417: * 1418: * @param name the simple name 1419: * @param type the reference type 1420: * @return the index of the NameAndTypeInfo structure in the constant pool 1421: */ 1422: private char nameAndTypeInfo(String name, String type) 1423: { 1424: char nindex = utf8Info(name); 1425: char tindex = utf8Info(type); 1426: char[] c = {12, (char) (nindex >> 8), (char) (nindex & 0xff), 1427: (char) (tindex >> 8), (char) (tindex & 0xff)}; 1428: return poolIndex(new String(c)); 1429: } 1430: 1431: /** 1432: * Converts a regular string to a UTF8 string, where the upper byte 1433: * of every char is 0, and '\\u0000' is not in the string. This is 1434: * basically to use a String as a fancy byte[], and while it is less 1435: * efficient in memory use, it is easier for hashing. 1436: * 1437: * @param str the original, in straight unicode 1438: * @return a modified string, in UTF8 format in the low bytes 1439: */ 1440: private String toUtf8(String str) 1441: { 1442: final char[] ca = str.toCharArray(); 1443: final int len = ca.length; 1444: 1445: // Avoid object creation, if str is already fits UTF8. 1446: int i; 1447: for (i = 0; i < len; i++) 1448: if (ca[i] == 0 || ca[i] > '\u007f') 1449: break; 1450: if (i == len) 1451: return str; 1452: 1453: final StringBuffer sb = new StringBuffer(str); 1454: sb.setLength(i); 1455: for ( ; i < len; i++) 1456: { 1457: final char c = ca[i]; 1458: if (c > 0 && c <= '\u007f') 1459: sb.append(c); 1460: else if (c <= '\u07ff') // includes '\0' 1461: { 1462: sb.append((char) (0xc0 | (c >> 6))); 1463: sb.append((char) (0x80 | (c & 0x6f))); 1464: } 1465: else 1466: { 1467: sb.append((char) (0xe0 | (c >> 12))); 1468: sb.append((char) (0x80 | ((c >> 6) & 0x6f))); 1469: sb.append((char) (0x80 | (c & 0x6f))); 1470: } 1471: } 1472: return sb.toString(); 1473: } 1474: 1475: /** 1476: * Returns the location of a byte sequence (conveniently wrapped in 1477: * a String with all characters between \u0001 and \u00ff inclusive) 1478: * in the constant pool, adding it if necessary. 1479: * 1480: * @param sequence the byte sequence to look for 1481: * @return the index of the sequence 1482: * @throws IllegalArgumentException if this would make the constant 1483: * pool overflow 1484: */ 1485: private char poolIndex(String sequence) 1486: { 1487: Integer i = (Integer) poolEntries.get(sequence); 1488: if (i == null) 1489: { 1490: // pool starts at index 1 1491: int size = poolEntries.size() + 1; 1492: if (size >= 65535) 1493: throw new IllegalArgumentException("exceeds VM limitations"); 1494: i = new Integer(size); 1495: poolEntries.put(sequence, i); 1496: pool.append(sequence); 1497: } 1498: return (char) i.intValue(); 1499: } 1500: } // class ClassFactory 1501: }
GNU Classpath (0.20) |