package nginx.clojure.wave; import nginx.clojure.asm.Label; import nginx.clojure.asm.MethodVisitor; import nginx.clojure.asm.commons.AdviceAdapter; public class SuspendMethodTracerAdvice extends AdviceAdapter { protected MethodDatabase db; protected String owner; protected String method; private final Label start = new Label(); private final Label handler = new Label(); public SuspendMethodTracerAdvice(MethodDatabase db,String owner, MethodVisitor mv, int access, String name, String desc) { super(ASM4, mv, access, name, desc); this.db = db; this.owner = owner; this.method = name + desc; } public void visitCode() { super.visitCode(); mv.visitLabel(start); }; @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { if (owner == null) { super.visitMethodInsn(opcode, owner, name, desc); return; } if (owner.equals("nginx/clojure/Coroutine") && name.equals("yield")) { super.visitMethodInsn(opcode, owner, "_yieldp", desc); }else if (owner.equals("nginx/clojure/Coroutine") && name.equals("resume")) { super.visitMethodInsn(opcode, owner, "_resumep", desc); }else { super.visitMethodInsn(opcode, owner, name, desc); } } @Override protected void onMethodEnter() { if (owner != null) { mv.visitLdcInsn(owner); } else { mv.visitInsn(ACONST_NULL); } mv.visitLdcInsn(method); mv.visitMethodInsn(INVOKESTATIC, "nginx/clojure/wave/SuspendMethodTracer", "enter", "(Ljava/lang/String;Ljava/lang/String;)V"); if (method.equals("invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;")) { mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKESTATIC, "nginx/clojure/wave/SuspendMethodTracer", "downProxyInvoke", "(Ljava/lang/reflect/Method;)V"); } } private final void doExitCode() { if (method.equals("invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;")) { mv.visitVarInsn(ALOAD, 2); mv.visitMethodInsn(INVOKESTATIC, "nginx/clojure/wave/SuspendMethodTracer", "upProxyInvoke", "(Ljava/lang/reflect/Method;)V"); } if (owner != null) { mv.visitLdcInsn(owner); } else { mv.visitInsn(ACONST_NULL); } mv.visitLdcInsn(method); mv.visitMethodInsn(INVOKESTATIC, "nginx/clojure/wave/SuspendMethodTracer", "leave", "(Ljava/lang/String;Ljava/lang/String;)V"); } @Override protected void onMethodExit(int opcode) { if (opcode != ATHROW) { doExitCode(); } } @Override public void visitMaxs(int maxStack, int maxLocals) { mv.visitTryCatchBlock(start, handler, handler, null); mv.visitLabel(this.handler); doExitCode(); mv.visitInsn(ATHROW); mv.visitMaxs(0, 0); } }