PageRenderTime 126ms CodeModel.GetById 70ms app.highlight 30ms RepoModel.GetById 20ms app.codeStats 0ms

/bundles/plugins-trunk/JavaInsight/javainsight/JasminVisitor.java

#
Java | 307 lines | 226 code | 61 blank | 20 comment | 42 complexity | 672b823d1e071d71d3f828662044ed1e MD5 | raw file
  1package javainsight;
  2
  3import java.io.*;
  4import java.util.*;
  5
  6import org.apache.bcel.classfile.Attribute;
  7import org.apache.bcel.classfile.ClassParser;
  8import org.apache.bcel.classfile.Code;
  9import org.apache.bcel.classfile.ConstantValue;
 10import org.apache.bcel.classfile.Deprecated;
 11import org.apache.bcel.classfile.ExceptionTable;
 12import org.apache.bcel.classfile.Field;
 13import org.apache.bcel.classfile.JavaClass;
 14import org.apache.bcel.classfile.Method;
 15import org.apache.bcel.classfile.Synthetic;
 16import org.apache.bcel.classfile.Utility;
 17import org.apache.bcel.generic.*;
 18import org.apache.bcel.Constants;
 19import org.apache.bcel.Repository;
 20
 21/**
 22 * Disassemble Java class object into the <A HREF="http://www.cat.nyu.edu/meyer/jasmin">
 23 * JASMIN</A> format.
 24 *
 25 * @version $Id: JasminVisitor.java 9456 2007-04-18 20:09:54Z dmoebius $
 26 * @author  <A HREF="http://www.berlin.de/~markus.dahm/">M. Dahm</A>
 27 */
 28public class JasminVisitor extends org.apache.bcel.classfile.EmptyVisitor
 29{
 30  private JavaClass       clazz;
 31  private PrintWriter     out;
 32  private String          class_name;
 33  private ConstantPoolGen cp;
 34
 35  public JasminVisitor(JavaClass clazz, Writer out) {
 36    this.clazz = clazz;
 37    this.out   = new PrintWriter(out);
 38    class_name = clazz.getClassName();
 39    cp = new ConstantPoolGen(clazz.getConstantPool());
 40  }
 41
 42  /**
 43   * Start traversal using DefaultVisitor pattern.
 44   */
 45  public void disassemble() {
 46    new org.apache.bcel.classfile.DescendingVisitor(clazz, this).visit();
 47    out.close();
 48  }
 49
 50  @Override
 51  public void visitJavaClass(JavaClass clazz) {
 52    out.println(";; Produced by JasminVisitor");
 53    out.println(";; http://jakarta.apache.org/bcel");
 54    out.println(";; " + new Date() + "\n");
 55
 56    out.println(".source " + clazz.getSourceFileName());
 57    out.println("." + Utility.classOrInterface(clazz.getAccessFlags()) + " " +
 58                Utility.accessToString(clazz.getAccessFlags(), true) +
 59                " " + clazz.getClassName().replace('.', '/'));
 60    out.println(".super " + clazz.getSuperclassName().replace('.', '/'));
 61
 62    String[] interfaces = clazz.getInterfaceNames();
 63
 64    for(int i=0; i < interfaces.length; i++)
 65      out.println(".implements " + interfaces[i].replace('.', '/'));
 66
 67    out.print("\n");
 68  }
 69
 70  @Override
 71  public void visitField(Field field) {
 72    out.print(".field " + Utility.accessToString(field.getAccessFlags()) +
 73                " " + field.getName() + " " + field.getSignature());
 74    if(field.getAttributes().length == 0)
 75      out.print("\n");
 76  }
 77
 78  @Override
 79  public void visitConstantValue(ConstantValue cv) {
 80    out.println(" = " + cv);
 81  }
 82
 83  private Method method;
 84
 85  /**
 86   * Unfortunately Jasmin expects ".end method" after each method. Thus we've to check
 87   * for every of the method's attributes if it's the last one and print ".end method"
 88   * then.
 89   */
 90  private final void printEndMethod(Attribute attr) {
 91    Attribute[] attributes = method.getAttributes();
 92
 93    if(attr == attributes[attributes.length - 1])
 94      out.println(".end method");
 95  }
 96
 97  @Override
 98  public void visitDeprecated(Deprecated attribute) {
 99    printEndMethod(attribute); 
100  }
101  
102  @Override
103  public void visitSynthetic(Synthetic attribute) {
104    printEndMethod(attribute); 
105  }
106
107  @Override
108  public void visitMethod(Method method) {
109    out.println("\n.method " + Utility.accessToString(method.getAccessFlags()) +
110                " " + method.getName() + method.getSignature());
111
112    this.method = method; // Remember for use in subsequent visitXXX calls
113
114    Attribute[] attributes = method.getAttributes();
115    if((attributes == null) || (attributes.length == 0))
116      out.println(".end method");
117  }
118
119  @Override
120  public void visitExceptionTable(ExceptionTable e) {
121    String[] names = e.getExceptionNames();
122    for(int i=0; i < names.length; i++)
123      out.println(".throws " + names[i].replace('.', '/'));
124
125    printEndMethod(e);
126  }
127
128  private HashMap<InstructionHandle,String> map;
129
130  @Override
131  public void visitCode(Code code) {
132    int label_counter = 0;
133
134    out.println(".limit stack " + code.getMaxStack());
135    out.println(".limit locals " + code.getMaxLocals());
136
137    MethodGen           mg  = new MethodGen(method, class_name, cp);
138    InstructionList     il  = mg.getInstructionList();
139    InstructionHandle[] ihs = il.getInstructionHandles();
140
141    /* Pass 1: Give all referenced instruction handles a symbolic name, i.e. a
142     * label.
143     */
144    map = new HashMap<InstructionHandle,String>();
145
146    for(int i=0; i < ihs.length; i++) {
147      if(ihs[i] instanceof BranchHandle) {
148        BranchInstruction bi = (BranchInstruction)ihs[i].getInstruction();
149
150        if(bi instanceof Select) { // Special cases LOOKUPSWITCH and TABLESWITCH
151          InstructionHandle[] targets = ((Select)bi).getTargets();
152
153          for(int j=0; j < targets.length; j++)
154            put(targets[j], "Label" + label_counter++ + ":");
155        }
156
157        InstructionHandle ih = bi.getTarget();
158        put(ih, "Label" + label_counter++ + ":");
159      }
160    }
161
162    LocalVariableGen[] lvs = mg.getLocalVariables();
163    for(int i=0; i < lvs.length; i++) {
164      InstructionHandle ih = lvs[i].getStart();
165      put(ih, "Label" + label_counter++ + ":");
166      ih = lvs[i].getEnd();
167      put(ih, "Label" + label_counter++ + ":");
168    }
169
170    CodeExceptionGen[] ehs = mg.getExceptionHandlers();
171    for(int i=0; i < ehs.length; i++) {
172      CodeExceptionGen  c  = ehs[i];
173      InstructionHandle ih = c.getStartPC();
174
175      put(ih, "Label" + label_counter++ + ":");
176      ih = c.getEndPC();
177      put(ih, "Label" + label_counter++ + ":");
178      ih = c.getHandlerPC();
179      put(ih, "Label" + label_counter++ + ":");
180    }
181
182    LineNumberGen[] lns = mg.getLineNumbers();
183    for(int i=0; i < lns.length; i++) {
184      InstructionHandle ih = lns[i].getInstruction();
185      put(ih, ".line " + lns[i].getSourceLine());
186    }
187
188    /* Pass 2: Output code.
189     */
190    for(int i=0; i < lvs.length; i++) {
191      LocalVariableGen l = lvs[i];
192      out.println(".var " + l.getIndex() + " is " + l.getName() + " " +
193                  l.getType().getSignature() +
194                  " from " + get(l.getStart()) +
195                  " to " + get(l.getEnd()));
196    }
197
198    out.print("\n");
199
200    for(int i=0; i < ihs.length; i++) {
201      InstructionHandle ih   = ihs[i];
202      Instruction       inst = ih.getInstruction();
203      String            str  = map.get(ih);
204
205      if(str != null)
206        out.println(str);
207
208      if(inst instanceof BranchInstruction) {
209        if(inst instanceof Select) { // Special cases LOOKUPSWITCH and TABLESWITCH
210          Select              s       = (Select)inst;
211          int[]               matchs  = s.getMatchs();
212          InstructionHandle[] targets = s.getTargets();
213
214          if(s instanceof TABLESWITCH) {
215            out.println("\ttableswitch " + matchs[0] + " " +
216                        matchs[matchs.length - 1]);
217
218            for(int j=0; j < targets.length; j++)
219              out.println("\t\t" + get(targets[j]));
220
221          } else { // LOOKUPSWITCH
222            out.println("\tlookupswitch ");
223
224            for(int j=0; j < targets.length; j++)
225              out.println("\t\t" + matchs[j] + " : " + get(targets[j]));
226          }
227
228          out.println("\t\tdefault: " + get(s.getTarget())); // Applies for both
229        } else {
230          BranchInstruction bi  = (BranchInstruction)inst;
231          ih  = bi.getTarget();
232          str = get(ih);
233          out.println("\t" + Constants.OPCODE_NAMES[bi.getOpcode()] + " " + str);
234        }
235      }
236      else
237        out.println("\t" + inst.toString(cp.getConstantPool()));
238    }
239
240    out.print("\n");
241
242    for(int i=0; i < ehs.length; i++) {
243      CodeExceptionGen c = ehs[i];
244      ObjectType caught = c.getCatchType();
245      String class_name = (caught == null)?  // catch any exception, used when compiling finally
246        "all" : caught.getClassName().replace('.', '/');
247
248      out.println(".catch " + class_name + " from " +
249                  get(c.getStartPC()) + " to " + get(c.getEndPC()) +
250                  " using " + get(c.getHandlerPC()));
251    }
252
253    printEndMethod(code);
254  }
255
256
257  private final String get(InstructionHandle ih) {
258    String str = new StringTokenizer(map.get(ih), "\n").nextToken();
259    return str.substring(0, str.length() - 1);
260  }
261
262  private final void put(InstructionHandle ih, String line) {
263    String str = map.get(ih);
264
265    if(str == null)
266      map.put(ih, line);
267    else {
268      if(line.startsWith("Label") || str.endsWith(line)) // Already have a label in the map
269        return;
270
271      map.put(ih, str + "\n" + line); // append
272    }
273  }
274
275  public static void main(String[] argv) {
276    JavaClass   java_class;
277
278    try {
279      if(argv.length == 0) {
280        System.err.println("disassemble: No input files specified");
281      }
282      else {
283        for(int i=0; i < argv.length; i++) {
284          if((java_class = Repository.lookupClass(argv[i])) == null)
285            java_class = new ClassParser(argv[i]).parse();
286
287          String class_name = java_class.getClassName();
288          int    index      = class_name.lastIndexOf('.');
289          String path       = class_name.substring(0, index + 1).replace('.', File.separatorChar);
290          class_name = class_name.substring(index + 1);
291
292          if(!path.equals("")) {
293            File f = new File(path);
294            f.mkdirs();
295          }
296
297          FileWriter out = new FileWriter(path + class_name + ".j");
298          new JasminVisitor(java_class, out).disassemble();
299        }
300      }
301    } catch(Exception e) {
302      e.printStackTrace();
303    }
304  }
305
306}
307