CacheAsmMethodBoost

This commit is contained in:
redkale
2023-12-22 00:00:31 +08:00
parent cfbf4bbe85
commit ec26e3c9f7
8 changed files with 121 additions and 23 deletions

View File

@@ -174,11 +174,10 @@ public abstract class AsmMethodBoost<T> {
} }
} }
protected List<Integer> visitVarInsnParamTypes(MethodVisitor mv, Method method) { protected List<Integer> visitVarInsnParamTypes(MethodVisitor mv, Method method, int insn) {
//传参数 //传参数
Class[] paramTypes = method.getParameterTypes(); Class[] paramTypes = method.getParameterTypes();
List<Integer> insns = new ArrayList<>(); List<Integer> insns = new ArrayList<>();
int insn = 0;
for (Class pt : paramTypes) { for (Class pt : paramTypes) {
insn++; insn++;
if (pt.isPrimitive()) { if (pt.isPrimitive()) {
@@ -199,6 +198,18 @@ public abstract class AsmMethodBoost<T> {
return insns; return insns;
} }
protected void visitParamTypesLocalVariable(MethodVisitor mv, Method method, Label l0, Label l2, List<Integer> insns, AsmMethodBean methodBean) {
Class[] paramTypes = method.getParameterTypes();
if (methodBean != null && paramTypes.length > 0) {
mv.visitLabel(l2);
List<AsmMethodParam> 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<Integer> insns, AsmMethodBean methodBean) { protected void visitInsnReturn(MethodVisitor mv, Method method, Label l0, List<Integer> insns, AsmMethodBean methodBean) {
if (method.getGenericReturnType() == void.class) { if (method.getGenericReturnType() == void.class) {
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
@@ -218,17 +229,7 @@ public abstract class AsmMethodBoost<T> {
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
} }
} }
Class[] paramTypes = method.getParameterTypes(); visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean);
if (methodBean != null && paramTypes.length > 0) {
Label l2 = new Label();
mv.visitLabel(l2);
//mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0);
List<AsmMethodParam> 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));
}
}
} }
/** /**

View File

@@ -29,6 +29,10 @@ public final class Asms {
private 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) { public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
try { try {
for (Method anm : ann.annotationType().getMethods()) { for (Method anm : ann.annotationType().getMethods()) {

View File

@@ -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) { public void visitFieldInsn(int opcode, String owner, String name, String desc) {
visitor.visitFieldInsn(opcode, owner, name, desc); visitor.visitFieldInsn(opcode, owner, name, desc);
if (debug) { if (debug) {

View File

@@ -10,6 +10,7 @@ import java.util.Objects;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.redkale.annotation.Nullable; import org.redkale.annotation.Nullable;
import org.redkale.annotation.Resource; import org.redkale.annotation.Resource;
import org.redkale.asm.AsmDepends;
import org.redkale.cache.CacheManager; import org.redkale.cache.CacheManager;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import org.redkale.net.sncp.Sncp; import org.redkale.net.sncp.Sncp;
@@ -29,6 +30,7 @@ import org.redkale.util.TypeToken;
* *
* @since 2.8.0 * @since 2.8.0
*/ */
@AsmDepends
public class CacheAction { public class CacheAction {
@Resource @Resource
@@ -100,6 +102,7 @@ public class CacheAction {
this.remoteExpire = createDuration(cached.getRemoteExpire()); this.remoteExpire = createDuration(cached.getRemoteExpire());
} }
@AsmDepends
public <T> T get(ThrowSupplier<T> supplier, Object... args) { public <T> T get(ThrowSupplier<T> supplier, Object... args) {
if (async) { if (async) {
ThrowSupplier supplier0 = supplier; ThrowSupplier supplier0 = supplier;

View File

@@ -17,14 +17,17 @@ import org.redkale.asm.AsmMethodBoost;
import org.redkale.asm.Asms; import org.redkale.asm.Asms;
import org.redkale.asm.ClassWriter; import org.redkale.asm.ClassWriter;
import org.redkale.asm.FieldVisitor; import org.redkale.asm.FieldVisitor;
import org.redkale.asm.Handle;
import org.redkale.asm.Label; import org.redkale.asm.Label;
import org.redkale.asm.MethodVisitor; import org.redkale.asm.MethodVisitor;
import org.redkale.asm.Opcodes;
import static org.redkale.asm.Opcodes.*; import static org.redkale.asm.Opcodes.*;
import org.redkale.asm.Type; import org.redkale.asm.Type;
import org.redkale.cache.Cached; import org.redkale.cache.Cached;
import org.redkale.inject.ResourceFactory; import org.redkale.inject.ResourceFactory;
import org.redkale.util.RedkaleClassLoader; import org.redkale.util.RedkaleClassLoader;
import org.redkale.util.RedkaleException; import org.redkale.util.RedkaleException;
import org.redkale.util.ThrowSupplier;
import org.redkale.util.TypeToken; import org.redkale.util.TypeToken;
/** /**
@@ -72,34 +75,104 @@ public class CacheAsmMethodBoost extends AsmMethodBoost {
if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) { if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) {
throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method); 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 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 { //定义一个新方法调用 this.rsMethodName
final AsmMethodBean methodBean = getMethodBean(method);
final String cacheDynDesc = Type.getDescriptor(DynForCache.class); final String cacheDynDesc = Type.getDescriptor(DynForCache.class);
final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean); final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean);
//mv.setDebug(true); //mv.setDebug(true);
Label l0 = new Label();
mv.visitLabel(l0);
AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true); AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true);
av.visit("dynField", dynFieldName); av.visit("dynField", dynFieldName);
Asms.visitAnnotation(av, cached); Asms.visitAnnotation(av, cached);
visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns); visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns);
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
//传参数 List<Integer> insns = visitVarInsnParamTypes(mv, method, 0);
List<Integer> insns = visitVarInsnParamTypes(mv, method); String dynDesc = methodBean.getDesc();
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false); dynDesc = "(L" + newDynName + ";" + dynDesc.substring(1, dynDesc.lastIndexOf(')') + 1) + Type.getDescriptor(ThrowSupplier.class);
visitInsnReturn(mv, method, l0, insns, methodBean); 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.visitMaxs(20, 20);
mv.visitEnd(); mv.visitEnd();
CacheAction action = new CacheAction(new CacheEntry(cached), method.getGenericReturnType(), serviceType, CacheAction action = new CacheAction(new CacheEntry(cached), method.getGenericReturnType(), serviceType,
method.getParameterTypes(), methodBean.fieldNameArray(), method.getName(), dynFieldName); method.getParameterTypes(), methodBean.fieldNameArray(), method.getName(), dynFieldName);
actions.put(dynFieldName, action); 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); FieldVisitor fv = cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null);
fv.visitEnd(); 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; return rsMethodName;
} }

View File

@@ -67,7 +67,7 @@ public class LockAsmMethodBoost extends AsmMethodBoost {
Asms.visitAnnotation(av, locked); Asms.visitAnnotation(av, locked);
visitRawAnnotation(method, newMethodName, mv, Locked.class, filterAnns); visitRawAnnotation(method, newMethodName, mv, Locked.class, filterAnns);
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
List<Integer> insns = visitVarInsnParamTypes(mv, method); List<Integer> insns = visitVarInsnParamTypes(mv, method, 0);
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false); mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false);
visitInsnReturn(mv, method, l0, insns, methodBean); visitInsnReturn(mv, method, l0, insns, methodBean);
mv.visitMaxs(20, 20); mv.visitMaxs(20, 20);

View File

@@ -3,6 +3,8 @@
*/ */
package org.redkale.util; package org.redkale.util;
import org.redkale.asm.AsmDepends;
/** /**
* 抛异常版的Supplier * 抛异常版的Supplier
* *
@@ -13,6 +15,7 @@ package org.redkale.util;
* *
* @since 2.8.0 * @since 2.8.0
*/ */
@AsmDepends
@FunctionalInterface @FunctionalInterface
public interface ThrowSupplier<T> { public interface ThrowSupplier<T> {

View File

@@ -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); 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, CacheInstance instance = Sncp.createLocalService(null, "", serviceClass, boost, resourceFactory,
grous, client, null, null, null); grous, client, null, null, null);
System.out.println(instance.getName()); //System.out.println(instance.getName());
} }
@Test @Test