From 3fba0a3eeb3df3f8167d464e57bdc1bb1fc68fec Mon Sep 17 00:00:00 2001 From: redkale Date: Wed, 20 Dec 2023 20:22:39 +0800 Subject: [PATCH] AsmMethodBoost --- .../java/org/redkale/asm/AsmMethodBoost.java | 156 +++++++++++++++++- .../cache/spi/CacheAsmMethodBoost.java | 122 ++------------ .../redkale/lock/spi/LockAsmMethodBoost.java | 126 ++------------ 3 files changed, 181 insertions(+), 223 deletions(-) diff --git a/src/main/java/org/redkale/asm/AsmMethodBoost.java b/src/main/java/org/redkale/asm/AsmMethodBoost.java index b7c410b0c..b83055e6a 100644 --- a/src/main/java/org/redkale/asm/AsmMethodBoost.java +++ b/src/main/java/org/redkale/asm/AsmMethodBoost.java @@ -6,12 +6,28 @@ package org.redkale.asm; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.redkale.annotation.Nullable; +import static org.redkale.asm.Opcodes.ACC_PRIVATE; +import static org.redkale.asm.Opcodes.ACC_PROTECTED; +import static org.redkale.asm.Opcodes.ACC_PUBLIC; +import static org.redkale.asm.Opcodes.ALOAD; +import static org.redkale.asm.Opcodes.ARETURN; +import static org.redkale.asm.Opcodes.DLOAD; +import static org.redkale.asm.Opcodes.DRETURN; +import static org.redkale.asm.Opcodes.FLOAD; +import static org.redkale.asm.Opcodes.FRETURN; +import static org.redkale.asm.Opcodes.ILOAD; +import static org.redkale.asm.Opcodes.IRETURN; +import static org.redkale.asm.Opcodes.LLOAD; +import static org.redkale.asm.Opcodes.LRETURN; +import static org.redkale.asm.Opcodes.RETURN; import org.redkale.util.Utility; /** @@ -21,7 +37,15 @@ import org.redkale.util.Utility; * * @since 2.8.0 */ -public interface AsmMethodBoost { +public abstract class AsmMethodBoost { + + protected final AtomicInteger fieldIndex = new AtomicInteger(); + + protected final Class serviceType; + + protected AsmMethodBoost(Class serviceType) { + this.serviceType = serviceType; + } public static AsmMethodBoost create(Collection list) { return new AsmMethodBoosts(list); @@ -31,6 +55,124 @@ public interface AsmMethodBoost { return new AsmMethodBoosts(items); } + protected AsmMethodBean getMethodBean(Method method) { + Map methodBeans = AsmMethodBoost.getMethodBeans(serviceType); + return AsmMethodBean.get(methodBeans, method); + } + + protected MethodVisitor createMethodVisitor(ClassWriter cw, Method method, String newMethodName, AsmMethodBean methodBean) { + return new MethodDebugVisitor(cw.visitMethod(getAcc(method, newMethodName), + getNowMethodName(method, newMethodName), Type.getMethodDescriptor(method), + getMethodSignature(method, methodBean), getMethodExceptions(method, methodBean))); + } + + protected int getAcc(Method method, String newMethodName) { + if (newMethodName != null) { + return ACC_PRIVATE; + } + return Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC; + } + + protected String getNowMethodName(Method method, String newMethodName) { + return newMethodName == null ? method.getName() : newMethodName; + } + + protected String getMethodSignature(Method method, AsmMethodBean methodBean) { + return methodBean != null ? methodBean.getSignature() : null; + } + + protected String[] getMethodExceptions(Method method, AsmMethodBean methodBean) { + if (methodBean == null) { + String[] exceptions = null; + Class[] expTypes = method.getExceptionTypes(); + if (expTypes.length > 0) { + exceptions = new String[expTypes.length]; + for (int i = 0; i < expTypes.length; i++) { + exceptions[i] = expTypes[i].getName().replace('.', '/'); + } + } + return exceptions; + } else { + return methodBean.getExceptions(); + } + } + + protected void visitRawAnnotation(Method method, String newMethodName, MethodVisitor mv, Class selfAnnType, List filterAnns) { + if (newMethodName == null) { + //给方法加上原有的Annotation + final Annotation[] anns = method.getAnnotations(); + for (Annotation ann : anns) { + if (ann.annotationType() != selfAnnType + && (filterAnns == null || !filterAnns.contains(ann.annotationType()))) { + Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); + } + } + //给参数加上原有的Annotation + final Annotation[][] annss = method.getParameterAnnotations(); + for (int k = 0; k < annss.length; k++) { + for (Annotation ann : annss[k]) { + Asms.visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); + } + } + } + } + + protected List visitVarInsnParamTypes(MethodVisitor mv, Method method) { + //传参数 + Class[] paramTypes = method.getParameterTypes(); + List insns = new ArrayList<>(); + int insn = 0; + for (Class pt : paramTypes) { + insn++; + if (pt.isPrimitive()) { + if (pt == long.class) { + mv.visitVarInsn(LLOAD, insn++); + } else if (pt == float.class) { + mv.visitVarInsn(FLOAD, insn++); + } else if (pt == double.class) { + mv.visitVarInsn(DLOAD, insn++); + } else { + mv.visitVarInsn(ILOAD, insn); + } + } else { + mv.visitVarInsn(ALOAD, insn); + } + insns.add(insn); + } + return insns; + } + + protected void visitInsnReturn(MethodVisitor mv, Method method, Label l0, List insns, AsmMethodBean methodBean) { + if (method.getGenericReturnType() == void.class) { + mv.visitInsn(RETURN); + } else { + Class returnclz = method.getReturnType(); + if (returnclz.isPrimitive()) { + if (returnclz == long.class) { + mv.visitInsn(LRETURN); + } else if (returnclz == float.class) { + mv.visitInsn(FRETURN); + } else if (returnclz == double.class) { + mv.visitInsn(DRETURN); + } else { + mv.visitInsn(IRETURN); + } + } else { + mv.visitInsn(ARETURN); + } + } + Class[] paramTypes = method.getParameterTypes(); + if (methodBean != null && paramTypes.length > 0) { + Label l2 = new Label(); + mv.visitLabel(l2); + //mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0); + List fieldNames = methodBean.getFieldNames(); + for (int i = 0; i < paramTypes.length; i++) { + mv.visitLocalVariable(fieldNames.get(i), Type.getDescriptor(paramTypes[i]), null, l0, l2, insns.get(i)); + } + } + } + /** * * 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method) @@ -53,7 +195,7 @@ public interface AsmMethodBoost { * * @return 需要屏蔽的注解 */ - public List> filterMethodAnnotations(Method method); + public abstract List> filterMethodAnnotations(Method method); /** * 对方法进行动态加强处理 @@ -67,7 +209,7 @@ public interface AsmMethodBoost { * * @return 下一个新的方法名,不做任何处理应返回参数newMethodName */ - public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, + public abstract String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, List> filterAnns, Method method, @Nullable String newMethodName); /** 处理所有动态方法后调用 @@ -76,14 +218,14 @@ public interface AsmMethodBoost { * @param newDynName 动态新类名 * @param fieldPrefix 动态字段的前缀 */ - public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix); + public abstract void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix); /** * 实例对象进行操作,通常用于给动态的字段赋值 * * @param service 实例对象 */ - public void doInstance(T service); + public abstract void doInstance(T service); /** * 生产动态字节码的方法扩展器, 可以进行方法加强动作 @@ -92,15 +234,17 @@ public interface AsmMethodBoost { * * @since 2.8.0 */ - static class AsmMethodBoosts implements AsmMethodBoost { + static class AsmMethodBoosts extends AsmMethodBoost { private final AsmMethodBoost[] items; public AsmMethodBoosts(Collection list) { + super(null); this.items = list.toArray(new AsmMethodBoost[list.size()]); } public AsmMethodBoosts(AsmMethodBoost... items) { + super(null); this.items = items; } diff --git a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java index c7bfed72d..6c27b0577 100644 --- a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java +++ b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java @@ -6,10 +6,7 @@ package org.redkale.cache.spi; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; import org.redkale.asm.AnnotationVisitor; import org.redkale.asm.AsmMethodBean; import org.redkale.asm.AsmMethodBoost; @@ -17,7 +14,7 @@ import org.redkale.asm.Asms; import org.redkale.asm.ClassWriter; import org.redkale.asm.FieldVisitor; import org.redkale.asm.Label; -import org.redkale.asm.MethodDebugVisitor; +import org.redkale.asm.MethodVisitor; import static org.redkale.asm.Opcodes.*; import org.redkale.asm.Type; import org.redkale.cache.Cached; @@ -27,16 +24,12 @@ import org.redkale.util.RedkaleException; * * @author zhangjx */ -public class CacheAsmMethodBoost implements AsmMethodBoost { +public class CacheAsmMethodBoost extends AsmMethodBoost { private static final List> FILTER_ANN = List.of(Cached.class, DynForCache.class); - private final AtomicInteger fieldIndex = new AtomicInteger(); - - protected final Class serviceType; - public CacheAsmMethodBoost(Class serviceType) { - this.serviceType = serviceType; + super(serviceType); } @Override @@ -50,123 +43,38 @@ public class CacheAsmMethodBoost implements AsmMethodBoost { if (cached == null) { return newMethodName; } + if (method.getAnnotation(DynForCache.class) != null) { + return newMethodName; + } if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { throw new RedkaleException("@" + Cached.class.getSimpleName() + " can not on final or static method, but on " + method); } if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { throw new RedkaleException("@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method); } - int acc; - String nowMethodName; - if (newMethodName == null) { - nowMethodName = method.getName(); - acc = Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC; - } else { - acc = ACC_PRIVATE; - nowMethodName = newMethodName; - } + final String rsMethodName = method.getName() + "_afterCache"; final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + fieldIndex.incrementAndGet(); - { - Map methodBeans = AsmMethodBoost.getMethodBeans(serviceType); - AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); - + { //定义一个新方法调用 this.rsMethodName + final AsmMethodBean methodBean = getMethodBean(method); final String cacheDynDesc = Type.getDescriptor(DynForCache.class); - MethodDebugVisitor mv; - AnnotationVisitor av; - String signature = null; - String[] exceptions = null; - if (methodBean == null) { - Class[] expTypes = method.getExceptionTypes(); - if (expTypes.length > 0) { - exceptions = new String[expTypes.length]; - for (int i = 0; i < expTypes.length; i++) { - exceptions[i] = expTypes[i].getName().replace('.', '/'); - } - } - } else { - signature = methodBean.getSignature(); - exceptions = methodBean.getExceptions(); - } - //需要定义一个新方法调用 this.rsMethodName - mv = new MethodDebugVisitor(cw.visitMethod(acc, nowMethodName, Type.getMethodDescriptor(method), signature, exceptions)); + final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); //mv.setDebug(true); Label l0 = new Label(); mv.visitLabel(l0); - av = mv.visitAnnotation(cacheDynDesc, true); + AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true); av.visit("dynField", dynFieldName); Asms.visitAnnotation(av, cached); - if (newMethodName == null) { - //给方法加上原有的Annotation - final Annotation[] anns = method.getAnnotations(); - for (Annotation ann : anns) { - if (ann.annotationType() != Cached.class - && (filterAnns == null || !filterAnns.contains(ann.annotationType()))) { - Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); - } - } - //给参数加上原有的Annotation - final Annotation[][] annss = method.getParameterAnnotations(); - for (int k = 0; k < annss.length; k++) { - for (Annotation ann : annss[k]) { - Asms.visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); - } - } - } + visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns); mv.visitVarInsn(ALOAD, 0); //传参数 - Class[] paramTypes = method.getParameterTypes(); - List insns = new ArrayList<>(); - int insn = 0; - for (Class pt : paramTypes) { - insn++; - if (pt.isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - } else { - mv.visitVarInsn(ALOAD, insn); - } - insns.add(insn); - } + List insns = visitVarInsnParamTypes(mv, method); mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false); - if (method.getGenericReturnType() == void.class) { - mv.visitInsn(RETURN); - } else { - Class returnclz = method.getReturnType(); - if (returnclz.isPrimitive()) { - if (returnclz == long.class) { - mv.visitInsn(LRETURN); - } else if (returnclz == float.class) { - mv.visitInsn(FRETURN); - } else if (returnclz == double.class) { - mv.visitInsn(DRETURN); - } else { - mv.visitInsn(IRETURN); - } - } else { - mv.visitInsn(ARETURN); - } - } - if (methodBean != null && paramTypes.length > 0) { - Label l2 = new Label(); - mv.visitLabel(l2); - //mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0); - List fieldNames = methodBean.getFieldNames(); - for (int i = 0; i < paramTypes.length; i++) { - mv.visitLocalVariable(fieldNames.get(i), Type.getDescriptor(paramTypes[i]), null, l0, l2, insns.get(i)); - } - } + visitInsnReturn(mv, method, l0, insns, methodBean); mv.visitMaxs(20, 20); mv.visitEnd(); } - { + { //定义字段 FieldVisitor fv = cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null); fv.visitEnd(); } diff --git a/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java b/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java index 32793fa2c..09258d443 100644 --- a/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java +++ b/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java @@ -6,17 +6,14 @@ package org.redkale.lock.spi; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; import org.redkale.asm.AnnotationVisitor; import org.redkale.asm.AsmMethodBean; import org.redkale.asm.AsmMethodBoost; import org.redkale.asm.Asms; import org.redkale.asm.ClassWriter; import org.redkale.asm.Label; -import org.redkale.asm.MethodDebugVisitor; +import org.redkale.asm.MethodVisitor; import static org.redkale.asm.Opcodes.*; import org.redkale.asm.Type; import org.redkale.lock.Locked; @@ -26,16 +23,12 @@ import org.redkale.util.RedkaleException; * * @author zhangjx */ -public class LockAsmMethodBoost implements AsmMethodBoost { +public class LockAsmMethodBoost extends AsmMethodBoost { private static final List> FILTER_ANN = List.of(Locked.class, DynForLock.class); - private final AtomicInteger fieldIndex = new AtomicInteger(); - - protected final Class serviceType; - public LockAsmMethodBoost(Class serviceType) { - this.serviceType = serviceType; + super(serviceType); } @Override @@ -45,8 +38,11 @@ public class LockAsmMethodBoost implements AsmMethodBoost { @Override public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, List filterAnns, Method method, final String newMethodName) { - Locked cached = method.getAnnotation(Locked.class); - if (cached == null) { + Locked locked = method.getAnnotation(Locked.class); + if (locked == null) { + return newMethodName; + } + if (method.getAnnotation(DynForLock.class) != null) { return newMethodName; } if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) { @@ -55,114 +51,24 @@ public class LockAsmMethodBoost implements AsmMethodBoost { if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) { throw new RedkaleException("@" + Locked.class.getSimpleName() + " must on protected or public method, but on " + method); } - int acc; - String nowMethodName; - if (newMethodName == null) { - nowMethodName = method.getName(); - acc = Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC; - } else { - acc = ACC_PRIVATE; - nowMethodName = newMethodName; - } final String rsMethodName = method.getName() + "_afterLock"; final String dynFieldName = fieldPrefix + "_" + method.getName() + "LockAction" + fieldIndex.incrementAndGet(); - { - Map methodBeans = AsmMethodBoost.getMethodBeans(serviceType); - AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method); - + { //定义一个新方法调用 this.rsMethodName + final AsmMethodBean methodBean = getMethodBean(method); final String lockDynDesc = Type.getDescriptor(DynForLock.class); - MethodDebugVisitor mv; - AnnotationVisitor av; - String signature = null; - String[] exceptions = null; - if (methodBean == null) { - Class[] expTypes = method.getExceptionTypes(); - if (expTypes.length > 0) { - exceptions = new String[expTypes.length]; - for (int i = 0; i < expTypes.length; i++) { - exceptions[i] = expTypes[i].getName().replace('.', '/'); - } - } - } else { - signature = methodBean.getSignature(); - exceptions = methodBean.getExceptions(); - } - //需要定义一个新方法调用 this.rsMethodName - mv = new MethodDebugVisitor(cw.visitMethod(acc, nowMethodName, Type.getMethodDescriptor(method), signature, exceptions)); + final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); //mv.setDebug(true); Label l0 = new Label(); mv.visitLabel(l0); - av = mv.visitAnnotation(lockDynDesc, true); + AnnotationVisitor av = mv.visitAnnotation(lockDynDesc, true); av.visit("dynField", dynFieldName); - Asms.visitAnnotation(av, cached); - if (newMethodName == null) { - //给方法加上原有的Annotation - final Annotation[] anns = method.getAnnotations(); - for (Annotation ann : anns) { - if (ann.annotationType() != Locked.class - && (filterAnns == null || !filterAnns.contains(ann.annotationType()))) { - Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann); - } - } - //给参数加上原有的Annotation - final Annotation[][] annss = method.getParameterAnnotations(); - for (int k = 0; k < annss.length; k++) { - for (Annotation ann : annss[k]) { - Asms.visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann); - } - } - } + Asms.visitAnnotation(av, locked); + visitRawAnnotation(method, newMethodName, mv, Locked.class, filterAnns); mv.visitVarInsn(ALOAD, 0); - //传参数 - Class[] paramTypes = method.getParameterTypes(); - List insns = new ArrayList<>(); - int insn = 0; - for (Class pt : paramTypes) { - insn++; - if (pt.isPrimitive()) { - if (pt == long.class) { - mv.visitVarInsn(LLOAD, insn++); - } else if (pt == float.class) { - mv.visitVarInsn(FLOAD, insn++); - } else if (pt == double.class) { - mv.visitVarInsn(DLOAD, insn++); - } else { - mv.visitVarInsn(ILOAD, insn); - } - } else { - mv.visitVarInsn(ALOAD, insn); - } - insns.add(insn); - } + List insns = visitVarInsnParamTypes(mv, method); mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false); - if (method.getGenericReturnType() == void.class) { - mv.visitInsn(RETURN); - } else { - Class returnclz = method.getReturnType(); - if (returnclz.isPrimitive()) { - if (returnclz == long.class) { - mv.visitInsn(LRETURN); - } else if (returnclz == float.class) { - mv.visitInsn(FRETURN); - } else if (returnclz == double.class) { - mv.visitInsn(DRETURN); - } else { - mv.visitInsn(IRETURN); - } - } else { - mv.visitInsn(ARETURN); - } - } - if (methodBean != null && paramTypes.length > 0) { - Label l2 = new Label(); - mv.visitLabel(l2); - //mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0); - List fieldNames = methodBean.getFieldNames(); - for (int i = 0; i < paramTypes.length; i++) { - mv.visitLocalVariable(fieldNames.get(i), Type.getDescriptor(paramTypes[i]), null, l0, l2, insns.get(i)); - } - } + visitInsnReturn(mv, method, l0, insns, methodBean); mv.visitMaxs(20, 20); mv.visitEnd(); }