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