CacheAsmMethodBoost
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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> {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user