1 16 package net.sf.cglib.reflect; 17 18 import java.lang.reflect.*; 19 import java.util.*; 20 import net.sf.cglib.core.*; 21 import org.objectweb.asm.ClassVisitor; 22 import org.objectweb.asm.Label; 23 import org.objectweb.asm.Type; 24 25 class FastClassEmitter extends ClassEmitter { 26 private static final Signature CSTRUCT_CLASS = 27 TypeUtils.parseConstructor("Class"); 28 private static final Signature METHOD_GET_INDEX = 29 TypeUtils.parseSignature("int getIndex(String, Class[])"); 30 private static final Signature SIGNATURE_GET_INDEX = 31 new Signature("getIndex", Type.INT_TYPE, new Type[]{ Constants.TYPE_SIGNATURE }); 32 private static final Signature TO_STRING = 33 TypeUtils.parseSignature("String toString()"); 34 private static final Signature CONSTRUCTOR_GET_INDEX = 35 TypeUtils.parseSignature("int getIndex(Class[])"); 36 private static final Signature INVOKE = 37 TypeUtils.parseSignature("Object invoke(int, Object, Object[])"); 38 private static final Signature NEW_INSTANCE = 39 TypeUtils.parseSignature("Object newInstance(int, Object[])"); 40 private static final Signature GET_MAX_INDEX = 41 TypeUtils.parseSignature("int getMaxIndex()"); 42 private static final Signature GET_SIGNATURE_WITHOUT_RETURN_TYPE = 43 TypeUtils.parseSignature("String getSignatureWithoutReturnType(String, Class[])"); 44 private static final Type FAST_CLASS = 45 TypeUtils.parseType("net.sf.cglib.reflect.FastClass"); 46 private static final Type ILLEGAL_ARGUMENT_EXCEPTION = 47 TypeUtils.parseType("IllegalArgumentException"); 48 private static final Type INVOCATION_TARGET_EXCEPTION = 49 TypeUtils.parseType("java.lang.reflect.InvocationTargetException"); 50 private static final Type[] INVOCATION_TARGET_EXCEPTION_ARRAY = { INVOCATION_TARGET_EXCEPTION }; 51 52 public FastClassEmitter(ClassVisitor v, String className, Class type) { 53 super(v); 54 55 Type base = Type.getType(type); 56 begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, FAST_CLASS, null, Constants.SOURCE_FILE); 57 58 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_CLASS, null); 60 e.load_this(); 61 e.load_args(); 62 e.super_invoke_constructor(CSTRUCT_CLASS); 63 e.return_value(); 64 e.end_method(); 65 66 VisibilityPredicate vp = new VisibilityPredicate(type, false); 67 List methods = ReflectUtils.addAllMethods(type, new ArrayList()); 68 CollectionUtils.filter(methods, vp); 69 CollectionUtils.filter(methods, new DuplicatesPredicate()); 70 List constructors = new ArrayList(Arrays.asList(type.getDeclaredConstructors())); 71 CollectionUtils.filter(constructors, vp); 72 73 emitIndexBySignature(methods); 75 76 emitIndexByClassArray(methods); 78 79 e = begin_method(Constants.ACC_PUBLIC, CONSTRUCTOR_GET_INDEX, null); 81 e.load_args(); 82 List info = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance()); 83 EmitUtils.constructor_switch(e, info, new GetIndexCallback(e, info)); 84 e.end_method(); 85 86 e = begin_method(Constants.ACC_PUBLIC, INVOKE, INVOCATION_TARGET_EXCEPTION_ARRAY); 88 e.load_arg(1); 89 e.checkcast(base); 90 e.load_arg(0); 91 invokeSwitchHelper(e, methods, 2, base); 92 e.end_method(); 93 94 e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, INVOCATION_TARGET_EXCEPTION_ARRAY); 96 e.new_instance(base); 97 e.dup(); 98 e.load_arg(0); 99 invokeSwitchHelper(e, constructors, 1, base); 100 e.end_method(); 101 102 e = begin_method(Constants.ACC_PUBLIC, GET_MAX_INDEX, null); 104 e.push(methods.size() - 1); 105 e.return_value(); 106 e.end_method(); 107 108 end_class(); 109 } 110 111 private void emitIndexBySignature(List methods) { 113 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SIGNATURE_GET_INDEX, null); 114 List signatures = CollectionUtils.transform(methods, new Transformer() { 115 public Object transform(Object obj) { 116 return ReflectUtils.getSignature((Method)obj).toString(); 117 } 118 }); 119 e.load_arg(0); 120 e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING); 121 signatureSwitchHelper(e, signatures); 122 e.end_method(); 123 } 124 125 private static final int TOO_MANY_METHODS = 100; private void emitIndexByClassArray(List methods) { 127 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, METHOD_GET_INDEX, null); 128 if (methods.size() > TOO_MANY_METHODS) { 129 List signatures = CollectionUtils.transform(methods, new Transformer() { 131 public Object transform(Object obj) { 132 String s = ReflectUtils.getSignature((Method)obj).toString(); 133 return s.substring(0, s.lastIndexOf(')') + 1); 134 } 135 }); 136 e.load_args(); 137 e.invoke_static(FAST_CLASS, GET_SIGNATURE_WITHOUT_RETURN_TYPE); 138 signatureSwitchHelper(e, signatures); 139 } else { 140 e.load_args(); 141 List info = CollectionUtils.transform(methods, MethodInfoTransformer.getInstance()); 142 EmitUtils.method_switch(e, info, new GetIndexCallback(e, info)); 143 } 144 e.end_method(); 145 } 146 147 private void signatureSwitchHelper(final CodeEmitter e, final List signatures) { 148 ObjectSwitchCallback callback = new ObjectSwitchCallback() { 149 public void processCase(Object key, Label end) { 150 e.push(signatures.indexOf(key)); 152 e.return_value(); 153 } 154 public void processDefault() { 155 e.push(-1); 156 e.return_value(); 157 } 158 }; 159 EmitUtils.string_switch(e, 160 (String [])signatures.toArray(new String [signatures.size()]), 161 Constants.SWITCH_STYLE_HASH, 162 callback); 163 } 164 165 private static void invokeSwitchHelper(final CodeEmitter e, List members, final int arg, final Type base) { 166 final List info = CollectionUtils.transform(members, MethodInfoTransformer.getInstance()); 167 final Label illegalArg = e.make_label(); 168 Block block = e.begin_block(); 169 e.process_switch(getIntRange(info.size()), new ProcessSwitchCallback() { 170 public void processCase(int key, Label end) { 171 MethodInfo method = (MethodInfo)info.get(key); 172 Type[] types = method.getSignature().getArgumentTypes(); 173 for (int i = 0; i < types.length; i++) { 174 e.load_arg(arg); 175 e.aaload(i); 176 e.unbox(types[i]); 177 } 178 e.invoke(method, base); 181 if (!TypeUtils.isConstructor(method)) { 182 e.box(method.getSignature().getReturnType()); 183 } 184 e.return_value(); 185 } 186 public void processDefault() { 187 e.goTo(illegalArg); 188 } 189 }); 190 block.end(); 191 EmitUtils.wrap_throwable(block, INVOCATION_TARGET_EXCEPTION); 192 e.mark(illegalArg); 193 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Cannot find matching method/constructor"); 194 } 195 196 private static class GetIndexCallback implements ObjectSwitchCallback { 197 private CodeEmitter e; 198 private Map indexes = new HashMap(); 199 200 public GetIndexCallback(CodeEmitter e, List methods) { 201 this.e = e; 202 int index = 0; 203 for (Iterator it = methods.iterator(); it.hasNext();) { 204 indexes.put(it.next(), new Integer (index++)); 205 } 206 } 207 208 public void processCase(Object key, Label end) { 209 e.push(((Integer )indexes.get(key)).intValue()); 210 e.return_value(); 211 } 212 213 public void processDefault() { 214 e.push(-1); 215 e.return_value(); 216 } 217 } 218 219 private static int[] getIntRange(int length) { 220 int[] range = new int[length]; 221 for (int i = 0; i < length; i++) { 222 range[i] = i; 223 } 224 return range; 225 } 226 } 227 | Popular Tags |