From ec26e3c9f7093713cf8ca5c55444bf5840f15166 Mon Sep 17 00:00:00 2001 From: redkale Date: Fri, 22 Dec 2023 00:00:31 +0800 Subject: [PATCH] CacheAsmMethodBoost --- .../java/org/redkale/asm/AsmMethodBoost.java | 27 +++--- src/main/java/org/redkale/asm/Asms.java | 4 + .../org/redkale/asm/MethodDebugVisitor.java | 14 +++ .../org/redkale/cache/spi/CacheAction.java | 3 + .../cache/spi/CacheAsmMethodBoost.java | 89 +++++++++++++++++-- .../redkale/lock/spi/LockAsmMethodBoost.java | 2 +- .../java/org/redkale/util/ThrowSupplier.java | 3 + .../redkale/test/cache/CacheInstanceTest.java | 2 +- 8 files changed, 121 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/redkale/asm/AsmMethodBoost.java b/src/main/java/org/redkale/asm/AsmMethodBoost.java index 3d210690f..44c543f1a 100644 --- a/src/main/java/org/redkale/asm/AsmMethodBoost.java +++ b/src/main/java/org/redkale/asm/AsmMethodBoost.java @@ -174,11 +174,10 @@ public abstract class AsmMethodBoost { } } - protected List visitVarInsnParamTypes(MethodVisitor mv, Method method) { + protected List visitVarInsnParamTypes(MethodVisitor mv, Method method, int insn) { //传参数 Class[] paramTypes = method.getParameterTypes(); List insns = new ArrayList<>(); - int insn = 0; for (Class pt : paramTypes) { insn++; if (pt.isPrimitive()) { @@ -199,6 +198,18 @@ public abstract class AsmMethodBoost { return insns; } + protected void visitParamTypesLocalVariable(MethodVisitor mv, Method method, Label l0, Label l2, List insns, AsmMethodBean methodBean) { + Class[] paramTypes = method.getParameterTypes(); + if (methodBean != null && paramTypes.length > 0) { + mv.visitLabel(l2); + List params = methodBean.getParams(); + for (int i = 0; i < paramTypes.length; i++) { + AsmMethodParam param = params.get(i); + mv.visitLocalVariable(param.getName(), param.getDescription(), param.getSignature(), l0, l2, insns.get(i)); + } + } + } + protected void visitInsnReturn(MethodVisitor mv, Method method, Label l0, List insns, AsmMethodBean methodBean) { if (method.getGenericReturnType() == void.class) { mv.visitInsn(RETURN); @@ -218,17 +229,7 @@ public abstract class AsmMethodBoost { 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 params = methodBean.getParams(); - for (int i = 0; i < paramTypes.length; i++) { - AsmMethodParam param = params.get(i); - mv.visitLocalVariable(param.getName(), param.getDescription(), param.getSignature(), l0, l2, insns.get(i)); - } - } + visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean); } /** diff --git a/src/main/java/org/redkale/asm/Asms.java b/src/main/java/org/redkale/asm/Asms.java index 9686702de..94731392e 100644 --- a/src/main/java/org/redkale/asm/Asms.java +++ b/src/main/java/org/redkale/asm/Asms.java @@ -29,6 +29,10 @@ public final class Asms { private Asms() { } + public static Handle createLambdaMetaHandle() { + return new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", false); + } + public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) { try { for (Method anm : ann.annotationType().getMethods()) { diff --git a/src/main/java/org/redkale/asm/MethodDebugVisitor.java b/src/main/java/org/redkale/asm/MethodDebugVisitor.java index 0b17d50a5..fa3a66716 100644 --- a/src/main/java/org/redkale/asm/MethodDebugVisitor.java +++ b/src/main/java/org/redkale/asm/MethodDebugVisitor.java @@ -183,6 +183,20 @@ public class MethodDebugVisitor extends MethodVisitor { } } + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { + visitor.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + if (debug) { + System.out.println("mv.visitInvokeDynamicInsn(\"" + name + "\", \"" + desc + "\", null, null);"); + } + } + + public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { + visitor.visitLocalVariable(name, desc, signature, start, end, index); + if (debug) { + System.out.println("mv.visitLocalVariable(\"" + name + "\", \"" + desc + "\", \"" + signature + "\", null, null, -1);"); + } + } + public void visitFieldInsn(int opcode, String owner, String name, String desc) { visitor.visitFieldInsn(opcode, owner, name, desc); if (debug) { diff --git a/src/main/java/org/redkale/cache/spi/CacheAction.java b/src/main/java/org/redkale/cache/spi/CacheAction.java index 1d4cc6a91..b7f5ef16d 100644 --- a/src/main/java/org/redkale/cache/spi/CacheAction.java +++ b/src/main/java/org/redkale/cache/spi/CacheAction.java @@ -10,6 +10,7 @@ import java.util.Objects; import java.util.concurrent.CompletableFuture; import org.redkale.annotation.Nullable; import org.redkale.annotation.Resource; +import org.redkale.asm.AsmDepends; import org.redkale.cache.CacheManager; import org.redkale.convert.json.JsonConvert; import org.redkale.net.sncp.Sncp; @@ -29,6 +30,7 @@ import org.redkale.util.TypeToken; * * @since 2.8.0 */ +@AsmDepends public class CacheAction { @Resource @@ -100,6 +102,7 @@ public class CacheAction { this.remoteExpire = createDuration(cached.getRemoteExpire()); } + @AsmDepends public T get(ThrowSupplier supplier, Object... args) { if (async) { ThrowSupplier supplier0 = supplier; diff --git a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java index 3ff71899d..7ca48d9ea 100644 --- a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java +++ b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java @@ -17,14 +17,17 @@ import org.redkale.asm.AsmMethodBoost; import org.redkale.asm.Asms; import org.redkale.asm.ClassWriter; import org.redkale.asm.FieldVisitor; +import org.redkale.asm.Handle; import org.redkale.asm.Label; import org.redkale.asm.MethodVisitor; +import org.redkale.asm.Opcodes; import static org.redkale.asm.Opcodes.*; import org.redkale.asm.Type; import org.redkale.cache.Cached; import org.redkale.inject.ResourceFactory; import org.redkale.util.RedkaleClassLoader; import org.redkale.util.RedkaleException; +import org.redkale.util.ThrowSupplier; import org.redkale.util.TypeToken; /** @@ -72,34 +75,104 @@ public class CacheAsmMethodBoost extends AsmMethodBoost { if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) { throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method); } + final int actionIndex = fieldIndex.incrementAndGet(); final String rsMethodName = method.getName() + "_afterCache"; - final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + fieldIndex.incrementAndGet(); + final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + actionIndex; + final AsmMethodBean methodBean = getMethodBean(method); { //定义一个新方法调用 this.rsMethodName - final AsmMethodBean methodBean = getMethodBean(method); final String cacheDynDesc = Type.getDescriptor(DynForCache.class); final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); //mv.setDebug(true); - Label l0 = new Label(); - mv.visitLabel(l0); AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true); av.visit("dynField", dynFieldName); Asms.visitAnnotation(av, cached); visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns); + + Label l0 = new Label(); + mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 0); - //传参数 - List insns = visitVarInsnParamTypes(mv, method); - mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false); - visitInsnReturn(mv, method, l0, insns, methodBean); + List insns = visitVarInsnParamTypes(mv, method, 0); + String dynDesc = methodBean.getDesc(); + dynDesc = "(L" + newDynName + ";" + dynDesc.substring(1, dynDesc.lastIndexOf(')') + 1) + Type.getDescriptor(ThrowSupplier.class); + mv.visitInvokeDynamicInsn("get", dynDesc, Asms.createLambdaMetaHandle(), + new Object[]{ + org.redkale.asm.Type.getType("()Ljava/lang/Object;"), + new Handle(Opcodes.H_INVOKESPECIAL, newDynName, "lambda$" + actionIndex, methodBean.getDesc(), false), + org.redkale.asm.Type.getType("()" + Type.getDescriptor(method.getReturnType())) + }); + mv.visitVarInsn(ASTORE, 1 + method.getParameterCount()); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, dynFieldName, Type.getDescriptor(CacheAction.class)); + + mv.visitVarInsn(ALOAD, 1 + method.getParameterCount()); + Asms.visitInsn(mv, method.getParameterCount()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); + int insn = 0; + Class[] paramtypes = method.getParameterTypes(); + for (int j = 0; j < paramtypes.length; j++) { + final Class pt = paramtypes[j]; + mv.visitInsn(DUP); + insn++; + Asms.visitInsn(mv, j); + 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); + } + Class bigclaz = TypeToken.primitiveToWrapper(pt); + mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", + "(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz), false); + } else { + mv.visitVarInsn(ALOAD, insn); + } + mv.visitInsn(AASTORE); + } + + mv.visitMethodInsn(INVOKEVIRTUAL, CacheAction.class.getName().replace('.', '/'), "get", "(Lorg/redkale/util/ThrowSupplier;[Ljava/lang/Object;)Ljava/lang/Object;", false); + mv.visitTypeInsn(CHECKCAST, method.getReturnType().getName().replace('.', '/')); + mv.visitInsn(ARETURN); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l2, 0); + visitParamTypesLocalVariable(mv, method, l0, l2, insns, methodBean); + mv.visitLocalVariable("_redkale_supplier", Type.getDescriptor(ThrowSupplier.class), null, l1, l2, ++insn); + mv.visitMaxs(20, 20); mv.visitEnd(); CacheAction action = new CacheAction(new CacheEntry(cached), method.getGenericReturnType(), serviceType, method.getParameterTypes(), methodBean.fieldNameArray(), method.getName(), dynFieldName); actions.put(dynFieldName, action); } + { //ThrowSupplier + final MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_SYNTHETIC, + "lambda$" + actionIndex, methodBean.getDesc(), null, new String[]{"java/lang/Throwable"}); + //mv.setDebug(true); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + visitVarInsnParamTypes(mv, method, 0); + mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, methodBean.getDesc(), false); + mv.visitInsn(ARETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitLocalVariable("this", "L" + newDynName + ";", null, l0, l1, 0); + mv.visitMaxs(5, 5); + mv.visitEnd(); + } { //定义字段 FieldVisitor fv = cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null); fv.visitEnd(); } + if (actions.size() == 1) { + cw.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup", ACC_PUBLIC + ACC_FINAL + ACC_STATIC); + } return rsMethodName; } diff --git a/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java b/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java index fc6610f0b..5030ba461 100644 --- a/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java +++ b/src/main/java/org/redkale/lock/spi/LockAsmMethodBoost.java @@ -67,7 +67,7 @@ public class LockAsmMethodBoost extends AsmMethodBoost { Asms.visitAnnotation(av, locked); visitRawAnnotation(method, newMethodName, mv, Locked.class, filterAnns); mv.visitVarInsn(ALOAD, 0); - List insns = visitVarInsnParamTypes(mv, method); + List insns = visitVarInsnParamTypes(mv, method, 0); mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false); visitInsnReturn(mv, method, l0, insns, methodBean); mv.visitMaxs(20, 20); diff --git a/src/main/java/org/redkale/util/ThrowSupplier.java b/src/main/java/org/redkale/util/ThrowSupplier.java index e22914926..36136a7a5 100644 --- a/src/main/java/org/redkale/util/ThrowSupplier.java +++ b/src/main/java/org/redkale/util/ThrowSupplier.java @@ -3,6 +3,8 @@ */ package org.redkale.util; +import org.redkale.asm.AsmDepends; + /** * 抛异常版的Supplier * @@ -13,6 +15,7 @@ package org.redkale.util; * * @since 2.8.0 */ +@AsmDepends @FunctionalInterface public interface ThrowSupplier { diff --git a/src/test/java/org/redkale/test/cache/CacheInstanceTest.java b/src/test/java/org/redkale/test/cache/CacheInstanceTest.java index 6d8e7c17e..860409cdc 100644 --- a/src/test/java/org/redkale/test/cache/CacheInstanceTest.java +++ b/src/test/java/org/redkale/test/cache/CacheInstanceTest.java @@ -56,7 +56,7 @@ public class CacheInstanceTest { SncpClient client = new SncpClient("", iGroup, 0, new InetSocketAddress("127.0.0.1", 8080), new ClientAddress(), "TCP", 1, 16); CacheInstance instance = Sncp.createLocalService(null, "", serviceClass, boost, resourceFactory, grous, client, null, null, null); - System.out.println(instance.getName()); + //System.out.println(instance.getName()); } @Test