1 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 className, Class type) { 91 super(v); 92 begin_class(Constants.ACC_PUBLIC, className, FAST_CLASS, null, Constants.SOURCE_FILE); 93 94 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 emitIndexBySignature(methods); 111 112 emitIndexByClassArray(methods); 114 115 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 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 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 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 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 transform(Object 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; 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 List signatures = CollectionUtils.transform(Arrays.asList(methods), new Transformer() { 166 public Object transform(Object obj) { 167 String 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 key, Label end) { 184 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 [])signatures.toArray(new String [signatures.size()]), 195 Constants.SWITCH_STYLE_HASH, 196 callback); 197 } 198 199 private static void invokeSwitchHelper(final CodeEmitter e, final Object [] 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 [] members) { 236 this.e = e; 237 for (int i = 0; i < members.length; i++) { 238 indexes.put(members[i], new Integer (i)); 239 } 240 } 241 242 public void processCase(Object key, Label end) { 243 e.push(((Integer )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 |