clean code

pull/1182/head
hengyunabc 5 years ago
parent 7d7b5460ad
commit a55b471ea7

@ -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;
/**
* <br/>
* <p/>
@ -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/>
* ClassLoaderClassLoader
*
*/
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;
}
}
}

Loading…
Cancel
Save