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