| /* |
| * Javassist, a Java-bytecode translator toolkit. |
| * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved. |
| * |
| * The contents of this file are subject to the Mozilla Public License Version |
| * 1.1 (the "License"); you may not use this file except in compliance with |
| * the License. Alternatively, the contents of this file may be used under |
| * the terms of the GNU Lesser General Public License Version 2.1 or later. |
| * |
| * Software distributed under the License is distributed on an "AS IS" basis, |
| * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
| * for the specific language governing rights and limitations under the |
| * License. |
| */ |
| package javassist.bytecode.analysis; |
| |
| import java.io.PrintStream; |
| |
| import javassist.CtClass; |
| import javassist.CtMethod; |
| import javassist.Modifier; |
| import javassist.NotFoundException; |
| import javassist.bytecode.BadBytecode; |
| import javassist.bytecode.CodeAttribute; |
| import javassist.bytecode.CodeIterator; |
| import javassist.bytecode.ConstPool; |
| import javassist.bytecode.Descriptor; |
| import javassist.bytecode.InstructionPrinter; |
| import javassist.bytecode.MethodInfo; |
| |
| /** |
| * A utility class for printing a merged view of the frame state and the |
| * instructions of a method. |
| * |
| * @author Jason T. Greene |
| */ |
| public final class FramePrinter { |
| private final PrintStream stream; |
| |
| /** |
| * Constructs a bytecode printer. |
| */ |
| public FramePrinter(PrintStream stream) { |
| this.stream = stream; |
| } |
| |
| /** |
| * Prints all the methods declared in the given class. |
| */ |
| public static void print(CtClass clazz, PrintStream stream) { |
| (new FramePrinter(stream)).print(clazz); |
| } |
| |
| /** |
| * Prints all the methods declared in the given class. |
| */ |
| public void print(CtClass clazz) { |
| CtMethod[] methods = clazz.getDeclaredMethods(); |
| for (int i = 0; i < methods.length; i++) { |
| print(methods[i]); |
| } |
| } |
| |
| private String getMethodString(CtMethod method) { |
| try { |
| return Modifier.toString(method.getModifiers()) + " " |
| + method.getReturnType().getName() + " " + method.getName() |
| + Descriptor.toString(method.getSignature()) + ";"; |
| } catch (NotFoundException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| /** |
| * Prints the instructions and the frame states of the given method. |
| */ |
| public void print(CtMethod method) { |
| stream.println("\n" + getMethodString(method)); |
| MethodInfo info = method.getMethodInfo2(); |
| ConstPool pool = info.getConstPool(); |
| CodeAttribute code = info.getCodeAttribute(); |
| if (code == null) |
| return; |
| |
| Frame[] frames; |
| try { |
| frames = (new Analyzer()).analyze(method.getDeclaringClass(), info); |
| } catch (BadBytecode e) { |
| throw new RuntimeException(e); |
| } |
| |
| int spacing = String.valueOf(code.getCodeLength()).length(); |
| |
| CodeIterator iterator = code.iterator(); |
| while (iterator.hasNext()) { |
| int pos; |
| try { |
| pos = iterator.next(); |
| } catch (BadBytecode e) { |
| throw new RuntimeException(e); |
| } |
| |
| stream.println(pos + ": " + InstructionPrinter.instructionString(iterator, pos, pool)); |
| |
| addSpacing(spacing + 3); |
| Frame frame = frames[pos]; |
| if (frame == null) { |
| stream.println("--DEAD CODE--"); |
| continue; |
| } |
| printStack(frame); |
| |
| addSpacing(spacing + 3); |
| printLocals(frame); |
| } |
| |
| } |
| |
| private void printStack(Frame frame) { |
| stream.print("stack ["); |
| int top = frame.getTopIndex(); |
| for (int i = 0; i <= top; i++) { |
| if (i > 0) |
| stream.print(", "); |
| Type type = frame.getStack(i); |
| stream.print(type); |
| } |
| stream.println("]"); |
| } |
| |
| private void printLocals(Frame frame) { |
| stream.print("locals ["); |
| int length = frame.localsLength(); |
| for (int i = 0; i < length; i++) { |
| if (i > 0) |
| stream.print(", "); |
| Type type = frame.getLocal(i); |
| stream.print(type == null ? "empty" : type.toString()); |
| } |
| stream.println("]"); |
| } |
| |
| private void addSpacing(int count) { |
| while (count-- > 0) |
| stream.print(' '); |
| } |
| } |