169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.bytecode.analysis;
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.PrintStream;
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtClass;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtMethod;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.Modifier;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.NotFoundException;
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.BadBytecode;
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.CodeAttribute;
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.CodeIterator;
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.ConstPool;
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.Descriptor;
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.InstructionPrinter;
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.MethodInfo;
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A utility class for printing a merged view of the frame state and the
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instructions of a method.
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Jason T. Greene
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic final class FramePrinter {
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private final PrintStream stream;
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a bytecode printer.
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public FramePrinter(PrintStream stream) {
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.stream = stream;
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Prints all the methods declared in the given class.
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static void print(CtClass clazz, PrintStream stream) {
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        (new FramePrinter(stream)).print(clazz);
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Prints all the methods declared in the given class.
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void print(CtClass clazz) {
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod[] methods = clazz.getDeclaredMethods();
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < methods.length; i++) {
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            print(methods[i]);
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private String getMethodString(CtMethod method) {
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return Modifier.toString(method.getModifiers()) + " "
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    + method.getReturnType().getName() + " " + method.getName()
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    + Descriptor.toString(method.getSignature()) + ";";
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } catch (NotFoundException e) {
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e);
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Prints the instructions and the frame states of the given method.
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void print(CtMethod method) {
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        stream.println("\n" + getMethodString(method));
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodInfo info = method.getMethodInfo2();
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ConstPool pool = info.getConstPool();
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeAttribute code = info.getCodeAttribute();
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (code == null)
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return;
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Frame[] frames;
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            frames = (new Analyzer()).analyze(method.getDeclaringClass(), info);
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } catch (BadBytecode e) {
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException(e);
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int spacing = String.valueOf(code.getCodeLength()).length();
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeIterator iterator = code.iterator();
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (iterator.hasNext()) {
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int pos;
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                pos = iterator.next();
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            } catch (BadBytecode e) {
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new RuntimeException(e);
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            stream.println(pos + ": " + InstructionPrinter.instructionString(iterator, pos, pool));
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            addSpacing(spacing + 3);
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Frame frame = frames[pos];
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (frame == null) {
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                stream.println("--DEAD CODE--");
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                continue;
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            printStack(frame);
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            addSpacing(spacing + 3);
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            printLocals(frame);
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void printStack(Frame frame) {
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        stream.print("stack [");
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int top = frame.getTopIndex();
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i <= top; i++) {
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (i > 0)
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                stream.print(", ");
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Type type = frame.getStack(i);
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            stream.print(type);
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        stream.println("]");
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void printLocals(Frame frame) {
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        stream.print("locals [");
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int length = frame.localsLength();
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < length; i++) {
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (i > 0)
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                stream.print(", ");
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Type type = frame.getLocal(i);
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            stream.print(type == null ? "empty" : type.toString());
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        stream.println("]");
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void addSpacing(int count) {
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (count-- > 0)
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            stream.print(' ');
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
148