package org.nutz.lang.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.concurrent.ConcurrentHashMap; import org.nutz.aop.DefaultClassDefiner; import org.nutz.lang.Lang; import org.nutz.repo.org.objectweb.asm.ClassWriter; import org.nutz.repo.org.objectweb.asm.Label; import org.nutz.repo.org.objectweb.asm.Opcodes; import org.nutz.repo.org.objectweb.asm.Type; import org.nutz.repo.org.objectweb.asm.commons.GeneratorAdapter; public class FastMethodFactory implements Opcodes { protected static ConcurrentHashMap<String, FastMethod> cache = new ConcurrentHashMap<String, FastMethod>(); protected static org.nutz.repo.org.objectweb.asm.commons.Method _M; protected static org.nutz.repo.org.objectweb.asm.Type Exception_TYPE; static { _M = _Method("invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); Exception_TYPE = Type.getType(Throwable.class); } protected static FastMethod make(Method method) { Class<?> klass = method.getDeclaringClass(); String descriptor = Type.getMethodDescriptor(method); String key = "$FM$" + method.getName() + "$" + Lang.md5(descriptor); String className = klass.getName() + key; if (klass.getName().startsWith("java")) className = FastMethod.class.getPackage().getName() + ".fast." + className; FastMethod fm = cache.get(className); if (fm != null) return fm; try { fm = (FastMethod) klass.getClassLoader().loadClass(className).newInstance(); cache.put(className, fm); return fm; } catch (Exception e) {} byte[] buf = _make(klass, method.getModifiers(), method.getParameterTypes(), _Method(method), method.getReturnType(), className, descriptor); Class<?> t = DefaultClassDefiner.defaultOne().define(className, buf, klass.getClassLoader()); try { fm = (FastMethod) t.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } cache.put(className, fm); return fm; } protected static FastMethod make(Constructor<?> constructor) { Class<?> klass = constructor.getDeclaringClass(); String descriptor = Type.getConstructorDescriptor(constructor); String key = Lang.md5(descriptor); String className = klass.getName() + "$FC$" + key; if (klass.getName().startsWith("java")) className = FastMethod.class.getPackage().getName() + ".fast." + className; FastMethod fm = (FastMethod) cache.get(className); if (fm != null) return fm; try { fm = (FastMethod) klass.getClassLoader().loadClass(className).newInstance(); cache.put(key, fm); return fm; } catch (Exception e) {} byte[] buf = _make(klass, constructor.getModifiers(), constructor.getParameterTypes(), _Method(constructor), null, className, descriptor); Class<?> t = DefaultClassDefiner.defaultOne().define(className, buf, klass.getClassLoader()); try { fm = (FastMethod) t.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } cache.put(className, fm); return fm; } public static byte[] _make(Class<?> klass, int mod, Class<?>[] params, org.nutz.repo.org.objectweb.asm.commons.Method method, Class<?> returnType, String className, String descriptor) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); cw.visit(V1_5, ACC_PUBLIC, className.replace('.', '/'), null, "java/lang/Object", new String[]{FastMethod.class.getName().replace('.', '/')}); Type klassType = Type.getType(klass); // 首先, 定义默认构造方法 addConstructor(cw, Type.getType(Object.class), org.nutz.repo.org.objectweb.asm.commons.Method.getMethod("void <init> ()")); // 然后定义执行方法 GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, _M, null, new Type[]{Exception_TYPE}, cw); if (returnType == null) { mg.newInstance(klassType); mg.dup(); } else if (!Modifier.isStatic(mod)) { mg.loadThis(); mg.loadArg(0); mg.checkCast(klassType); } if (params.length > 0) { for (int i = 0; i < params.length; i++) { mg.loadArg(1); mg.push(i); mg.arrayLoad(Type.getType(Object.class)); Type paramType = Type.getType(params[i]); if (params[i].isPrimitive()) { mg.unbox(paramType); } else { mg.checkCast(paramType); } } } if (returnType == null) { mg.invokeConstructor(klassType, method); } else { if (Modifier.isStatic(mod)) { mg.invokeStatic(klassType, method); } else if (Modifier.isInterface(klass.getModifiers())) { mg.invokeInterface(klassType, method); } else { mg.invokeVirtual(klassType, method); } if (Void.class.equals(returnType)) { mg.visitInsn(ACONST_NULL); } else if (returnType.isPrimitive()) { mg.box(Type.getType(returnType)); } } Label tmp = new Label(); mg.visitLabel(tmp); mg.visitLineNumber(1, tmp); mg.returnValue(); mg.endMethod(); cw.visitSource(klass.getSimpleName() + ".java", null); cw.visitEnd(); return cw.toByteArray(); } public static org.nutz.repo.org.objectweb.asm.commons.Method _Method(String name, String desc) { return new org.nutz.repo.org.objectweb.asm.commons.Method(name, desc); } public static org.nutz.repo.org.objectweb.asm.commons.Method _Method(Method method) { return org.nutz.repo.org.objectweb.asm.commons.Method.getMethod(method); } public static org.nutz.repo.org.objectweb.asm.commons.Method _Method(String method) { return org.nutz.repo.org.objectweb.asm.commons.Method.getMethod(method); } private static org.nutz.repo.org.objectweb.asm.commons.Method _Method(Constructor<?> constructor) { return org.nutz.repo.org.objectweb.asm.commons.Method.getMethod(constructor); } public static void addConstructor(ClassWriter cw, Type parent, org.nutz.repo.org.objectweb.asm.commons.Method m) { GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw); mg.loadThis(); mg.loadArgs(); mg.invokeConstructor(parent, m); mg.returnValue(); mg.endMethod(); } }