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