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