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