View Javadoc
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