001/* 002 * Copyright 2002,2003,2004 The Apache Software Foundation 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.cglib.proxy; 018 019import java.lang.ref.WeakReference; 020import java.lang.reflect.Constructor; 021import java.lang.reflect.Field; 022import java.lang.reflect.InvocationTargetException; 023import java.lang.reflect.Method; 024import java.security.ProtectionDomain; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.HashMap; 028import java.util.HashSet; 029import java.util.Iterator; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033 034import org.springframework.asm.ClassVisitor; 035import org.springframework.asm.Label; 036import org.springframework.asm.Type; 037import org.springframework.cglib.core.AbstractClassGenerator; 038import org.springframework.cglib.core.ClassEmitter; 039import org.springframework.cglib.core.CodeEmitter; 040import org.springframework.cglib.core.CodeGenerationException; 041import org.springframework.cglib.core.CollectionUtils; 042import org.springframework.cglib.core.Constants; 043import org.springframework.cglib.core.DuplicatesPredicate; 044import org.springframework.cglib.core.EmitUtils; 045import org.springframework.cglib.core.KeyFactory; 046import org.springframework.cglib.core.Local; 047import org.springframework.cglib.core.MethodInfo; 048import org.springframework.cglib.core.MethodInfoTransformer; 049import org.springframework.cglib.core.MethodWrapper; 050import org.springframework.cglib.core.ObjectSwitchCallback; 051import org.springframework.cglib.core.ProcessSwitchCallback; 052import org.springframework.cglib.core.ReflectUtils; 053import org.springframework.cglib.core.RejectModifierPredicate; 054import org.springframework.cglib.core.Signature; 055import org.springframework.cglib.core.Transformer; 056import org.springframework.cglib.core.TypeUtils; 057import org.springframework.cglib.core.VisibilityPredicate; 058import org.springframework.cglib.core.WeakCacheKey; 059 060/** 061 * Generates dynamic subclasses to enable method interception. This 062 * class started as a substitute for the standard Dynamic Proxy support 063 * included with JDK 1.3, but one that allowed the proxies to extend a 064 * concrete base class, in addition to implementing interfaces. The dynamically 065 * generated subclasses override the non-final methods of the superclass and 066 * have hooks which callback to user-defined interceptor 067 * implementations. 068 * <p> 069 * The original and most general callback type is the {@link MethodInterceptor}, which 070 * in AOP terms enables "around advice"--that is, you can invoke custom code both before 071 * and after the invocation of the "super" method. In addition you can modify the 072 * arguments before calling the super method, or not call it at all. 073 * <p> 074 * Although <code>MethodInterceptor</code> is generic enough to meet any 075 * interception need, it is often overkill. For simplicity and performance, additional 076 * specialized callback types, such as {@link LazyLoader} are also available. 077 * Often a single callback will be used per enhanced class, but you can control 078 * which callback is used on a per-method basis with a {@link CallbackFilter}. 079 * <p> 080 * The most common uses of this class are embodied in the static helper methods. For 081 * advanced needs, such as customizing the <code>ClassLoader</code> to use, you should create 082 * a new instance of <code>Enhancer</code>. Other classes within CGLIB follow a similar pattern. 083 * <p> 084 * All enhanced objects implement the {@link Factory} interface, unless {@link #setUseFactory} is 085 * used to explicitly disable this feature. The <code>Factory</code> interface provides an API 086 * to change the callbacks of an existing object, as well as a faster and easier way to create 087 * new instances of the same type. 088 * <p> 089 * For an almost drop-in replacement for 090 * <code>java.lang.reflect.Proxy</code>, see the {@link Proxy} class. 091 */ 092@SuppressWarnings({"rawtypes", "unchecked"}) 093public class Enhancer extends AbstractClassGenerator { 094 095 private static final CallbackFilter ALL_ZERO = new CallbackFilter() { 096 public int accept(Method method) { 097 return 0; 098 } 099 }; 100 101 private static final Source SOURCE = new Source(Enhancer.class.getName()); 102 103 private static final EnhancerKey KEY_FACTORY = 104 (EnhancerKey) KeyFactory.create(EnhancerKey.class, KeyFactory.HASH_ASM_TYPE, null); 105 106 private static final String BOUND_FIELD = "CGLIB$BOUND"; 107 108 private static final String FACTORY_DATA_FIELD = "CGLIB$FACTORY_DATA"; 109 110 private static final String THREAD_CALLBACKS_FIELD = "CGLIB$THREAD_CALLBACKS"; 111 112 private static final String STATIC_CALLBACKS_FIELD = "CGLIB$STATIC_CALLBACKS"; 113 114 private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS"; 115 116 private static final String SET_STATIC_CALLBACKS_NAME = "CGLIB$SET_STATIC_CALLBACKS"; 117 118 private static final String CONSTRUCTED_FIELD = "CGLIB$CONSTRUCTED"; 119 120 /** 121 * {@link org.springframework.cglib.core.AbstractClassGenerator.ClassLoaderData#generatedClasses} requires to keep cache key 122 * in a good shape (the keys should be up and running if the proxy class is alive), and one of the cache keys is 123 * {@link CallbackFilter}. That is why the generated class contains static field that keeps strong reference to 124 * the {@link #filter}. 125 * <p>This dance achieves two goals: ensures generated class is reusable and available through generatedClasses 126 * cache, and it enables to unload classloader and the related {@link CallbackFilter} in case user does not need 127 * that</p> 128 */ 129 private static final String CALLBACK_FILTER_FIELD = "CGLIB$CALLBACK_FILTER"; 130 131 private static final Type OBJECT_TYPE = 132 TypeUtils.parseType("Object"); 133 134 private static final Type FACTORY = 135 TypeUtils.parseType("org.springframework.cglib.proxy.Factory"); 136 137 private static final Type ILLEGAL_STATE_EXCEPTION = 138 TypeUtils.parseType("IllegalStateException"); 139 140 private static final Type ILLEGAL_ARGUMENT_EXCEPTION = 141 TypeUtils.parseType("IllegalArgumentException"); 142 143 private static final Type THREAD_LOCAL = 144 TypeUtils.parseType("ThreadLocal"); 145 146 private static final Type CALLBACK = 147 TypeUtils.parseType("org.springframework.cglib.proxy.Callback"); 148 149 private static final Type CALLBACK_ARRAY = 150 Type.getType(Callback[].class); 151 152 private static final Signature CSTRUCT_NULL = 153 TypeUtils.parseConstructor(""); 154 155 private static final Signature SET_THREAD_CALLBACKS = 156 new Signature(SET_THREAD_CALLBACKS_NAME, Type.VOID_TYPE, new Type[]{CALLBACK_ARRAY}); 157 158 private static final Signature SET_STATIC_CALLBACKS = 159 new Signature(SET_STATIC_CALLBACKS_NAME, Type.VOID_TYPE, new Type[]{CALLBACK_ARRAY}); 160 161 private static final Signature NEW_INSTANCE = 162 new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{CALLBACK_ARRAY}); 163 164 private static final Signature MULTIARG_NEW_INSTANCE = 165 new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{ 166 Constants.TYPE_CLASS_ARRAY, 167 Constants.TYPE_OBJECT_ARRAY, 168 CALLBACK_ARRAY, 169 }); 170 171 private static final Signature SINGLE_NEW_INSTANCE = 172 new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{CALLBACK}); 173 174 private static final Signature SET_CALLBACK = 175 new Signature("setCallback", Type.VOID_TYPE, new Type[]{Type.INT_TYPE, CALLBACK}); 176 177 private static final Signature GET_CALLBACK = 178 new Signature("getCallback", CALLBACK, new Type[]{Type.INT_TYPE}); 179 180 private static final Signature SET_CALLBACKS = 181 new Signature("setCallbacks", Type.VOID_TYPE, new Type[]{CALLBACK_ARRAY}); 182 183 private static final Signature GET_CALLBACKS = 184 new Signature("getCallbacks", CALLBACK_ARRAY, new Type[0]); 185 186 private static final Signature THREAD_LOCAL_GET = 187 TypeUtils.parseSignature("Object get()"); 188 189 private static final Signature THREAD_LOCAL_SET = 190 TypeUtils.parseSignature("void set(Object)"); 191 192 private static final Signature BIND_CALLBACKS = 193 TypeUtils.parseSignature("void CGLIB$BIND_CALLBACKS(Object)"); 194 195 private EnhancerFactoryData currentData; 196 197 private Object currentKey; 198 199 200 /** 201 * Internal interface, only public due to ClassLoader issues. 202 */ 203 public interface EnhancerKey { 204 205 public Object newInstance(String type, 206 String[] interfaces, 207 WeakCacheKey<CallbackFilter> filter, 208 Type[] callbackTypes, 209 boolean useFactory, 210 boolean interceptDuringConstruction, 211 Long serialVersionUID); 212 } 213 214 215 private Class[] interfaces; 216 217 private CallbackFilter filter; 218 219 private Callback[] callbacks; 220 221 private Type[] callbackTypes; 222 223 private boolean validateCallbackTypes; 224 225 private boolean classOnly; 226 227 private Class superclass; 228 229 private Class[] argumentTypes; 230 231 private Object[] arguments; 232 233 private boolean useFactory = true; 234 235 private Long serialVersionUID; 236 237 private boolean interceptDuringConstruction = true; 238 239 /** 240 * Create a new <code>Enhancer</code>. A new <code>Enhancer</code> 241 * object should be used for each generated object, and should not 242 * be shared across threads. To create additional instances of a 243 * generated class, use the <code>Factory</code> interface. 244 * @see Factory 245 */ 246 public Enhancer() { 247 super(SOURCE); 248 } 249 250 /** 251 * Set the class which the generated class will extend. As a convenience, 252 * if the supplied superclass is actually an interface, <code>setInterfaces</code> 253 * will be called with the appropriate argument instead. 254 * A non-interface argument must not be declared as final, and must have an 255 * accessible constructor. 256 * @param superclass class to extend or interface to implement 257 * @see #setInterfaces(Class[]) 258 */ 259 public void setSuperclass(Class superclass) { 260 if (superclass != null && superclass.isInterface()) { 261 setInterfaces(new Class[]{superclass}); 262 // SPRING PATCH BEGIN 263 setContextClass(superclass); 264 // SPRING PATCH END 265 } 266 else if (superclass != null && superclass.equals(Object.class)) { 267 // affects choice of ClassLoader 268 this.superclass = null; 269 } 270 else { 271 this.superclass = superclass; 272 // SPRING PATCH BEGIN 273 setContextClass(superclass); 274 // SPRING PATCH END 275 } 276 } 277 278 /** 279 * Set the interfaces to implement. The <code>Factory</code> interface will 280 * always be implemented regardless of what is specified here. 281 * @param interfaces array of interfaces to implement, or null 282 * @see Factory 283 */ 284 public void setInterfaces(Class[] interfaces) { 285 this.interfaces = interfaces; 286 } 287 288 /** 289 * Set the {@link CallbackFilter} used to map the generated class' methods 290 * to a particular callback index. 291 * New object instances will always use the same mapping, but may use different 292 * actual callback objects. 293 * @param filter the callback filter to use when generating a new class 294 * @see #setCallbacks 295 */ 296 public void setCallbackFilter(CallbackFilter filter) { 297 this.filter = filter; 298 } 299 300 301 /** 302 * Set the single {@link Callback} to use. 303 * Ignored if you use {@link #createClass}. 304 * @param callback the callback to use for all methods 305 * @see #setCallbacks 306 */ 307 public void setCallback(final Callback callback) { 308 setCallbacks(new Callback[]{callback}); 309 } 310 311 /** 312 * Set the array of callbacks to use. 313 * Ignored if you use {@link #createClass}. 314 * You must use a {@link CallbackFilter} to specify the index into this 315 * array for each method in the proxied class. 316 * @param callbacks the callback array 317 * @see #setCallbackFilter 318 * @see #setCallback 319 */ 320 public void setCallbacks(Callback[] callbacks) { 321 if (callbacks != null && callbacks.length == 0) { 322 throw new IllegalArgumentException("Array cannot be empty"); 323 } 324 this.callbacks = callbacks; 325 } 326 327 /** 328 * Set whether the enhanced object instances should implement 329 * the {@link Factory} interface. 330 * This was added for tools that need for proxies to be more 331 * indistinguishable from their targets. Also, in some cases it may 332 * be necessary to disable the <code>Factory</code> interface to 333 * prevent code from changing the underlying callbacks. 334 * @param useFactory whether to implement <code>Factory</code>; default is <code>true</code> 335 */ 336 public void setUseFactory(boolean useFactory) { 337 this.useFactory = useFactory; 338 } 339 340 /** 341 * Set whether methods called from within the proxy's constructer 342 * will be intercepted. The default value is true. Unintercepted methods 343 * will call the method of the proxy's base class, if it exists. 344 * @param interceptDuringConstruction whether to intercept methods called from the constructor 345 */ 346 public void setInterceptDuringConstruction(boolean interceptDuringConstruction) { 347 this.interceptDuringConstruction = interceptDuringConstruction; 348 } 349 350 /** 351 * Set the single type of {@link Callback} to use. 352 * This may be used instead of {@link #setCallback} when calling 353 * {@link #createClass}, since it may not be possible to have 354 * an array of actual callback instances. 355 * @param callbackType the type of callback to use for all methods 356 * @see #setCallbackTypes 357 */ 358 public void setCallbackType(Class callbackType) { 359 setCallbackTypes(new Class[]{callbackType}); 360 } 361 362 /** 363 * Set the array of callback types to use. 364 * This may be used instead of {@link #setCallbacks} when calling 365 * {@link #createClass}, since it may not be possible to have 366 * an array of actual callback instances. 367 * You must use a {@link CallbackFilter} to specify the index into this 368 * array for each method in the proxied class. 369 * @param callbackTypes the array of callback types 370 */ 371 public void setCallbackTypes(Class[] callbackTypes) { 372 if (callbackTypes != null && callbackTypes.length == 0) { 373 throw new IllegalArgumentException("Array cannot be empty"); 374 } 375 this.callbackTypes = CallbackInfo.determineTypes(callbackTypes); 376 } 377 378 /** 379 * Generate a new class if necessary and uses the specified 380 * callbacks (if any) to create a new object instance. 381 * Uses the no-arg constructor of the superclass. 382 * @return a new instance 383 */ 384 public Object create() { 385 classOnly = false; 386 argumentTypes = null; 387 return createHelper(); 388 } 389 390 /** 391 * Generate a new class if necessary and uses the specified 392 * callbacks (if any) to create a new object instance. 393 * Uses the constructor of the superclass matching the <code>argumentTypes</code> 394 * parameter, with the given arguments. 395 * @param argumentTypes constructor signature 396 * @param arguments compatible wrapped arguments to pass to constructor 397 * @return a new instance 398 */ 399 public Object create(Class[] argumentTypes, Object[] arguments) { 400 classOnly = false; 401 if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) { 402 throw new IllegalArgumentException("Arguments must be non-null and of equal length"); 403 } 404 this.argumentTypes = argumentTypes; 405 this.arguments = arguments; 406 return createHelper(); 407 } 408 409 /** 410 * Generate a new class if necessary and return it without creating a new instance. 411 * This ignores any callbacks that have been set. 412 * To create a new instance you will have to use reflection, and methods 413 * called during the constructor will not be intercepted. To avoid this problem, 414 * use the multi-arg <code>create</code> method. 415 * @see #create(Class[], Object[]) 416 */ 417 public Class createClass() { 418 classOnly = true; 419 return (Class) createHelper(); 420 } 421 422 /** 423 * Insert a static serialVersionUID field into the generated class. 424 * @param sUID the field value, or null to avoid generating field. 425 */ 426 public void setSerialVersionUID(Long sUID) { 427 serialVersionUID = sUID; 428 } 429 430 private void preValidate() { 431 if (callbackTypes == null) { 432 callbackTypes = CallbackInfo.determineTypes(callbacks, false); 433 validateCallbackTypes = true; 434 } 435 if (filter == null) { 436 if (callbackTypes.length > 1) { 437 throw new IllegalStateException("Multiple callback types possible but no filter specified"); 438 } 439 filter = ALL_ZERO; 440 } 441 } 442 443 private void validate() { 444 if (classOnly ^ (callbacks == null)) { 445 if (classOnly) { 446 throw new IllegalStateException("createClass does not accept callbacks"); 447 } 448 else { 449 throw new IllegalStateException("Callbacks are required"); 450 } 451 } 452 if (classOnly && (callbackTypes == null)) { 453 throw new IllegalStateException("Callback types are required"); 454 } 455 if (validateCallbackTypes) { 456 callbackTypes = null; 457 } 458 if (callbacks != null && callbackTypes != null) { 459 if (callbacks.length != callbackTypes.length) { 460 throw new IllegalStateException("Lengths of callback and callback types array must be the same"); 461 } 462 Type[] check = CallbackInfo.determineTypes(callbacks); 463 for (int i = 0; i < check.length; i++) { 464 if (!check[i].equals(callbackTypes[i])) { 465 throw new IllegalStateException("Callback " + check[i] + " is not assignable to " + callbackTypes[i]); 466 } 467 } 468 } 469 else if (callbacks != null) { 470 callbackTypes = CallbackInfo.determineTypes(callbacks); 471 } 472 if (interfaces != null) { 473 for (int i = 0; i < interfaces.length; i++) { 474 if (interfaces[i] == null) { 475 throw new IllegalStateException("Interfaces cannot be null"); 476 } 477 if (!interfaces[i].isInterface()) { 478 throw new IllegalStateException(interfaces[i] + " is not an interface"); 479 } 480 } 481 } 482 } 483 484 /** 485 * The idea of the class is to cache relevant java.lang.reflect instances so 486 * proxy-class can be instantiated faster that when using {@link ReflectUtils#newInstance(Class, Class[], Object[])} 487 * and {@link Enhancer#setThreadCallbacks(Class, Callback[])} 488 */ 489 static class EnhancerFactoryData { 490 491 public final Class generatedClass; 492 493 private final Method setThreadCallbacks; 494 495 private final Class[] primaryConstructorArgTypes; 496 497 private final Constructor primaryConstructor; 498 499 public EnhancerFactoryData(Class generatedClass, Class[] primaryConstructorArgTypes, boolean classOnly) { 500 this.generatedClass = generatedClass; 501 try { 502 setThreadCallbacks = getCallbacksSetter(generatedClass, SET_THREAD_CALLBACKS_NAME); 503 if (classOnly) { 504 this.primaryConstructorArgTypes = null; 505 this.primaryConstructor = null; 506 } 507 else { 508 this.primaryConstructorArgTypes = primaryConstructorArgTypes; 509 this.primaryConstructor = ReflectUtils.getConstructor(generatedClass, primaryConstructorArgTypes); 510 } 511 } 512 catch (NoSuchMethodException e) { 513 throw new CodeGenerationException(e); 514 } 515 } 516 517 /** 518 * Creates proxy instance for given argument types, and assigns the callbacks. 519 * Ideally, for each proxy class, just one set of argument types should be used, 520 * otherwise it would have to spend time on constructor lookup. 521 * Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)}, 522 * with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}" 523 * @param argumentTypes constructor argument types 524 * @param arguments constructor arguments 525 * @param callbacks callbacks to set for the new instance 526 * @return newly created proxy 527 * @see #createUsingReflection(Class) 528 */ 529 public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) { 530 setThreadCallbacks(callbacks); 531 try { 532 // Explicit reference equality is added here just in case Arrays.equals does not have one 533 if (primaryConstructorArgTypes == argumentTypes || 534 Arrays.equals(primaryConstructorArgTypes, argumentTypes)) { 535 // If we have relevant Constructor instance at hand, just call it 536 // This skips "get constructors" machinery 537 return ReflectUtils.newInstance(primaryConstructor, arguments); 538 } 539 // Take a slow path if observing unexpected argument types 540 return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments); 541 } 542 finally { 543 // clear thread callbacks to allow them to be gc'd 544 setThreadCallbacks(null); 545 } 546 547 } 548 549 private void setThreadCallbacks(Callback[] callbacks) { 550 try { 551 setThreadCallbacks.invoke(generatedClass, (Object) callbacks); 552 } 553 catch (IllegalAccessException e) { 554 throw new CodeGenerationException(e); 555 } 556 catch (InvocationTargetException e) { 557 throw new CodeGenerationException(e.getTargetException()); 558 } 559 } 560 } 561 562 private Object createHelper() { 563 preValidate(); 564 Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, 565 ReflectUtils.getNames(interfaces), 566 filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), 567 callbackTypes, 568 useFactory, 569 interceptDuringConstruction, 570 serialVersionUID); 571 this.currentKey = key; 572 Object result = super.create(key); 573 return result; 574 } 575 576 @Override 577 protected Class generate(ClassLoaderData data) { 578 validate(); 579 if (superclass != null) { 580 setNamePrefix(superclass.getName()); 581 } 582 else if (interfaces != null) { 583 setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName()); 584 } 585 return super.generate(data); 586 } 587 588 protected ClassLoader getDefaultClassLoader() { 589 if (superclass != null) { 590 return superclass.getClassLoader(); 591 } 592 else if (interfaces != null) { 593 return interfaces[0].getClassLoader(); 594 } 595 else { 596 return null; 597 } 598 } 599 600 protected ProtectionDomain getProtectionDomain() { 601 if (superclass != null) { 602 return ReflectUtils.getProtectionDomain(superclass); 603 } 604 else if (interfaces != null) { 605 return ReflectUtils.getProtectionDomain(interfaces[0]); 606 } 607 else { 608 return null; 609 } 610 } 611 612 private Signature rename(Signature sig, int index) { 613 return new Signature("CGLIB$" + sig.getName() + "$" + index, 614 sig.getDescriptor()); 615 } 616 617 /** 618 * Finds all of the methods that will be extended by an 619 * Enhancer-generated class using the specified superclass and 620 * interfaces. This can be useful in building a list of Callback 621 * objects. The methods are added to the end of the given list. Due 622 * to the subclassing nature of the classes generated by Enhancer, 623 * the methods are guaranteed to be non-static, non-final, and 624 * non-private. Each method signature will only occur once, even if 625 * it occurs in multiple classes. 626 * @param superclass the class that will be extended, or null 627 * @param interfaces the list of interfaces that will be implemented, or null 628 * @param methods the list into which to copy the applicable methods 629 */ 630 public static void getMethods(Class superclass, Class[] interfaces, List methods) { 631 getMethods(superclass, interfaces, methods, null, null); 632 } 633 634 private static void getMethods(Class superclass, Class[] interfaces, List methods, List interfaceMethods, Set forcePublic) { 635 ReflectUtils.addAllMethods(superclass, methods); 636 List target = (interfaceMethods != null) ? interfaceMethods : methods; 637 if (interfaces != null) { 638 for (int i = 0; i < interfaces.length; i++) { 639 if (interfaces[i] != Factory.class) { 640 ReflectUtils.addAllMethods(interfaces[i], target); 641 } 642 } 643 } 644 if (interfaceMethods != null) { 645 if (forcePublic != null) { 646 forcePublic.addAll(MethodWrapper.createSet(interfaceMethods)); 647 } 648 methods.addAll(interfaceMethods); 649 } 650 CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_STATIC)); 651 CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true)); 652 CollectionUtils.filter(methods, new DuplicatesPredicate()); 653 CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_FINAL)); 654 } 655 656 public void generateClass(ClassVisitor v) throws Exception { 657 Class sc = (superclass == null) ? Object.class : superclass; 658 659 if (TypeUtils.isFinal(sc.getModifiers())) 660 throw new IllegalArgumentException("Cannot subclass final class " + sc.getName()); 661 List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors())); 662 filterConstructors(sc, constructors); 663 664 // Order is very important: must add superclass, then 665 // its superclass chain, then each interface and 666 // its superinterfaces. 667 List actualMethods = new ArrayList(); 668 List interfaceMethods = new ArrayList(); 669 final Set forcePublic = new HashSet(); 670 getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic); 671 672 List methods = CollectionUtils.transform(actualMethods, new Transformer() { 673 public Object transform(Object value) { 674 Method method = (Method) value; 675 int modifiers = Constants.ACC_FINAL 676 | (method.getModifiers() 677 & ~Constants.ACC_ABSTRACT 678 & ~Constants.ACC_NATIVE 679 & ~Constants.ACC_SYNCHRONIZED); 680 if (forcePublic.contains(MethodWrapper.create(method))) { 681 modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC; 682 } 683 return ReflectUtils.getMethodInfo(method, modifiers); 684 } 685 }); 686 687 ClassEmitter e = new ClassEmitter(v); 688 if (currentData == null) { 689 e.begin_class(Constants.V1_8, 690 Constants.ACC_PUBLIC, 691 getClassName(), 692 Type.getType(sc), 693 (useFactory ? 694 TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) : 695 TypeUtils.getTypes(interfaces)), 696 Constants.SOURCE_FILE); 697 } 698 else { 699 e.begin_class(Constants.V1_8, 700 Constants.ACC_PUBLIC, 701 getClassName(), 702 null, 703 new Type[]{FACTORY}, 704 Constants.SOURCE_FILE); 705 } 706 List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance()); 707 708 e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null); 709 e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null); 710 if (!interceptDuringConstruction) { 711 e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null); 712 } 713 e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null); 714 e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null); 715 if (serialVersionUID != null) { 716 e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID); 717 } 718 719 for (int i = 0; i < callbackTypes.length; i++) { 720 e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null); 721 } 722 // This is declared private to avoid "public field" pollution 723 e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null); 724 725 if (currentData == null) { 726 emitMethods(e, methods, actualMethods); 727 emitConstructors(e, constructorInfo); 728 } 729 else { 730 emitDefaultConstructor(e); 731 } 732 emitSetThreadCallbacks(e); 733 emitSetStaticCallbacks(e); 734 emitBindCallbacks(e); 735 736 if (useFactory || currentData != null) { 737 int[] keys = getCallbackKeys(); 738 emitNewInstanceCallbacks(e); 739 emitNewInstanceCallback(e); 740 emitNewInstanceMultiarg(e, constructorInfo); 741 emitGetCallback(e, keys); 742 emitSetCallback(e, keys); 743 emitGetCallbacks(e); 744 emitSetCallbacks(e); 745 } 746 747 e.end_class(); 748 } 749 750 /** 751 * Filter the list of constructors from the superclass. The 752 * constructors which remain will be included in the generated 753 * class. The default implementation is to filter out all private 754 * constructors, but subclasses may extend Enhancer to override this 755 * behavior. 756 * @param sc the superclass 757 * @param constructors the list of all declared constructors from the superclass 758 * @throws IllegalArgumentException if there are no non-private constructors 759 */ 760 protected void filterConstructors(Class sc, List constructors) { 761 CollectionUtils.filter(constructors, new VisibilityPredicate(sc, true)); 762 if (constructors.size() == 0) 763 throw new IllegalArgumentException("No visible constructors in " + sc); 764 } 765 766 /** 767 * This method should not be called in regular flow. 768 * Technically speaking {@link #wrapCachedClass(Class)} uses {@link Enhancer.EnhancerFactoryData} as a cache value, 769 * and the latter enables faster instantiation than plain old reflection lookup and invoke. 770 * This method is left intact for backward compatibility reasons: just in case it was ever used. 771 * @param type class to instantiate 772 * @return newly created proxy instance 773 * @throws Exception if something goes wrong 774 */ 775 protected Object firstInstance(Class type) throws Exception { 776 if (classOnly) { 777 return type; 778 } 779 else { 780 return createUsingReflection(type); 781 } 782 } 783 784 protected Object nextInstance(Object instance) { 785 EnhancerFactoryData data = (EnhancerFactoryData) instance; 786 787 if (classOnly) { 788 return data.generatedClass; 789 } 790 791 Class[] argumentTypes = this.argumentTypes; 792 Object[] arguments = this.arguments; 793 if (argumentTypes == null) { 794 argumentTypes = Constants.EMPTY_CLASS_ARRAY; 795 arguments = null; 796 } 797 return data.newInstance(argumentTypes, arguments, callbacks); 798 } 799 800 @Override 801 protected Object wrapCachedClass(Class klass) { 802 Class[] argumentTypes = this.argumentTypes; 803 if (argumentTypes == null) { 804 argumentTypes = Constants.EMPTY_CLASS_ARRAY; 805 } 806 EnhancerFactoryData factoryData = new EnhancerFactoryData(klass, argumentTypes, classOnly); 807 Field factoryDataField = null; 808 try { 809 // The subsequent dance is performed just once for each class, 810 // so it does not matter much how fast it goes 811 factoryDataField = klass.getField(FACTORY_DATA_FIELD); 812 factoryDataField.set(null, factoryData); 813 Field callbackFilterField = klass.getDeclaredField(CALLBACK_FILTER_FIELD); 814 callbackFilterField.setAccessible(true); 815 callbackFilterField.set(null, this.filter); 816 } 817 catch (NoSuchFieldException e) { 818 throw new CodeGenerationException(e); 819 } 820 catch (IllegalAccessException e) { 821 throw new CodeGenerationException(e); 822 } 823 return new WeakReference<EnhancerFactoryData>(factoryData); 824 } 825 826 @Override 827 protected Object unwrapCachedValue(Object cached) { 828 if (currentKey instanceof EnhancerKey) { 829 EnhancerFactoryData data = ((WeakReference<EnhancerFactoryData>) cached).get(); 830 return data; 831 } 832 return super.unwrapCachedValue(cached); 833 } 834 835 /** 836 * Call this method to register the {@link Callback} array to use before 837 * creating a new instance of the generated class via reflection. If you are using 838 * an instance of <code>Enhancer</code> or the {@link Factory} interface to create 839 * new instances, this method is unnecessary. Its primary use is for when you want to 840 * cache and reuse a generated class yourself, and the generated class does 841 * <i>not</i> implement the {@link Factory} interface. 842 * <p> 843 * Note that this method only registers the callbacks on the current thread. 844 * If you want to register callbacks for instances created by multiple threads, 845 * use {@link #registerStaticCallbacks}. 846 * <p> 847 * The registered callbacks are overwritten and subsequently cleared 848 * when calling any of the <code>create</code> methods (such as 849 * {@link #create}), or any {@link Factory} <code>newInstance</code> method. 850 * Otherwise they are <i>not</i> cleared, and you should be careful to set them 851 * back to <code>null</code> after creating new instances via reflection if 852 * memory leakage is a concern. 853 * @param generatedClass a class previously created by {@link Enhancer} 854 * @param callbacks the array of callbacks to use when instances of the generated 855 * class are created 856 * @see #setUseFactory 857 */ 858 public static void registerCallbacks(Class generatedClass, Callback[] callbacks) { 859 setThreadCallbacks(generatedClass, callbacks); 860 } 861 862 /** 863 * Similar to {@link #registerCallbacks}, but suitable for use 864 * when multiple threads will be creating instances of the generated class. 865 * The thread-level callbacks will always override the static callbacks. 866 * Static callbacks are never cleared. 867 * @param generatedClass a class previously created by {@link Enhancer} 868 * @param callbacks the array of callbacks to use when instances of the generated 869 * class are created 870 */ 871 public static void registerStaticCallbacks(Class generatedClass, Callback[] callbacks) { 872 setCallbacksHelper(generatedClass, callbacks, SET_STATIC_CALLBACKS_NAME); 873 } 874 875 /** 876 * Determine if a class was generated using <code>Enhancer</code>. 877 * @param type any class 878 * @return whether the class was generated using <code>Enhancer</code> 879 */ 880 public static boolean isEnhanced(Class type) { 881 try { 882 getCallbacksSetter(type, SET_THREAD_CALLBACKS_NAME); 883 return true; 884 } 885 catch (NoSuchMethodException e) { 886 return false; 887 } 888 } 889 890 private static void setThreadCallbacks(Class type, Callback[] callbacks) { 891 setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME); 892 } 893 894 private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) { 895 // TODO: optimize 896 try { 897 Method setter = getCallbacksSetter(type, methodName); 898 setter.invoke(null, new Object[]{callbacks}); 899 } 900 catch (NoSuchMethodException e) { 901 throw new IllegalArgumentException(type + " is not an enhanced class"); 902 } 903 catch (IllegalAccessException e) { 904 throw new CodeGenerationException(e); 905 } 906 catch (InvocationTargetException e) { 907 throw new CodeGenerationException(e); 908 } 909 } 910 911 private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException { 912 return type.getDeclaredMethod(methodName, new Class[]{Callback[].class}); 913 } 914 915 /** 916 * Instantiates a proxy instance and assigns callback values. 917 * Implementation detail: java.lang.reflect instances are not cached, so this method should not 918 * be used on a hot path. 919 * This method is used when {@link #setUseCache(boolean)} is set to {@code false}. 920 * @param type class to instantiate 921 * @return newly created instance 922 */ 923 private Object createUsingReflection(Class type) { 924 setThreadCallbacks(type, callbacks); 925 try { 926 927 if (argumentTypes != null) { 928 929 return ReflectUtils.newInstance(type, argumentTypes, arguments); 930 931 } 932 else { 933 934 return ReflectUtils.newInstance(type); 935 936 } 937 } 938 finally { 939 // clear thread callbacks to allow them to be gc'd 940 setThreadCallbacks(type, null); 941 } 942 } 943 944 /** 945 * Helper method to create an intercepted object. 946 * For finer control over the generated instance, use a new instance of <code>Enhancer</code> 947 * instead of this static method. 948 * @param type class to extend or interface to implement 949 * @param callback the callback to use for all methods 950 */ 951 public static Object create(Class type, Callback callback) { 952 Enhancer e = new Enhancer(); 953 e.setSuperclass(type); 954 e.setCallback(callback); 955 return e.create(); 956 } 957 958 /** 959 * Helper method to create an intercepted object. 960 * For finer control over the generated instance, use a new instance of <code>Enhancer</code> 961 * instead of this static method. 962 * @param superclass class to extend or interface to implement 963 * @param interfaces array of interfaces to implement, or null 964 * @param callback the callback to use for all methods 965 */ 966 public static Object create(Class superclass, Class interfaces[], Callback callback) { 967 Enhancer e = new Enhancer(); 968 e.setSuperclass(superclass); 969 e.setInterfaces(interfaces); 970 e.setCallback(callback); 971 return e.create(); 972 } 973 974 /** 975 * Helper method to create an intercepted object. 976 * For finer control over the generated instance, use a new instance of <code>Enhancer</code> 977 * instead of this static method. 978 * @param superclass class to extend or interface to implement 979 * @param interfaces array of interfaces to implement, or null 980 * @param filter the callback filter to use when generating a new class 981 * @param callbacks callback implementations to use for the enhanced object 982 */ 983 public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks) { 984 Enhancer e = new Enhancer(); 985 e.setSuperclass(superclass); 986 e.setInterfaces(interfaces); 987 e.setCallbackFilter(filter); 988 e.setCallbacks(callbacks); 989 return e.create(); 990 } 991 992 private void emitDefaultConstructor(ClassEmitter ce) { 993 Constructor<Object> declaredConstructor; 994 try { 995 declaredConstructor = Object.class.getDeclaredConstructor(); 996 } 997 catch (NoSuchMethodException e) { 998 throw new IllegalStateException("Object should have default constructor ", e); 999 } 1000 MethodInfo constructor = (MethodInfo) MethodInfoTransformer.getInstance().transform(declaredConstructor); 1001 CodeEmitter e = EmitUtils.begin_method(ce, constructor, Constants.ACC_PUBLIC); 1002 e.load_this(); 1003 e.dup(); 1004 Signature sig = constructor.getSignature(); 1005 e.super_invoke_constructor(sig); 1006 e.return_value(); 1007 e.end_method(); 1008 } 1009 1010 private void emitConstructors(ClassEmitter ce, List constructors) { 1011 boolean seenNull = false; 1012 for (Iterator it = constructors.iterator(); it.hasNext(); ) { 1013 MethodInfo constructor = (MethodInfo) it.next(); 1014 if (currentData != null && !"()V".equals(constructor.getSignature().getDescriptor())) { 1015 continue; 1016 } 1017 CodeEmitter e = EmitUtils.begin_method(ce, constructor, Constants.ACC_PUBLIC); 1018 e.load_this(); 1019 e.dup(); 1020 e.load_args(); 1021 Signature sig = constructor.getSignature(); 1022 seenNull = seenNull || sig.getDescriptor().equals("()V"); 1023 e.super_invoke_constructor(sig); 1024 if (currentData == null) { 1025 e.invoke_static_this(BIND_CALLBACKS); 1026 if (!interceptDuringConstruction) { 1027 e.load_this(); 1028 e.push(1); 1029 e.putfield(CONSTRUCTED_FIELD); 1030 } 1031 } 1032 e.return_value(); 1033 e.end_method(); 1034 } 1035 if (!classOnly && !seenNull && arguments == null) 1036 throw new IllegalArgumentException("Superclass has no null constructors but no arguments were given"); 1037 } 1038 1039 private int[] getCallbackKeys() { 1040 int[] keys = new int[callbackTypes.length]; 1041 for (int i = 0; i < callbackTypes.length; i++) { 1042 keys[i] = i; 1043 } 1044 return keys; 1045 } 1046 1047 private void emitGetCallback(ClassEmitter ce, int[] keys) { 1048 final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, GET_CALLBACK, null); 1049 e.load_this(); 1050 e.invoke_static_this(BIND_CALLBACKS); 1051 e.load_this(); 1052 e.load_arg(0); 1053 e.process_switch(keys, new ProcessSwitchCallback() { 1054 public void processCase(int key, Label end) { 1055 e.getfield(getCallbackField(key)); 1056 e.goTo(end); 1057 } 1058 1059 public void processDefault() { 1060 e.pop(); // stack height 1061 e.aconst_null(); 1062 } 1063 }); 1064 e.return_value(); 1065 e.end_method(); 1066 } 1067 1068 private void emitSetCallback(ClassEmitter ce, int[] keys) { 1069 final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SET_CALLBACK, null); 1070 e.load_arg(0); 1071 e.process_switch(keys, new ProcessSwitchCallback() { 1072 public void processCase(int key, Label end) { 1073 e.load_this(); 1074 e.load_arg(1); 1075 e.checkcast(callbackTypes[key]); 1076 e.putfield(getCallbackField(key)); 1077 e.goTo(end); 1078 } 1079 1080 public void processDefault() { 1081 // TODO: error? 1082 } 1083 }); 1084 e.return_value(); 1085 e.end_method(); 1086 } 1087 1088 private void emitSetCallbacks(ClassEmitter ce) { 1089 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SET_CALLBACKS, null); 1090 e.load_this(); 1091 e.load_arg(0); 1092 for (int i = 0; i < callbackTypes.length; i++) { 1093 e.dup2(); 1094 e.aaload(i); 1095 e.checkcast(callbackTypes[i]); 1096 e.putfield(getCallbackField(i)); 1097 } 1098 e.return_value(); 1099 e.end_method(); 1100 } 1101 1102 private void emitGetCallbacks(ClassEmitter ce) { 1103 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, GET_CALLBACKS, null); 1104 e.load_this(); 1105 e.invoke_static_this(BIND_CALLBACKS); 1106 e.load_this(); 1107 e.push(callbackTypes.length); 1108 e.newarray(CALLBACK); 1109 for (int i = 0; i < callbackTypes.length; i++) { 1110 e.dup(); 1111 e.push(i); 1112 e.load_this(); 1113 e.getfield(getCallbackField(i)); 1114 e.aastore(); 1115 } 1116 e.return_value(); 1117 e.end_method(); 1118 } 1119 1120 private void emitNewInstanceCallbacks(ClassEmitter ce) { 1121 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null); 1122 Type thisType = getThisType(e); 1123 e.load_arg(0); 1124 e.invoke_static(thisType, SET_THREAD_CALLBACKS, false); 1125 emitCommonNewInstance(e); 1126 } 1127 1128 private Type getThisType(CodeEmitter e) { 1129 if (currentData == null) { 1130 return e.getClassEmitter().getClassType(); 1131 } 1132 else { 1133 return Type.getType(currentData.generatedClass); 1134 } 1135 } 1136 1137 private void emitCommonNewInstance(CodeEmitter e) { 1138 Type thisType = getThisType(e); 1139 e.new_instance(thisType); 1140 e.dup(); 1141 e.invoke_constructor(thisType); 1142 e.aconst_null(); 1143 e.invoke_static(thisType, SET_THREAD_CALLBACKS, false); 1144 e.return_value(); 1145 e.end_method(); 1146 } 1147 1148 private void emitNewInstanceCallback(ClassEmitter ce) { 1149 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SINGLE_NEW_INSTANCE, null); 1150 switch (callbackTypes.length) { 1151 case 0: 1152 // TODO: make sure Callback is null 1153 break; 1154 case 1: 1155 // for now just make a new array; TODO: optimize 1156 e.push(1); 1157 e.newarray(CALLBACK); 1158 e.dup(); 1159 e.push(0); 1160 e.load_arg(0); 1161 e.aastore(); 1162 e.invoke_static(getThisType(e), SET_THREAD_CALLBACKS, false); 1163 break; 1164 default: 1165 e.throw_exception(ILLEGAL_STATE_EXCEPTION, "More than one callback object required"); 1166 } 1167 emitCommonNewInstance(e); 1168 } 1169 1170 private void emitNewInstanceMultiarg(ClassEmitter ce, List constructors) { 1171 final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, MULTIARG_NEW_INSTANCE, null); 1172 final Type thisType = getThisType(e); 1173 e.load_arg(2); 1174 e.invoke_static(thisType, SET_THREAD_CALLBACKS, false); 1175 e.new_instance(thisType); 1176 e.dup(); 1177 e.load_arg(0); 1178 EmitUtils.constructor_switch(e, constructors, new ObjectSwitchCallback() { 1179 public void processCase(Object key, Label end) { 1180 MethodInfo constructor = (MethodInfo) key; 1181 Type types[] = constructor.getSignature().getArgumentTypes(); 1182 for (int i = 0; i < types.length; i++) { 1183 e.load_arg(1); 1184 e.push(i); 1185 e.aaload(); 1186 e.unbox(types[i]); 1187 } 1188 e.invoke_constructor(thisType, constructor.getSignature()); 1189 e.goTo(end); 1190 } 1191 1192 public void processDefault() { 1193 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Constructor not found"); 1194 } 1195 }); 1196 e.aconst_null(); 1197 e.invoke_static(thisType, SET_THREAD_CALLBACKS, false); 1198 e.return_value(); 1199 e.end_method(); 1200 } 1201 1202 private void emitMethods(final ClassEmitter ce, List methods, List actualMethods) { 1203 CallbackGenerator[] generators = CallbackInfo.getGenerators(callbackTypes); 1204 1205 Map groups = new HashMap(); 1206 final Map indexes = new HashMap(); 1207 final Map originalModifiers = new HashMap(); 1208 final Map positions = CollectionUtils.getIndexMap(methods); 1209 final Map declToBridge = new HashMap(); 1210 1211 Iterator it1 = methods.iterator(); 1212 Iterator it2 = (actualMethods != null) ? actualMethods.iterator() : null; 1213 1214 while (it1.hasNext()) { 1215 MethodInfo method = (MethodInfo) it1.next(); 1216 Method actualMethod = (it2 != null) ? (Method) it2.next() : null; 1217 int index = filter.accept(actualMethod); 1218 if (index >= callbackTypes.length) { 1219 throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index); 1220 } 1221 originalModifiers.put(method, (actualMethod != null ? actualMethod.getModifiers() : method.getModifiers())); 1222 indexes.put(method, index); 1223 List group = (List) groups.get(generators[index]); 1224 if (group == null) { 1225 groups.put(generators[index], group = new ArrayList(methods.size())); 1226 } 1227 group.add(method); 1228 1229 // Optimization: build up a map of Class -> bridge methods in class 1230 // so that we can look up all the bridge methods in one pass for a class. 1231 if (TypeUtils.isBridge(actualMethod.getModifiers())) { 1232 Set bridges = (Set) declToBridge.get(actualMethod.getDeclaringClass()); 1233 if (bridges == null) { 1234 bridges = new HashSet(); 1235 declToBridge.put(actualMethod.getDeclaringClass(), bridges); 1236 } 1237 bridges.add(method.getSignature()); 1238 } 1239 } 1240 1241 final Map bridgeToTarget = new BridgeMethodResolver(declToBridge, getClassLoader()).resolveAll(); 1242 1243 Set seenGen = new HashSet(); 1244 CodeEmitter se = ce.getStaticHook(); 1245 se.new_instance(THREAD_LOCAL); 1246 se.dup(); 1247 se.invoke_constructor(THREAD_LOCAL, CSTRUCT_NULL); 1248 se.putfield(THREAD_CALLBACKS_FIELD); 1249 1250 final Object[] state = new Object[1]; 1251 CallbackGenerator.Context context = new CallbackGenerator.Context() { 1252 public ClassLoader getClassLoader() { 1253 return Enhancer.this.getClassLoader(); 1254 } 1255 1256 public int getOriginalModifiers(MethodInfo method) { 1257 return ((Integer) originalModifiers.get(method)).intValue(); 1258 } 1259 1260 public int getIndex(MethodInfo method) { 1261 return ((Integer) indexes.get(method)).intValue(); 1262 } 1263 1264 public void emitCallback(CodeEmitter e, int index) { 1265 emitCurrentCallback(e, index); 1266 } 1267 1268 public Signature getImplSignature(MethodInfo method) { 1269 return rename(method.getSignature(), ((Integer) positions.get(method)).intValue()); 1270 } 1271 1272 public void emitLoadArgsAndInvoke(CodeEmitter e, MethodInfo method) { 1273 // If this is a bridge and we know the target was called from invokespecial, 1274 // then we need to invoke_virtual w/ the bridge target instead of doing 1275 // a super, because super may itself be using super, which would bypass 1276 // any proxies on the target. 1277 Signature bridgeTarget = (Signature) bridgeToTarget.get(method.getSignature()); 1278 if (bridgeTarget != null) { 1279 // checkcast each argument against the target's argument types 1280 for (int i = 0; i < bridgeTarget.getArgumentTypes().length; i++) { 1281 e.load_arg(i); 1282 Type target = bridgeTarget.getArgumentTypes()[i]; 1283 if (!target.equals(method.getSignature().getArgumentTypes()[i])) { 1284 e.checkcast(target); 1285 } 1286 } 1287 1288 e.invoke_virtual_this(bridgeTarget); 1289 1290 Type retType = method.getSignature().getReturnType(); 1291 // Not necessary to cast if the target & bridge have 1292 // the same return type. 1293 // (This conveniently includes void and primitive types, 1294 // which would fail if casted. It's not possible to 1295 // covariant from boxed to unbox (or vice versa), so no having 1296 // to box/unbox for bridges). 1297 // TODO: It also isn't necessary to checkcast if the return is 1298 // assignable from the target. (This would happen if a subclass 1299 // used covariant returns to narrow the return type within a bridge 1300 // method.) 1301 if (!retType.equals(bridgeTarget.getReturnType())) { 1302 e.checkcast(retType); 1303 } 1304 } 1305 else { 1306 e.load_args(); 1307 e.super_invoke(method.getSignature()); 1308 } 1309 } 1310 1311 public CodeEmitter beginMethod(ClassEmitter ce, MethodInfo method) { 1312 CodeEmitter e = EmitUtils.begin_method(ce, method); 1313 if (!interceptDuringConstruction && 1314 !TypeUtils.isAbstract(method.getModifiers())) { 1315 Label constructed = e.make_label(); 1316 e.load_this(); 1317 e.getfield(CONSTRUCTED_FIELD); 1318 e.if_jump(CodeEmitter.NE, constructed); 1319 e.load_this(); 1320 e.load_args(); 1321 e.super_invoke(); 1322 e.return_value(); 1323 e.mark(constructed); 1324 } 1325 return e; 1326 } 1327 }; 1328 for (int i = 0; i < callbackTypes.length; i++) { 1329 CallbackGenerator gen = generators[i]; 1330 if (!seenGen.contains(gen)) { 1331 seenGen.add(gen); 1332 final List fmethods = (List) groups.get(gen); 1333 if (fmethods != null) { 1334 try { 1335 gen.generate(ce, context, fmethods); 1336 gen.generateStatic(se, context, fmethods); 1337 } 1338 catch (RuntimeException x) { 1339 throw x; 1340 } 1341 catch (Exception x) { 1342 throw new CodeGenerationException(x); 1343 } 1344 } 1345 } 1346 } 1347 se.return_value(); 1348 se.end_method(); 1349 } 1350 1351 private void emitSetThreadCallbacks(ClassEmitter ce) { 1352 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC, 1353 SET_THREAD_CALLBACKS, 1354 null); 1355 e.getfield(THREAD_CALLBACKS_FIELD); 1356 e.load_arg(0); 1357 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET); 1358 e.return_value(); 1359 e.end_method(); 1360 } 1361 1362 private void emitSetStaticCallbacks(ClassEmitter ce) { 1363 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC, 1364 SET_STATIC_CALLBACKS, 1365 null); 1366 e.load_arg(0); 1367 e.putfield(STATIC_CALLBACKS_FIELD); 1368 e.return_value(); 1369 e.end_method(); 1370 } 1371 1372 private void emitCurrentCallback(CodeEmitter e, int index) { 1373 e.load_this(); 1374 e.getfield(getCallbackField(index)); 1375 e.dup(); 1376 Label end = e.make_label(); 1377 e.ifnonnull(end); 1378 e.pop(); // stack height 1379 e.load_this(); 1380 e.invoke_static_this(BIND_CALLBACKS); 1381 e.load_this(); 1382 e.getfield(getCallbackField(index)); 1383 e.mark(end); 1384 } 1385 1386 private void emitBindCallbacks(ClassEmitter ce) { 1387 CodeEmitter e = ce.begin_method(Constants.PRIVATE_FINAL_STATIC, 1388 BIND_CALLBACKS, 1389 null); 1390 Local me = e.make_local(); 1391 e.load_arg(0); 1392 e.checkcast_this(); 1393 e.store_local(me); 1394 1395 Label end = e.make_label(); 1396 e.load_local(me); 1397 e.getfield(BOUND_FIELD); 1398 e.if_jump(CodeEmitter.NE, end); 1399 e.load_local(me); 1400 e.push(1); 1401 e.putfield(BOUND_FIELD); 1402 1403 e.getfield(THREAD_CALLBACKS_FIELD); 1404 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_GET); 1405 e.dup(); 1406 Label found_callback = e.make_label(); 1407 e.ifnonnull(found_callback); 1408 e.pop(); 1409 1410 e.getfield(STATIC_CALLBACKS_FIELD); 1411 e.dup(); 1412 e.ifnonnull(found_callback); 1413 e.pop(); 1414 e.goTo(end); 1415 1416 e.mark(found_callback); 1417 e.checkcast(CALLBACK_ARRAY); 1418 e.load_local(me); 1419 e.swap(); 1420 for (int i = callbackTypes.length - 1; i >= 0; i--) { 1421 if (i != 0) { 1422 e.dup2(); 1423 } 1424 e.aaload(i); 1425 e.checkcast(callbackTypes[i]); 1426 e.putfield(getCallbackField(i)); 1427 } 1428 1429 e.mark(end); 1430 e.return_value(); 1431 e.end_method(); 1432 } 1433 1434 private static String getCallbackField(int index) { 1435 return "CGLIB$CALLBACK_" + index; 1436 } 1437 1438}