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}