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();
List<Integer> insns = new ArrayList<>();
int insn = 0;
for (Class pt : paramTypes) {
insn++;
if (pt.isPrimitive()) {
@@ -199,6 +198,18 @@ public abstract class AsmMethodBoost<T> {
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) {
if (method.getGenericReturnType() == void.class) {
mv.visitInsn(RETURN);
@@ -218,17 +229,7 @@ public abstract class AsmMethodBoost<T> {
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<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));
}
}
visitParamTypesLocalVariable(mv, method, l0, new Label(), insns, methodBean);
}
/**

View File

@@ -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()) {

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

View File

@@ -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> T get(ThrowSupplier<T> supplier, Object... args) {
if (async) {
ThrowSupplier supplier0 = supplier;

View File

@@ -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<Integer> insns = visitVarInsnParamTypes(mv, method);
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false);
visitInsnReturn(mv, method, l0, insns, methodBean);
List<Integer> 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;
}

View File

@@ -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<Integer> insns = visitVarInsnParamTypes(mv, method);
List<Integer> insns = visitVarInsnParamTypes(mv, method, 0);
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false);
visitInsnReturn(mv, method, l0, insns, methodBean);
mv.visitMaxs(20, 20);

View File

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