View Javadoc

1   package serp.bytecode.visitor;
2   
3   import java.io.*;
4   
5   import serp.bytecode.*;
6   import serp.bytecode.lowlevel.*;
7   
8   /**
9    * Visitor type that outputs a detailed, formatted document of the
10   * visited entity; similar to the <i>javap -c</i> command but more detailed.
11   *
12   * @author Abe White
13   */
14  public class PrettyPrintVisitor extends BCVisitor {
15      private PrintWriter _out = null;
16      private String _prefix = "";
17  
18      /**
19       * Constructor; all pritning will go to stdout.
20       */
21      public PrettyPrintVisitor() {
22          _out = new PrintWriter(System.out);
23      }
24  
25      /**
26       * Constructor.
27       *
28       * @param out the stream to print to
29       */
30      public PrettyPrintVisitor(PrintWriter out) {
31          _out = out;
32      }
33  
34      /**
35       * Invoke with the class or file names to pretty print; the
36       * functionality is similar to the <i>javap -c</i> command, but more
37       * detailed.
38       */
39      public static void main(String[] args)
40          throws ClassNotFoundException, IOException {
41          if (args.length == 0) {
42              System.err.println("Usage: java " 
43                  + PrettyPrintVisitor.class.getName() 
44                  + " <class name | .class file>+");
45              System.exit(1);
46          }
47  
48          PrettyPrintVisitor ppv = new PrettyPrintVisitor();
49          Project project = new Project();
50          BCClass type;
51          for (int i = 0; i < args.length; i++) {
52              if (args[i].endsWith(".class"))
53                  type = project.loadClass(new File(args[i]));
54              else
55                  type = project.loadClass(Class.forName(args[i], false, 
56                      PrettyPrintVisitor.class.getClassLoader()));
57              ppv.visit(type);
58          }
59      }
60  
61      public void visit(VisitAcceptor entity) {
62          super.visit(entity);
63          _out.flush();
64      }
65  
66      public void enterProject(Project obj) {
67          openBlock("Project");
68          println("name=" + obj.getName());
69      }
70  
71      public void exitProject(Project obj) {
72          closeBlock();
73      }
74  
75      public void enterBCClass(BCClass obj) {
76          openBlock("Class");
77  
78          println("magic=" + obj.getMagic());
79          println("minor=" + obj.getMinorVersion());
80          println("major=" + obj.getMajorVersion());
81          println("access=" + obj.getAccessFlags());
82          println("name=" + obj.getIndex() + " <" + obj.getName() + ">");
83          println("super=" + obj.getSuperclassIndex() + " <" +
84              obj.getSuperclassName() + ">");
85  
86          int[] indexes = obj.getDeclaredInterfaceIndexes();
87          String[] names = obj.getDeclaredInterfaceNames();
88          for (int i = 0; i < indexes.length; i++)
89              println("interface=" + indexes[i] + " <" + names[i] + ">");
90      }
91  
92      public void exitBCClass(BCClass obj) {
93          closeBlock();
94      }
95  
96      public void enterBCField(BCField obj) {
97          openBlock("Field");
98          println("access=" + obj.getAccessFlags());
99          println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">");
100         println("type=" + obj.getDescriptorIndex() + " <" + obj.getTypeName() 
101             + ">");
102     }
103 
104     public void exitBCField(BCField obj) {
105         closeBlock();
106     }
107 
108     public void enterBCMethod(BCMethod obj) {
109         openBlock("Method");
110         println("access=" + obj.getAccessFlags());
111         println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">");
112         println("descriptor=" + obj.getDescriptorIndex());
113         println("return=" + obj.getReturnName());
114         String[] params = obj.getParamNames();
115         for (int i = 0; i < params.length; i++)
116             println("param=" + params[i]);
117     }
118 
119     public void exitBCMethod(BCMethod obj) {
120         closeBlock();
121     }
122 
123     public void enterAttribute(Attribute obj) {
124         openBlock(obj.getName());
125     }
126 
127     public void exitAttribute(Attribute obj) {
128         closeBlock();
129     }
130 
131     public void enterConstantValue(ConstantValue obj) {
132         println("value=" + obj.getValueIndex() + " <" + obj.getTypeName() +
133             "=" + obj.getValue() + ">");
134     }
135 
136     public void enterExceptions(Exceptions obj) {
137         int[] indexes = obj.getExceptionIndexes();
138         String[] names = obj.getExceptionNames();
139         for (int i = 0; i < indexes.length; i++)
140             println("exception=" + indexes[i] + " <" + names[i] + ">");
141     }
142 
143     public void enterSourceFile(SourceFile obj) {
144         println("source=" + obj.getFileIndex() + " <" + obj.getFileName() 
145             + ">");
146     }
147 
148     public void enterCode(Code obj) {
149         println("maxStack=" + obj.getMaxStack());
150         println("maxLocals=" + obj.getMaxLocals());
151         println("");
152     }
153 
154     public void enterExceptionHandler(ExceptionHandler obj) {
155         openBlock("ExceptionHandler");
156         println("startPc=" + obj.getTryStartPc());
157         println("endPc=" + obj.getTryEndPc());
158         println("handlerPc=" + obj.getHandlerStartPc());
159         println("catch=" + obj.getCatchIndex() + " <" + obj.getCatchName() 
160             + ">");
161     }
162 
163     public void exitExceptionHandler(ExceptionHandler obj) {
164         closeBlock();
165     }
166 
167     public void enterInnerClass(InnerClass obj) {
168         openBlock("InnerClass");
169         println("access=" + obj.getAccessFlags());
170         println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">");
171         println("type=" + obj.getTypeIndex() + "<" + obj.getTypeName() + ">");
172         println("declarer=" + obj.getDeclarerIndex() + "<" 
173             + obj.getDeclarerName() + ">");
174     }
175 
176     public void exitInnerClass(InnerClass obj) {
177         closeBlock();
178     }
179 
180     public void enterLineNumber(LineNumber obj) {
181         openBlock("LineNumber");
182         println("startPc=" + obj.getStartPc());
183         println("line=" + obj.getLine());
184     }
185 
186     public void exitLineNumber(LineNumber obj) {
187         closeBlock();
188     }
189 
190     public void enterLocalVariable(LocalVariable obj) {
191         openBlock("LocalVariable");
192         println("startPc=" + obj.getStartPc());
193         println("length=" + obj.getLength());
194         println("local=" + obj.getLocal());
195         println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">");
196         println("type=" + obj.getTypeIndex() + " <" + obj.getTypeName() + ">");
197     }
198 
199     public void exitLocalVariable(LocalVariable obj) {
200         closeBlock();
201     }
202 
203     public void enterLocalVariableType(LocalVariableType obj) {
204         openBlock("LocalVariableType");
205         println("startPc=" + obj.getStartPc());
206         println("length=" + obj.getLength());
207         println("local=" + obj.getLocal());
208         println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">");
209         println("signature=" + obj.getTypeIndex() + " <" + obj.getTypeName() 
210             + ">");
211     }
212 
213     public void exitLocalVariableType(LocalVariableType obj) {
214         closeBlock();
215     }
216 
217     public void enterAnnotation(Annotation obj) {
218         openBlock("Annotation");
219         println("type=" + obj.getTypeIndex() + " <" + obj.getTypeName() + ">");
220     }
221 
222     public void exitAnnotation(Annotation obj) {
223         closeBlock();
224     }
225 
226     public void enterAnnotationProperty(Annotation.Property obj) {
227         openBlock("Property");
228         println("name=" + obj.getNameIndex() + " <" + obj.getName() + ">");
229         Object val = obj.getValue();
230         if (val instanceof Object[]) {
231             Object[] arr = (Object[]) val;
232             for (int i = 0; i < arr.length; i++)
233                 printAnnotationPropertyValue(arr[i]);
234         } else
235             printAnnotationPropertyValue(val);
236     }
237 
238     private void printAnnotationPropertyValue(Object obj) {
239         if (obj == null)
240             println("value=null");
241         else if (obj instanceof Annotation) {
242             _out.print(_prefix);
243             _out.print("value=");
244             ((Annotation) obj).acceptVisit(this);
245         } else
246             println("value=(" + obj.getClass().getName() + ") " + obj);
247     }
248 
249     public void exitAnnotationProperty(Annotation.Property obj) {
250         closeBlock();
251     }
252 
253     public void enterInstruction(Instruction obj) {
254         _out.print(_prefix + obj.getByteIndex() + " " + obj.getName() + " ");
255     }
256 
257     public void exitInstruction(Instruction obj) {
258         _out.println();
259     }
260 
261     public void enterClassInstruction(ClassInstruction obj) {
262         _out.print(obj.getTypeIndex() + " <" + obj.getTypeName() + ">");
263     }
264 
265     public void enterConstantInstruction(ConstantInstruction obj) {
266         _out.print("<" + obj.getValue() + ">");
267     }
268 
269     public void enterGetFieldInstruction(GetFieldInstruction obj) {
270         _out.print(obj.getFieldIndex() + " <" + obj.getFieldTypeName() + " " 
271             + obj.getFieldDeclarerName() + "." + obj.getFieldName() + ">");
272     }
273 
274     public void enterIIncInstruction(IIncInstruction obj) {
275         _out.print(obj.getLocal() + " ");
276         if (obj.getIncrement() < 0)
277             _out.print("-");
278         _out.print(obj.getIncrement());
279     }
280 
281     public void enterJumpInstruction(JumpInstruction obj) {
282         _out.print(obj.getOffset());
283     }
284 
285     public void enterIfInstruction(IfInstruction obj) {
286         _out.print(obj.getOffset());
287     }
288 
289     public void enterLoadInstruction(LoadInstruction obj) {
290         _out.print("<" + obj.getLocal() + ">");
291     }
292 
293     public void enterLookupSwitchInstruction(LookupSwitchInstruction obj) {
294         _out.println();
295         _prefix += "  ";
296 
297         int[] offsets = obj.getOffsets();
298         int[] matches = obj.getMatches();
299         for (int i = 0; i < offsets.length; i++)
300             println("case " + matches[i] + "=" + offsets[i]);
301         _out.print(_prefix + "default=" + obj.getDefaultOffset());
302         _prefix = _prefix.substring(2);
303     }
304 
305     public void enterMethodInstruction(MethodInstruction obj) {
306         _out.print(obj.getMethodIndex() + " <" + obj.getMethodReturnName() 
307             + " " + obj.getMethodDeclarerName() + "." + obj.getMethodName() 
308             + "(");
309 
310         String[] params = obj.getMethodParamNames();
311         int dotIndex;
312         for (int i = 0; i < params.length; i++) {
313             dotIndex = params[i].lastIndexOf('.');
314             if (dotIndex != -1)
315                 params[i] = params[i].substring(dotIndex + 1);
316 
317             _out.print(params[i]);
318             if (i != (params.length - 1))
319                 _out.print(", ");
320         }
321         _out.print(")>");
322     }
323 
324     public void enterMultiANewArrayInstruction(MultiANewArrayInstruction obj) {
325         _out.print(obj.getTypeIndex() + " " + obj.getDimensions() + " <" 
326             + obj.getTypeName());
327         String post = "";
328         for (int i = 0; i < obj.getDimensions(); i++)
329             post += "[]";
330         _out.print(post + ">");
331     }
332 
333     public void enterNewArrayInstruction(NewArrayInstruction obj) {
334         _out.print(obj.getTypeCode() + " <" + obj.getTypeName() + "[]>");
335     }
336 
337     public void enterPutFieldInstruction(PutFieldInstruction obj) {
338         _out.print(obj.getFieldIndex() + " <" + obj.getFieldTypeName() + " " 
339             + obj.getFieldDeclarerName() + "." + obj.getFieldName() + ">");
340     }
341 
342     public void enterRetInstruction(RetInstruction obj) {
343         _out.print(obj.getLocal());
344     }
345 
346     public void enterStoreInstruction(StoreInstruction obj) {
347         _out.print("<" + obj.getLocal() + ">");
348     }
349 
350     public void enterTableSwitchInstruction(TableSwitchInstruction obj) {
351         _out.println();
352         _prefix += "  ";
353 
354         println("low=" + obj.getLow());
355         println("high=" + obj.getHigh());
356         int[] offsets = obj.getOffsets();
357         for (int i = 0; i < offsets.length; i++)
358             println("case=" + offsets[i]);
359         _out.print(_prefix + "default=" + obj.getDefaultOffset());
360         _prefix = _prefix.substring(2);
361     }
362 
363     public void enterWideInstruction(WideInstruction obj) {
364         int ins = obj.getInstruction();
365         _out.print(ins + " <" + Constants.OPCODE_NAMES[ins] + ">");
366     }
367 
368     public void enterConstantPool(ConstantPool obj) {
369         openBlock("ConstantPool");
370     }
371 
372     public void exitConstantPool(ConstantPool obj) {
373         closeBlock();
374     }
375 
376     public void enterEntry(Entry obj) {
377         String name = obj.getClass().getName();
378         openBlock(obj.getIndex() + ": " 
379             + name.substring(name.lastIndexOf('.') + 1));
380     }
381 
382     public void exitEntry(Entry obj) {
383         closeBlock();
384     }
385 
386     public void enterClassEntry(ClassEntry obj) {
387         println("name=" + obj.getNameIndex());
388     }
389 
390     public void enterDoubleEntry(DoubleEntry obj) {
391         println("value=" + obj.getValue());
392     }
393 
394     public void enterFieldEntry(FieldEntry obj) {
395         println("class=" + obj.getClassIndex());
396         println("nameAndType=" + obj.getNameAndTypeIndex());
397     }
398 
399     public void enterFloatEntry(FloatEntry obj) {
400         println("value=" + obj.getValue());
401     }
402 
403     public void enterIntEntry(IntEntry obj) {
404         println("value=" + obj.getValue());
405     }
406 
407     public void enterInterfaceMethodEntry(InterfaceMethodEntry obj) {
408         println("class=" + obj.getClassIndex());
409         println("nameAndType=" + obj.getNameAndTypeIndex());
410     }
411 
412     public void enterLongEntry(LongEntry obj) {
413         println("value=" + obj.getValue());
414     }
415 
416     public void enterMethodEntry(MethodEntry obj) {
417         println("class=" + obj.getClassIndex());
418         println("nameAndType=" + obj.getNameAndTypeIndex());
419     }
420 
421     public void enterNameAndTypeEntry(NameAndTypeEntry obj) {
422         println("name=" + obj.getNameIndex());
423         println("descriptor=" + obj.getDescriptorIndex());
424     }
425 
426     public void enterStringEntry(StringEntry obj) {
427         println("index=" + obj.getStringIndex());
428     }
429 
430     public void enterUTF8Entry(UTF8Entry obj) {
431         println("value=" + obj.getValue());
432     }
433 
434     private void println(String ln) {
435         _out.print(_prefix);
436         _out.println(ln);
437     }
438 
439     private void openBlock(String name) {
440         println(name + " {");
441         _prefix += "  ";
442     }
443 
444     private void closeBlock() {
445         _prefix = _prefix.substring(2);
446         println("}");
447     }
448 }