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