AttributeWriter.java revision 3294:9adfb22ff08f
1/*
2 * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javap;
27
28import com.sun.tools.classfile.AccessFlags;
29import com.sun.tools.classfile.AnnotationDefault_attribute;
30import com.sun.tools.classfile.Attribute;
31import com.sun.tools.classfile.Attributes;
32import com.sun.tools.classfile.BootstrapMethods_attribute;
33import com.sun.tools.classfile.CharacterRangeTable_attribute;
34import com.sun.tools.classfile.CharacterRangeTable_attribute.Entry;
35import com.sun.tools.classfile.Code_attribute;
36import com.sun.tools.classfile.CompilationID_attribute;
37import com.sun.tools.classfile.ConcealedPackages_attribute;
38import com.sun.tools.classfile.ConstantPool;
39import com.sun.tools.classfile.ConstantPoolException;
40import com.sun.tools.classfile.ConstantValue_attribute;
41import com.sun.tools.classfile.DefaultAttribute;
42import com.sun.tools.classfile.Deprecated_attribute;
43import com.sun.tools.classfile.EnclosingMethod_attribute;
44import com.sun.tools.classfile.Exceptions_attribute;
45import com.sun.tools.classfile.Hashes_attribute;
46import com.sun.tools.classfile.InnerClasses_attribute;
47import com.sun.tools.classfile.InnerClasses_attribute.Info;
48import com.sun.tools.classfile.LineNumberTable_attribute;
49import com.sun.tools.classfile.LocalVariableTable_attribute;
50import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
51import com.sun.tools.classfile.MainClass_attribute;
52import com.sun.tools.classfile.MethodParameters_attribute;
53import com.sun.tools.classfile.Module_attribute;
54import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
55import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
56import com.sun.tools.classfile.RuntimeInvisibleTypeAnnotations_attribute;
57import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
58import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
59import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
60import com.sun.tools.classfile.Signature_attribute;
61import com.sun.tools.classfile.SourceDebugExtension_attribute;
62import com.sun.tools.classfile.SourceFile_attribute;
63import com.sun.tools.classfile.SourceID_attribute;
64import com.sun.tools.classfile.StackMapTable_attribute;
65import com.sun.tools.classfile.StackMap_attribute;
66import com.sun.tools.classfile.Synthetic_attribute;
67import com.sun.tools.classfile.TargetPlatform_attribute;
68import com.sun.tools.classfile.Version_attribute;
69
70import static com.sun.tools.classfile.AccessFlags.*;
71
72import com.sun.tools.javac.util.Assert;
73import com.sun.tools.javac.util.StringUtils;
74
75/*
76 *  A writer for writing Attributes as text.
77 *
78 *  <p><b>This is NOT part of any supported API.
79 *  If you write code that depends on this, you do so at your own risk.
80 *  This code and its internal interfaces are subject to change or
81 *  deletion without notice.</b>
82 */
83public class AttributeWriter extends BasicWriter
84        implements Attribute.Visitor<Void,Void>
85{
86    public static AttributeWriter instance(Context context) {
87        AttributeWriter instance = context.get(AttributeWriter.class);
88        if (instance == null)
89            instance = new AttributeWriter(context);
90        return instance;
91    }
92
93    protected AttributeWriter(Context context) {
94        super(context);
95        context.put(AttributeWriter.class, this);
96        annotationWriter = AnnotationWriter.instance(context);
97        codeWriter = CodeWriter.instance(context);
98        constantWriter = ConstantWriter.instance(context);
99        options = Options.instance(context);
100    }
101
102    public void write(Object owner, Attribute attr, ConstantPool constant_pool) {
103        if (attr != null) {
104            Assert.checkNonNull(constant_pool);
105            Assert.checkNonNull(owner);
106            this.constant_pool = constant_pool;
107            this.owner = owner;
108            attr.accept(this, null);
109        }
110    }
111
112    public void write(Object owner, Attributes attrs, ConstantPool constant_pool) {
113        if (attrs != null) {
114            Assert.checkNonNull(constant_pool);
115            Assert.checkNonNull(owner);
116            this.constant_pool = constant_pool;
117            this.owner = owner;
118            for (Attribute attr: attrs)
119                attr.accept(this, null);
120        }
121    }
122
123    @Override
124    public Void visitDefault(DefaultAttribute attr, Void ignore) {
125        if (attr.reason != null) {
126            report(attr.reason);
127        }
128        byte[] data = attr.info;
129        int i = 0;
130        int j = 0;
131        print("  ");
132        try {
133            print(attr.getName(constant_pool));
134        } catch (ConstantPoolException e) {
135            report(e);
136            print("attribute name = #" + attr.attribute_name_index);
137        }
138        print(": ");
139        println("length = 0x" + toHex(attr.info.length));
140
141        print("   ");
142
143        while (i < data.length) {
144            print(toHex(data[i], 2));
145
146            j++;
147            if (j == 16) {
148                println();
149                print("   ");
150                j = 0;
151            } else {
152                print(" ");
153            }
154            i++;
155        }
156        println();
157        return null;
158    }
159
160    @Override
161    public Void visitAnnotationDefault(AnnotationDefault_attribute attr, Void ignore) {
162        println("AnnotationDefault:");
163        indent(+1);
164        print("default_value: ");
165        annotationWriter.write(attr.default_value);
166        indent(-1);
167        return null;
168    }
169
170    @Override
171    public Void visitBootstrapMethods(BootstrapMethods_attribute attr, Void p) {
172        println(Attribute.BootstrapMethods + ":");
173        for (int i = 0; i < attr.bootstrap_method_specifiers.length ; i++) {
174            BootstrapMethods_attribute.BootstrapMethodSpecifier bsm = attr.bootstrap_method_specifiers[i];
175            indent(+1);
176            print(i + ": #" + bsm.bootstrap_method_ref + " ");
177            println(constantWriter.stringValue(bsm.bootstrap_method_ref));
178            indent(+1);
179            println("Method arguments:");
180            indent(+1);
181            for (int j = 0; j < bsm.bootstrap_arguments.length; j++) {
182                print("#" + bsm.bootstrap_arguments[j] + " ");
183                println(constantWriter.stringValue(bsm.bootstrap_arguments[j]));
184            }
185            indent(-3);
186        }
187        return null;
188    }
189
190    @Override
191    public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, Void ignore) {
192        println("CharacterRangeTable:");
193        indent(+1);
194        for (Entry e : attr.character_range_table) {
195            print(String.format("    %2d, %2d, %6x, %6x, %4x",
196                    e.start_pc, e.end_pc,
197                    e.character_range_start, e.character_range_end,
198                    e.flags));
199            tab();
200            print(String.format("// %2d, %2d, %4d:%02d, %4d:%02d",
201                    e.start_pc, e.end_pc,
202                    (e.character_range_start >> 10), (e.character_range_start & 0x3ff),
203                    (e.character_range_end >> 10), (e.character_range_end & 0x3ff)));
204            if ((e.flags & CharacterRangeTable_attribute.CRT_STATEMENT) != 0)
205                print(", statement");
206            if ((e.flags & CharacterRangeTable_attribute.CRT_BLOCK) != 0)
207                print(", block");
208            if ((e.flags & CharacterRangeTable_attribute.CRT_ASSIGNMENT) != 0)
209                print(", assignment");
210            if ((e.flags & CharacterRangeTable_attribute.CRT_FLOW_CONTROLLER) != 0)
211                print(", flow-controller");
212            if ((e.flags & CharacterRangeTable_attribute.CRT_FLOW_TARGET) != 0)
213                print(", flow-target");
214            if ((e.flags & CharacterRangeTable_attribute.CRT_INVOKE) != 0)
215                print(", invoke");
216            if ((e.flags & CharacterRangeTable_attribute.CRT_CREATE) != 0)
217                print(", create");
218            if ((e.flags & CharacterRangeTable_attribute.CRT_BRANCH_TRUE) != 0)
219                print(", branch-true");
220            if ((e.flags & CharacterRangeTable_attribute.CRT_BRANCH_FALSE) != 0)
221                print(", branch-false");
222            println();
223        }
224        indent(-1);
225        return null;
226    }
227
228    @Override
229    public Void visitCode(Code_attribute attr, Void ignore) {
230        codeWriter.write(attr, constant_pool);
231        return null;
232    }
233
234    @Override
235    public Void visitCompilationID(CompilationID_attribute attr, Void ignore) {
236        constantWriter.write(attr.compilationID_index);
237        return null;
238    }
239
240    private String getJavaPackage(ConcealedPackages_attribute attr, int index) {
241        try {
242            return getJavaName(attr.getPackage(index, constant_pool));
243        } catch (ConstantPoolException e) {
244            return report(e);
245        }
246    }
247
248    @Override
249    public Void visitConcealedPackages(ConcealedPackages_attribute attr, Void ignore) {
250        println("ConcealedPackages: ");
251        indent(+1);
252        for (int i = 0; i < attr.packages_count; i++) {
253            print("#" + attr.packages_index[i]);
254            tab();
255            println("// " + getJavaPackage(attr, i));
256        }
257        indent(-1);
258        return null;
259    }
260
261    @Override
262    public Void visitConstantValue(ConstantValue_attribute attr, Void ignore) {
263        print("ConstantValue: ");
264        constantWriter.write(attr.constantvalue_index);
265        println();
266        return null;
267    }
268
269    @Override
270    public Void visitDeprecated(Deprecated_attribute attr, Void ignore) {
271        println("Deprecated: true");
272        return null;
273    }
274
275    @Override
276    public Void visitEnclosingMethod(EnclosingMethod_attribute attr, Void ignore) {
277        print("EnclosingMethod: #" + attr.class_index + ".#" + attr.method_index);
278        tab();
279        print("// " + getJavaClassName(attr));
280        if (attr.method_index != 0)
281            print("." + getMethodName(attr));
282        println();
283        return null;
284    }
285
286    private String getJavaClassName(EnclosingMethod_attribute a) {
287        try {
288            return getJavaName(a.getClassName(constant_pool));
289        } catch (ConstantPoolException e) {
290            return report(e);
291        }
292    }
293
294    private String getMethodName(EnclosingMethod_attribute a) {
295        try {
296            return a.getMethodName(constant_pool);
297        } catch (ConstantPoolException e) {
298            return report(e);
299        }
300    }
301
302    @Override
303    public Void visitExceptions(Exceptions_attribute attr, Void ignore) {
304        println("Exceptions:");
305        indent(+1);
306        print("throws ");
307        for (int i = 0; i < attr.number_of_exceptions; i++) {
308            if (i > 0)
309                print(", ");
310            print(getJavaException(attr, i));
311        }
312        println();
313        indent(-1);
314        return null;
315    }
316
317    private String getJavaException(Exceptions_attribute attr, int index) {
318        try {
319            return getJavaName(attr.getException(index, constant_pool));
320        } catch (ConstantPoolException e) {
321            return report(e);
322        }
323    }
324
325    @Override
326    public Void visitHashes(Hashes_attribute attr, Void ignore) {
327        println("Hashes:");
328        indent(+1);
329        print("algorithm #" + attr.algorithm_index);
330        tab();
331        println("// " + getAlgorithm(attr));
332        for (Hashes_attribute.Entry e : attr.hashes_table) {
333            print("#" + e.requires_index + ", #" + e.hash_index);
334            tab();
335            println("// " + getRequires(e) + ": " + getHash(e));
336        }
337        indent(-1);
338        return null;
339    }
340
341    private String getAlgorithm(Hashes_attribute attr) {
342        try {
343            return constant_pool.getUTF8Value(attr.algorithm_index);
344        } catch (ConstantPoolException e) {
345            return report(e);
346        }
347    }
348
349    private String getRequires(Hashes_attribute.Entry entry) {
350        try {
351            return constant_pool.getUTF8Value(entry.requires_index);
352        } catch (ConstantPoolException e) {
353            return report(e);
354        }
355    }
356
357    private String getHash(Hashes_attribute.Entry entry) {
358        try {
359            return constant_pool.getUTF8Value(entry.hash_index);
360        } catch (ConstantPoolException e) {
361            return report(e);
362        }
363    }
364
365    @Override
366    public Void visitInnerClasses(InnerClasses_attribute attr, Void ignore) {
367        boolean first = true;
368        for (Info info : attr.classes) {
369            //access
370            AccessFlags access_flags = info.inner_class_access_flags;
371            if (options.checkAccess(access_flags)) {
372                if (first) {
373                    writeInnerClassHeader();
374                    first = false;
375                }
376                for (String name: access_flags.getInnerClassModifiers())
377                    print(name + " ");
378                if (info.inner_name_index != 0) {
379                    print("#" + info.inner_name_index + "= ");
380                }
381                print("#" + info.inner_class_info_index);
382                if (info.outer_class_info_index != 0) {
383                    print(" of #" + info.outer_class_info_index);
384                }
385                print(";");
386                tab();
387                print("// ");
388                if (info.inner_name_index != 0) {
389                    print(getInnerName(constant_pool, info) + "=");
390                }
391                constantWriter.write(info.inner_class_info_index);
392                if (info.outer_class_info_index != 0) {
393                    print(" of ");
394                    constantWriter.write(info.outer_class_info_index);
395                }
396                println();
397            }
398        }
399        if (!first)
400            indent(-1);
401        return null;
402    }
403
404    String getInnerName(ConstantPool constant_pool, InnerClasses_attribute.Info info) {
405        try {
406            return info.getInnerName(constant_pool);
407        } catch (ConstantPoolException e) {
408            return report(e);
409        }
410    }
411
412    private void writeInnerClassHeader() {
413        println("InnerClasses:");
414        indent(+1);
415    }
416
417    @Override
418    public Void visitLineNumberTable(LineNumberTable_attribute attr, Void ignore) {
419        println("LineNumberTable:");
420        indent(+1);
421        for (LineNumberTable_attribute.Entry entry: attr.line_number_table) {
422            println("line " + entry.line_number + ": " + entry.start_pc);
423        }
424        indent(-1);
425        return null;
426    }
427
428    @Override
429    public Void visitLocalVariableTable(LocalVariableTable_attribute attr, Void ignore) {
430        println("LocalVariableTable:");
431        indent(+1);
432        println("Start  Length  Slot  Name   Signature");
433        for (LocalVariableTable_attribute.Entry entry : attr.local_variable_table) {
434            println(String.format("%5d %7d %5d %5s   %s",
435                    entry.start_pc, entry.length, entry.index,
436                    constantWriter.stringValue(entry.name_index),
437                    constantWriter.stringValue(entry.descriptor_index)));
438        }
439        indent(-1);
440        return null;
441    }
442
443    @Override
444    public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, Void ignore) {
445        println("LocalVariableTypeTable:");
446        indent(+1);
447        println("Start  Length  Slot  Name   Signature");
448        for (LocalVariableTypeTable_attribute.Entry entry : attr.local_variable_table) {
449            println(String.format("%5d %7d %5d %5s   %s",
450                    entry.start_pc, entry.length, entry.index,
451                    constantWriter.stringValue(entry.name_index),
452                    constantWriter.stringValue(entry.signature_index)));
453        }
454        indent(-1);
455        return null;
456    }
457
458    @Override
459    public Void visitMainClass(MainClass_attribute attr, Void ignore) {
460        print("MainClass: #" + attr.main_class_index);
461        tab();
462        print("// " + getJavaClassName(attr));
463        println();
464        return null;
465    }
466
467    private String getJavaClassName(MainClass_attribute a) {
468        try {
469            return getJavaName(a.getMainClassName(constant_pool));
470        } catch (ConstantPoolException e) {
471            return report(e);
472        }
473    }
474
475    private static final String format = "%-31s%s";
476
477    @Override
478    public Void visitMethodParameters(MethodParameters_attribute attr,
479                                      Void ignore) {
480
481        final String header = String.format(format, "Name", "Flags");
482        println("MethodParameters:");
483        indent(+1);
484        println(header);
485        for (MethodParameters_attribute.Entry entry :
486                 attr.method_parameter_table) {
487            String namestr =
488                entry.name_index != 0 ?
489                constantWriter.stringValue(entry.name_index) : "<no name>";
490            String flagstr =
491                (0 != (entry.flags & ACC_FINAL) ? "final " : "") +
492                (0 != (entry.flags & ACC_MANDATED) ? "mandated " : "") +
493                (0 != (entry.flags & ACC_SYNTHETIC) ? "synthetic" : "");
494            println(String.format(format, namestr, flagstr));
495        }
496        indent(-1);
497        return null;
498    }
499
500    @Override
501    public Void visitModule(Module_attribute attr, Void ignore) {
502        println("Module:");
503        indent(+1);
504        printRequiresTable(attr);
505        printExportsTable(attr);
506        printUsesTable(attr);
507        printProvidesTable(attr);
508        indent(-1);
509        return null;
510    }
511
512    protected void printRequiresTable(Module_attribute attr) {
513        Module_attribute.RequiresEntry[] entries = attr.requires;
514        println(entries.length + "\t// " + "requires");
515        indent(+1);
516        for (Module_attribute.RequiresEntry e: entries) {
517            print("#" + e.requires_index + "," +
518                    String.format("%x", e.requires_flags)+ "\t// requires");
519            if ((e.requires_flags & Module_attribute.ACC_PUBLIC) != 0)
520                print(" public");
521            if ((e.requires_flags & Module_attribute.ACC_SYNTHETIC) != 0)
522                print(" synthetic");
523            if ((e.requires_flags & Module_attribute.ACC_MANDATED) != 0)
524                print(" mandated");
525            println(" " + constantWriter.stringValue(e.requires_index));
526        }
527        indent(-1);
528    }
529
530    protected void printExportsTable(Module_attribute attr) {
531        Module_attribute.ExportsEntry[] entries = attr.exports;
532        println(entries.length + "\t// " + "exports");
533        indent(+1);
534        for (Module_attribute.ExportsEntry e: entries) {
535            print("#" + e.exports_index + "\t// exports");
536            print(" " + constantWriter.stringValue(e.exports_index));
537            if (e.exports_to_index.length == 0) {
538                println();
539            } else {
540                println(" to ... " + e.exports_to_index.length);
541                indent(+1);
542                for (int to: e.exports_to_index) {
543                    println("#" + to + "\t// ... to " + constantWriter.stringValue(to));
544                }
545                indent(-1);
546            }
547        }
548        indent(-1);
549    }
550
551    protected void printUsesTable(Module_attribute attr) {
552        int[] entries = attr.uses_index;
553        println(entries.length + "\t// " + "uses services");
554        indent(+1);
555        for (int e: entries) {
556            println("#" + e + "\t// uses " + constantWriter.stringValue(e));
557        }
558        indent(-1);
559    }
560
561    protected void printProvidesTable(Module_attribute attr) {
562        Module_attribute.ProvidesEntry[] entries = attr.provides;
563        println(entries.length + "\t// " + "provides services");
564        indent(+1);
565        for (Module_attribute.ProvidesEntry e: entries) {
566            print("#" + e.provides_index + ",#" +
567                    e.with_index + "\t// provides ");
568            print(constantWriter.stringValue(e.provides_index));
569            print (" with ");
570            println(constantWriter.stringValue(e.with_index));
571        }
572        indent(-1);
573    }
574
575    @Override
576    public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, Void ignore) {
577        println("RuntimeVisibleAnnotations:");
578        indent(+1);
579        for (int i = 0; i < attr.annotations.length; i++) {
580            print(i + ": ");
581            annotationWriter.write(attr.annotations[i]);
582            println();
583        }
584        indent(-1);
585        return null;
586    }
587
588    @Override
589    public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, Void ignore) {
590        println("RuntimeInvisibleAnnotations:");
591        indent(+1);
592        for (int i = 0; i < attr.annotations.length; i++) {
593            print(i + ": ");
594            annotationWriter.write(attr.annotations[i]);
595            println();
596        }
597        indent(-1);
598        return null;
599    }
600
601    @Override
602    public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, Void ignore) {
603        println("RuntimeVisibleTypeAnnotations:");
604        indent(+1);
605        for (int i = 0; i < attr.annotations.length; i++) {
606            print(i + ": ");
607            annotationWriter.write(attr.annotations[i]);
608            println();
609        }
610        indent(-1);
611        return null;
612    }
613
614    @Override
615    public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, Void ignore) {
616        println("RuntimeInvisibleTypeAnnotations:");
617        indent(+1);
618        for (int i = 0; i < attr.annotations.length; i++) {
619            print(i + ": ");
620            annotationWriter.write(attr.annotations[i]);
621            println();
622        }
623        indent(-1);
624        return null;
625    }
626
627    @Override
628    public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, Void ignore) {
629        println("RuntimeVisibleParameterAnnotations:");
630        indent(+1);
631        for (int param = 0; param < attr.parameter_annotations.length; param++) {
632            println("parameter " + param + ": ");
633            indent(+1);
634            for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
635                print(i + ": ");
636                annotationWriter.write(attr.parameter_annotations[param][i]);
637                println();
638            }
639            indent(-1);
640        }
641        indent(-1);
642        return null;
643    }
644
645    @Override
646    public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, Void ignore) {
647        println("RuntimeInvisibleParameterAnnotations:");
648        indent(+1);
649        for (int param = 0; param < attr.parameter_annotations.length; param++) {
650            println(param + ": ");
651            indent(+1);
652            for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
653                print(i + ": ");
654                annotationWriter.write(attr.parameter_annotations[param][i]);
655                println();
656            }
657            indent(-1);
658        }
659        indent(-1);
660        return null;
661    }
662
663    @Override
664    public Void visitSignature(Signature_attribute attr, Void ignore) {
665        print("Signature: #" + attr.signature_index);
666        tab();
667        println("// " + getSignature(attr));
668        return null;
669    }
670
671    String getSignature(Signature_attribute info) {
672        try {
673            return info.getSignature(constant_pool);
674        } catch (ConstantPoolException e) {
675            return report(e);
676        }
677    }
678
679    @Override
680    public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, Void ignore) {
681        println("SourceDebugExtension:");
682        indent(+1);
683        for (String s: attr.getValue().split("[\r\n]+")) {
684            println(s);
685        }
686        indent(-1);
687        return null;
688    }
689
690    @Override
691    public Void visitSourceFile(SourceFile_attribute attr, Void ignore) {
692        println("SourceFile: \"" + getSourceFile(attr) + "\"");
693        return null;
694    }
695
696    private String getSourceFile(SourceFile_attribute attr) {
697        try {
698            return attr.getSourceFile(constant_pool);
699        } catch (ConstantPoolException e) {
700            return report(e);
701        }
702    }
703
704    @Override
705    public Void visitSourceID(SourceID_attribute attr, Void ignore) {
706        constantWriter.write(attr.sourceID_index);
707        return null;
708    }
709
710    @Override
711    public Void visitStackMap(StackMap_attribute attr, Void ignore) {
712        println("StackMap: number_of_entries = " + attr.number_of_entries);
713        indent(+1);
714        StackMapTableWriter w = new StackMapTableWriter();
715        for (StackMapTable_attribute.stack_map_frame entry : attr.entries) {
716            w.write(entry);
717        }
718        indent(-1);
719        return null;
720    }
721
722    @Override
723    public Void visitStackMapTable(StackMapTable_attribute attr, Void ignore) {
724        println("StackMapTable: number_of_entries = " + attr.number_of_entries);
725        indent(+1);
726        StackMapTableWriter w = new StackMapTableWriter();
727        for (StackMapTable_attribute.stack_map_frame entry : attr.entries) {
728            w.write(entry);
729        }
730        indent(-1);
731        return null;
732    }
733
734    class StackMapTableWriter // also handles CLDC StackMap attributes
735            implements StackMapTable_attribute.stack_map_frame.Visitor<Void,Void> {
736        public void write(StackMapTable_attribute.stack_map_frame frame) {
737            frame.accept(this, null);
738        }
739
740        @Override
741        public Void visit_same_frame(StackMapTable_attribute.same_frame frame, Void p) {
742            printHeader(frame, "/* same */");
743            return null;
744        }
745
746        @Override
747        public Void visit_same_locals_1_stack_item_frame(StackMapTable_attribute.same_locals_1_stack_item_frame frame, Void p) {
748            printHeader(frame, "/* same_locals_1_stack_item */");
749            indent(+1);
750            printMap("stack", frame.stack);
751            indent(-1);
752            return null;
753        }
754
755        @Override
756        public Void visit_same_locals_1_stack_item_frame_extended(StackMapTable_attribute.same_locals_1_stack_item_frame_extended frame, Void p) {
757            printHeader(frame, "/* same_locals_1_stack_item_frame_extended */");
758            indent(+1);
759            println("offset_delta = " + frame.offset_delta);
760            printMap("stack", frame.stack);
761            indent(-1);
762            return null;
763        }
764
765        @Override
766        public Void visit_chop_frame(StackMapTable_attribute.chop_frame frame, Void p) {
767            printHeader(frame, "/* chop */");
768            indent(+1);
769            println("offset_delta = " + frame.offset_delta);
770            indent(-1);
771            return null;
772        }
773
774        @Override
775        public Void visit_same_frame_extended(StackMapTable_attribute.same_frame_extended frame, Void p) {
776            printHeader(frame, "/* same_frame_extended */");
777            indent(+1);
778            println("offset_delta = " + frame.offset_delta);
779            indent(-1);
780            return null;
781        }
782
783        @Override
784        public Void visit_append_frame(StackMapTable_attribute.append_frame frame, Void p) {
785            printHeader(frame, "/* append */");
786            indent(+1);
787            println("offset_delta = " + frame.offset_delta);
788            printMap("locals", frame.locals);
789            indent(-1);
790            return null;
791        }
792
793        @Override
794        public Void visit_full_frame(StackMapTable_attribute.full_frame frame, Void p) {
795            if (frame instanceof StackMap_attribute.stack_map_frame) {
796                printHeader(frame, "offset = " + frame.offset_delta);
797                indent(+1);
798            } else {
799                printHeader(frame, "/* full_frame */");
800                indent(+1);
801                println("offset_delta = " + frame.offset_delta);
802            }
803            printMap("locals", frame.locals);
804            printMap("stack", frame.stack);
805            indent(-1);
806            return null;
807        }
808
809        void printHeader(StackMapTable_attribute.stack_map_frame frame, String extra) {
810            print("frame_type = " + frame.frame_type + " ");
811            println(extra);
812        }
813
814        void printMap(String name, StackMapTable_attribute.verification_type_info[] map) {
815            print(name + " = [");
816            for (int i = 0; i < map.length; i++) {
817                StackMapTable_attribute.verification_type_info info = map[i];
818                int tag = info.tag;
819                switch (tag) {
820                    case StackMapTable_attribute.verification_type_info.ITEM_Object:
821                        print(" ");
822                        constantWriter.write(((StackMapTable_attribute.Object_variable_info) info).cpool_index);
823                        break;
824                    case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized:
825                        print(" " + mapTypeName(tag));
826                        print(" " + ((StackMapTable_attribute.Uninitialized_variable_info) info).offset);
827                        break;
828                    default:
829                        print(" " + mapTypeName(tag));
830                }
831                print(i == (map.length - 1) ? " " : ",");
832            }
833            println("]");
834        }
835
836        String mapTypeName(int tag) {
837            switch (tag) {
838            case StackMapTable_attribute.verification_type_info.ITEM_Top:
839                return "top";
840
841            case StackMapTable_attribute.verification_type_info.ITEM_Integer:
842                return "int";
843
844            case StackMapTable_attribute.verification_type_info.ITEM_Float:
845                return "float";
846
847            case StackMapTable_attribute.verification_type_info.ITEM_Long:
848                return "long";
849
850            case StackMapTable_attribute.verification_type_info.ITEM_Double:
851                return "double";
852
853            case StackMapTable_attribute.verification_type_info.ITEM_Null:
854                return "null";
855
856            case StackMapTable_attribute.verification_type_info.ITEM_UninitializedThis:
857                return "this";
858
859            case StackMapTable_attribute.verification_type_info.ITEM_Object:
860                return "CP";
861
862            case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized:
863                return "uninitialized";
864
865            default:
866                report("unrecognized verification_type_info tag: " + tag);
867                return "[tag:" + tag + "]";
868            }
869        }
870    }
871
872    @Override
873    public Void visitSynthetic(Synthetic_attribute attr, Void ignore) {
874        println("Synthetic: true");
875        return null;
876    }
877
878    @Override
879    public Void visitTargetPlatform(TargetPlatform_attribute attr, Void ignore) {
880        println("TargetPlatform:");
881        indent(+1);
882        print("os_name: #" + attr.os_name_index);
883        if (attr.os_name_index != 0) {
884            tab();
885            print("// " + getOSName(attr));
886        }
887        println();
888        print("os_arch: #" + attr.os_arch_index);
889        if (attr.os_arch_index != 0) {
890            tab();
891            print("// " + getOSArch(attr));
892        }
893        println();
894        print("os_version: #" + attr.os_version_index);
895        if (attr.os_version_index != 0) {
896            tab();
897            print("// " + getOSVersion(attr));
898        }
899        println();
900        indent(-1);
901        return null;
902    }
903
904    private String getOSName(TargetPlatform_attribute attr) {
905        try {
906            return constant_pool.getUTF8Value(attr.os_name_index);
907        } catch (ConstantPoolException e) {
908            return report(e);
909        }
910    }
911
912    private String getOSArch(TargetPlatform_attribute attr) {
913        try {
914            return constant_pool.getUTF8Value(attr.os_arch_index);
915        } catch (ConstantPoolException e) {
916            return report(e);
917        }
918    }
919
920    private String getOSVersion(TargetPlatform_attribute attr) {
921        try {
922            return constant_pool.getUTF8Value(attr.os_version_index);
923        } catch (ConstantPoolException e) {
924            return report(e);
925        }
926    }
927
928    @Override
929    public Void visitVersion(Version_attribute attr, Void ignore) {
930        print("Version: #" + attr.version_index);
931        indent(+1);
932        tab();
933        println("// " + getVersion(attr));
934        indent(-1);
935        return null;
936    }
937
938    private String getVersion(Version_attribute attr) {
939        try {
940            return constant_pool.getUTF8Value(attr.version_index);
941        } catch (ConstantPoolException e) {
942            return report(e);
943        }
944    }
945
946    static String getJavaName(String name) {
947        return name.replace('/', '.');
948    }
949
950    String toHex(byte b, int w) {
951        return toHex(b & 0xff, w);
952    }
953
954    static String toHex(int i) {
955        return StringUtils.toUpperCase(Integer.toString(i, 16));
956    }
957
958    static String toHex(int i, int w) {
959        String s = StringUtils.toUpperCase(Integer.toHexString(i));
960        while (s.length() < w)
961            s = "0" + s;
962        return StringUtils.toUpperCase(s);
963    }
964
965    private final AnnotationWriter annotationWriter;
966    private final CodeWriter codeWriter;
967    private final ConstantWriter constantWriter;
968    private final Options options;
969
970    private ConstantPool constant_pool;
971    private Object owner;
972}
973