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