1   /*
2    * The Apache Software License, Version 1.1
3    *
4    * Copyright (c) 2002 The Apache Software Foundation.  All rights
5    * reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer.
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution,
20   *    if any, must include the following acknowledgment:
21   *       "This product includes software developed by the
22   *        Apache Software Foundation (http://www.apache.org/)."
23   *    Alternately, this acknowledgment may appear in the software itself,
24   *    if and wherever such third-party acknowledgments normally appear.
25   *
26   * 4. The names "Apache" and "Apache Software Foundation" must
27   *    not be used to endorse or promote products derived from this
28   *    software without prior written permission. For written
29   *    permission, please contact apache@apache.org.
30   *
31   * 5. Products derived from this software may not be called "Apache",
32   *    nor may "Apache" appear in their name, without prior written
33   *    permission of the Apache Software Foundation.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46   * SUCH DAMAGE.
47   * ====================================================================
48   *
49   * This software consists of voluntary contributions made by many
50   * individuals on behalf of the Apache Software Foundation.  For more
51   * information on the Apache Software Foundation, please see
52   * <http://www.apache.org/>.
53   */
54  package net.sf.cglib.reflect;
55  
56  import java.lang.reflect.*;
57  import java.util.*;
58  import net.sf.cglib.core.*;
59  import org.objectweb.asm.ClassVisitor;
60  import org.objectweb.asm.Label;
61  import org.objectweb.asm.Type;
62      
63  class FastClassEmitter extends ClassEmitter {
64      private static final Signature CSTRUCT_CLASS =
65        TypeUtils.parseConstructor("Class");
66      private static final Signature METHOD_GET_INDEX =
67        TypeUtils.parseSignature("int getIndex(String, Class[])");
68      private static final Signature SIGNATURE_GET_INDEX =
69        TypeUtils.parseSignature("int getIndex(net.sf.cglib.core.Signature)");
70      private static final Signature TO_STRING =
71        TypeUtils.parseSignature("String toString()");
72      private static final Signature CONSTRUCTOR_GET_INDEX =
73        TypeUtils.parseSignature("int getIndex(Class[])");
74      private static final Signature INVOKE =
75        TypeUtils.parseSignature("Object invoke(int, Object, Object[])");
76      private static final Signature NEW_INSTANCE =
77        TypeUtils.parseSignature("Object newInstance(int, Object[])");
78      private static final Signature GET_MAX_INDEX =
79        TypeUtils.parseSignature("int getMaxIndex()");
80      private static final Signature GET_SIGNATURE_WITHOUT_RETURN_TYPE =
81        TypeUtils.parseSignature("String getSignatureWithoutReturnType(String, Class[])");
82      private static final Type FAST_CLASS =
83        TypeUtils.parseType("net.sf.cglib.reflect.FastClass");
84      private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
85        TypeUtils.parseType("IllegalArgumentException");
86      private static final Type INVOCATION_TARGET_EXCEPTION =
87        TypeUtils.parseType("java.lang.reflect.InvocationTargetException");
88      private static final Type[] INVOCATION_TARGET_EXCEPTION_ARRAY = { INVOCATION_TARGET_EXCEPTION };
89      
90      public FastClassEmitter(ClassVisitor v, String className, Class type) {
91          super(v);
92        
93          
94          
95          begin_class(Constants.ACC_PUBLIC, className, FAST_CLASS, null, Constants.SOURCE_FILE);
96  
97          // constructor
98          CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_CLASS, null, null);
99          e.load_this();
100         e.load_args();
101         e.super_invoke_constructor(CSTRUCT_CLASS);
102         e.return_value();
103         e.end_method();
104 
105         VisibilityPredicate vp = new VisibilityPredicate(type, false);
106         List methodList = ReflectUtils.addAllMethods(type, new ArrayList());
107         CollectionUtils.filter(methodList, vp);
108         CollectionUtils.filter(methodList, new DuplicatesPredicate());
109         final Method[] methods = (Method[])methodList.toArray(new Method[methodList.size()]);
110         final Constructor[] constructors = (Constructor[])
111           CollectionUtils.filter(
112                type.getDeclaredConstructors(  ),
113                vp
114              );
115         
116         // getIndex(String)
117         emitIndexBySignature(methods);
118 
119         // getIndex(String, Class[])
120         emitIndexByClassArray(methods);
121         
122         // getIndex(Class[])
123         e = begin_method(Constants.ACC_PUBLIC, CONSTRUCTOR_GET_INDEX, null, null);
124         e.load_args();
125         EmitUtils.constructor_switch(e, constructors, new GetIndexCallback(e, constructors));
126         e.end_method();
127 
128         // invoke(int, Object, Object[])
129         e = begin_method(Constants.ACC_PUBLIC, INVOKE, INVOCATION_TARGET_EXCEPTION_ARRAY, null);
130         e.load_arg(1);
131         e.checkcast(Type.getType(type));
132         e.load_arg(0);
133         invokeSwitchHelper(e, methods, 2);
134         e.end_method();
135 
136         // newInstance(int, Object[])
137         e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, INVOCATION_TARGET_EXCEPTION_ARRAY, null);
138         e.new_instance(Type.getType(type));
139         e.dup();
140         e.load_arg(0);
141         invokeSwitchHelper(e, constructors, 1);
142         e.end_method();
143 
144         // getMaxIndex()
145         e = begin_method(Constants.ACC_PUBLIC, GET_MAX_INDEX, null, null);
146         e.push(methods.length - 1);
147         e.return_value();
148         e.end_method();
149 
150         end_class();
151     }
152 
153     // TODO: support constructor indices ("<init>")
154     private void emitIndexBySignature(Method[] methods) {
155         CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SIGNATURE_GET_INDEX, null, null);
156         List signatures = CollectionUtils.transform(Arrays.asList(methods), new Transformer() {
157             public Object transform(Object obj) {
158                 return ReflectUtils.getSignature((Method)obj).toString();
159             }
160         });
161         e.load_arg(0);
162         e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
163         signatureSwitchHelper(e, signatures);
164         e.end_method();
165     }
166 
167     private static final int TOO_MANY_METHODS = 100; // TODO
168     private void emitIndexByClassArray(Method[] methods) {
169         CodeEmitter e = begin_method(Constants.ACC_PUBLIC, METHOD_GET_INDEX, null, null);
170         if (methods.length > TOO_MANY_METHODS) {
171             // hack for big classes
172             List signatures = CollectionUtils.transform(Arrays.asList(methods), new Transformer() {
173                 public Object transform(Object obj) {
174                     String s = ReflectUtils.getSignature((Method)obj).toString();
175                     return s.substring(0, s.lastIndexOf(')') + 1);
176                 }
177             });
178             e.load_args();
179             e.invoke_static(FAST_CLASS, GET_SIGNATURE_WITHOUT_RETURN_TYPE);
180             signatureSwitchHelper(e, signatures);
181         } else {
182             e.load_args();
183             EmitUtils.method_switch(e, methods, new GetIndexCallback(e, methods));
184         }
185         e.end_method();
186     }
187 
188     private void signatureSwitchHelper(final CodeEmitter e, final List signatures) {
189         ObjectSwitchCallback callback = new ObjectSwitchCallback() {
190             public void processCase(Object key, Label end) {
191                 // TODO: remove linear indexOf
192                 e.push(signatures.indexOf(key));
193                 e.return_value();
194             }
195             public void processDefault() {
196                 e.push(-1);
197                 e.return_value();
198             }
199         };
200         EmitUtils.string_switch(e,
201                                 (String[])signatures.toArray(new String[signatures.size()]),
202                                 Constants.SWITCH_STYLE_HASH,
203                                 callback);
204     }
205 
206     private static void invokeSwitchHelper(final CodeEmitter e, final Object[] members, final int arg) {
207         final Label illegalArg = e.make_label();
208         Block block = e.begin_block();
209         e.process_switch(getIntRange(members.length), new ProcessSwitchCallback() {
210             public void processCase(int key, Label end) {
211                 Member member = (Member)members[key];
212                 Signature sig = ReflectUtils.getSignature(member);
213                 Type[] types = sig.getArgumentTypes();
214                 for (int i = 0; i < types.length; i++) {
215                     e.load_arg(arg);
216                     e.aaload(i);
217                     e.unbox(types[i]);
218                 }
219                 if (member instanceof Method) {
220                     e.invoke((Method)member);
221                     e.box(Type.getType(((Method)member).getReturnType()));
222                 } else {
223                     e.invoke_constructor(Type.getType(member.getDeclaringClass()), sig);
224                 }
225                 e.return_value();
226             }
227 
228             public void processDefault() {
229                 e.goTo(illegalArg);
230             }
231         });
232         block.end();
233         EmitUtils.wrap_throwable(block, INVOCATION_TARGET_EXCEPTION);
234         e.mark(illegalArg);
235         e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Cannot find matching method/constructor");
236     }
237 
238     private static class GetIndexCallback implements ObjectSwitchCallback {
239         private CodeEmitter e;
240         private Map indexes = new HashMap();
241 
242         public GetIndexCallback(CodeEmitter e, Object[] members) {
243             this.e = e;
244             for (int i = 0; i < members.length; i++) {
245                 indexes.put(members[i], new Integer(i));
246             }
247         }
248             
249         public void processCase(Object key, Label end) {
250             e.push(((Integer)indexes.get(key)).intValue());
251             e.return_value();
252         }
253         
254         public void processDefault() {
255             e.push(-1);
256             e.return_value();
257         }
258     }
259     
260     private static int[] getIntRange(int length) {
261         int[] range = new int[length];
262         for (int i = 0; i < length; i++) {
263             range[i] = i;
264         }
265         return range;
266     }
267 }
This page was automatically generated by Maven