001    package serp.bytecode.visitor;
002    
003    import java.io.*;
004    
005    import serp.bytecode.*;
006    import 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     */
014    public 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    }