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;
55
56 import java.io.ObjectStreamException;
57 import java.lang.reflect.*;
58 import java.util.*;
59 import net.sf.cglib.core.*;
60 import org.objectweb.asm.ClassVisitor;
61 import org.objectweb.asm.Label;
62 import org.objectweb.asm.Type;
63
64 class EnhancerEmitter extends ClassEmitter {
65 private static final String CONSTRUCTED_FIELD = "CGLIB$CONSTRUCTED";
66
67 private static final Type ILLEGAL_STATE_EXCEPTION =
68 TypeUtils.parseType("IllegalStateException");
69 private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
70 TypeUtils.parseType("IllegalArgumentException");
71 private static final Type THREAD_LOCAL =
72 TypeUtils.parseType("ThreadLocal");
73 private static final Type FACTORY =
74 TypeUtils.parseType("net.sf.cglib.Factory");
75 private static final Type CALLBACKS =
76 TypeUtils.parseType("net.sf.cglib.Callbacks");
77
78 private static final Signature CSTRUCT_NULL =
79 TypeUtils.parseConstructor("");
80 private static final Signature SET_THREAD_CALLBACKS =
81 TypeUtils.parseSignature("void CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.Callbacks)");
82 private static final Signature NEW_INSTANCE =
83 TypeUtils.parseSignature("net.sf.cglib.Factory newInstance(net.sf.cglib.Callbacks)");
84 private static final Signature MULTIARG_NEW_INSTANCE =
85 TypeUtils.parseSignature("net.sf.cglib.Factory newInstance(Class[], Object[], net.sf.cglib.Callbacks)");
86 private static final Signature SINGLE_NEW_INSTANCE =
87 TypeUtils.parseSignature("net.sf.cglib.Factory newInstance(net.sf.cglib.Callback)");
88 private static final Signature GET_CALLBACK =
89 TypeUtils.parseSignature("net.sf.cglib.Callback getCallback(int)");
90 private static final Signature SET_CALLBACK =
91 TypeUtils.parseSignature("void setCallback(int, net.sf.cglib.Callback)");
92 private static final Signature SET_CALLBACKS =
93 TypeUtils.parseSignature("void setCallbacks(net.sf.cglib.Callbacks)");
94 private static final Signature CALLBACKS_GET =
95 TypeUtils.parseSignature("net.sf.cglib.Callback get(int)");
96
97 private static final Signature THREAD_LOCAL_GET =
98 TypeUtils.parseSignature("Object get()");
99 private static final Signature THREAD_LOCAL_SET =
100 TypeUtils.parseSignature("void set(Object)");
101
102 private final TinyBitSet usedCallbacks = new TinyBitSet();
103
104 public EnhancerEmitter(ClassVisitor v,
105 String className,
106 Class superclass,
107 Class[] interfaces,
108 CallbackFilter filter) throws Exception {
109 super(v);
110 if (superclass == null) {
111 superclass = Object.class;
112 }
113
114 begin_class(Constants.ACC_PUBLIC,
115 className,
116 Type.getType(superclass),
117 TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY),
118 Constants.SOURCE_FILE);
119
120 List clist = new ArrayList(Arrays.asList(superclass.getDeclaredConstructors()));
121 CollectionUtils.filter(clist, new VisibilityPredicate(superclass, true));
122 if (clist.size() == 0) {
123 throw new IllegalArgumentException("No visible constructors in " + superclass);
124 }
125 Constructor[] constructors = (Constructor[])clist.toArray(new Constructor[clist.size()]);
126
127 // Order is very important: must add superclass, then
128 // its superclass chain, then each interface and
129 // its superinterfaces.
130 List methods = new ArrayList();
131 ReflectUtils.addAllMethods(superclass, methods);
132
133 List interfaceMethods = new ArrayList();
134 if (interfaces != null) {
135 for (int i = 0; i < interfaces.length; i++) {
136 if (interfaces[i] != Factory.class) {
137 ReflectUtils.addAllMethods(interfaces[i], interfaceMethods);
138 }
139 }
140 }
141 Set forcePublic = MethodWrapper.createSet(interfaceMethods);
142 methods.addAll(interfaceMethods);
143 CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true));
144 CollectionUtils.filter(methods, new DuplicatesPredicate());
145 removeFinal(methods);
146
147 int len = Callbacks.MAX_VALUE + 1;
148 CallbackGenerator[] generators = new CallbackGenerator[len];
149 List[] group = new List[len];
150 for (Iterator it = methods.iterator(); it.hasNext();) {
151 Method method = (Method)it.next();
152 int ctype = filter.accept(method);
153 if (ctype > Callbacks.MAX_VALUE) {
154 // TODO: error
155 }
156 if (group[ctype] == null) {
157 group[ctype] = new ArrayList(methods.size());
158 generators[ctype] = CallbackUtils.getGenerator(ctype);
159 }
160 group[ctype].add(method);
161 }
162
163 declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
164 emitConstructors(constructors);
165
166 CallbackGenerator.Context[] contexts = createContexts(generators, group, forcePublic);
167 emitMethods(generators, contexts);
168 emitStatic(generators, contexts);
169
170 final int[] keys = getCallbackKeys();
171 emitGetCallback(keys);
172 emitSetCallback(keys);
173 emitSetCallbacks();
174 emitNewInstanceCallbacks();
175 emitNewInstanceCallback();
176 emitNewInstanceMultiarg(constructors);
177
178 emitSetThreadCallbacks();
179 end_class();
180 }
181
182 private void emitConstructors(Constructor[] constructors) {
183 for (int i = 0; i < constructors.length; i++) {
184 Signature sig = ReflectUtils.getSignature(constructors[i]);
185 CodeEmitter e = begin_method(Constants.ACC_PUBLIC,
186 sig,
187 ReflectUtils.getExceptionTypes(constructors[i]));
188 e.load_this();
189 e.dup();
190 e.load_args();
191 e.super_invoke_constructor(sig);
192 e.push(1);
193 e.putfield(CONSTRUCTED_FIELD);
194 e.return_value();
195 e.end_method();
196 }
197 }
198
199 private void emitGetCallback(int[] keys) {
200 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_CALLBACK, null);
201 e.load_this();
202 e.load_arg(0);
203 e.process_switch(keys, new ProcessSwitchCallback() {
204 public void processCase(int key, Label end) {
205 e.getfield(getCallbackField(key));
206 e.goTo(end);
207 }
208 public void processDefault() {
209 e.pop(); // stack height
210 e.aconst_null();
211 }
212 });
213 e.return_value();
214 e.end_method();
215 }
216
217 private void emitSetCallback(int[] keys) {
218 // Factory.setCallback(int, Callback)
219 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_CALLBACK, null);
220 e.load_this();
221 e.load_arg(1);
222 e.load_arg(0);
223 e.process_switch(keys, new ProcessSwitchCallback() {
224 public void processCase(int key, Label end) {
225 e.checkcast(CallbackUtils.getType(key));
226 e.putfield(getCallbackField(key));
227 e.goTo(end);
228 }
229 public void processDefault() {
230 e.pop2(); // stack height
231 }
232 });
233 e.return_value();
234 e.end_method();
235 }
236
237 private void emitSetCallbacks() {
238 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_CALLBACKS, null);
239 e.load_this();
240 e.load_arg(0);
241 emitSetCallbacks(e);
242 e.return_value();
243 e.end_method();
244 }
245
246 private void emitNewInstanceCallbacks() {
247 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
248 e.load_arg(0);
249 e.invoke_static_this(SET_THREAD_CALLBACKS);
250 e.new_instance_this();
251 e.dup();
252 e.invoke_constructor_this();
253 e.dup();
254 e.load_arg(0);
255 emitSetCallbacks(e);
256 e.return_value();
257 e.end_method();
258 }
259
260 private void emitNewInstanceCallback() {
261 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SINGLE_NEW_INSTANCE, null);
262 switch (usedCallbacks.cardinality()) {
263 case 1:
264 int type = usedCallbacks.length() - 1;
265 e.getfield(getThreadLocal(type));
266 e.load_arg(0);
267 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET);
268 e.new_instance_this();
269 e.dup();
270 e.invoke_constructor_this();
271 e.dup();
272 e.push(type);
273 e.load_arg(0);
274 e.invoke_virtual_this(SET_CALLBACK);
275 break;
276 case 0:
277 // TODO: make sure Callback is null?
278 e.new_instance_this();
279 e.dup();
280 e.invoke_constructor_this();
281 break;
282 default:
283 e.throw_exception(ILLEGAL_STATE_EXCEPTION, "More than one callback object required");
284 }
285 e.return_value();
286 e.end_method();
287 }
288
289 private void emitNewInstanceMultiarg(Constructor[] constructors) {
290 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, MULTIARG_NEW_INSTANCE, null);
291 Label skipSetCallbacks = e.make_label();
292 e.load_arg(2);
293 e.invoke_static_this(SET_THREAD_CALLBACKS);
294 e.new_instance_this();
295 e.dup();
296 e.load_arg(0);
297 ComplexOps.constructor_switch(e, constructors, new ObjectSwitchCallback() {
298 public void processCase(Object key, Label end) {
299 Constructor constructor = (Constructor)key;
300 Type types[] = TypeUtils.getTypes(constructor.getParameterTypes());
301 for (int i = 0; i < types.length; i++) {
302 e.load_arg(1);
303 e.push(i);
304 e.aaload();
305 e.unbox(types[i]);
306 }
307 e.invoke_constructor_this(ReflectUtils.getSignature(constructor));
308 e.goTo(end);
309 }
310 public void processDefault() {
311 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Constructor not found");
312 }
313 });
314 e.load_arg(2);
315 e.ifnull(skipSetCallbacks);
316 e.dup();
317 e.load_arg(2);
318 emitSetCallbacks(e);
319 e.mark(skipSetCallbacks);
320 e.return_value();
321 e.end_method();
322 }
323
324 private void emitSetCallbacks(CodeEmitter e) {
325 if (usedCallbacks.length() == 0) {
326 e.pop2(); // stack height
327 } else {
328 for (int i = 0; i <= Callbacks.MAX_VALUE; i++) {
329 if (usedCallbacks.get(i)) {
330 if (i + 1 < usedCallbacks.length()) {
331 e.dup2();
332 }
333 e.push(i);
334 e.invoke_interface(CALLBACKS, CALLBACKS_GET);
335 e.checkcast(CallbackUtils.getType(i));
336 e.putfield(getCallbackField(i));
337 }
338 }
339 }
340 }
341
342 private int[] getCallbackKeys() {
343 int c = 0;
344 for (int i = 0; i <= Callbacks.MAX_VALUE; i++) {
345 if (usedCallbacks.get(i)) {
346 c++;
347 }
348 }
349 int[] keys = new int[c];
350 c = 0;
351 for (int i = 0; i <= Callbacks.MAX_VALUE; i++) {
352 if (usedCallbacks.get(i)) {
353 keys[c++] = i;
354 }
355 }
356 return keys;
357 }
358
359 private CallbackGenerator.Context[] createContexts(CallbackGenerator[] generators,
360 List[] methods,
361 final Set forcePublic) {
362 CallbackGenerator.Context[] contexts = new CallbackGenerator.Context[Callbacks.MAX_VALUE + 1];
363 for (int i = 0; i <= Callbacks.MAX_VALUE; i++) {
364 final int type = i;
365 final List fmethods = methods[i];
366 if (generators[type] != null) {
367 contexts[type] = new CallbackGenerator.Context() {
368 public Iterator getMethods() {
369 return fmethods.iterator();
370 }
371 public void emitCallback(CodeEmitter e) {
372 emitCurrentCallback(e, type);
373 }
374 public int getModifiers(Method method) {
375 int modifiers = Constants.ACC_FINAL
376 | (method.getModifiers()
377 & ~Constants.ACC_ABSTRACT
378 & ~Constants.ACC_NATIVE
379 & ~Constants.ACC_SYNCHRONIZED);
380 if (forcePublic.contains(MethodWrapper.create(method))) {
381 modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
382 }
383 return modifiers;
384 }
385 // TODO: this is probably slow
386 public String getUniqueName(Method method) {
387 return method.getName() + "_" + fmethods.indexOf(method);
388 }
389 };
390 }
391 }
392 return contexts;
393 }
394
395 private void emitMethods(CallbackGenerator[] generators, CallbackGenerator.Context[] contexts) throws Exception {
396 for (int i = 0; i <= Callbacks.MAX_VALUE; i++) {
397 if (generators[i] != null) {
398 Type callbackType = CallbackUtils.getType(i);
399 if (callbackType != null) {
400 declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackType, null);
401 declare_field(Constants.PRIVATE_FINAL_STATIC, getThreadLocal(i), THREAD_LOCAL, null);
402 }
403 generators[i].generate(this, contexts[i]);
404 }
405 }
406 }
407
408 private void emitSetThreadCallbacks() {
409 CodeEmitter e = begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
410 SET_THREAD_CALLBACKS,
411 null);
412 Label end = e.make_label();
413 e.load_arg(0);
414 e.ifnull(end);
415 for (int i = 0; i <= Callbacks.MAX_VALUE; i++) {
416 if (usedCallbacks.get(i)) {
417 e.load_arg(0);
418 e.push(i);
419 e.invoke_interface(CALLBACKS, CALLBACKS_GET);
420 e.getfield(getThreadLocal(i));
421 e.swap();
422 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET);
423 }
424 }
425 e.mark(end);
426 e.return_value();
427 e.end_method();
428 }
429
430 private void emitCurrentCallback(CodeEmitter e, int type) {
431 usedCallbacks.set(type);
432 e.load_this();
433 e.getfield(getCallbackField(type));
434 e.dup();
435 Label end = e.make_label();
436 e.ifnonnull(end);
437 e.load_this();
438 e.getfield(CONSTRUCTED_FIELD);
439 e.if_jump(e.NE, end);
440 e.pop();
441 e.getfield(getThreadLocal(type));
442 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_GET);
443 e.checkcast(CallbackUtils.getType(type));
444 e.mark(end);
445 }
446
447 private String getCallbackField(int type) {
448 return "CGLIB$CALLBACK_" + type;
449 }
450
451 private String getThreadLocal(int type) {
452 return "CGLIB$TL_CALLBACK_" + type;
453 }
454
455 private void emitStatic(CallbackGenerator[] generators,
456 CallbackGenerator.Context[] contexts) throws Exception {
457 CodeEmitter e = begin_static();
458 for (int i = 0; i <= Callbacks.MAX_VALUE; i++) {
459 if (usedCallbacks.get(i)) {
460 e.new_instance(THREAD_LOCAL);
461 e.dup();
462 e.invoke_constructor(THREAD_LOCAL, CSTRUCT_NULL);
463 e.putfield(getThreadLocal(i));
464 }
465 }
466 for (int i = 0; i <= Callbacks.MAX_VALUE; i++) {
467 if (generators[i] != null) {
468 generators[i].generateStatic(e, contexts[i]);
469 }
470 }
471 e.return_value();
472 e.end_method();
473 }
474
475 private static void removeFinal(List list) {
476 CollectionUtils.filter(list, new Predicate() {
477 public boolean evaluate(Object arg) {
478 return !Modifier.isFinal(((Method)arg).getModifiers());
479 }
480 });
481 }
482 }
This page was automatically generated by Maven