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