diff --git a/core/src/main/java/com/taobao/arthas/core/advisor/AdviceWeaver.java b/core/src/main/java/com/taobao/arthas/core/advisor/AdviceWeaver.java
index aa84db690..2b607da6f 100644
--- a/core/src/main/java/com/taobao/arthas/core/advisor/AdviceWeaver.java
+++ b/core/src/main/java/com/taobao/arthas/core/advisor/AdviceWeaver.java
@@ -1,24 +1,11 @@
package com.taobao.arthas.core.advisor;
-import com.alibaba.arthas.deps.org.slf4j.Logger;
-import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
-import com.taobao.arthas.core.GlobalOptions;
-import com.taobao.arthas.core.util.matcher.Matcher;
-import com.taobao.arthas.core.util.*;
-import com.taobao.arthas.core.util.affect.EnhancerAffect;
-import com.taobao.arthas.core.util.collection.GaStack;
-import com.taobao.arthas.core.util.collection.ThreadUnsafeFixGaStack;
-import com.taobao.arthas.core.util.collection.ThreadUnsafeGaStack;
-import org.objectweb.asm.*;
-import org.objectweb.asm.commons.AdviceAdapter;
-import org.objectweb.asm.commons.JSRInlinerAdapter;
-import org.objectweb.asm.commons.Method;
-
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import com.alibaba.arthas.deps.org.slf4j.Logger;
+import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
+
/**
* 通知编织者
*
@@ -27,36 +14,13 @@ import java.util.concurrent.ConcurrentHashMap;
*
* Created by vlinux on 15/5/17.
*/
-public class AdviceWeaver extends ClassVisitor implements Opcodes {
+public class AdviceWeaver {
private static final Logger logger = LoggerFactory.getLogger(AdviceWeaver.class);
- public static final String ON_BEFORE = "methodOnBegin";
- public static final String ON_RETURN = "methodOnReturnEnd";
- public static final String ON_THROWS = "methodOnThrowingEnd";
- public static final String BEFORE_INVOKE = "methodOnInvokeBeforeTracing";
- public static final String AFTER_INVOKE = "methodOnInvokeAfterTracing";
- public static final String THROW_INVOKE = "methodOnInvokeThrowTracing";
- public static final String RESET = "resetArthasClassLoader";
-
- // 线程帧栈堆栈大小
- private final static int FRAME_STACK_SIZE = 7;
// 通知监听器集合
private final static Map advices
= new ConcurrentHashMap();
- // 线程帧封装
- private static final ThreadLocal>> threadBoundContext
- = new ThreadLocal>>();
- // 防止自己递归调用
- private static final ThreadLocal isSelfCallRef = new ThreadLocal() {
-
- @Override
- protected Boolean initialValue() {
- return false;
- }
-
- };
-
/**
* 注册监听器
@@ -112,665 +76,4 @@ public class AdviceWeaver extends ClassVisitor implements Opcodes {
return advices.remove(adviceId);
}
- private final int adviceId;
- private final boolean isTracing;
- private final boolean skipJDKTrace;
- private final String className;
- private String superName;
- private final Matcher matcher;
- private final EnhancerAffect affect;
-
-
- /**
- * 构建通知编织器
- *
- * @param adviceId 通知ID
- * @param isTracing 可跟踪方法调用
- * @param skipJDKTrace 是否忽略对JDK内部方法的跟踪
- * @param className 类名称
- * @param matcher 方法匹配
- * 只有匹配上的方法才会被织入通知器
- * @param affect 影响计数
- * @param cv ClassVisitor for ASM
- */
- public AdviceWeaver(int adviceId, boolean isTracing, boolean skipJDKTrace, String className, Matcher matcher, EnhancerAffect affect, ClassVisitor cv) {
- super(Opcodes.ASM8, cv);
- this.adviceId = adviceId;
- this.isTracing = isTracing;
- this.skipJDKTrace = skipJDKTrace;
- this.className = className;
- this.matcher = matcher;
- this.affect = affect;
- }
-
- @Override
- public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
- super.visit(version, access, name, signature, superName, interfaces);
- this.superName = superName;
- }
-
- protected boolean isSuperOrSiblingConstructorCall(int opcode, String owner, String name) {
- return (opcode == Opcodes.INVOKESPECIAL && name.equals("")
- && (superName.equals(owner) || className.equals(owner)));
- }
-
- /**
- * 是否抽象属性
- */
- private boolean isAbstract(int access) {
- return (ACC_ABSTRACT & access) == ACC_ABSTRACT;
- }
-
-
- /**
- * 是否需要忽略
- */
- private boolean isIgnore(MethodVisitor mv, int access, String methodName) {
- return null == mv
- || isAbstract(access)
- || !matcher.matching(methodName)
- || ArthasCheckUtils.isEquals(methodName, "");
- }
-
- @Override
- public MethodVisitor visitMethod(
- final int access,
- final String name,
- final String desc,
- final String signature,
- final String[] exceptions) {
-
- final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
-
- if (isIgnore(mv, access, name)) {
- return mv;
- }
-
- // 编织方法计数
- affect.mCnt(1);
-
- return new AdviceAdapter(Opcodes.ASM8, new JSRInlinerAdapter(mv, access, name, desc, signature, exceptions), access, name, desc) {
-
- // -- Label for try...catch block
- private final Label beginLabel = new Label();
- private final Label endLabel = new Label();
-
- // -- KEY of advice --
- private final int KEY_ARTHAS_ADVICE_BEFORE_METHOD = 0;
- private final int KEY_ARTHAS_ADVICE_RETURN_METHOD = 1;
- private final int KEY_ARTHAS_ADVICE_THROWS_METHOD = 2;
- private final int KEY_ARTHAS_ADVICE_BEFORE_INVOKING_METHOD = 3;
- private final int KEY_ARTHAS_ADVICE_AFTER_INVOKING_METHOD = 4;
- private final int KEY_ARTHAS_ADVICE_THROW_INVOKING_METHOD = 5;
-
-
- // -- KEY of ASM_TYPE or ASM_METHOD --
- private final Type ASM_TYPE_SPY = Type.getType("Ljava/arthas/Spy;");
- private final Type ASM_TYPE_OBJECT = Type.getType(Object.class);
- private final Type ASM_TYPE_OBJECT_ARRAY = Type.getType(Object[].class);
- private final Type ASM_TYPE_CLASS = Type.getType(Class.class);
- private final Type ASM_TYPE_INTEGER = Type.getType(Integer.class);
- private final Type ASM_TYPE_CLASS_LOADER = Type.getType(ClassLoader.class);
- private final Type ASM_TYPE_STRING = Type.getType(String.class);
- private final Type ASM_TYPE_THROWABLE = Type.getType(Throwable.class);
- private final Type ASM_TYPE_INT = Type.getType(int.class);
- private final Type ASM_TYPE_METHOD = Type.getType(java.lang.reflect.Method.class);
- private final Method ASM_METHOD_METHOD_INVOKE = Method.getMethod("Object invoke(Object,Object[])");
-
- // 代码锁
- private final CodeLock codeLockForTracing = new TracingAsmCodeLock(this);
-
- private int lineNumber;
-
- private void _debug(final StringBuilder append, final String msg) {
-
- if (!GlobalOptions.isDebugForAsm) {
- return;
- }
-
- // println msg
- visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
- if (StringUtils.isBlank(append.toString())) {
- visitLdcInsn(append.append(msg).toString());
- } else {
- visitLdcInsn(append.append(" >> ").append(msg).toString());
- }
-
- visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
- }
-
-// private void _debug_dup(final String msg) {
-//
-// if (!isDebugForAsm) {
-// return;
-// }
-//
-// // print prefix
-// visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
-// visitLdcInsn(msg);
-// visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V", false);
-//
-// // println msg
-// dup();
-// visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
-// swap();
-// visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false);
-// visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
-// }
-
- /**
- * 加载通知方法
- * @param keyOfMethod 通知方法KEY
- */
- private void loadAdviceMethod(int keyOfMethod) {
-
- switch (keyOfMethod) {
-
- case KEY_ARTHAS_ADVICE_BEFORE_METHOD: {
- getStatic(ASM_TYPE_SPY, "ON_BEFORE_METHOD", ASM_TYPE_METHOD);
- break;
- }
-
- case KEY_ARTHAS_ADVICE_RETURN_METHOD: {
- getStatic(ASM_TYPE_SPY, "ON_RETURN_METHOD", ASM_TYPE_METHOD);
- break;
- }
-
- case KEY_ARTHAS_ADVICE_THROWS_METHOD: {
- getStatic(ASM_TYPE_SPY, "ON_THROWS_METHOD", ASM_TYPE_METHOD);
- break;
- }
-
- case KEY_ARTHAS_ADVICE_BEFORE_INVOKING_METHOD: {
- getStatic(ASM_TYPE_SPY, "BEFORE_INVOKING_METHOD", ASM_TYPE_METHOD);
- break;
- }
-
- case KEY_ARTHAS_ADVICE_AFTER_INVOKING_METHOD: {
- getStatic(ASM_TYPE_SPY, "AFTER_INVOKING_METHOD", ASM_TYPE_METHOD);
- break;
- }
-
- case KEY_ARTHAS_ADVICE_THROW_INVOKING_METHOD: {
- getStatic(ASM_TYPE_SPY, "THROW_INVOKING_METHOD", ASM_TYPE_METHOD);
- break;
- }
-
- default: {
- throw new IllegalArgumentException("illegal keyOfMethod=" + keyOfMethod);
- }
-
- }
-
- }
-
- /**
- * 加载ClassLoader
- * 这里分开静态方法中ClassLoader的获取以及普通方法中ClassLoader的获取
- * 主要是性能上的考虑
- */
- private void loadClassLoader() {
-
- if (this.isStaticMethod()) {
- visitLdcInsn(StringUtils.normalizeClassName(className));
- invokeStatic(ASM_TYPE_CLASS, Method.getMethod("Class forName(String)"));
- invokeVirtual(ASM_TYPE_CLASS, Method.getMethod("ClassLoader getClassLoader()"));
-
- } else {
- loadThis();
- invokeVirtual(ASM_TYPE_OBJECT, Method.getMethod("Class getClass()"));
- invokeVirtual(ASM_TYPE_CLASS, Method.getMethod("ClassLoader getClassLoader()"));
- }
-
- }
-
- /**
- * 加载before通知参数数组
- */
- private void loadArrayForBefore() {
- push(7);
- newArray(ASM_TYPE_OBJECT);
-
- dup();
- push(0);
- push(adviceId);
- box(ASM_TYPE_INT);
- arrayStore(ASM_TYPE_INTEGER);
-
- dup();
- push(1);
- loadClassLoader();
- arrayStore(ASM_TYPE_CLASS_LOADER);
-
- dup();
- push(2);
- push(className);
- arrayStore(ASM_TYPE_STRING);
-
- dup();
- push(3);
- push(name);
- arrayStore(ASM_TYPE_STRING);
-
- dup();
- push(4);
- push(desc);
- arrayStore(ASM_TYPE_STRING);
-
- dup();
- push(5);
- loadThisOrPushNullIfIsStatic();
- arrayStore(ASM_TYPE_OBJECT);
-
- dup();
- push(6);
- loadArgArray();
- arrayStore(ASM_TYPE_OBJECT_ARRAY);
- }
-
-
- @Override
- protected void onMethodEnter() {
-
- codeLockForTracing.lock(new CodeLock.Block() {
- @Override
- public void code() {
-
- final StringBuilder append = new StringBuilder();
- _debug(append, "debug:onMethodEnter()");
-
- // 加载before方法
- loadAdviceMethod(KEY_ARTHAS_ADVICE_BEFORE_METHOD);
-
- _debug(append, "debug:onMethodEnter() > loadAdviceMethod()");
-
- // 推入Method.invoke()的第一个参数
- pushNull();
-
- // 方法参数
- loadArrayForBefore();
-
- _debug(append, "debug:onMethodEnter() > loadAdviceMethod() > loadArrayForBefore()");
-
- // 调用方法
- invokeVirtual(ASM_TYPE_METHOD, ASM_METHOD_METHOD_INVOKE);
- pop();
-
- _debug(append, "debug:onMethodEnter() > loadAdviceMethod() > loadArrayForBefore() > invokeVirtual()");
- }
- });
-
- mark(beginLabel);
-
- }
-
-
- /*
- * 加载return通知参数数组
- */
- private void loadReturnArgs() {
- dup2X1();
- pop2();
- push(1);
- newArray(ASM_TYPE_OBJECT);
- dup();
- dup2X1();
- pop2();
- push(0);
- swap();
- arrayStore(ASM_TYPE_OBJECT);
- }
-
- @Override
- protected void onMethodExit(final int opcode) {
-
- if (!isThrow(opcode)) {
- codeLockForTracing.lock(new CodeLock.Block() {
- @Override
- public void code() {
-
- final StringBuilder append = new StringBuilder();
- _debug(append, "debug:onMethodExit()");
-
- // 加载返回对象
- loadReturn(opcode);
- _debug(append, "debug:onMethodExit() > loadReturn()");
-
-
- // 加载returning方法
- loadAdviceMethod(KEY_ARTHAS_ADVICE_RETURN_METHOD);
- _debug(append, "debug:onMethodExit() > loadReturn() > loadAdviceMethod()");
-
- // 推入Method.invoke()的第一个参数
- pushNull();
-
- // 加载return通知参数数组
- loadReturnArgs();
- _debug(append, "debug:onMethodExit() > loadReturn() > loadAdviceMethod() > loadReturnArgs()");
-
- invokeVirtual(ASM_TYPE_METHOD, ASM_METHOD_METHOD_INVOKE);
- pop();
-
- _debug(append, "debug:onMethodExit() > loadReturn() > loadAdviceMethod() > loadReturnArgs() > invokeVirtual()");
- }
- });
- }
-
- }
-
-
- /*
- * 创建throwing通知参数本地变量
- */
- private void loadThrowArgs() {
- dup2X1();
- pop2();
- push(1);
- newArray(ASM_TYPE_OBJECT);
- dup();
- dup2X1();
- pop2();
- push(0);
- swap();
- arrayStore(ASM_TYPE_THROWABLE);
- }
-
- @Override
- public void visitMaxs(int maxStack, int maxLocals) {
-
- mark(endLabel);
-// catchException(beginLabel, endLabel, ASM_TYPE_THROWABLE);
- visitTryCatchBlock(beginLabel, endLabel, mark(),
- ASM_TYPE_THROWABLE.getInternalName());
-
- codeLockForTracing.lock(new CodeLock.Block() {
- @Override
- public void code() {
-
- final StringBuilder append = new StringBuilder();
- _debug(append, "debug:catchException()");
-
- // 加载异常
- loadThrow();
- _debug(append, "debug:catchException() > loadThrow() > loadAdviceMethod()");
-
- // 加载throwing方法
- loadAdviceMethod(KEY_ARTHAS_ADVICE_THROWS_METHOD);
- _debug(append, "debug:catchException() > loadThrow() > loadAdviceMethod()");
-
-
- // 推入Method.invoke()的第一个参数
- pushNull();
-
- // 加载throw通知参数数组
- loadThrowArgs();
- _debug(append, "debug:catchException() > loadThrow() > loadAdviceMethod() > loadThrowArgs()");
-
- // 调用方法
- invokeVirtual(ASM_TYPE_METHOD, ASM_METHOD_METHOD_INVOKE);
- pop();
- _debug(append, "debug:catchException() > loadThrow() > loadAdviceMethod() > loadThrowArgs() > invokeVirtual()");
-
- }
- });
-
- throwException();
-
- super.visitMaxs(maxStack, maxLocals);
- }
-
- @Override
- public void visitLineNumber(int line, Label start) {
- super.visitLineNumber(line, start);
- lineNumber = line;
- }
-
- /**
- * 是否静态方法
- * @return true:静态方法 / false:非静态方法
- */
- private boolean isStaticMethod() {
- return (methodAccess & ACC_STATIC) != 0;
- }
-
- /**
- * 是否抛出异常返回(通过字节码判断)
- * @param opcode 操作码
- * @return true:以抛异常形式返回 / false:非抛异常形式返回(return)
- */
- private boolean isThrow(int opcode) {
- return opcode == ATHROW;
- }
-
- /**
- * 将NULL推入堆栈
- */
- private void pushNull() {
- push((Type) null);
- }
-
- /**
- * 加载this/null
- */
- private void loadThisOrPushNullIfIsStatic() {
- if (isStaticMethod()) {
- pushNull();
- } else {
- loadThis();
- }
- }
-
- /**
- * 加载返回值
- * @param opcode 操作吗
- */
- private void loadReturn(int opcode) {
- switch (opcode) {
-
- case RETURN: {
- pushNull();
- break;
- }
-
- case ARETURN: {
- dup();
- break;
- }
-
- case LRETURN:
- case DRETURN: {
- dup2();
- box(Type.getReturnType(methodDesc));
- break;
- }
-
- default: {
- dup();
- box(Type.getReturnType(methodDesc));
- break;
- }
-
- }
- }
-
- /**
- * 加载异常
- */
- private void loadThrow() {
- dup();
- }
-
-
- /**
- * 加载方法调用跟踪通知所需参数数组
- */
- private void loadArrayForInvokeTracing(String owner, String name, String desc, int lineNumber) {
- push(5);
- newArray(ASM_TYPE_OBJECT);
-
- dup();
- push(0);
- push(adviceId);
- box(ASM_TYPE_INT);
- arrayStore(ASM_TYPE_INTEGER);
-
- dup();
- push(1);
- push(owner);
- arrayStore(ASM_TYPE_STRING);
-
- dup();
- push(2);
- push(name);
- arrayStore(ASM_TYPE_STRING);
-
- dup();
- push(3);
- push(desc);
- arrayStore(ASM_TYPE_STRING);
-
- dup();
- push(4);
- push(lineNumber);
- box(ASM_TYPE_INT);
- arrayStore(ASM_TYPE_INTEGER);
- }
-
-
- @Override
- public void visitInsn(int opcode) {
- super.visitInsn(opcode);
- codeLockForTracing.code(opcode);
- }
-
- @Override
- public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
- tcbs.add(new AsmTryCatchBlock(start, end, handler, type));
- }
-
- List tcbs = new ArrayList();
-
- @Override
- public void visitEnd() {
- for (AsmTryCatchBlock tcb : tcbs) {
- super.visitTryCatchBlock(tcb.start, tcb.end, tcb.handler, tcb.type);
- }
-
- super.visitEnd();
- }
-
- /*
- * 跟踪代码
- */
- private void tracing(final int tracingType, final String owner, final String name, final String desc, final int lineNumber) {
-
- final String label;
- switch (tracingType) {
- case KEY_ARTHAS_ADVICE_BEFORE_INVOKING_METHOD: {
- label = "beforeInvoking";
- break;
- }
- case KEY_ARTHAS_ADVICE_AFTER_INVOKING_METHOD: {
- label = "afterInvoking";
- break;
- }
- case KEY_ARTHAS_ADVICE_THROW_INVOKING_METHOD: {
- label = "throwInvoking";
- break;
- }
- default: {
- throw new IllegalStateException("illegal tracing type: " + tracingType);
- }
- }
-
- codeLockForTracing.lock(new CodeLock.Block() {
- @Override
- public void code() {
-
- final StringBuilder append = new StringBuilder();
- _debug(append, "debug:" + label + "()");
-
- loadAdviceMethod(tracingType);
- _debug(append, "loadAdviceMethod()");
-
- pushNull();
- loadArrayForInvokeTracing(owner, name, desc, lineNumber);
- _debug(append, "loadArrayForInvokeTracing()");
-
- invokeVirtual(ASM_TYPE_METHOD, ASM_METHOD_METHOD_INVOKE);
- pop();
- _debug(append, "invokeVirtual()");
-
- }
- });
-
- }
-
- @Override
- public void visitMethodInsn(int opcode, final String owner, final String name, final String desc, boolean itf) {
- if (isSuperOrSiblingConstructorCall(opcode, owner, name)) {
- super.visitMethodInsn(opcode, owner, name, desc, itf);
- return;
- }
-
- if (!isTracing || codeLockForTracing.isLock()) {
- super.visitMethodInsn(opcode, owner, name, desc, itf);
- return;
- }
-
- //是否要对JDK内部的方法调用进行trace
- if (skipJDKTrace && owner.startsWith("java/")) {
- super.visitMethodInsn(opcode, owner, name, desc, itf);
- return;
- }
-
- // 方法调用前通知
- tracing(KEY_ARTHAS_ADVICE_BEFORE_INVOKING_METHOD, owner, name, desc, lineNumber);
-
- final Label beginLabel = new Label();
- final Label endLabel = new Label();
- final Label finallyLabel = new Label();
-
- // try
- // {
-
- mark(beginLabel);
- super.visitMethodInsn(opcode, owner, name, desc, itf);
- mark(endLabel);
-
- // 方法调用后通知
- tracing(KEY_ARTHAS_ADVICE_AFTER_INVOKING_METHOD, owner, name, desc, lineNumber);
- goTo(finallyLabel);
-
- // }
- // catch
- // {
-
- catchException(beginLabel, endLabel, ASM_TYPE_THROWABLE);
- tracing(KEY_ARTHAS_ADVICE_THROW_INVOKING_METHOD, owner, name, desc, lineNumber);
-
- throwException();
-
- // }
- // finally
- // {
- mark(finallyLabel);
- // }
- }
- };
- }
-
- static class AsmTryCatchBlock {
- Label start;
- Label end;
- Label handler;
- String type;
-
- AsmTryCatchBlock(Label start, Label end, Label handler, String type) {
- this.start = start;
- this.end = end;
- this.handler = handler;
- this.type = type;
- }
- }
}