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