package com.github.ompc.greys.core.advisor; import com.github.ompc.greys.core.util.AsmCodeLock; import com.github.ompc.greys.core.util.CodeLock; import com.github.ompc.greys.core.util.GaMethod; import com.github.ompc.greys.core.util.LogUtil; import com.github.ompc.greys.core.util.affect.EnhancerAffect; import com.github.ompc.greys.core.util.collection.GaStack; import com.github.ompc.greys.core.util.collection.ThreadUnsafeFixGaStack; import com.github.ompc.greys.core.util.collection.ThreadUnsafeGaStack; import com.github.ompc.greys.core.util.matcher.Matcher; import org.apache.commons.lang3.StringUtils; import org.objectweb.asm.*; import org.objectweb.asm.commons.AdviceAdapter; import org.objectweb.asm.commons.JSRInlinerAdapter; import org.objectweb.asm.commons.Method; import org.slf4j.Logger; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static com.github.ompc.greys.core.GlobalOptions.isDebugForAsm; import static com.github.ompc.greys.core.util.GaCheckUtils.isEquals; import static com.github.ompc.greys.core.util.GaStringUtils.tranClassName; import static java.lang.Thread.currentThread; /** * 用于Tracing的代码锁 */ class TracingAsmCodeLock extends AsmCodeLock { TracingAsmCodeLock(AdviceAdapter aa) { super( aa, new int[]{ ICONST_0, POP }, new int[]{ ICONST_1, POP } ); } } /** * Method在Asm内部的封装,用于封装Asm方法 */ class AsmMethod { protected final String name; protected final String desc; AsmMethod(String name, String desc) { this.name = name; this.desc = desc; } } /** * Method匹配器,用于封装Asm方法的匹配 */ class AsmMethodMatcher implements Matcher<AsmMethod> { private final GaMethod gaMethod; AsmMethodMatcher(GaMethod gaMethod) { this.gaMethod = gaMethod; } @Override public boolean matching(AsmMethod target) { return StringUtils.equals(gaMethod.getName(), target.name) && StringUtils.equals(gaMethod.getDesc(), target.desc); } } /** * TryCatch块,用于ExceptionsTable重排序 */ class AsmTryCatchBlock { protected final Label start; protected final Label end; protected final Label handler; protected final String type; AsmTryCatchBlock(Label start, Label end, Label handler, String type) { this.start = start; this.end = end; this.handler = handler; this.type = type; } } /** * 通知编织者<br/> * <p/> * <h2>线程帧栈与执行帧栈</h2> * 编织者在执行通知的时候有两个重要的栈:线程帧栈(threadFrameStack),执行帧栈(frameStack) * <p/> * Created by oldmanpushcart@gmail.com on 15/5/17. */ public class AdviceWeaver extends ClassVisitor implements Opcodes { private final static Logger logger = LogUtil.getLogger(); // 线程帧栈堆栈大小 private final static int FRAME_STACK_SIZE = 7; // 通知监听器集合 private final static Map<Integer/*ADVICE_ID*/, AdviceListener> advices = new ConcurrentHashMap<Integer, AdviceListener>(); // 线程帧封装 private static final Map<Thread, GaStack<GaStack<Object>>> threadBoundContexts = new ConcurrentHashMap<Thread, GaStack<GaStack<Object>>>(); // 防止自己递归调用 private static final ThreadLocal<Boolean> isSelfCallRef = new ThreadLocal<Boolean>() { @Override protected Boolean initialValue() { return false; } }; /** * 方法开始<br/> * 用于编织通知器,外部不会直接调用 * * @param loader 类加载器 * @param adviceId 通知ID * @param className 类名 * @param methodName 方法名 * @param methodDesc 方法描述 * @param target 返回结果 * 若为无返回值方法(void),则为null * @param args 参数列表 */ public static void methodOnBegin( int adviceId, ClassLoader loader, String className, String methodName, String methodDesc, Object target, Object[] args) { if (!advices.containsKey(adviceId)) { return; } if (isSelfCallRef.get()) { return; } else { isSelfCallRef.set(true); } try { // 构建执行帧栈,保护当前的执行现场 final GaStack<Object> frameStack = new ThreadUnsafeFixGaStack<Object>(FRAME_STACK_SIZE); frameStack.push(loader); frameStack.push(className); frameStack.push(methodName); frameStack.push(methodDesc); frameStack.push(target); frameStack.push(args); final AdviceListener listener = getListener(adviceId); frameStack.push(listener); // 获取通知器并做前置通知 before(listener, loader, className, methodName, methodDesc, target, args); // 保护当前执行帧栈,压入线程帧栈 threadFrameStackPush(frameStack); } finally { isSelfCallRef.set(false); } } /** * 方法以返回结束<br/> * 用于编织通知器,外部不会直接调用 * * @param returnObject 返回对象 * 若目标为静态方法,则为null */ public static void methodOnReturnEnd(Object returnObject, int adviceId) { methodOnEnd(adviceId, false, returnObject); } /** * 方法以抛异常结束<br/> * 用于编织通知器,外部不会直接调用 * * @param throwable 抛出异常 */ public static void methodOnThrowingEnd(Throwable throwable, int adviceId) { methodOnEnd(adviceId, true, throwable); } /** * 所有的返回都统一处理 * * @param isThrowing 标记正常返回结束还是抛出异常结束 * @param returnOrThrowable 正常返回或者抛出异常对象 */ private static void methodOnEnd(int adviceId, boolean isThrowing, Object returnOrThrowable) { if (!advices.containsKey(adviceId)) { return; } if (isSelfCallRef.get()) { return; } else { isSelfCallRef.set(true); } try { // 弹射线程帧栈,恢复Begin所保护的执行帧栈 final GaStack<Object> frameStack = threadFrameStackPop(); // 用于保护reg和before执行并发的情况 // 如果before没有注入,则不对end做任何处理 if (null == frameStack) { return; } // 弹射执行帧栈,恢复Begin所保护的现场 final AdviceListener listener = (AdviceListener) frameStack.pop(); final Object[] args = (Object[]) frameStack.pop(); final Object target = frameStack.pop(); final String methodDesc = (String) frameStack.pop(); final String methodName = (String) frameStack.pop(); final String className = (String) frameStack.pop(); final ClassLoader loader = (ClassLoader) frameStack.pop(); // 异常通知 if (isThrowing) { afterThrowing(listener, loader, className, methodName, methodDesc, target, args, (Throwable) returnOrThrowable); } // 返回通知 else { afterReturning(listener, loader, className, methodName, methodDesc, target, args, returnOrThrowable); } } finally { isSelfCallRef.set(false); } } /** * 方法内部调用开始 * * @param adviceId 通知ID * @param lineNumber 代码行号 * @param owner 调用类名 * @param name 调用方法名 * @param desc 调用方法描述 */ public static void methodOnInvokeBeforeTracing(int adviceId, Integer lineNumber, String owner, String name, String desc) { if (!advices.containsKey(adviceId)) { return; } final InvokeTraceable listener = (InvokeTraceable) getListener(adviceId); if (null != listener) { try { listener.invokeBeforeTracing(lineNumber, owner, name, desc); } catch (Throwable t) { logger.warn("advice before tracing failed.", t); } } } /** * 方法内部调用结束(正常返回) * * @param adviceId 通知ID * @param lineNumber 代码行号 * @param owner 调用类名 * @param name 调用方法名 * @param desc 调用方法描述 */ public static void methodOnInvokeAfterTracing(int adviceId, Integer lineNumber, String owner, String name, String desc) { if (!advices.containsKey(adviceId)) { return; } final InvokeTraceable listener = (InvokeTraceable) getListener(adviceId); if (null != listener) { try { listener.invokeAfterTracing(lineNumber, owner, name, desc); } catch (Throwable t) { logger.warn("advice after tracing failed.", t); } } } /** * 方法内部调用结束(异常返回) * * @param adviceId 通知ID * @param lineNumber 代码行号 * @param owner 调用类名 * @param name 调用方法名 * @param desc 调用方法描述 * @param throwException 抛出的异常 */ public static void methodOnInvokeThrowTracing(int adviceId, Integer lineNumber, String owner, String name, String desc, String throwException) { if (!advices.containsKey(adviceId)) { return; } final InvokeTraceable listener = (InvokeTraceable) getListener(adviceId); if (null != listener) { try { listener.invokeThrowTracing(lineNumber, owner, name, desc, throwException); } catch (Throwable t) { logger.warn("advice throw tracing failed.", t); } } } /* * 线程帧栈压栈<br/> * 将当前执行帧栈压入线程栈 */ private static void threadFrameStackPush(GaStack<Object> frameStack) { final Thread thread = currentThread(); GaStack<GaStack<Object>> threadFrameStack = threadBoundContexts.get(thread); if (null == threadFrameStack) { threadBoundContexts.put(thread, threadFrameStack = new ThreadUnsafeGaStack<GaStack<Object>>()); } threadFrameStack.push(frameStack); } private static GaStack<Object> threadFrameStackPop() { final GaStack<GaStack<Object>> stackGaStack = threadBoundContexts.get(currentThread()); // 用于保护reg和before并发导致before/end乱序的场景 if (null == stackGaStack || stackGaStack.isEmpty()) { return null; } return stackGaStack.pop(); } private static AdviceListener getListener(int adviceId) { return advices.get(adviceId); } /** * 注册监听器 * * @param adviceId 通知ID * @param listener 通知监听器 */ public static void reg(int adviceId, AdviceListener listener) { // 触发监听器创建 listener.create(); // 注册监听器 advices.put(adviceId, listener); logger.info("reg adviceId={};listener={}", adviceId, listener); } /** * 注销监听器 * * @param adviceId 通知ID */ public static void unReg(int adviceId) { // 注销监听器 final AdviceListener listener = advices.remove(adviceId); // 触发监听器销毁 if (null != listener) { listener.destroy(); } logger.info("unReg adviceId={};listener={}", adviceId, listener); } private static void before(AdviceListener listener, ClassLoader loader, String className, String methodName, String methodDesc, Object target, Object[] args) { if (null != listener) { try { listener.before(loader, className, methodName, methodDesc, target, args); } catch (Throwable t) { logger.warn("advice before failed.", t); } } } private static void afterReturning(AdviceListener listener, ClassLoader loader, String className, String methodName, String methodDesc, Object target, Object[] args, Object returnObject) { if (null != listener) { try { listener.afterReturning(loader, className, methodName, methodDesc, target, args, returnObject); } catch (Throwable t) { logger.warn("advice returning failed.", t); } } } private static void afterThrowing(AdviceListener listener, ClassLoader loader, String className, String methodName, String methodDesc, Object target, Object[] args, Throwable throwable) { if (null != listener) { try { listener.afterThrowing(loader, className, methodName, methodDesc, target, args, throwable); } catch (Throwable t) { logger.warn("advice throwing failed.", t); } } } private final int adviceId; private final boolean isTracing; private final String internalClassName; private final String javaClassName; private final Matcher<AsmMethod> asmMethodMatcher; private final EnhancerAffect affect; /** * 构建通知编织器 * * @param adviceId 通知ID * @param isTracing 可跟踪方法调用 * @param internalClassName 类名称(透传) * @param asmMethodMatcher asm方法匹配 * 只有匹配上的方法才会被织入通知器 * @param affect 影响计数 * @param cv ClassVisitor for ASM */ public AdviceWeaver( final int adviceId, final boolean isTracing, final String internalClassName, final Matcher<AsmMethod> asmMethodMatcher, final EnhancerAffect affect, final ClassVisitor cv) { super(ASM5, cv); this.adviceId = adviceId; this.isTracing = isTracing; this.internalClassName = internalClassName; this.javaClassName = tranClassName(internalClassName); this.asmMethodMatcher = asmMethodMatcher; this.affect = affect; } /** * 是否抽象属性 */ private boolean isAbstract(int access) { return (ACC_ABSTRACT & access) == ACC_ABSTRACT; } /** * 是否需要忽略 */ private boolean isIgnore(MethodVisitor mv, int access, String name, String desc) { return null == mv || isAbstract(access) || !asmMethodMatcher.matching(new AsmMethod(name, desc)) || isEquals(name, "<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, desc)) { return mv; } // 编织方法计数 affect.mCnt(1); return new AdviceAdapter(ASM5, new JSRInlinerAdapter(mv, access, name, desc, signature, exceptions), access, name, desc) { // -- Lebel for try...catch block private final Label beginLabel = new Label(); private final Label endLabel = new Label(); // -- KEY of advice -- private final int KEY_GREYS_ADVICE_BEFORE_METHOD = 0; private final int KEY_GREYS_ADVICE_RETURN_METHOD = 1; private final int KEY_GREYS_ADVICE_THROWS_METHOD = 2; private final int KEY_GREYS_ADVICE_BEFORE_INVOKING_METHOD = 3; private final int KEY_GREYS_ADVICE_AFTER_INVOKING_METHOD = 4; private final int KEY_GREYS_ADVICE_THROW_INVOKING_METHOD = 5; // -- KEY of ASM_TYPE or ASM_METHOD -- private final Type ASM_TYPE_SPY = Type.getType("Lcom/github/ompc/greys/agent/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 void _debug(final StringBuilder append, final String msg) { if (!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); } /** * 加载通知方法 * @param keyOfMethod 通知方法KEY */ private void loadAdviceMethod(int keyOfMethod) { switch (keyOfMethod) { case KEY_GREYS_ADVICE_BEFORE_METHOD: { getStatic(ASM_TYPE_SPY, "ON_BEFORE_METHOD", ASM_TYPE_METHOD); break; } case KEY_GREYS_ADVICE_RETURN_METHOD: { getStatic(ASM_TYPE_SPY, "ON_RETURN_METHOD", ASM_TYPE_METHOD); break; } case KEY_GREYS_ADVICE_THROWS_METHOD: { getStatic(ASM_TYPE_SPY, "ON_THROWS_METHOD", ASM_TYPE_METHOD); break; } case KEY_GREYS_ADVICE_BEFORE_INVOKING_METHOD: { getStatic(ASM_TYPE_SPY, "BEFORE_INVOKING_METHOD", ASM_TYPE_METHOD); break; } case KEY_GREYS_ADVICE_AFTER_INVOKING_METHOD: { getStatic(ASM_TYPE_SPY, "AFTER_INVOKING_METHOD", ASM_TYPE_METHOD); break; } case KEY_GREYS_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()) { // // fast enhance // if (GlobalOptions.isEnableFastEnhance) { // visitLdcInsn(Type.getType(String.format("L%s;", internalClassName))); // visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); // } // normal enhance // else { // 这里不得不用性能极差的Class.forName()来完成类的获取,因为有可能当前这个静态方法在执行的时候 // 当前类并没有完成实例化,会引起JVM对class文件的合法性校验失败 // 未来我可能会在这一块考虑性能优化,但对于当前而言,功能远远重要于性能,也就不打算折腾这么复杂了 visitLdcInsn(javaClassName); 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(tranClassName(javaClassName)); 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_GREYS_ADVICE_BEFORE_METHOD); _debug(append, "loadAdviceMethod()"); // 推入Method.invoke()的第一个参数 pushNull(); // 方法参数 loadArrayForBefore(); _debug(append, "loadArrayForBefore()"); // 调用方法 invokeVirtual(ASM_TYPE_METHOD, ASM_METHOD_METHOD_INVOKE); pop(); _debug(append, "invokeVirtual()"); } }); mark(beginLabel); } /* * 加载return通知参数数组 */ private void loadReturnArgs() { dup2X1(); pop2(); push(2); newArray(ASM_TYPE_OBJECT); dup(); dup2X1(); pop2(); push(0); swap(); arrayStore(ASM_TYPE_OBJECT); dup(); push(1); push(adviceId); box(ASM_TYPE_INT); arrayStore(ASM_TYPE_INTEGER); } @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, "loadReturn()"); // 加载returning方法 loadAdviceMethod(KEY_GREYS_ADVICE_RETURN_METHOD); _debug(append, "loadAdviceMethod()"); // 推入Method.invoke()的第一个参数 pushNull(); // 加载return通知参数数组 loadReturnArgs(); _debug(append, "loadReturnArgs()"); invokeVirtual(ASM_TYPE_METHOD, ASM_METHOD_METHOD_INVOKE); pop(); _debug(append, "invokeVirtual()"); } }); } } /* * 创建throwing通知参数本地变量 */ private void loadThrowArgs() { dup2X1(); pop2(); push(2); newArray(ASM_TYPE_OBJECT); dup(); dup2X1(); pop2(); push(0); swap(); arrayStore(ASM_TYPE_THROWABLE); dup(); push(1); push(adviceId); box(ASM_TYPE_INT); arrayStore(ASM_TYPE_INTEGER); } @Override public void visitMaxs(int maxStack, int maxLocals) { mark(endLabel); visitTryCatchBlock(beginLabel, endLabel, mark(), ASM_TYPE_THROWABLE.getInternalName()); // catchException(beginLabel, endLabel, ASM_TYPE_THROWABLE); codeLockForTracing.lock(new CodeLock.Block() { @Override public void code() { final StringBuilder append = new StringBuilder(); _debug(append, "debug:catchException()"); // 加载异常 loadThrow(); _debug(append, "loadAdviceMethod()"); // 加载throwing方法 loadAdviceMethod(KEY_GREYS_ADVICE_THROWS_METHOD); _debug(append, "loadAdviceMethod()"); // 推入Method.invoke()的第一个参数 pushNull(); // 加载throw通知参数数组 loadThrowArgs(); _debug(append, "loadThrowArgs()"); // 调用方法 invokeVirtual(ASM_TYPE_METHOD, ASM_METHOD_METHOD_INVOKE); pop(); _debug(append, "invokeVirtual()"); } }); throwException(); super.visitMaxs(maxStack, maxLocals); } /** * 是否静态方法 * @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(); } /** * 加载方法调用跟踪通知所需参数数组(for before/after) */ private void loadArrayForInvokeBeforeOrAfterTracing(String owner, String name, String desc) { push(5); newArray(ASM_TYPE_OBJECT); dup(); push(0); push(adviceId); box(ASM_TYPE_INT); arrayStore(ASM_TYPE_INTEGER); if (null != currentLineNumber) { dup(); push(1); push(currentLineNumber); box(ASM_TYPE_INT); arrayStore(ASM_TYPE_INTEGER); } dup(); push(2); push(owner); arrayStore(ASM_TYPE_STRING); dup(); push(3); push(name); arrayStore(ASM_TYPE_STRING); dup(); push(4); push(desc); arrayStore(ASM_TYPE_STRING); } /** * 加载方法调用跟踪通知所需参数数组(for throw) */ private void loadArrayForInvokeThrowTracing(String owner, String name, String desc) { push(6); newArray(ASM_TYPE_OBJECT); dup(); push(0); push(adviceId); box(ASM_TYPE_INT); arrayStore(ASM_TYPE_INTEGER); if (null != currentLineNumber) { dup(); push(1); push(currentLineNumber); box(ASM_TYPE_INT); arrayStore(ASM_TYPE_INTEGER); } dup(); push(2); push(owner); arrayStore(ASM_TYPE_STRING); dup(); push(3); push(name); arrayStore(ASM_TYPE_STRING); dup(); push(4); push(desc); arrayStore(ASM_TYPE_STRING); dup2(); // e,a,e,a swap(); // e,a,a,e invokeVirtual(ASM_TYPE_OBJECT, Method.getMethod("Class getClass()")); invokeVirtual(ASM_TYPE_CLASS, Method.getMethod("String getName()")); // e,a,a,s push(5); // e,a,a,s,4 swap(); // e,a,a,4,s arrayStore(ASM_TYPE_STRING); // e,a } @Override public void visitInsn(int opcode) { super.visitInsn(opcode); codeLockForTracing.code(opcode); } /* * 跟踪代码 */ private void tracing(final int tracingType, final String owner, final String name, final String desc) { final String label; switch (tracingType) { case KEY_GREYS_ADVICE_BEFORE_INVOKING_METHOD: { label = "beforeInvoking"; break; } case KEY_GREYS_ADVICE_AFTER_INVOKING_METHOD: { label = "afterInvoking"; break; } case KEY_GREYS_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 + "()"); if (tracingType == KEY_GREYS_ADVICE_THROW_INVOKING_METHOD) { loadArrayForInvokeThrowTracing(owner, name, desc); } else { loadArrayForInvokeBeforeOrAfterTracing(owner, name, desc); } _debug(append, "loadArrayForInvokeTracing()"); loadAdviceMethod(tracingType); swap(); _debug(append, "loadAdviceMethod()"); pushNull(); swap(); invokeVirtual(ASM_TYPE_METHOD, ASM_METHOD_METHOD_INVOKE); pop(); _debug(append, "invokeVirtual()"); } }); } private Integer currentLineNumber; @Override public void visitLineNumber(int line, Label start) { super.visitLineNumber(line, start); currentLineNumber = line; } @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) { if (!isTracing || codeLockForTracing.isLock()) { super.visitMethodInsn(opcode, owner, name, desc, itf); return; } // 方法调用前通知 tracing(KEY_GREYS_ADVICE_BEFORE_INVOKING_METHOD, owner, name, desc); 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_GREYS_ADVICE_AFTER_INVOKING_METHOD, owner, name, desc); goTo(finallyLabel); // } // catch // { catchException(beginLabel, endLabel, ASM_TYPE_THROWABLE); tracing(KEY_GREYS_ADVICE_THROW_INVOKING_METHOD, owner, name, desc); throwException(); // } // finally // { mark(finallyLabel); // } } // 用于try-catch的冲排序,目的是让tracing的try...catch能在exceptions tables排在前边 private final Collection<AsmTryCatchBlock> asmTryCatchBlocks = new ArrayList<AsmTryCatchBlock>(); @Override public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { asmTryCatchBlocks.add(new AsmTryCatchBlock(start, end, handler, type)); } @Override public void visitEnd() { for (AsmTryCatchBlock tcb : asmTryCatchBlocks) { super.visitTryCatchBlock(tcb.start, tcb.end, tcb.handler, tcb.type); } super.visitEnd(); } }; } }