KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > cglib > reflect > FastClassEmitter


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 org.logicalcobwebs.cglib.reflect;
55
56 import java.lang.reflect.*;
57 import java.util.*;
58 import org.logicalcobwebs.cglib.core.*;
59 import org.logicalcobwebs.asm.ClassVisitor;
60 import org.logicalcobwebs.asm.Label;
61 import org.logicalcobwebs.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(org.logicalcobwebs.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("org.logicalcobwebs.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 JavaDoc className, Class JavaDoc type) {
91         super(v);
92         begin_class(Constants.ACC_PUBLIC, className, FAST_CLASS, null, Constants.SOURCE_FILE);
93
94         // constructor
95
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_CLASS, null, null);
96         e.load_this();
97         e.load_args();
98         e.super_invoke_constructor(CSTRUCT_CLASS);
99         e.return_value();
100         e.end_method();
101
102         VisibilityPredicate vp = new VisibilityPredicate(type, false);
103         List methodList = ReflectUtils.addAllMethods(type, new ArrayList());
104         CollectionUtils.filter(methodList, vp);
105         CollectionUtils.filter(methodList, new DuplicatesPredicate());
106         final Method[] methods = (Method[])methodList.toArray(new Method[methodList.size()]);
107         final Constructor[] constructors = (Constructor[])CollectionUtils.filter(type.getDeclaredConstructors(), vp);
108         
109         // getIndex(String)
110
emitIndexBySignature(methods);
111
112         // getIndex(String, Class[])
113
emitIndexByClassArray(methods);
114         
115         // getIndex(Class[])
116
e = begin_method(Constants.ACC_PUBLIC, CONSTRUCTOR_GET_INDEX, null, null);
117         e.load_args();
118         EmitUtils.constructor_switch(e, constructors, new GetIndexCallback(e, constructors));
119         e.end_method();
120
121         // invoke(int, Object, Object[])
122
e = begin_method(Constants.ACC_PUBLIC, INVOKE, INVOCATION_TARGET_EXCEPTION_ARRAY, null);
123         e.load_arg(1);
124         e.checkcast(Type.getType(type));
125         e.load_arg(0);
126         invokeSwitchHelper(e, methods, 2);
127         e.end_method();
128
129         // newInstance(int, Object[])
130
e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, INVOCATION_TARGET_EXCEPTION_ARRAY, null);
131         e.new_instance(Type.getType(type));
132         e.dup();
133         e.load_arg(0);
134         invokeSwitchHelper(e, constructors, 1);
135         e.end_method();
136
137         // getMaxIndex()
138
e = begin_method(Constants.ACC_PUBLIC, GET_MAX_INDEX, null, null);
139         e.push(methods.length - 1);
140         e.return_value();
141         e.end_method();
142
143         end_class();
144     }
145
146     // TODO: support constructor indices ("<init>")
147
private void emitIndexBySignature(Method[] methods) {
148         CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SIGNATURE_GET_INDEX, null, null);
149         List signatures = CollectionUtils.transform(Arrays.asList(methods), new Transformer() {
150             public Object JavaDoc transform(Object JavaDoc obj) {
151                 return ReflectUtils.getSignature((Method)obj).toString();
152             }
153         });
154         e.load_arg(0);
155         e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
156         signatureSwitchHelper(e, signatures);
157         e.end_method();
158     }
159
160     private static final int TOO_MANY_METHODS = 100; // TODO
161
private void emitIndexByClassArray(Method[] methods) {
162         CodeEmitter e = begin_method(Constants.ACC_PUBLIC, METHOD_GET_INDEX, null, null);
163         if (methods.length > TOO_MANY_METHODS) {
164             // hack for big classes
165
List signatures = CollectionUtils.transform(Arrays.asList(methods), new Transformer() {
166                 public Object JavaDoc transform(Object JavaDoc obj) {
167                     String JavaDoc s = ReflectUtils.getSignature((Method)obj).toString();
168                     return s.substring(0, s.lastIndexOf(')') + 1);
169                 }
170             });
171             e.load_args();
172             e.invoke_static(FAST_CLASS, GET_SIGNATURE_WITHOUT_RETURN_TYPE);
173             signatureSwitchHelper(e, signatures);
174         } else {
175             e.load_args();
176             EmitUtils.method_switch(e, methods, new GetIndexCallback(e, methods));
177         }
178         e.end_method();
179     }
180
181     private void signatureSwitchHelper(final CodeEmitter e, final List signatures) {
182         ObjectSwitchCallback callback = new ObjectSwitchCallback() {
183             public void processCase(Object JavaDoc key, Label end) {
184                 // TODO: remove linear indexOf
185
e.push(signatures.indexOf(key));
186                 e.return_value();
187             }
188             public void processDefault() {
189                 e.push(-1);
190                 e.return_value();
191             }
192         };
193         EmitUtils.string_switch(e,
194                                 (String JavaDoc[])signatures.toArray(new String JavaDoc[signatures.size()]),
195                                 Constants.SWITCH_STYLE_HASH,
196                                 callback);
197     }
198
199     private static void invokeSwitchHelper(final CodeEmitter e, final Object JavaDoc[] members, final int arg) {
200         final Label illegalArg = e.make_label();
201         Block block = e.begin_block();
202         e.process_switch(getIntRange(members.length), new ProcessSwitchCallback() {
203             public void processCase(int key, Label end) {
204                 Member member = (Member)members[key];
205                 Signature sig = ReflectUtils.getSignature(member);
206                 Type[] types = sig.getArgumentTypes();
207                 for (int i = 0; i < types.length; i++) {
208                     e.load_arg(arg);
209                     e.aaload(i);
210                     e.unbox(types[i]);
211                 }
212                 if (member instanceof Method) {
213                     e.invoke((Method)member);
214                     e.box(Type.getType(((Method)member).getReturnType()));
215                 } else {
216                     e.invoke_constructor(Type.getType(member.getDeclaringClass()), sig);
217                 }
218                 e.return_value();
219             }
220
221             public void processDefault() {
222                 e.goTo(illegalArg);
223             }
224         });
225         block.end();
226         EmitUtils.wrap_throwable(block, INVOCATION_TARGET_EXCEPTION);
227         e.mark(illegalArg);
228         e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Cannot find matching method/constructor");
229     }
230
231     private static class GetIndexCallback implements ObjectSwitchCallback {
232         private CodeEmitter e;
233         private Map indexes = new HashMap();
234
235         public GetIndexCallback(CodeEmitter e, Object JavaDoc[] members) {
236             this.e = e;
237             for (int i = 0; i < members.length; i++) {
238                 indexes.put(members[i], new Integer JavaDoc(i));
239             }
240         }
241             
242         public void processCase(Object JavaDoc key, Label end) {
243             e.push(((Integer JavaDoc)indexes.get(key)).intValue());
244             e.return_value();
245         }
246         
247         public void processDefault() {
248             e.push(-1);
249             e.return_value();
250         }
251     }
252     
253     private static int[] getIntRange(int length) {
254         int[] range = new int[length];
255         for (int i = 0; i < length; i++) {
256             range[i] = i;
257         }
258         return range;
259     }
260 }
261
Popular Tags