我试图通过从AdviceAdapter实现onMethodEnter()来捕获每个方法调用的调用。我遇到的问题是,我的检测代码没有被添加到所有方法中。实际上,它仅添加到“<init>
”之后的第一个方法中,并且跳过了其余的方法。请在下面的代码中告诉我我做错了什么。
感谢。 灰分。
public class FunctionLevelDependency extends AdviceAdapter implements Opcodes {
String className;
String methodName;
int currentThread_idx, threadId_idx, stringBuffer_idx, output_idx;
protected FunctionLevelDependency(int api, MethodVisitor mv, int access,
String methodName, String desc, String className) {
super(api, mv, access, methodName, desc);
this.className = className;
this.methodName = methodName;
}
@Override
protected void onMethodEnter() {
currentThread_idx = newLocal(Type.getType(Thread.class));
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread",
"()Ljava/lang/Thread;", false);
mv.visitVarInsn(ASTORE, currentThread_idx);
mv.visitVarInsn(ALOAD, currentThread_idx);
threadId_idx = newLocal(Type.getType(String.class));
mv.visitTypeInsn(NEW, "java/lang/String");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "<init>",
"()V", false);
mv.visitVarInsn(ASTORE, threadId_idx);
mv.visitVarInsn(ALOAD, currentThread_idx);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getName", "()Ljava/lang/String;",
false);
mv.visitVarInsn(ASTORE, threadId_idx);
stringBuffer_idx = newLocal(Type.getType(StringBuffer.class));
mv.visitTypeInsn(NEW, "java/lang/StringBuffer");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>",
"()V", false);
mv.visitVarInsn(ASTORE, stringBuffer_idx);
mv.visitVarInsn(ALOAD, stringBuffer_idx);
mv.visitVarInsn(ALOAD, threadId_idx);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append",
"(Ljava/lang/String;)Ljava/lang/StringBuffer;", false);
mv.visitInsn(POP);
mv.visitVarInsn(ALOAD, stringBuffer_idx);
mv.visitLdcInsn(",[" + className + "][" + methodName + "]");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append",
"(Ljava/lang/String;)Ljava/lang/StringBuffer;", false);
mv.visitInsn(POP);
mv.visitVarInsn(ALOAD, stringBuffer_idx);
output_idx = newLocal(Type.getType(String.class));
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString",
"()Ljava/lang/String;", false);
mv.visitVarInsn(ASTORE, output_idx);
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
"Ljava/io/PrintStream;");
mv.visitVarInsn(ALOAD, output_idx);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(Ljava/lang/String;)V", false);
}
}
public class FunctionDependencyPrinter extends ClassVisitor {
private String className;
private boolean isInterface;
public FunctionDependencyPrinter(ClassWriter writer, String className) {
super(Opcodes.ASM5, writer);
this.className = className;
}
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
isInterface = (access & ACC_INTERFACE) != 0;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature,
exceptions);
if (!isInterface && mv != null && !name.equals("<init>") && !name.equals("<clinit>")) {
System.out.println("Transforming " + name + " for " + className);
mv = new FunctionLevelDependency(Opcodes.ASM5, mv, access, name,
desc, className);
}
return mv;
}
}