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.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