mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
clean code
This commit is contained in:
@@ -1,23 +1,10 @@
|
||||
package com.taobao.arthas.core.advisor;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 通知编织者<br/>
|
||||
@@ -27,36 +14,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* <p/>
|
||||
* 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<Integer/*ADVICE_ID*/, AdviceListener> advices
|
||||
= new ConcurrentHashMap<Integer, AdviceListener>();
|
||||
// 线程帧封装
|
||||
private static final ThreadLocal<GaStack<GaStack<Object>>> threadBoundContext
|
||||
= new ThreadLocal<GaStack<GaStack<Object>>>();
|
||||
// 防止自己递归调用
|
||||
private static final ThreadLocal<Boolean> isSelfCallRef = new ThreadLocal<Boolean>() {
|
||||
|
||||
@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("<init>")
|
||||
&& (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, "<clinit>");
|
||||
}
|
||||
|
||||
@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<br/>
|
||||
* 这里分开静态方法中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<AsmTryCatchBlock> tcbs = new ArrayList<AsmTryCatchBlock>();
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user