1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * This file is available under and governed by the GNU General Public
27  * License version 2 only, as published by the Free Software Foundation.
28  * However, the following notice accompanied the original version of this
29  * file:
30  *
31  * ASM: a very small and fast Java bytecode manipulation framework
32  * Copyright (c) 2000-2011 INRIA, France Telecom
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  * 3. Neither the name of the copyright holders nor the names of its
44  *    contributors may be used to endorse or promote products derived from
45  *    this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57  * THE POSSIBILITY OF SUCH DAMAGE.
58  */
59 package jdk.internal.org.objectweb.asm.util;
60 
61 import java.io.FileInputStream;
62 import java.io.PrintWriter;
63 import java.util.HashMap;
64 import java.util.Map;
65 
66 import jdk.internal.org.objectweb.asm.Attribute;
67 import jdk.internal.org.objectweb.asm.ClassReader;
68 import jdk.internal.org.objectweb.asm.Handle;
69 import jdk.internal.org.objectweb.asm.Label;
70 import jdk.internal.org.objectweb.asm.Opcodes;
71 import jdk.internal.org.objectweb.asm.Type;
72 import jdk.internal.org.objectweb.asm.TypePath;
73 import jdk.internal.org.objectweb.asm.TypeReference;
74 import jdk.internal.org.objectweb.asm.signature.SignatureReader;
75 
76 /**
77  * A {@link Printer} that prints a disassembled view of the classes it visits.
78  *
79  * @author Eric Bruneton
80  */
81 public class Textifier extends Printer {
82 
83     /**
84      * Constant used in {@link #appendDescriptor appendDescriptor} for internal
85      * type names in bytecode notation.
86      */
87     public static final int INTERNAL_NAME = 0;
88 
89     /**
90      * Constant used in {@link #appendDescriptor appendDescriptor} for field
91      * descriptors, formatted in bytecode notation
92      */
93     public static final int FIELD_DESCRIPTOR = 1;
94 
95     /**
96      * Constant used in {@link #appendDescriptor appendDescriptor} for field
97      * signatures, formatted in bytecode notation
98      */
99     public static final int FIELD_SIGNATURE = 2;
100 
101     /**
102      * Constant used in {@link #appendDescriptor appendDescriptor} for method
103      * descriptors, formatted in bytecode notation
104      */
105     public static final int METHOD_DESCRIPTOR = 3;
106 
107     /**
108      * Constant used in {@link #appendDescriptor appendDescriptor} for method
109      * signatures, formatted in bytecode notation
110      */
111     public static final int METHOD_SIGNATURE = 4;
112 
113     /**
114      * Constant used in {@link #appendDescriptor appendDescriptor} for class
115      * signatures, formatted in bytecode notation
116      */
117     public static final int CLASS_SIGNATURE = 5;
118 
119     /**
120      * Constant used in {@link #appendDescriptor appendDescriptor} for field or
121      * method return value signatures, formatted in default Java notation
122      * (non-bytecode)
123      */
124     public static final int TYPE_DECLARATION = 6;
125 
126     /**
127      * Constant used in {@link #appendDescriptor appendDescriptor} for class
128      * signatures, formatted in default Java notation (non-bytecode)
129      */
130     public static final int CLASS_DECLARATION = 7;
131 
132     /**
133      * Constant used in {@link #appendDescriptor appendDescriptor} for method
134      * parameter signatures, formatted in default Java notation (non-bytecode)
135      */
136     public static final int PARAMETERS_DECLARATION = 8;
137 
138     /**
139      * Constant used in {@link #appendDescriptor appendDescriptor} for handle
140      * descriptors, formatted in bytecode notation
141      */
142     public static final int HANDLE_DESCRIPTOR = 9;
143 
144     /**
145      * Tab for class members.
146      */
147     protected String tab = "  ";
148 
149     /**
150      * Tab for bytecode instructions.
151      */
152     protected String tab2 = "    ";
153 
154     /**
155      * Tab for table and lookup switch instructions.
156      */
157     protected String tab3 = "      ";
158 
159     /**
160      * Tab for labels.
161      */
162     protected String ltab = "   ";
163 
164     /**
165      * The label names. This map associate String values to Label keys.
166      */
167     protected Map<Label, String> labelNames;
168 
169     /**
170      * Class access flags
171      */
172     private int access;
173 
174     private int valueNumber = 0;
175 
176     /**
177      * Constructs a new {@link Textifier}. <i>Subclasses must not use this
178      * constructor</i>. Instead, they must use the {@link #Textifier(int)}
179      * version.
180      *
181      * @throws IllegalStateException
182      *             If a subclass calls this constructor.
183      */
Textifier()184     public Textifier() {
185         this(Opcodes.ASM5);
186         if (getClass() != Textifier.class) {
187             throw new IllegalStateException();
188         }
189     }
190 
191     /**
192      * Constructs a new {@link Textifier}.
193      *
194      * @param api
195      *            the ASM API version implemented by this visitor. Must be one
196      *            of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
197      */
Textifier(final int api)198     protected Textifier(final int api) {
199         super(api);
200     }
201 
202     /**
203      * Prints a disassembled view of the given class to the standard output.
204      * <p>
205      * Usage: Textifier [-debug] &lt;binary class name or class file name &gt;
206      *
207      * @param args
208      *            the command line arguments.
209      *
210      * @throws Exception
211      *             if the class cannot be found, or if an IO exception occurs.
212      */
main(final String[] args)213     public static void main(final String[] args) throws Exception {
214         int i = 0;
215         int flags = ClassReader.SKIP_DEBUG;
216 
217         boolean ok = true;
218         if (args.length < 1 || args.length > 2) {
219             ok = false;
220         }
221         if (ok && "-debug".equals(args[0])) {
222             i = 1;
223             flags = 0;
224             if (args.length != 2) {
225                 ok = false;
226             }
227         }
228         if (!ok) {
229             System.err
230                     .println("Prints a disassembled view of the given class.");
231             System.err.println("Usage: Textifier [-debug] "
232                     + "<fully qualified class name or class file name>");
233             return;
234         }
235         ClassReader cr;
236         if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
237                 || args[i].indexOf('/') > -1) {
238             cr = new ClassReader(new FileInputStream(args[i]));
239         } else {
240             cr = new ClassReader(args[i]);
241         }
242         cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), flags);
243     }
244 
245     // ------------------------------------------------------------------------
246     // Classes
247     // ------------------------------------------------------------------------
248 
249     @Override
visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)250     public void visit(final int version, final int access, final String name,
251             final String signature, final String superName,
252             final String[] interfaces) {
253         this.access = access;
254         int major = version & 0xFFFF;
255         int minor = version >>> 16;
256         buf.setLength(0);
257         buf.append("// class version ").append(major).append('.').append(minor)
258                 .append(" (").append(version).append(")\n");
259         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
260             buf.append("// DEPRECATED\n");
261         }
262         buf.append("// access flags 0x")
263                 .append(Integer.toHexString(access).toUpperCase()).append('\n');
264 
265         appendDescriptor(CLASS_SIGNATURE, signature);
266         if (signature != null) {
267             TraceSignatureVisitor sv = new TraceSignatureVisitor(access);
268             SignatureReader r = new SignatureReader(signature);
269             r.accept(sv);
270             buf.append("// declaration: ").append(name)
271                     .append(sv.getDeclaration()).append('\n');
272         }
273 
274         appendAccess(access & ~Opcodes.ACC_SUPER);
275         if ((access & Opcodes.ACC_ANNOTATION) != 0) {
276             buf.append("@interface ");
277         } else if ((access & Opcodes.ACC_INTERFACE) != 0) {
278             buf.append("interface ");
279         } else if ((access & Opcodes.ACC_ENUM) == 0) {
280             buf.append("class ");
281         }
282         appendDescriptor(INTERNAL_NAME, name);
283 
284         if (superName != null && !"java/lang/Object".equals(superName)) {
285             buf.append(" extends ");
286             appendDescriptor(INTERNAL_NAME, superName);
287             buf.append(' ');
288         }
289         if (interfaces != null && interfaces.length > 0) {
290             buf.append(" implements ");
291             for (int i = 0; i < interfaces.length; ++i) {
292                 appendDescriptor(INTERNAL_NAME, interfaces[i]);
293                 buf.append(' ');
294             }
295         }
296         buf.append(" {\n\n");
297 
298         text.add(buf.toString());
299     }
300 
301     @Override
visitSource(final String file, final String debug)302     public void visitSource(final String file, final String debug) {
303         buf.setLength(0);
304         if (file != null) {
305             buf.append(tab).append("// compiled from: ").append(file)
306                     .append('\n');
307         }
308         if (debug != null) {
309             buf.append(tab).append("// debug info: ").append(debug)
310                     .append('\n');
311         }
312         if (buf.length() > 0) {
313             text.add(buf.toString());
314         }
315     }
316 
317     @Override
visitOuterClass(final String owner, final String name, final String desc)318     public void visitOuterClass(final String owner, final String name,
319             final String desc) {
320         buf.setLength(0);
321         buf.append(tab).append("OUTERCLASS ");
322         appendDescriptor(INTERNAL_NAME, owner);
323         buf.append(' ');
324         if (name != null) {
325             buf.append(name).append(' ');
326         }
327         appendDescriptor(METHOD_DESCRIPTOR, desc);
328         buf.append('\n');
329         text.add(buf.toString());
330     }
331 
332     @Override
visitClassAnnotation(final String desc, final boolean visible)333     public Textifier visitClassAnnotation(final String desc,
334             final boolean visible) {
335         text.add("\n");
336         return visitAnnotation(desc, visible);
337     }
338 
339     @Override
visitClassTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible)340     public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath,
341             String desc, boolean visible) {
342         text.add("\n");
343         return visitTypeAnnotation(typeRef, typePath, desc, visible);
344     }
345 
346     @Override
visitClassAttribute(final Attribute attr)347     public void visitClassAttribute(final Attribute attr) {
348         text.add("\n");
349         visitAttribute(attr);
350     }
351 
352     @Override
visitInnerClass(final String name, final String outerName, final String innerName, final int access)353     public void visitInnerClass(final String name, final String outerName,
354             final String innerName, final int access) {
355         buf.setLength(0);
356         buf.append(tab).append("// access flags 0x");
357         buf.append(
358                 Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase())
359                 .append('\n');
360         buf.append(tab);
361         appendAccess(access);
362         buf.append("INNERCLASS ");
363         appendDescriptor(INTERNAL_NAME, name);
364         buf.append(' ');
365         appendDescriptor(INTERNAL_NAME, outerName);
366         buf.append(' ');
367         appendDescriptor(INTERNAL_NAME, innerName);
368         buf.append('\n');
369         text.add(buf.toString());
370     }
371 
372     @Override
visitField(final int access, final String name, final String desc, final String signature, final Object value)373     public Textifier visitField(final int access, final String name,
374             final String desc, final String signature, final Object value) {
375         buf.setLength(0);
376         buf.append('\n');
377         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
378             buf.append(tab).append("// DEPRECATED\n");
379         }
380         buf.append(tab).append("// access flags 0x")
381                 .append(Integer.toHexString(access).toUpperCase()).append('\n');
382         if (signature != null) {
383             buf.append(tab);
384             appendDescriptor(FIELD_SIGNATURE, signature);
385 
386             TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
387             SignatureReader r = new SignatureReader(signature);
388             r.acceptType(sv);
389             buf.append(tab).append("// declaration: ")
390                     .append(sv.getDeclaration()).append('\n');
391         }
392 
393         buf.append(tab);
394         appendAccess(access);
395 
396         appendDescriptor(FIELD_DESCRIPTOR, desc);
397         buf.append(' ').append(name);
398         if (value != null) {
399             buf.append(" = ");
400             if (value instanceof String) {
401                 buf.append('\"').append(value).append('\"');
402             } else {
403                 buf.append(value);
404             }
405         }
406 
407         buf.append('\n');
408         text.add(buf.toString());
409 
410         Textifier t = createTextifier();
411         text.add(t.getText());
412         return t;
413     }
414 
415     @Override
visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions)416     public Textifier visitMethod(final int access, final String name,
417             final String desc, final String signature, final String[] exceptions) {
418         buf.setLength(0);
419         buf.append('\n');
420         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
421             buf.append(tab).append("// DEPRECATED\n");
422         }
423         buf.append(tab).append("// access flags 0x")
424                 .append(Integer.toHexString(access).toUpperCase()).append('\n');
425 
426         if (signature != null) {
427             buf.append(tab);
428             appendDescriptor(METHOD_SIGNATURE, signature);
429 
430             TraceSignatureVisitor v = new TraceSignatureVisitor(0);
431             SignatureReader r = new SignatureReader(signature);
432             r.accept(v);
433             String genericDecl = v.getDeclaration();
434             String genericReturn = v.getReturnType();
435             String genericExceptions = v.getExceptions();
436 
437             buf.append(tab).append("// declaration: ").append(genericReturn)
438                     .append(' ').append(name).append(genericDecl);
439             if (genericExceptions != null) {
440                 buf.append(" throws ").append(genericExceptions);
441             }
442             buf.append('\n');
443         }
444 
445         buf.append(tab);
446         appendAccess(access & ~Opcodes.ACC_VOLATILE);
447         if ((access & Opcodes.ACC_NATIVE) != 0) {
448             buf.append("native ");
449         }
450         if ((access & Opcodes.ACC_VARARGS) != 0) {
451             buf.append("varargs ");
452         }
453         if ((access & Opcodes.ACC_BRIDGE) != 0) {
454             buf.append("bridge ");
455         }
456         if ((this.access & Opcodes.ACC_INTERFACE) != 0
457                 && (access & Opcodes.ACC_ABSTRACT) == 0
458                 && (access & Opcodes.ACC_STATIC) == 0) {
459             buf.append("default ");
460         }
461 
462         buf.append(name);
463         appendDescriptor(METHOD_DESCRIPTOR, desc);
464         if (exceptions != null && exceptions.length > 0) {
465             buf.append(" throws ");
466             for (int i = 0; i < exceptions.length; ++i) {
467                 appendDescriptor(INTERNAL_NAME, exceptions[i]);
468                 buf.append(' ');
469             }
470         }
471 
472         buf.append('\n');
473         text.add(buf.toString());
474 
475         Textifier t = createTextifier();
476         text.add(t.getText());
477         return t;
478     }
479 
480     @Override
visitClassEnd()481     public void visitClassEnd() {
482         text.add("}\n");
483     }
484 
485     // ------------------------------------------------------------------------
486     // Annotations
487     // ------------------------------------------------------------------------
488 
489     @Override
visit(final String name, final Object value)490     public void visit(final String name, final Object value) {
491         buf.setLength(0);
492         appendComa(valueNumber++);
493 
494         if (name != null) {
495             buf.append(name).append('=');
496         }
497 
498         if (value instanceof String) {
499             visitString((String) value);
500         } else if (value instanceof Type) {
501             visitType((Type) value);
502         } else if (value instanceof Byte) {
503             visitByte(((Byte) value).byteValue());
504         } else if (value instanceof Boolean) {
505             visitBoolean(((Boolean) value).booleanValue());
506         } else if (value instanceof Short) {
507             visitShort(((Short) value).shortValue());
508         } else if (value instanceof Character) {
509             visitChar(((Character) value).charValue());
510         } else if (value instanceof Integer) {
511             visitInt(((Integer) value).intValue());
512         } else if (value instanceof Float) {
513             visitFloat(((Float) value).floatValue());
514         } else if (value instanceof Long) {
515             visitLong(((Long) value).longValue());
516         } else if (value instanceof Double) {
517             visitDouble(((Double) value).doubleValue());
518         } else if (value.getClass().isArray()) {
519             buf.append('{');
520             if (value instanceof byte[]) {
521                 byte[] v = (byte[]) value;
522                 for (int i = 0; i < v.length; i++) {
523                     appendComa(i);
524                     visitByte(v[i]);
525                 }
526             } else if (value instanceof boolean[]) {
527                 boolean[] v = (boolean[]) value;
528                 for (int i = 0; i < v.length; i++) {
529                     appendComa(i);
530                     visitBoolean(v[i]);
531                 }
532             } else if (value instanceof short[]) {
533                 short[] v = (short[]) value;
534                 for (int i = 0; i < v.length; i++) {
535                     appendComa(i);
536                     visitShort(v[i]);
537                 }
538             } else if (value instanceof char[]) {
539                 char[] v = (char[]) value;
540                 for (int i = 0; i < v.length; i++) {
541                     appendComa(i);
542                     visitChar(v[i]);
543                 }
544             } else if (value instanceof int[]) {
545                 int[] v = (int[]) value;
546                 for (int i = 0; i < v.length; i++) {
547                     appendComa(i);
548                     visitInt(v[i]);
549                 }
550             } else if (value instanceof long[]) {
551                 long[] v = (long[]) value;
552                 for (int i = 0; i < v.length; i++) {
553                     appendComa(i);
554                     visitLong(v[i]);
555                 }
556             } else if (value instanceof float[]) {
557                 float[] v = (float[]) value;
558                 for (int i = 0; i < v.length; i++) {
559                     appendComa(i);
560                     visitFloat(v[i]);
561                 }
562             } else if (value instanceof double[]) {
563                 double[] v = (double[]) value;
564                 for (int i = 0; i < v.length; i++) {
565                     appendComa(i);
566                     visitDouble(v[i]);
567                 }
568             }
569             buf.append('}');
570         }
571 
572         text.add(buf.toString());
573     }
574 
visitInt(final int value)575     private void visitInt(final int value) {
576         buf.append(value);
577     }
578 
visitLong(final long value)579     private void visitLong(final long value) {
580         buf.append(value).append('L');
581     }
582 
visitFloat(final float value)583     private void visitFloat(final float value) {
584         buf.append(value).append('F');
585     }
586 
visitDouble(final double value)587     private void visitDouble(final double value) {
588         buf.append(value).append('D');
589     }
590 
visitChar(final char value)591     private void visitChar(final char value) {
592         buf.append("(char)").append((int) value);
593     }
594 
visitShort(final short value)595     private void visitShort(final short value) {
596         buf.append("(short)").append(value);
597     }
598 
visitByte(final byte value)599     private void visitByte(final byte value) {
600         buf.append("(byte)").append(value);
601     }
602 
visitBoolean(final boolean value)603     private void visitBoolean(final boolean value) {
604         buf.append(value);
605     }
606 
visitString(final String value)607     private void visitString(final String value) {
608         appendString(buf, value);
609     }
610 
visitType(final Type value)611     private void visitType(final Type value) {
612         buf.append(value.getClassName()).append(".class");
613     }
614 
615     @Override
visitEnum(final String name, final String desc, final String value)616     public void visitEnum(final String name, final String desc,
617             final String value) {
618         buf.setLength(0);
619         appendComa(valueNumber++);
620         if (name != null) {
621             buf.append(name).append('=');
622         }
623         appendDescriptor(FIELD_DESCRIPTOR, desc);
624         buf.append('.').append(value);
625         text.add(buf.toString());
626     }
627 
628     @Override
visitAnnotation(final String name, final String desc)629     public Textifier visitAnnotation(final String name, final String desc) {
630         buf.setLength(0);
631         appendComa(valueNumber++);
632         if (name != null) {
633             buf.append(name).append('=');
634         }
635         buf.append('@');
636         appendDescriptor(FIELD_DESCRIPTOR, desc);
637         buf.append('(');
638         text.add(buf.toString());
639         Textifier t = createTextifier();
640         text.add(t.getText());
641         text.add(")");
642         return t;
643     }
644 
645     @Override
visitArray(final String name)646     public Textifier visitArray(final String name) {
647         buf.setLength(0);
648         appendComa(valueNumber++);
649         if (name != null) {
650             buf.append(name).append('=');
651         }
652         buf.append('{');
653         text.add(buf.toString());
654         Textifier t = createTextifier();
655         text.add(t.getText());
656         text.add("}");
657         return t;
658     }
659 
660     @Override
visitAnnotationEnd()661     public void visitAnnotationEnd() {
662     }
663 
664     // ------------------------------------------------------------------------
665     // Fields
666     // ------------------------------------------------------------------------
667 
668     @Override
visitFieldAnnotation(final String desc, final boolean visible)669     public Textifier visitFieldAnnotation(final String desc,
670             final boolean visible) {
671         return visitAnnotation(desc, visible);
672     }
673 
674     @Override
visitFieldTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible)675     public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath,
676             String desc, boolean visible) {
677         return visitTypeAnnotation(typeRef, typePath, desc, visible);
678     }
679 
680     @Override
visitFieldAttribute(final Attribute attr)681     public void visitFieldAttribute(final Attribute attr) {
682         visitAttribute(attr);
683     }
684 
685     @Override
visitFieldEnd()686     public void visitFieldEnd() {
687     }
688 
689     // ------------------------------------------------------------------------
690     // Methods
691     // ------------------------------------------------------------------------
692 
693     @Override
visitParameter(final String name, final int access)694     public void visitParameter(final String name, final int access) {
695         buf.setLength(0);
696         buf.append(tab2).append("// parameter ");
697         appendAccess(access);
698         buf.append(' ').append((name == null) ? "<no name>" : name)
699                 .append('\n');
700         text.add(buf.toString());
701     }
702 
703     @Override
visitAnnotationDefault()704     public Textifier visitAnnotationDefault() {
705         text.add(tab2 + "default=");
706         Textifier t = createTextifier();
707         text.add(t.getText());
708         text.add("\n");
709         return t;
710     }
711 
712     @Override
visitMethodAnnotation(final String desc, final boolean visible)713     public Textifier visitMethodAnnotation(final String desc,
714             final boolean visible) {
715         return visitAnnotation(desc, visible);
716     }
717 
718     @Override
visitMethodTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible)719     public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath,
720             String desc, boolean visible) {
721         return visitTypeAnnotation(typeRef, typePath, desc, visible);
722     }
723 
724     @Override
visitParameterAnnotation(final int parameter, final String desc, final boolean visible)725     public Textifier visitParameterAnnotation(final int parameter,
726             final String desc, final boolean visible) {
727         buf.setLength(0);
728         buf.append(tab2).append('@');
729         appendDescriptor(FIELD_DESCRIPTOR, desc);
730         buf.append('(');
731         text.add(buf.toString());
732         Textifier t = createTextifier();
733         text.add(t.getText());
734         text.add(visible ? ") // parameter " : ") // invisible, parameter ");
735         text.add(parameter);
736         text.add("\n");
737         return t;
738     }
739 
740     @Override
visitMethodAttribute(final Attribute attr)741     public void visitMethodAttribute(final Attribute attr) {
742         buf.setLength(0);
743         buf.append(tab).append("ATTRIBUTE ");
744         appendDescriptor(-1, attr.type);
745 
746         if (attr instanceof Textifiable) {
747             ((Textifiable) attr).textify(buf, labelNames);
748         } else {
749             buf.append(" : unknown\n");
750         }
751 
752         text.add(buf.toString());
753     }
754 
755     @Override
visitCode()756     public void visitCode() {
757     }
758 
759     @Override
visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack)760     public void visitFrame(final int type, final int nLocal,
761             final Object[] local, final int nStack, final Object[] stack) {
762         buf.setLength(0);
763         buf.append(ltab);
764         buf.append("FRAME ");
765         switch (type) {
766         case Opcodes.F_NEW:
767         case Opcodes.F_FULL:
768             buf.append("FULL [");
769             appendFrameTypes(nLocal, local);
770             buf.append("] [");
771             appendFrameTypes(nStack, stack);
772             buf.append(']');
773             break;
774         case Opcodes.F_APPEND:
775             buf.append("APPEND [");
776             appendFrameTypes(nLocal, local);
777             buf.append(']');
778             break;
779         case Opcodes.F_CHOP:
780             buf.append("CHOP ").append(nLocal);
781             break;
782         case Opcodes.F_SAME:
783             buf.append("SAME");
784             break;
785         case Opcodes.F_SAME1:
786             buf.append("SAME1 ");
787             appendFrameTypes(1, stack);
788             break;
789         }
790         buf.append('\n');
791         text.add(buf.toString());
792     }
793 
794     @Override
visitInsn(final int opcode)795     public void visitInsn(final int opcode) {
796         buf.setLength(0);
797         buf.append(tab2).append(OPCODES[opcode]).append('\n');
798         text.add(buf.toString());
799     }
800 
801     @Override
visitIntInsn(final int opcode, final int operand)802     public void visitIntInsn(final int opcode, final int operand) {
803         buf.setLength(0);
804         buf.append(tab2)
805                 .append(OPCODES[opcode])
806                 .append(' ')
807                 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer
808                         .toString(operand)).append('\n');
809         text.add(buf.toString());
810     }
811 
812     @Override
visitVarInsn(final int opcode, final int var)813     public void visitVarInsn(final int opcode, final int var) {
814         buf.setLength(0);
815         buf.append(tab2).append(OPCODES[opcode]).append(' ').append(var)
816                 .append('\n');
817         text.add(buf.toString());
818     }
819 
820     @Override
visitTypeInsn(final int opcode, final String type)821     public void visitTypeInsn(final int opcode, final String type) {
822         buf.setLength(0);
823         buf.append(tab2).append(OPCODES[opcode]).append(' ');
824         appendDescriptor(INTERNAL_NAME, type);
825         buf.append('\n');
826         text.add(buf.toString());
827     }
828 
829     @Override
visitFieldInsn(final int opcode, final String owner, final String name, final String desc)830     public void visitFieldInsn(final int opcode, final String owner,
831             final String name, final String desc) {
832         buf.setLength(0);
833         buf.append(tab2).append(OPCODES[opcode]).append(' ');
834         appendDescriptor(INTERNAL_NAME, owner);
835         buf.append('.').append(name).append(" : ");
836         appendDescriptor(FIELD_DESCRIPTOR, desc);
837         buf.append('\n');
838         text.add(buf.toString());
839     }
840 
841     @Deprecated
842     @Override
visitMethodInsn(final int opcode, final String owner, final String name, final String desc)843     public void visitMethodInsn(final int opcode, final String owner,
844             final String name, final String desc) {
845         if (api >= Opcodes.ASM5) {
846             super.visitMethodInsn(opcode, owner, name, desc);
847             return;
848         }
849         doVisitMethodInsn(opcode, owner, name, desc,
850                 opcode == Opcodes.INVOKEINTERFACE);
851     }
852 
853     @Override
visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf)854     public void visitMethodInsn(final int opcode, final String owner,
855             final String name, final String desc, final boolean itf) {
856         if (api < Opcodes.ASM5) {
857             super.visitMethodInsn(opcode, owner, name, desc, itf);
858             return;
859         }
860         doVisitMethodInsn(opcode, owner, name, desc, itf);
861     }
862 
doVisitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf)863     private void doVisitMethodInsn(final int opcode, final String owner,
864             final String name, final String desc, final boolean itf) {
865         buf.setLength(0);
866         buf.append(tab2).append(OPCODES[opcode]).append(' ');
867         appendDescriptor(INTERNAL_NAME, owner);
868         buf.append('.').append(name).append(' ');
869         appendDescriptor(METHOD_DESCRIPTOR, desc);
870         buf.append('\n');
871         text.add(buf.toString());
872     }
873 
874     @Override
visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs)875     public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
876             Object... bsmArgs) {
877         buf.setLength(0);
878         buf.append(tab2).append("INVOKEDYNAMIC").append(' ');
879         buf.append(name);
880         appendDescriptor(METHOD_DESCRIPTOR, desc);
881         buf.append(" [");
882         buf.append('\n');
883         buf.append(tab3);
884         appendHandle(bsm);
885         buf.append('\n');
886         buf.append(tab3).append("// arguments:");
887         if (bsmArgs.length == 0) {
888             buf.append(" none");
889         } else {
890             buf.append('\n');
891             for (int i = 0; i < bsmArgs.length; i++) {
892                 buf.append(tab3);
893                 Object cst = bsmArgs[i];
894                 if (cst instanceof String) {
895                     Printer.appendString(buf, (String) cst);
896                 } else if (cst instanceof Type) {
897                     Type type = (Type) cst;
898                     if(type.getSort() == Type.METHOD){
899                         appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
900                     } else {
901                         buf.append(type.getDescriptor()).append(".class");
902                     }
903                 } else if (cst instanceof Handle) {
904                     appendHandle((Handle) cst);
905                 } else {
906                     buf.append(cst);
907                 }
908                 buf.append(", \n");
909             }
910             buf.setLength(buf.length() - 3);
911         }
912         buf.append('\n');
913         buf.append(tab2).append("]\n");
914         text.add(buf.toString());
915     }
916 
917     @Override
visitJumpInsn(final int opcode, final Label label)918     public void visitJumpInsn(final int opcode, final Label label) {
919         buf.setLength(0);
920         buf.append(tab2).append(OPCODES[opcode]).append(' ');
921         appendLabel(label);
922         buf.append('\n');
923         text.add(buf.toString());
924     }
925 
926     @Override
visitLabel(final Label label)927     public void visitLabel(final Label label) {
928         buf.setLength(0);
929         buf.append(ltab);
930         appendLabel(label);
931         buf.append('\n');
932         text.add(buf.toString());
933     }
934 
935     @Override
visitLdcInsn(final Object cst)936     public void visitLdcInsn(final Object cst) {
937         buf.setLength(0);
938         buf.append(tab2).append("LDC ");
939         if (cst instanceof String) {
940             Printer.appendString(buf, (String) cst);
941         } else if (cst instanceof Type) {
942             buf.append(((Type) cst).getDescriptor()).append(".class");
943         } else {
944             buf.append(cst);
945         }
946         buf.append('\n');
947         text.add(buf.toString());
948     }
949 
950     @Override
visitIincInsn(final int var, final int increment)951     public void visitIincInsn(final int var, final int increment) {
952         buf.setLength(0);
953         buf.append(tab2).append("IINC ").append(var).append(' ')
954                 .append(increment).append('\n');
955         text.add(buf.toString());
956     }
957 
958     @Override
visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels)959     public void visitTableSwitchInsn(final int min, final int max,
960             final Label dflt, final Label... labels) {
961         buf.setLength(0);
962         buf.append(tab2).append("TABLESWITCH\n");
963         for (int i = 0; i < labels.length; ++i) {
964             buf.append(tab3).append(min + i).append(": ");
965             appendLabel(labels[i]);
966             buf.append('\n');
967         }
968         buf.append(tab3).append("default: ");
969         appendLabel(dflt);
970         buf.append('\n');
971         text.add(buf.toString());
972     }
973 
974     @Override
visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)975     public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
976             final Label[] labels) {
977         buf.setLength(0);
978         buf.append(tab2).append("LOOKUPSWITCH\n");
979         for (int i = 0; i < labels.length; ++i) {
980             buf.append(tab3).append(keys[i]).append(": ");
981             appendLabel(labels[i]);
982             buf.append('\n');
983         }
984         buf.append(tab3).append("default: ");
985         appendLabel(dflt);
986         buf.append('\n');
987         text.add(buf.toString());
988     }
989 
990     @Override
visitMultiANewArrayInsn(final String desc, final int dims)991     public void visitMultiANewArrayInsn(final String desc, final int dims) {
992         buf.setLength(0);
993         buf.append(tab2).append("MULTIANEWARRAY ");
994         appendDescriptor(FIELD_DESCRIPTOR, desc);
995         buf.append(' ').append(dims).append('\n');
996         text.add(buf.toString());
997     }
998 
999     @Override
visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible)1000     public Printer visitInsnAnnotation(int typeRef, TypePath typePath,
1001             String desc, boolean visible) {
1002         return visitTypeAnnotation(typeRef, typePath, desc, visible);
1003     }
1004 
1005     @Override
visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type)1006     public void visitTryCatchBlock(final Label start, final Label end,
1007             final Label handler, final String type) {
1008         buf.setLength(0);
1009         buf.append(tab2).append("TRYCATCHBLOCK ");
1010         appendLabel(start);
1011         buf.append(' ');
1012         appendLabel(end);
1013         buf.append(' ');
1014         appendLabel(handler);
1015         buf.append(' ');
1016         appendDescriptor(INTERNAL_NAME, type);
1017         buf.append('\n');
1018         text.add(buf.toString());
1019     }
1020 
1021     @Override
visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible)1022     public Printer visitTryCatchAnnotation(int typeRef, TypePath typePath,
1023             String desc, boolean visible) {
1024         buf.setLength(0);
1025         buf.append(tab2).append("TRYCATCHBLOCK @");
1026         appendDescriptor(FIELD_DESCRIPTOR, desc);
1027         buf.append('(');
1028         text.add(buf.toString());
1029         Textifier t = createTextifier();
1030         text.add(t.getText());
1031         buf.setLength(0);
1032         buf.append(") : ");
1033         appendTypeReference(typeRef);
1034         buf.append(", ").append(typePath);
1035         buf.append(visible ? "\n" : " // invisible\n");
1036         text.add(buf.toString());
1037         return t;
1038     }
1039 
1040     @Override
visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index)1041     public void visitLocalVariable(final String name, final String desc,
1042             final String signature, final Label start, final Label end,
1043             final int index) {
1044         buf.setLength(0);
1045         buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' ');
1046         appendDescriptor(FIELD_DESCRIPTOR, desc);
1047         buf.append(' ');
1048         appendLabel(start);
1049         buf.append(' ');
1050         appendLabel(end);
1051         buf.append(' ').append(index).append('\n');
1052 
1053         if (signature != null) {
1054             buf.append(tab2);
1055             appendDescriptor(FIELD_SIGNATURE, signature);
1056 
1057             TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
1058             SignatureReader r = new SignatureReader(signature);
1059             r.acceptType(sv);
1060             buf.append(tab2).append("// declaration: ")
1061                     .append(sv.getDeclaration()).append('\n');
1062         }
1063         text.add(buf.toString());
1064     }
1065 
1066     @Override
visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible)1067     public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
1068             Label[] start, Label[] end, int[] index, String desc,
1069             boolean visible) {
1070         buf.setLength(0);
1071         buf.append(tab2).append("LOCALVARIABLE @");
1072         appendDescriptor(FIELD_DESCRIPTOR, desc);
1073         buf.append('(');
1074         text.add(buf.toString());
1075         Textifier t = createTextifier();
1076         text.add(t.getText());
1077         buf.setLength(0);
1078         buf.append(") : ");
1079         appendTypeReference(typeRef);
1080         buf.append(", ").append(typePath);
1081         for (int i = 0; i < start.length; ++i) {
1082             buf.append(" [ ");
1083             appendLabel(start[i]);
1084             buf.append(" - ");
1085             appendLabel(end[i]);
1086             buf.append(" - ").append(index[i]).append(" ]");
1087         }
1088         buf.append(visible ? "\n" : " // invisible\n");
1089         text.add(buf.toString());
1090         return t;
1091     }
1092 
1093     @Override
visitLineNumber(final int line, final Label start)1094     public void visitLineNumber(final int line, final Label start) {
1095         buf.setLength(0);
1096         buf.append(tab2).append("LINENUMBER ").append(line).append(' ');
1097         appendLabel(start);
1098         buf.append('\n');
1099         text.add(buf.toString());
1100     }
1101 
1102     @Override
visitMaxs(final int maxStack, final int maxLocals)1103     public void visitMaxs(final int maxStack, final int maxLocals) {
1104         buf.setLength(0);
1105         buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n');
1106         text.add(buf.toString());
1107 
1108         buf.setLength(0);
1109         buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n');
1110         text.add(buf.toString());
1111     }
1112 
1113     @Override
visitMethodEnd()1114     public void visitMethodEnd() {
1115     }
1116 
1117     // ------------------------------------------------------------------------
1118     // Common methods
1119     // ------------------------------------------------------------------------
1120 
1121     /**
1122      * Prints a disassembled view of the given annotation.
1123      *
1124      * @param desc
1125      *            the class descriptor of the annotation class.
1126      * @param visible
1127      *            <tt>true</tt> if the annotation is visible at runtime.
1128      * @return a visitor to visit the annotation values.
1129      */
visitAnnotation(final String desc, final boolean visible)1130     public Textifier visitAnnotation(final String desc, final boolean visible) {
1131         buf.setLength(0);
1132         buf.append(tab).append('@');
1133         appendDescriptor(FIELD_DESCRIPTOR, desc);
1134         buf.append('(');
1135         text.add(buf.toString());
1136         Textifier t = createTextifier();
1137         text.add(t.getText());
1138         text.add(visible ? ")\n" : ") // invisible\n");
1139         return t;
1140     }
1141 
1142     /**
1143      * Prints a disassembled view of the given type annotation.
1144      *
1145      * @param typeRef
1146      *            a reference to the annotated type. See {@link TypeReference}.
1147      * @param typePath
1148      *            the path to the annotated type argument, wildcard bound, array
1149      *            element type, or static inner type within 'typeRef'. May be
1150      *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
1151      * @param desc
1152      *            the class descriptor of the annotation class.
1153      * @param visible
1154      *            <tt>true</tt> if the annotation is visible at runtime.
1155      * @return a visitor to visit the annotation values.
1156      */
visitTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible)1157     public Textifier visitTypeAnnotation(final int typeRef,
1158             final TypePath typePath, final String desc, final boolean visible) {
1159         buf.setLength(0);
1160         buf.append(tab).append('@');
1161         appendDescriptor(FIELD_DESCRIPTOR, desc);
1162         buf.append('(');
1163         text.add(buf.toString());
1164         Textifier t = createTextifier();
1165         text.add(t.getText());
1166         buf.setLength(0);
1167         buf.append(") : ");
1168         appendTypeReference(typeRef);
1169         buf.append(", ").append(typePath);
1170         buf.append(visible ? "\n" : " // invisible\n");
1171         text.add(buf.toString());
1172         return t;
1173     }
1174 
1175     /**
1176      * Prints a disassembled view of the given attribute.
1177      *
1178      * @param attr
1179      *            an attribute.
1180      */
visitAttribute(final Attribute attr)1181     public void visitAttribute(final Attribute attr) {
1182         buf.setLength(0);
1183         buf.append(tab).append("ATTRIBUTE ");
1184         appendDescriptor(-1, attr.type);
1185 
1186         if (attr instanceof Textifiable) {
1187             ((Textifiable) attr).textify(buf, null);
1188         } else {
1189             buf.append(" : unknown\n");
1190         }
1191 
1192         text.add(buf.toString());
1193     }
1194 
1195     // ------------------------------------------------------------------------
1196     // Utility methods
1197     // ------------------------------------------------------------------------
1198 
1199     /**
1200      * Creates a new TraceVisitor instance.
1201      *
1202      * @return a new TraceVisitor.
1203      */
createTextifier()1204     protected Textifier createTextifier() {
1205         return new Textifier();
1206     }
1207 
1208     /**
1209      * Appends an internal name, a type descriptor or a type signature to
1210      * {@link #buf buf}.
1211      *
1212      * @param type
1213      *            indicates if desc is an internal name, a field descriptor, a
1214      *            method descriptor, a class signature, ...
1215      * @param desc
1216      *            an internal name, type descriptor, or type signature. May be
1217      *            <tt>null</tt>.
1218      */
appendDescriptor(final int type, final String desc)1219     protected void appendDescriptor(final int type, final String desc) {
1220         if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE
1221                 || type == METHOD_SIGNATURE) {
1222             if (desc != null) {
1223                 buf.append("// signature ").append(desc).append('\n');
1224             }
1225         } else {
1226             buf.append(desc);
1227         }
1228     }
1229 
1230     /**
1231      * Appends the name of the given label to {@link #buf buf}. Creates a new
1232      * label name if the given label does not yet have one.
1233      *
1234      * @param l
1235      *            a label.
1236      */
appendLabel(final Label l)1237     protected void appendLabel(final Label l) {
1238         if (labelNames == null) {
1239             labelNames = new HashMap<Label, String>();
1240         }
1241         String name = labelNames.get(l);
1242         if (name == null) {
1243             name = "L" + labelNames.size();
1244             labelNames.put(l, name);
1245         }
1246         buf.append(name);
1247     }
1248 
1249     /**
1250      * Appends the information about the given handle to {@link #buf buf}.
1251      *
1252      * @param h
1253      *            a handle, non null.
1254      */
appendHandle(final Handle h)1255     protected void appendHandle(final Handle h) {
1256         int tag = h.getTag();
1257         buf.append("// handle kind 0x").append(Integer.toHexString(tag))
1258                 .append(" : ");
1259         boolean isMethodHandle = false;
1260         switch (tag) {
1261         case Opcodes.H_GETFIELD:
1262             buf.append("GETFIELD");
1263             break;
1264         case Opcodes.H_GETSTATIC:
1265             buf.append("GETSTATIC");
1266             break;
1267         case Opcodes.H_PUTFIELD:
1268             buf.append("PUTFIELD");
1269             break;
1270         case Opcodes.H_PUTSTATIC:
1271             buf.append("PUTSTATIC");
1272             break;
1273         case Opcodes.H_INVOKEINTERFACE:
1274             buf.append("INVOKEINTERFACE");
1275             isMethodHandle = true;
1276             break;
1277         case Opcodes.H_INVOKESPECIAL:
1278             buf.append("INVOKESPECIAL");
1279             isMethodHandle = true;
1280             break;
1281         case Opcodes.H_INVOKESTATIC:
1282             buf.append("INVOKESTATIC");
1283             isMethodHandle = true;
1284             break;
1285         case Opcodes.H_INVOKEVIRTUAL:
1286             buf.append("INVOKEVIRTUAL");
1287             isMethodHandle = true;
1288             break;
1289         case Opcodes.H_NEWINVOKESPECIAL:
1290             buf.append("NEWINVOKESPECIAL");
1291             isMethodHandle = true;
1292             break;
1293         }
1294         buf.append('\n');
1295         buf.append(tab3);
1296         appendDescriptor(INTERNAL_NAME, h.getOwner());
1297         buf.append('.');
1298         buf.append(h.getName());
1299         if(!isMethodHandle){
1300             buf.append('(');
1301         }
1302         appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc());
1303         if(!isMethodHandle){
1304             buf.append(')');
1305         }
1306     }
1307 
1308     /**
1309      * Appends a string representation of the given access modifiers to
1310      * {@link #buf buf}.
1311      *
1312      * @param access
1313      *            some access modifiers.
1314      */
appendAccess(final int access)1315     private void appendAccess(final int access) {
1316         if ((access & Opcodes.ACC_PUBLIC) != 0) {
1317             buf.append("public ");
1318         }
1319         if ((access & Opcodes.ACC_PRIVATE) != 0) {
1320             buf.append("private ");
1321         }
1322         if ((access & Opcodes.ACC_PROTECTED) != 0) {
1323             buf.append("protected ");
1324         }
1325         if ((access & Opcodes.ACC_FINAL) != 0) {
1326             buf.append("final ");
1327         }
1328         if ((access & Opcodes.ACC_STATIC) != 0) {
1329             buf.append("static ");
1330         }
1331         if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
1332             buf.append("synchronized ");
1333         }
1334         if ((access & Opcodes.ACC_VOLATILE) != 0) {
1335             buf.append("volatile ");
1336         }
1337         if ((access & Opcodes.ACC_TRANSIENT) != 0) {
1338             buf.append("transient ");
1339         }
1340         if ((access & Opcodes.ACC_ABSTRACT) != 0) {
1341             buf.append("abstract ");
1342         }
1343         if ((access & Opcodes.ACC_STRICT) != 0) {
1344             buf.append("strictfp ");
1345         }
1346         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
1347             buf.append("synthetic ");
1348         }
1349         if ((access & Opcodes.ACC_MANDATED) != 0) {
1350             buf.append("mandated ");
1351         }
1352         if ((access & Opcodes.ACC_ENUM) != 0) {
1353             buf.append("enum ");
1354         }
1355     }
1356 
appendComa(final int i)1357     private void appendComa(final int i) {
1358         if (i != 0) {
1359             buf.append(", ");
1360         }
1361     }
1362 
appendTypeReference(final int typeRef)1363     private void appendTypeReference(final int typeRef) {
1364         TypeReference ref = new TypeReference(typeRef);
1365         switch (ref.getSort()) {
1366         case TypeReference.CLASS_TYPE_PARAMETER:
1367             buf.append("CLASS_TYPE_PARAMETER ").append(
1368                     ref.getTypeParameterIndex());
1369             break;
1370         case TypeReference.METHOD_TYPE_PARAMETER:
1371             buf.append("METHOD_TYPE_PARAMETER ").append(
1372                     ref.getTypeParameterIndex());
1373             break;
1374         case TypeReference.CLASS_EXTENDS:
1375             buf.append("CLASS_EXTENDS ").append(ref.getSuperTypeIndex());
1376             break;
1377         case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
1378             buf.append("CLASS_TYPE_PARAMETER_BOUND ")
1379                     .append(ref.getTypeParameterIndex()).append(", ")
1380                     .append(ref.getTypeParameterBoundIndex());
1381             break;
1382         case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
1383             buf.append("METHOD_TYPE_PARAMETER_BOUND ")
1384                     .append(ref.getTypeParameterIndex()).append(", ")
1385                     .append(ref.getTypeParameterBoundIndex());
1386             break;
1387         case TypeReference.FIELD:
1388             buf.append("FIELD");
1389             break;
1390         case TypeReference.METHOD_RETURN:
1391             buf.append("METHOD_RETURN");
1392             break;
1393         case TypeReference.METHOD_RECEIVER:
1394             buf.append("METHOD_RECEIVER");
1395             break;
1396         case TypeReference.METHOD_FORMAL_PARAMETER:
1397             buf.append("METHOD_FORMAL_PARAMETER ").append(
1398                     ref.getFormalParameterIndex());
1399             break;
1400         case TypeReference.THROWS:
1401             buf.append("THROWS ").append(ref.getExceptionIndex());
1402             break;
1403         case TypeReference.LOCAL_VARIABLE:
1404             buf.append("LOCAL_VARIABLE");
1405             break;
1406         case TypeReference.RESOURCE_VARIABLE:
1407             buf.append("RESOURCE_VARIABLE");
1408             break;
1409         case TypeReference.EXCEPTION_PARAMETER:
1410             buf.append("EXCEPTION_PARAMETER ").append(
1411                     ref.getTryCatchBlockIndex());
1412             break;
1413         case TypeReference.INSTANCEOF:
1414             buf.append("INSTANCEOF");
1415             break;
1416         case TypeReference.NEW:
1417             buf.append("NEW");
1418             break;
1419         case TypeReference.CONSTRUCTOR_REFERENCE:
1420             buf.append("CONSTRUCTOR_REFERENCE");
1421             break;
1422         case TypeReference.METHOD_REFERENCE:
1423             buf.append("METHOD_REFERENCE");
1424             break;
1425         case TypeReference.CAST:
1426             buf.append("CAST ").append(ref.getTypeArgumentIndex());
1427             break;
1428         case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
1429             buf.append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ").append(
1430                     ref.getTypeArgumentIndex());
1431             break;
1432         case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
1433             buf.append("METHOD_INVOCATION_TYPE_ARGUMENT ").append(
1434                     ref.getTypeArgumentIndex());
1435             break;
1436         case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
1437             buf.append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ").append(
1438                     ref.getTypeArgumentIndex());
1439             break;
1440         case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
1441             buf.append("METHOD_REFERENCE_TYPE_ARGUMENT ").append(
1442                     ref.getTypeArgumentIndex());
1443             break;
1444         }
1445     }
1446 
appendFrameTypes(final int n, final Object[] o)1447     private void appendFrameTypes(final int n, final Object[] o) {
1448         for (int i = 0; i < n; ++i) {
1449             if (i > 0) {
1450                 buf.append(' ');
1451             }
1452             if (o[i] instanceof String) {
1453                 String desc = (String) o[i];
1454                 if (desc.startsWith("[")) {
1455                     appendDescriptor(FIELD_DESCRIPTOR, desc);
1456                 } else {
1457                     appendDescriptor(INTERNAL_NAME, desc);
1458                 }
1459             } else if (o[i] instanceof Integer) {
1460                 switch (((Integer) o[i]).intValue()) {
1461                 case 0:
1462                     appendDescriptor(FIELD_DESCRIPTOR, "T");
1463                     break;
1464                 case 1:
1465                     appendDescriptor(FIELD_DESCRIPTOR, "I");
1466                     break;
1467                 case 2:
1468                     appendDescriptor(FIELD_DESCRIPTOR, "F");
1469                     break;
1470                 case 3:
1471                     appendDescriptor(FIELD_DESCRIPTOR, "D");
1472                     break;
1473                 case 4:
1474                     appendDescriptor(FIELD_DESCRIPTOR, "J");
1475                     break;
1476                 case 5:
1477                     appendDescriptor(FIELD_DESCRIPTOR, "N");
1478                     break;
1479                 case 6:
1480                     appendDescriptor(FIELD_DESCRIPTOR, "U");
1481                     break;
1482                 }
1483             } else {
1484                 appendLabel((Label) o[i]);
1485             }
1486         }
1487     }
1488 }
1489