Home | History | Annotate | Download | only in analysis
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 package javassist.bytecode.analysis;
     16 
     17 import java.io.PrintStream;
     18 
     19 import javassist.CtClass;
     20 import javassist.CtMethod;
     21 import javassist.Modifier;
     22 import javassist.NotFoundException;
     23 import javassist.bytecode.BadBytecode;
     24 import javassist.bytecode.CodeAttribute;
     25 import javassist.bytecode.CodeIterator;
     26 import javassist.bytecode.ConstPool;
     27 import javassist.bytecode.Descriptor;
     28 import javassist.bytecode.InstructionPrinter;
     29 import javassist.bytecode.MethodInfo;
     30 
     31 /**
     32  * A utility class for printing a merged view of the frame state and the
     33  * instructions of a method.
     34  *
     35  * @author Jason T. Greene
     36  */
     37 public final class FramePrinter {
     38     private final PrintStream stream;
     39 
     40     /**
     41      * Constructs a bytecode printer.
     42      */
     43     public FramePrinter(PrintStream stream) {
     44         this.stream = stream;
     45     }
     46 
     47     /**
     48      * Prints all the methods declared in the given class.
     49      */
     50     public static void print(CtClass clazz, PrintStream stream) {
     51         (new FramePrinter(stream)).print(clazz);
     52     }
     53 
     54     /**
     55      * Prints all the methods declared in the given class.
     56      */
     57     public void print(CtClass clazz) {
     58         CtMethod[] methods = clazz.getDeclaredMethods();
     59         for (int i = 0; i < methods.length; i++) {
     60             print(methods[i]);
     61         }
     62     }
     63 
     64     private String getMethodString(CtMethod method) {
     65         try {
     66             return Modifier.toString(method.getModifiers()) + " "
     67                     + method.getReturnType().getName() + " " + method.getName()
     68                     + Descriptor.toString(method.getSignature()) + ";";
     69         } catch (NotFoundException e) {
     70             throw new RuntimeException(e);
     71         }
     72     }
     73 
     74     /**
     75      * Prints the instructions and the frame states of the given method.
     76      */
     77     public void print(CtMethod method) {
     78         stream.println("\n" + getMethodString(method));
     79         MethodInfo info = method.getMethodInfo2();
     80         ConstPool pool = info.getConstPool();
     81         CodeAttribute code = info.getCodeAttribute();
     82         if (code == null)
     83             return;
     84 
     85         Frame[] frames;
     86         try {
     87             frames = (new Analyzer()).analyze(method.getDeclaringClass(), info);
     88         } catch (BadBytecode e) {
     89             throw new RuntimeException(e);
     90         }
     91 
     92         int spacing = String.valueOf(code.getCodeLength()).length();
     93 
     94         CodeIterator iterator = code.iterator();
     95         while (iterator.hasNext()) {
     96             int pos;
     97             try {
     98                 pos = iterator.next();
     99             } catch (BadBytecode e) {
    100                 throw new RuntimeException(e);
    101             }
    102 
    103             stream.println(pos + ": " + InstructionPrinter.instructionString(iterator, pos, pool));
    104 
    105             addSpacing(spacing + 3);
    106             Frame frame = frames[pos];
    107             if (frame == null) {
    108                 stream.println("--DEAD CODE--");
    109                 continue;
    110             }
    111             printStack(frame);
    112 
    113             addSpacing(spacing + 3);
    114             printLocals(frame);
    115         }
    116 
    117     }
    118 
    119     private void printStack(Frame frame) {
    120         stream.print("stack [");
    121         int top = frame.getTopIndex();
    122         for (int i = 0; i <= top; i++) {
    123             if (i > 0)
    124                 stream.print(", ");
    125             Type type = frame.getStack(i);
    126             stream.print(type);
    127         }
    128         stream.println("]");
    129     }
    130 
    131     private void printLocals(Frame frame) {
    132         stream.print("locals [");
    133         int length = frame.localsLength();
    134         for (int i = 0; i < length; i++) {
    135             if (i > 0)
    136                 stream.print(", ");
    137             Type type = frame.getLocal(i);
    138             stream.print(type == null ? "empty" : type.toString());
    139         }
    140         stream.println("]");
    141     }
    142 
    143     private void addSpacing(int count) {
    144         while (count-- > 0)
    145             stream.print(' ');
    146     }
    147 }
    148