下面列出了怎么用org.objectweb.asm.util.TraceMethodVisitor的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public void visitEnd() {
try {
accept(inner);
super.visitEnd();
} catch(Exception e){
Textifier t = new Textifier();
accept(new TraceMethodVisitor(t));
StringBuilderWriter sw = new StringBuilderWriter();
PrintWriter pw = new PrintWriter(sw);
t.print(pw);
pw.flush();
String bytecode = sw.getBuilder().toString();
logger.error(String.format("Failure while rendering method %s, %s, %s. ByteCode:\n %s", name, desc, signature, bytecode), e);
throw new RuntimeException(String.format("Failure while rendering method %s, %s, %s. ByteCode:\n %s", name, desc, signature, bytecode), e);
}
}
public static void viewByteCode(byte[] bytecode) {
ClassReader cr = new ClassReader(bytecode);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
final List<MethodNode> mns = cn.methods;
Printer printer = new Textifier();
TraceMethodVisitor mp = new TraceMethodVisitor(printer);
for (MethodNode mn : mns) {
InsnList inList = mn.instructions;
System.out.println(mn.name);
for (int i = 0; i < inList.size(); i++) {
inList.get(i).accept(mp);
StringWriter sw = new StringWriter();
printer.print(new PrintWriter(sw));
printer.getText().clear();
System.out.print(sw.toString());
}
}
}
public static void viewByteCode(byte[] bytecode) {
ClassReader classReader = new ClassReader(bytecode);
ClassNode classNode = new ClassNode();
classReader.accept(classNode, 0);
final List<MethodNode> methodNodes = classNode.methods;
Printer printer = new Textifier();
TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(printer);
for (MethodNode methodNode : methodNodes) {
InsnList insnList = methodNode.instructions;
System.out.println(methodNode.name);
for (int i = 0; i < insnList.size(); i++) {
insnList.get(i).accept(traceMethodVisitor);
StringWriter sw = new StringWriter();
printer.print(new PrintWriter(sw));
printer.getText().clear();
System.out.print(sw.toString());
}
}
}
public static String getMethodInstructionList(final MethodNode methodNode) {
Preconditions.checkNotNull(methodNode, "methodNode");
final Printer printer = new NonMaxTextifier();
final TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(printer);
methodNode.accept(traceMethodVisitor);
final StringWriter stringWriter = new StringWriter();
final PrintWriter printWriter = new PrintWriter(stringWriter);
printer.print(printWriter);
printWriter.flush();
final String[] lines = PATTERN.split(stringWriter.toString());
int lineNr = 0;
for (int i = 0; i < lines.length; i++) {
if (!lines[i].startsWith(" @")) {
lines[i] = String.format("%2d %s", lineNr++, lines[i]);
}
}
return "Method '" + methodNode.name + "':\n"
+ NEWLINE.join(lines) + '\n';
}
/**
* Converts the given method to a String.
*/
public static String textify(@NonNull MethodNode method) {
Textifier textifier = new Textifier();
TraceMethodVisitor trace = new TraceMethodVisitor(textifier);
method.accept(trace);
String ret = "";
for (Object line : textifier.getText()) {
ret += line;
}
return ret;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (method.matches(name, desc)) {
Printer localPrinter = asmifier.visitMethod(access, name, desc, signature, exceptions);
return new TraceMethodVisitor(null, localPrinter);
}
return null;
}
public static void assertTraceDumpEquality(
final MethodNode method, final String traceDump) throws Exception {
Preconditions.checkNotNull(method, "method");
final Printer printer = new NonMaxTextifier();
final TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(printer);
// MethodAdapter checkMethodAdapter = new MethodAdapter(traceMethodVisitor);
final MethodVisitor checkMethodAdapter = new CheckMethodAdapter(traceMethodVisitor);
method.accept(checkMethodAdapter);
final StringWriter stringWriter = new StringWriter();
final PrintWriter printWriter = new PrintWriter(stringWriter);
printer.print(printWriter);
printWriter.flush();
assertEquals(stringWriter.toString(), traceDump);
}
private String toString(MethodTree mt) {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final TraceMethodVisitor mv = new TraceMethodVisitor(new Textifier());
mt.rawNode().accept(mv);
try (PrintWriter pw = new PrintWriter(bos)) {
mv.p.print(pw);
}
return "Byte code is \n" + new String(bos.toByteArray());
}
public String toString() {
Textifier t = new Textifier();
accept(new TraceMethodVisitor(t));
StringWriter sw = new StringWriter();
t.print(new PrintWriter(sw));
return sw.toString();
}
public void trace() {
PrintWriter printWriter = new PrintWriter(System.out);
printWriter.format("%nClass=%s, Method=%s [%s]%n", method.classCode.className, method.methodName,
method.methodDescriptor);
((TraceMethodVisitor) mv).p.print(printWriter);
printWriter.format("%n");
printWriter.flush();
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (methodName.equals(name) && methodType.toMethodDescriptorString().equals(desc)) {
Printer p = printer.visitMethod(access, name, desc, signature, exceptions);
return new TraceMethodVisitor(null, p);
}
return null;
}
@SuppressWarnings("unchecked")
public <T extends TypeEntry> void emitOuterType(T ast) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
this.cw = writer;
if (VERIFY_EMITTED_BYTECODE) {
this.cw = new CheckClassAdapter(this.cw);
}
AstEmitter<AbstractEmitterContext, T> emitter = (AstEmitter<AbstractEmitterContext, T>) this.set.getAstEmitter(ast.getClass());
if (emitter == null) {
throw new IllegalArgumentException("No emitter for ast entry " + ast.getClass().getName());
}
emitter.emit(this, ast);
this.cw.visitEnd();
byte[] clazz = writer.toByteArray();
if (DUMP_INSTRUCTIONS_AFTER_WRITE) {
ClassReader cr = new ClassReader(clazz);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
List<MethodNode> methods = cn.methods;
for (MethodNode mn : methods) {
System.out.println("Method: " + mn.name + mn.desc);
Printer printer = new Textifier();
TraceMethodVisitor mp = new TraceMethodVisitor(printer);
for (Iterator<AbstractInsnNode> it = mn.instructions.iterator(); it.hasNext();) {
AbstractInsnNode insn = it.next();
insn.accept(mp);
}
StringWriter sw = new StringWriter();
printer.print(new PrintWriter(sw));
String s = sw.toString();
if (s.endsWith("\n")) {
s = s.substring(0, s.length() - 1);
}
System.out.println(s);
mn.instructions.accept(mp);
}
}
try {
this.out.write(clazz);
} catch (IOException e) {
Throwables.propagate(e);
}
}
public static String toString(MethodNode mn) {
Textifier t = new Textifier();
TraceMethodVisitor tmv = new TraceMethodVisitor(t);
mn.accept(tmv);
return t.toString();
}
@Override
protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) {
controller.resetLineNumber();
Parameter[] parameters = node.getParameters();
String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), parameters);
String signature = BytecodeHelper.getGenericsMethodSignature(node);
int modifiers = node.getModifiers();
if (isVargs(node.getParameters())) modifiers |= ACC_VARARGS;
MethodVisitor mv = classVisitor.visitMethod(modifiers, node.getName(), methodType, signature, buildExceptions(node.getExceptions()));
controller.setMethodVisitor(mv);
visitAnnotations(node, mv);
for (int i = 0, n = parameters.length; i < n; i += 1) {
visitParameterAnnotations(parameters[i], i, mv);
}
// add parameter names to the MethodVisitor (jdk8+ only)
if (Optional.ofNullable(controller.getClassNode().getCompileUnit())
.orElseGet(context::getCompileUnit).getConfig().getParameters()) {
for (Parameter parameter : parameters) {
// TODO: handle ACC_SYNTHETIC for enum method parameters?
mv.visitParameter(parameter.getName(), 0);
}
}
if (controller.getClassNode().isAnnotationDefinition() && !node.isStaticConstructor()) {
visitAnnotationDefault(node, mv);
} else if (!node.isAbstract()) {
Statement code = node.getCode();
mv.visitCode();
BytecodeInstruction instruction; // fast path for getters, setters, etc.
if (code instanceof BytecodeSequence && (instruction = ((BytecodeSequence) code).getBytecodeInstruction()) != null) {
instruction.visit(mv);
} else {
visitStdMethod(node, isConstructor, parameters, code);
}
try {
mv.visitMaxs(0, 0);
} catch (Exception e) {
Writer writer = null;
if (mv instanceof TraceMethodVisitor) {
TraceMethodVisitor tracer = (TraceMethodVisitor) mv;
writer = new StringBuilderWriter();
PrintWriter p = new PrintWriter(writer);
tracer.p.print(p);
p.flush();
}
StringBuilder message = new StringBuilder(64);
message.append("ASM reporting processing error for ");
message.append(controller.getClassNode().toString()).append("#").append(node.getName());
message.append(" with signature ").append(node.getTypeDescriptor());
message.append(" in ").append(sourceFile).append(":").append(node.getLineNumber());
if (writer != null) {
message.append("\nLast known generated bytecode in last generated method or constructor:\n");
message.append(writer);
}
throw new GroovyRuntimeException(message.toString(), e);
}
}
mv.visitEnd();
}
private void verifyClassIntegrity(ClassNode classNode) {
// Do not COMPUTE_FRAMES. If you COMPUTE_FRAMES and you pop too many items off the stack or do other weird things that mess up the
// stack map frames, it'll crash on classNode.accept(cw).
ClassWriter cw = new SimpleClassWriter(ClassWriter.COMPUTE_MAXS/* | ClassWriter.COMPUTE_FRAMES*/, classRepo);
classNode.accept(cw);
byte[] classData = cw.toByteArray();
ClassReader cr = new ClassReader(classData);
classNode = new SimpleClassNode();
cr.accept(classNode, 0);
for (MethodNode methodNode : classNode.methods) {
Analyzer<BasicValue> analyzer = new Analyzer<>(new SimpleVerifier(classRepo));
try {
analyzer.analyze(classNode.name, methodNode);
} catch (AnalyzerException e) {
// IF WE DID OUR INSTRUMENTATION RIGHT, WE SHOULD NEVER GET AN EXCEPTION HERE!!!!
StringWriter writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
printWriter.append(methodNode.name + " encountered " + e);
Printer printer = new Textifier();
TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(printer);
AbstractInsnNode insn = methodNode.instructions.getFirst();
while (insn != null) {
if (insn == e.node) {
printer.getText().add("----------------- BAD INSTRUCTION HERE -----------------\n");
}
insn.accept(traceMethodVisitor);
insn = insn.getNext();
}
printer.print(printWriter);
printWriter.flush(); // we need this or we'll get incomplete results
throw new IllegalStateException(writer.toString(), e);
}
}
}
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions)
{
// Unused?
/*
final MethodVisitor mv = super.visitMethod(access, name, desc,
signature, exceptions);
*/
return new MethodNode(Opcodes.ASM5, access, name, desc, signature,
exceptions)
{
@Override
public void visitEnd()
{
super.visitEnd();
try {
final BasicInterpreter basicInterpreter
= new BasicInterpreter();
final Analyzer<BasicValue> analyzer
= new Analyzer<>(basicInterpreter);
final AbstractInsnNode[] nodes = instructions.toArray();
final Frame<BasicValue>[] frames
= analyzer.analyze(className, this);
int areturn = -1;
for (int i = nodes.length -1; i >= 0; i--)
{
if (nodes[i].getOpcode() == Opcodes.ARETURN) {
areturn = i;
System.out.println(className + "." + name + desc);
System.out.println("Found areturn at: " + i);
} else if (areturn != -1
&& nodes[i].getOpcode() != -1
&& frames[i].getStackSize() == 0) {
System.out.println("Found start of block at: " + i);
final InsnList list = new InsnList();
for (int j = i; j <= areturn; j++)
list.add(nodes[j]);
final Textifier textifier = new Textifier();
final PrintWriter pw = new PrintWriter(System.out);
list.accept(new TraceMethodVisitor(textifier));
textifier.print(pw);
pw.flush();
System.out.println("\n\n");
areturn = -1;
}
}
}
catch (AnalyzerException e) {
e.printStackTrace();
}
if (mv != null)
accept(mv);
}
};
}
$TraceMethodVisitor(MethodCode method, MethodVisitor mv) {
super(Opcodes.ASM5, new TraceMethodVisitor(mv, new SimpleTypeTextifier()));
this.method = method;
}