AttributeWriter.java revision 3792:d516975e8110
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.ConstantPool;
38import com.sun.tools.classfile.ConstantPoolException;
39import com.sun.tools.classfile.ConstantValue_attribute;
40import com.sun.tools.classfile.DefaultAttribute;
41import com.sun.tools.classfile.Deprecated_attribute;
42import com.sun.tools.classfile.EnclosingMethod_attribute;
43import com.sun.tools.classfile.Exceptions_attribute;
44import com.sun.tools.classfile.InnerClasses_attribute;
45import com.sun.tools.classfile.InnerClasses_attribute.Info;
46import com.sun.tools.classfile.LineNumberTable_attribute;
47import com.sun.tools.classfile.LocalVariableTable_attribute;
48import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
49import com.sun.tools.classfile.MethodParameters_attribute;
50import com.sun.tools.classfile.Module_attribute;
51import com.sun.tools.classfile.ModuleHashes_attribute;
52import com.sun.tools.classfile.ModuleMainClass_attribute;
53import com.sun.tools.classfile.ModulePackages_attribute;
54import com.sun.tools.classfile.ModuleTarget_attribute;
55import com.sun.tools.classfile.ModuleVersion_attribute;
56import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
57import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
58import com.sun.tools.classfile.RuntimeInvisibleTypeAnnotations_attribute;
59import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
60import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
61import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
62import com.sun.tools.classfile.Signature_attribute;
63import com.sun.tools.classfile.SourceDebugExtension_attribute;
64import com.sun.tools.classfile.SourceFile_attribute;
65import com.sun.tools.classfile.SourceID_attribute;
66import com.sun.tools.classfile.StackMapTable_attribute;
67import com.sun.tools.classfile.StackMap_attribute;
68import com.sun.tools.classfile.Synthetic_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(ModulePackages_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 visitModulePackages(ModulePackages_attribute attr, Void ignore) {
250        println("ModulePackages: ");
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 visitModuleHashes(ModuleHashes_attribute attr, Void ignore) {
327        println("ModuleHashes:");
328        indent(+1);
329        print("algorithm #" + attr.algorithm_index);
330        tab();
331        println("// " + getAlgorithm(attr));
332        for (ModuleHashes_attribute.Entry e : attr.hashes_table) {
333            print("#" + e.module_name_index);
334            tab();
335            println("// " + getModuleName(e));
336            println("hash_length: " + e.hash.length);
337            println("hash: [" + toHex(e.hash) + "]");
338        }
339        indent(-1);
340        return null;
341    }
342
343    private String getAlgorithm(ModuleHashes_attribute attr) {
344        try {
345            return constant_pool.getUTF8Value(attr.algorithm_index);
346        } catch (ConstantPoolException e) {
347            return report(e);
348        }
349    }
350
351    private String getModuleName(ModuleHashes_attribute.Entry entry) {
352        try {
353            return constant_pool.getUTF8Value(entry.module_name_index);
354        } catch (ConstantPoolException e) {
355            return report(e);
356        }
357    }
358
359    @Override
360    public Void visitInnerClasses(InnerClasses_attribute attr, Void ignore) {
361        boolean first = true;
362        for (Info info : attr.classes) {
363            //access
364            AccessFlags access_flags = info.inner_class_access_flags;
365            if (options.checkAccess(access_flags)) {
366                if (first) {
367                    writeInnerClassHeader();
368                    first = false;
369                }
370                for (String name: access_flags.getInnerClassModifiers())
371                    print(name + " ");
372                if (info.inner_name_index != 0) {
373                    print("#" + info.inner_name_index + "= ");
374                }
375                print("#" + info.inner_class_info_index);
376                if (info.outer_class_info_index != 0) {
377                    print(" of #" + info.outer_class_info_index);
378                }
379                print(";");
380                tab();
381                print("// ");
382                if (info.inner_name_index != 0) {
383                    print(getInnerName(constant_pool, info) + "=");
384                }
385                constantWriter.write(info.inner_class_info_index);
386                if (info.outer_class_info_index != 0) {
387                    print(" of ");
388                    constantWriter.write(info.outer_class_info_index);
389                }
390                println();
391            }
392        }
393        if (!first)
394            indent(-1);
395        return null;
396    }
397
398    String getInnerName(ConstantPool constant_pool, InnerClasses_attribute.Info info) {
399        try {
400            return info.getInnerName(constant_pool);
401        } catch (ConstantPoolException e) {
402            return report(e);
403        }
404    }
405
406    private void writeInnerClassHeader() {
407        println("InnerClasses:");
408        indent(+1);
409    }
410
411    @Override
412    public Void visitLineNumberTable(LineNumberTable_attribute attr, Void ignore) {
413        println("LineNumberTable:");
414        indent(+1);
415        for (LineNumberTable_attribute.Entry entry: attr.line_number_table) {
416            println("line " + entry.line_number + ": " + entry.start_pc);
417        }
418        indent(-1);
419        return null;
420    }
421
422    @Override
423    public Void visitLocalVariableTable(LocalVariableTable_attribute attr, Void ignore) {
424        println("LocalVariableTable:");
425        indent(+1);
426        println("Start  Length  Slot  Name   Signature");
427        for (LocalVariableTable_attribute.Entry entry : attr.local_variable_table) {
428            println(String.format("%5d %7d %5d %5s   %s",
429                    entry.start_pc, entry.length, entry.index,
430                    constantWriter.stringValue(entry.name_index),
431                    constantWriter.stringValue(entry.descriptor_index)));
432        }
433        indent(-1);
434        return null;
435    }
436
437    @Override
438    public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, Void ignore) {
439        println("LocalVariableTypeTable:");
440        indent(+1);
441        println("Start  Length  Slot  Name   Signature");
442        for (LocalVariableTypeTable_attribute.Entry entry : attr.local_variable_table) {
443            println(String.format("%5d %7d %5d %5s   %s",
444                    entry.start_pc, entry.length, entry.index,
445                    constantWriter.stringValue(entry.name_index),
446                    constantWriter.stringValue(entry.signature_index)));
447        }
448        indent(-1);
449        return null;
450    }
451
452    @Override
453    public Void visitModuleMainClass(ModuleMainClass_attribute attr, Void ignore) {
454        print("ModuleMainClass: #" + attr.main_class_index);
455        tab();
456        print("// " + getJavaClassName(attr));
457        println();
458        return null;
459    }
460
461    private String getJavaClassName(ModuleMainClass_attribute a) {
462        try {
463            return getJavaName(a.getMainClassName(constant_pool));
464        } catch (ConstantPoolException e) {
465            return report(e);
466        }
467    }
468
469    private static final String format = "%-31s%s";
470
471    @Override
472    public Void visitMethodParameters(MethodParameters_attribute attr,
473                                      Void ignore) {
474        final String header = String.format(format, "Name", "Flags");
475        println("MethodParameters:");
476        indent(+1);
477        println(header);
478        for (MethodParameters_attribute.Entry entry :
479                 attr.method_parameter_table) {
480            String namestr =
481                entry.name_index != 0 ?
482                constantWriter.stringValue(entry.name_index) : "<no name>";
483            String flagstr =
484                (0 != (entry.flags & ACC_FINAL) ? "final " : "") +
485                (0 != (entry.flags & ACC_MANDATED) ? "mandated " : "") +
486                (0 != (entry.flags & ACC_SYNTHETIC) ? "synthetic" : "");
487            println(String.format(format, namestr, flagstr));
488        }
489        indent(-1);
490        return null;
491    }
492
493    @Override
494    public Void visitModule(Module_attribute attr, Void ignore) {
495        println("Module:");
496        indent(+1);
497
498        print(attr.module_name);
499        tab();
500        println("// " + constantWriter.stringValue(attr.module_name));
501
502        print(String.format("%x", attr.module_flags));
503        tab();
504        print("// ");
505        if ((attr.module_flags & Module_attribute.ACC_OPEN) != 0)
506            print(" ACC_OPEN");
507        if ((attr.module_flags & Module_attribute.ACC_MANDATED) != 0)
508            print(" ACC_MANDATED");
509        if ((attr.module_flags & Module_attribute.ACC_SYNTHETIC) != 0)
510            print(" ACC_SYNTHETIC");
511        println();
512
513        printRequiresTable(attr);
514        printExportsTable(attr);
515        printOpensTable(attr);
516        printUsesTable(attr);
517        printProvidesTable(attr);
518        indent(-1);
519        return null;
520    }
521
522    protected void printRequiresTable(Module_attribute attr) {
523        Module_attribute.RequiresEntry[] entries = attr.requires;
524        print(entries.length);
525        tab();
526        println("// " + "requires");
527        indent(+1);
528        for (Module_attribute.RequiresEntry e: entries) {
529            print("#" + e.requires_index + "," + String.format("%x", e.requires_flags));
530            tab();
531            print("// " + constantWriter.stringValue(e.requires_index));
532            if ((e.requires_flags & Module_attribute.ACC_TRANSITIVE) != 0)
533                print(" ACC_TRANSITIVE");
534            if ((e.requires_flags & Module_attribute.ACC_STATIC_PHASE) != 0)
535                print(" ACC_STATIC_PHASE");
536            if ((e.requires_flags & Module_attribute.ACC_SYNTHETIC) != 0)
537                print(" ACC_SYNTHETIC");
538            if ((e.requires_flags & Module_attribute.ACC_MANDATED) != 0)
539                print(" ACC_MANDATED");
540            println();
541        }
542        indent(-1);
543    }
544
545    protected void printExportsTable(Module_attribute attr) {
546        Module_attribute.ExportsEntry[] entries = attr.exports;
547        print(entries.length);
548        tab();
549        println("// exports");
550        indent(+1);
551        for (Module_attribute.ExportsEntry e: entries) {
552            printExportOpenEntry(e.exports_index, e.exports_flags, e.exports_to_index);
553        }
554        indent(-1);
555    }
556
557    protected void printOpensTable(Module_attribute attr) {
558        Module_attribute.OpensEntry[] entries = attr.opens;
559        print(entries.length);
560        tab();
561        println("// opens");
562        indent(+1);
563        for (Module_attribute.OpensEntry e: entries) {
564            printExportOpenEntry(e.opens_index, e.opens_flags, e.opens_to_index);
565        }
566        indent(-1);
567    }
568
569    protected void printExportOpenEntry(int index, int flags, int[] to_index) {
570        print("#" + index + "," + String.format("%x", flags));
571        tab();
572        print("// ");
573        print(constantWriter.stringValue(index));
574        if ((flags & Module_attribute.ACC_MANDATED) != 0)
575            print(" ACC_MANDATED");
576        if ((flags & Module_attribute.ACC_SYNTHETIC) != 0)
577            print(" ACC_SYNTHETIC");
578        if (to_index.length == 0) {
579            println();
580        } else {
581            println(" to ... " + to_index.length);
582            indent(+1);
583            for (int to: to_index) {
584                print("#" + to);
585                tab();
586                println("// ... to " + constantWriter.stringValue(to));
587            }
588            indent(-1);
589        }
590    }
591
592    protected void printUsesTable(Module_attribute attr) {
593        int[] entries = attr.uses_index;
594        print(entries.length);
595        tab();
596        println("// " + "uses");
597        indent(+1);
598        for (int e: entries) {
599            print("#" + e);
600            tab();
601            println("// " + constantWriter.stringValue(e));
602        }
603        indent(-1);
604    }
605
606    protected void printProvidesTable(Module_attribute attr) {
607        Module_attribute.ProvidesEntry[] entries = attr.provides;
608        print(entries.length);
609        tab();
610        println("// " + "provides");
611        indent(+1);
612        for (Module_attribute.ProvidesEntry e: entries) {
613            print("#" + e.provides_index);
614            tab();
615            print("// ");
616            print(constantWriter.stringValue(e.provides_index));
617            println(" with ... " + e.with_count);
618            indent(+1);
619            for (int with : e.with_index) {
620                print("#" + with);
621                tab();
622                println("// ... with " + constantWriter.stringValue(with));
623            }
624            indent(-1);
625        }
626        indent(-1);
627    }
628
629    @Override
630    public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, Void ignore) {
631        println("RuntimeVisibleAnnotations:");
632        indent(+1);
633        for (int i = 0; i < attr.annotations.length; i++) {
634            print(i + ": ");
635            annotationWriter.write(attr.annotations[i]);
636            println();
637        }
638        indent(-1);
639        return null;
640    }
641
642    @Override
643    public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, Void ignore) {
644        println("RuntimeInvisibleAnnotations:");
645        indent(+1);
646        for (int i = 0; i < attr.annotations.length; i++) {
647            print(i + ": ");
648            annotationWriter.write(attr.annotations[i]);
649            println();
650        }
651        indent(-1);
652        return null;
653    }
654
655    @Override
656    public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, Void ignore) {
657        println("RuntimeVisibleTypeAnnotations:");
658        indent(+1);
659        for (int i = 0; i < attr.annotations.length; i++) {
660            print(i + ": ");
661            annotationWriter.write(attr.annotations[i]);
662            println();
663        }
664        indent(-1);
665        return null;
666    }
667
668    @Override
669    public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, Void ignore) {
670        println("RuntimeInvisibleTypeAnnotations:");
671        indent(+1);
672        for (int i = 0; i < attr.annotations.length; i++) {
673            print(i + ": ");
674            annotationWriter.write(attr.annotations[i]);
675            println();
676        }
677        indent(-1);
678        return null;
679    }
680
681    @Override
682    public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, Void ignore) {
683        println("RuntimeVisibleParameterAnnotations:");
684        indent(+1);
685        for (int param = 0; param < attr.parameter_annotations.length; param++) {
686            println("parameter " + param + ": ");
687            indent(+1);
688            for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
689                print(i + ": ");
690                annotationWriter.write(attr.parameter_annotations[param][i]);
691                println();
692            }
693            indent(-1);
694        }
695        indent(-1);
696        return null;
697    }
698
699    @Override
700    public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, Void ignore) {
701        println("RuntimeInvisibleParameterAnnotations:");
702        indent(+1);
703        for (int param = 0; param < attr.parameter_annotations.length; param++) {
704            println(param + ": ");
705            indent(+1);
706            for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
707                print(i + ": ");
708                annotationWriter.write(attr.parameter_annotations[param][i]);
709                println();
710            }
711            indent(-1);
712        }
713        indent(-1);
714        return null;
715    }
716
717    @Override
718    public Void visitSignature(Signature_attribute attr, Void ignore) {
719        print("Signature: #" + attr.signature_index);
720        tab();
721        println("// " + getSignature(attr));
722        return null;
723    }
724
725    String getSignature(Signature_attribute info) {
726        try {
727            return info.getSignature(constant_pool);
728        } catch (ConstantPoolException e) {
729            return report(e);
730        }
731    }
732
733    @Override
734    public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, Void ignore) {
735        println("SourceDebugExtension:");
736        indent(+1);
737        for (String s: attr.getValue().split("[\r\n]+")) {
738            println(s);
739        }
740        indent(-1);
741        return null;
742    }
743
744    @Override
745    public Void visitSourceFile(SourceFile_attribute attr, Void ignore) {
746        println("SourceFile: \"" + getSourceFile(attr) + "\"");
747        return null;
748    }
749
750    private String getSourceFile(SourceFile_attribute attr) {
751        try {
752            return attr.getSourceFile(constant_pool);
753        } catch (ConstantPoolException e) {
754            return report(e);
755        }
756    }
757
758    @Override
759    public Void visitSourceID(SourceID_attribute attr, Void ignore) {
760        constantWriter.write(attr.sourceID_index);
761        return null;
762    }
763
764    @Override
765    public Void visitStackMap(StackMap_attribute attr, Void ignore) {
766        println("StackMap: number_of_entries = " + attr.number_of_entries);
767        indent(+1);
768        StackMapTableWriter w = new StackMapTableWriter();
769        for (StackMapTable_attribute.stack_map_frame entry : attr.entries) {
770            w.write(entry);
771        }
772        indent(-1);
773        return null;
774    }
775
776    @Override
777    public Void visitStackMapTable(StackMapTable_attribute attr, Void ignore) {
778        println("StackMapTable: number_of_entries = " + attr.number_of_entries);
779        indent(+1);
780        StackMapTableWriter w = new StackMapTableWriter();
781        for (StackMapTable_attribute.stack_map_frame entry : attr.entries) {
782            w.write(entry);
783        }
784        indent(-1);
785        return null;
786    }
787
788    class StackMapTableWriter // also handles CLDC StackMap attributes
789            implements StackMapTable_attribute.stack_map_frame.Visitor<Void,Void> {
790        public void write(StackMapTable_attribute.stack_map_frame frame) {
791            frame.accept(this, null);
792        }
793
794        @Override
795        public Void visit_same_frame(StackMapTable_attribute.same_frame frame, Void p) {
796            printHeader(frame, "/* same */");
797            return null;
798        }
799
800        @Override
801        public Void visit_same_locals_1_stack_item_frame(StackMapTable_attribute.same_locals_1_stack_item_frame frame, Void p) {
802            printHeader(frame, "/* same_locals_1_stack_item */");
803            indent(+1);
804            printMap("stack", frame.stack);
805            indent(-1);
806            return null;
807        }
808
809        @Override
810        public Void visit_same_locals_1_stack_item_frame_extended(StackMapTable_attribute.same_locals_1_stack_item_frame_extended frame, Void p) {
811            printHeader(frame, "/* same_locals_1_stack_item_frame_extended */");
812            indent(+1);
813            println("offset_delta = " + frame.offset_delta);
814            printMap("stack", frame.stack);
815            indent(-1);
816            return null;
817        }
818
819        @Override
820        public Void visit_chop_frame(StackMapTable_attribute.chop_frame frame, Void p) {
821            printHeader(frame, "/* chop */");
822            indent(+1);
823            println("offset_delta = " + frame.offset_delta);
824            indent(-1);
825            return null;
826        }
827
828        @Override
829        public Void visit_same_frame_extended(StackMapTable_attribute.same_frame_extended frame, Void p) {
830            printHeader(frame, "/* same_frame_extended */");
831            indent(+1);
832            println("offset_delta = " + frame.offset_delta);
833            indent(-1);
834            return null;
835        }
836
837        @Override
838        public Void visit_append_frame(StackMapTable_attribute.append_frame frame, Void p) {
839            printHeader(frame, "/* append */");
840            indent(+1);
841            println("offset_delta = " + frame.offset_delta);
842            printMap("locals", frame.locals);
843            indent(-1);
844            return null;
845        }
846
847        @Override
848        public Void visit_full_frame(StackMapTable_attribute.full_frame frame, Void p) {
849            if (frame instanceof StackMap_attribute.stack_map_frame) {
850                printHeader(frame, "offset = " + frame.offset_delta);
851                indent(+1);
852            } else {
853                printHeader(frame, "/* full_frame */");
854                indent(+1);
855                println("offset_delta = " + frame.offset_delta);
856            }
857            printMap("locals", frame.locals);
858            printMap("stack", frame.stack);
859            indent(-1);
860            return null;
861        }
862
863        void printHeader(StackMapTable_attribute.stack_map_frame frame, String extra) {
864            print("frame_type = " + frame.frame_type + " ");
865            println(extra);
866        }
867
868        void printMap(String name, StackMapTable_attribute.verification_type_info[] map) {
869            print(name + " = [");
870            for (int i = 0; i < map.length; i++) {
871                StackMapTable_attribute.verification_type_info info = map[i];
872                int tag = info.tag;
873                switch (tag) {
874                    case StackMapTable_attribute.verification_type_info.ITEM_Object:
875                        print(" ");
876                        constantWriter.write(((StackMapTable_attribute.Object_variable_info) info).cpool_index);
877                        break;
878                    case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized:
879                        print(" " + mapTypeName(tag));
880                        print(" " + ((StackMapTable_attribute.Uninitialized_variable_info) info).offset);
881                        break;
882                    default:
883                        print(" " + mapTypeName(tag));
884                }
885                print(i == (map.length - 1) ? " " : ",");
886            }
887            println("]");
888        }
889
890        String mapTypeName(int tag) {
891            switch (tag) {
892            case StackMapTable_attribute.verification_type_info.ITEM_Top:
893                return "top";
894
895            case StackMapTable_attribute.verification_type_info.ITEM_Integer:
896                return "int";
897
898            case StackMapTable_attribute.verification_type_info.ITEM_Float:
899                return "float";
900
901            case StackMapTable_attribute.verification_type_info.ITEM_Long:
902                return "long";
903
904            case StackMapTable_attribute.verification_type_info.ITEM_Double:
905                return "double";
906
907            case StackMapTable_attribute.verification_type_info.ITEM_Null:
908                return "null";
909
910            case StackMapTable_attribute.verification_type_info.ITEM_UninitializedThis:
911                return "this";
912
913            case StackMapTable_attribute.verification_type_info.ITEM_Object:
914                return "CP";
915
916            case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized:
917                return "uninitialized";
918
919            default:
920                report("unrecognized verification_type_info tag: " + tag);
921                return "[tag:" + tag + "]";
922            }
923        }
924    }
925
926    @Override
927    public Void visitSynthetic(Synthetic_attribute attr, Void ignore) {
928        println("Synthetic: true");
929        return null;
930    }
931
932    @Override
933    public Void visitModuleTarget(ModuleTarget_attribute attr, Void ignore) {
934        println("ModuleTarget:");
935        indent(+1);
936        print("os_name: #" + attr.os_name_index);
937        if (attr.os_name_index != 0) {
938            tab();
939            print("// " + getOSName(attr));
940        }
941        println();
942        print("os_arch: #" + attr.os_arch_index);
943        if (attr.os_arch_index != 0) {
944            tab();
945            print("// " + getOSArch(attr));
946        }
947        println();
948        print("os_version: #" + attr.os_version_index);
949        if (attr.os_version_index != 0) {
950            tab();
951            print("// " + getOSVersion(attr));
952        }
953        println();
954        indent(-1);
955        return null;
956    }
957
958    private String getOSName(ModuleTarget_attribute attr) {
959        try {
960            return constant_pool.getUTF8Value(attr.os_name_index);
961        } catch (ConstantPoolException e) {
962            return report(e);
963        }
964    }
965
966    private String getOSArch(ModuleTarget_attribute attr) {
967        try {
968            return constant_pool.getUTF8Value(attr.os_arch_index);
969        } catch (ConstantPoolException e) {
970            return report(e);
971        }
972    }
973
974    private String getOSVersion(ModuleTarget_attribute attr) {
975        try {
976            return constant_pool.getUTF8Value(attr.os_version_index);
977        } catch (ConstantPoolException e) {
978            return report(e);
979        }
980    }
981
982    @Override
983    public Void visitModuleVersion(ModuleVersion_attribute attr, Void ignore) {
984        print("ModuleVersion: #" + attr.version_index);
985        indent(+1);
986        tab();
987        println("// " + getVersion(attr));
988        indent(-1);
989        return null;
990    }
991
992    private String getVersion(ModuleVersion_attribute attr) {
993        try {
994            return constant_pool.getUTF8Value(attr.version_index);
995        } catch (ConstantPoolException e) {
996            return report(e);
997        }
998    }
999
1000    static String getJavaName(String name) {
1001        return name.replace('/', '.');
1002    }
1003
1004    String toHex(byte b, int w) {
1005        return toHex(b & 0xff, w);
1006    }
1007
1008    static String toHex(int i) {
1009        return StringUtils.toUpperCase(Integer.toString(i, 16));
1010    }
1011
1012    static String toHex(int i, int w) {
1013        String s = StringUtils.toUpperCase(Integer.toHexString(i));
1014        while (s.length() < w)
1015            s = "0" + s;
1016        return StringUtils.toUpperCase(s);
1017    }
1018
1019    static String toHex(byte[] ba) {
1020        StringBuilder sb = new StringBuilder(ba.length);
1021        for (byte b: ba) {
1022            sb.append(String.format("%02x", b & 0xff));
1023        }
1024        return sb.toString();
1025    }
1026
1027    private final AnnotationWriter annotationWriter;
1028    private final CodeWriter codeWriter;
1029    private final ConstantWriter constantWriter;
1030    private final Options options;
1031
1032    private ConstantPool constant_pool;
1033    private Object owner;
1034}
1035