001package serp.bytecode.visitor;
002
003import java.io.*;
004
005import serp.bytecode.*;
006import serp.bytecode.lowlevel.*;
007
008/**
009 * Visitor type that outputs a detailed, formatted document of the
010 * visited entity; similar to the <i>javap -c</i> command but more detailed.
011 *
012 * @author Abe White
013 */
014public class PrettyPrintVisitor extends BCVisitor {
015    private PrintWriter _out = null;
016    private String _prefix = "";
017
018    /**
019     * Constructor; all pritning will go to stdout.
020     */
021    public PrettyPrintVisitor() {
022        _out = new PrintWriter(System.out);
023    }
024
025    /**
026     * Constructor.
027     *
028     * @param out the stream to print to
029     */
030    public PrettyPrintVisitor(PrintWriter out) {
031        _out = out;
032    }
033
034    /**
035     * Invoke with the class or file names to pretty print; the
036     * functionality is similar to the <i>javap -c</i> command, but more
037     * detailed.
038     */
039    public static void main(String[] args)
040        throws ClassNotFoundException, IOException {
041        if (args.length == 0) {
042            System.err.println("Usage: java " 
043                + PrettyPrintVisitor.class.getName() 
044                + " <class name | .class file>+");
045            System.exit(1);
046        }
047
048        PrettyPrintVisitor ppv = new PrettyPrintVisitor();
049        Project project = new Project();
050        BCClass type;
051        for (int i = 0; i < args.length; i++) {
052            if (args[i].endsWith(".class"))
053                type = project.loadClass(new File(args[i]));
054            else
055                type = project.loadClass(Class.forName(args[i], false, 
056                    PrettyPrintVisitor.class.getClassLoader()));
057            ppv.visit(type);
058        }
059    }
060
061    public void visit(VisitAcceptor entity) {
062        super.visit(entity);
063        _out.flush();
064    }
065
066    public void enterProject(Project obj) {
067        openBlock("Project");
068        println("name=" + obj.getName());
069    }
070
071    public void exitProject(Project obj) {
072        closeBlock();
073    }
074
075    public void enterBCClass(BCClass obj) {
076        openBlock("Class");
077
078        println("magic=" + obj.getMagic());
079        println("minor=" + obj.getMinorVersion());
080        println("major=" + obj.getMajorVersion());
081        println("access=" + obj.getAccessFlags());
082        println("name=" + obj.getIndex() + " <" + obj.getName() + ">");
083        println("super=" + obj.getSuperclassIndex() + " <" +
084            obj.getSuperclassName() + ">");
085
086        int[] indexes = obj.getDeclaredInterfaceIndexes();
087        String[] names = obj.getDeclaredInterfaceNames();
088        for (int i = 0; i < indexes.length; i++)
089            println("interface=" + indexes[i] + " <" + names[i] + ">");
090    }
091
092    public void exitBCClass(BCClass obj) {
093        closeBlock();
094    }
095
096    public void enterBCField(BCField obj) {
097        openBlock("Field");
098        println("access=" + obj.getAccessFlags());
099        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}