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