1 /*
   2  * Copyright (c) 2007, 2013, 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.Formatter;
  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.Code_attribute;
  37 import com.sun.tools.classfile.CompilationID_attribute;
  38 import com.sun.tools.classfile.ConstantPool;
  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.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.RuntimeInvisibleAnnotations_attribute;
  51 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
  52 import com.sun.tools.classfile.RuntimeInvisibleTypeAnnotations_attribute;
  53 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
  54 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
  55 import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
  56 import com.sun.tools.classfile.Signature_attribute;
  57 import com.sun.tools.classfile.SourceDebugExtension_attribute;
  58 import com.sun.tools.classfile.SourceFile_attribute;
  59 import com.sun.tools.classfile.SourceID_attribute;
  60 import com.sun.tools.classfile.StackMapTable_attribute;
  61 import com.sun.tools.classfile.StackMap_attribute;
  62 import com.sun.tools.classfile.Synthetic_attribute;
  63 
  64 import static com.sun.tools.classfile.AccessFlags.*;
  65 
  66 /*
  67  *  A writer for writing Attributes as text.
  68  *
  69  *  <p><b>This is NOT part of any supported API.
  70  *  If you write code that depends on this, you do so at your own risk.
  71  *  This code and its internal interfaces are subject to change or
  72  *  deletion without notice.</b>
  73  */
  74 public class AttributeWriter extends BasicWriter
  75         implements Attribute.Visitor<Void,Void>
  76 {
  77     public static AttributeWriter instance(Context context) {
  78         AttributeWriter instance = context.get(AttributeWriter.class);
  79         if (instance == null)
  80             instance = new AttributeWriter(context);
  81         return instance;
  82     }
  83 
  84     protected AttributeWriter(Context context) {
  85         super(context);
  86         context.put(AttributeWriter.class, this);
  87         annotationWriter = AnnotationWriter.instance(context);
  88         codeWriter = CodeWriter.instance(context);
  89         constantWriter = ConstantWriter.instance(context);
  90         options = Options.instance(context);
  91     }
  92 
  93     public void write(Object owner, Attribute attr, ConstantPool constant_pool) {
  94         if (attr != null) {
  95             // null checks
  96             owner.getClass();
  97             constant_pool.getClass();
  98             this.constant_pool = constant_pool;
  99             this.owner = owner;
 100             attr.accept(this, null);
 101         }
 102     }
 103 
 104     public void write(Object owner, Attributes attrs, ConstantPool constant_pool) {
 105         if (attrs != null) {
 106             // null checks
 107             owner.getClass();
 108             constant_pool.getClass();
 109             this.constant_pool = constant_pool;
 110             this.owner = owner;
 111             for (Attribute attr: attrs)
 112                 attr.accept(this, null);
 113         }
 114     }
 115 
 116     public Void visitDefault(DefaultAttribute attr, Void ignore) {
 117         byte[] data = attr.info;
 118         int i = 0;
 119         int j = 0;
 120         print("  ");
 121         try {
 122             print(attr.getName(constant_pool));
 123         } catch (ConstantPoolException e) {
 124             report(e);
 125             print("attribute name = #" + attr.attribute_name_index);
 126         }
 127         print(": ");
 128         println("length = 0x" + toHex(attr.info.length));
 129 
 130         print("   ");
 131 
 132         while (i < data.length) {
 133             print(toHex(data[i], 2));
 134 
 135             j++;
 136             if (j == 16) {
 137                 println();
 138                 print("   ");
 139                 j = 0;
 140             } else {
 141                 print(" ");
 142             }
 143             i++;
 144         }
 145         println();
 146         return null;
 147     }
 148 
 149     public Void visitAnnotationDefault(AnnotationDefault_attribute attr, Void ignore) {
 150         println("AnnotationDefault:");
 151         indent(+1);
 152         print("default_value: ");
 153         annotationWriter.write(attr.default_value);
 154         indent(-1);
 155         return null;
 156     }
 157 
 158     public Void visitBootstrapMethods(BootstrapMethods_attribute attr, Void p) {
 159         println(Attribute.BootstrapMethods + ":");
 160         for (int i = 0; i < attr.bootstrap_method_specifiers.length ; i++) {
 161             BootstrapMethods_attribute.BootstrapMethodSpecifier bsm = attr.bootstrap_method_specifiers[i];
 162             indent(+1);
 163             print(i + ": #" + bsm.bootstrap_method_ref + " ");
 164             println(constantWriter.stringValue(bsm.bootstrap_method_ref));
 165             indent(+1);
 166             println("Method arguments:");
 167             indent(+1);
 168             for (int j = 0; j < bsm.bootstrap_arguments.length; j++) {
 169                 print("#" + bsm.bootstrap_arguments[j] + " ");
 170                 println(constantWriter.stringValue(bsm.bootstrap_arguments[j]));
 171             }
 172             indent(-3);
 173         }
 174         return null;
 175     }
 176 
 177     public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, Void ignore) {
 178         println("CharacterRangeTable:");
 179         indent(+1);
 180         for (int i = 0; i < attr.character_range_table.length; i++) {
 181             CharacterRangeTable_attribute.Entry e = attr.character_range_table[i];
 182             print(String.format("    %2d, %2d, %6x, %6x, %4x",
 183                     e.start_pc, e.end_pc,
 184                     e.character_range_start, e.character_range_end,
 185                     e.flags));
 186             tab();
 187             print(String.format("// %2d, %2d, %4d:%02d, %4d:%02d",
 188                     e.start_pc, e.end_pc,
 189                     (e.character_range_start >> 10), (e.character_range_start & 0x3ff),
 190                     (e.character_range_end >> 10), (e.character_range_end & 0x3ff)));
 191             if ((e.flags & CharacterRangeTable_attribute.CRT_STATEMENT) != 0)
 192                 print(", statement");
 193             if ((e.flags & CharacterRangeTable_attribute.CRT_BLOCK) != 0)
 194                 print(", block");
 195             if ((e.flags & CharacterRangeTable_attribute.CRT_ASSIGNMENT) != 0)
 196                 print(", assignment");
 197             if ((e.flags & CharacterRangeTable_attribute.CRT_FLOW_CONTROLLER) != 0)
 198                 print(", flow-controller");
 199             if ((e.flags & CharacterRangeTable_attribute.CRT_FLOW_TARGET) != 0)
 200                 print(", flow-target");
 201             if ((e.flags & CharacterRangeTable_attribute.CRT_INVOKE) != 0)
 202                 print(", invoke");
 203             if ((e.flags & CharacterRangeTable_attribute.CRT_CREATE) != 0)
 204                 print(", create");
 205             if ((e.flags & CharacterRangeTable_attribute.CRT_BRANCH_TRUE) != 0)
 206                 print(", branch-true");
 207             if ((e.flags & CharacterRangeTable_attribute.CRT_BRANCH_FALSE) != 0)
 208                 print(", branch-false");
 209             println();
 210         }
 211         indent(-1);
 212         return null;
 213     }
 214 
 215     public Void visitCode(Code_attribute attr, Void ignore) {
 216         codeWriter.write(attr, constant_pool);
 217         return null;
 218     }
 219 
 220     public Void visitCompilationID(CompilationID_attribute attr, Void ignore) {
 221         constantWriter.write(attr.compilationID_index);
 222         return null;
 223     }
 224 
 225     public Void visitConstantValue(ConstantValue_attribute attr, Void ignore) {
 226         if (options.compat) // BUG 6622216 javap names some attributes incorrectly
 227             print("Constant value: ");
 228         else
 229             print("ConstantValue: ");
 230         constantWriter.write(attr.constantvalue_index);
 231         println();
 232         return null;
 233     }
 234 
 235     public Void visitDeprecated(Deprecated_attribute attr, Void ignore) {
 236         println("Deprecated: true");
 237         return null;
 238     }
 239 
 240     public Void visitEnclosingMethod(EnclosingMethod_attribute attr, Void ignore) {
 241         print("EnclosingMethod: #" + attr.class_index + ".#" + attr.method_index);
 242         tab();
 243         print("// " + getJavaClassName(attr));
 244         if (attr.method_index != 0)
 245             print("." + getMethodName(attr));
 246         println();
 247         return null;
 248     }
 249 
 250     private String getJavaClassName(EnclosingMethod_attribute a) {
 251         try {
 252             return getJavaName(a.getClassName(constant_pool));
 253         } catch (ConstantPoolException e) {
 254             return report(e);
 255         }
 256     }
 257 
 258     private String getMethodName(EnclosingMethod_attribute a) {
 259         try {
 260             return a.getMethodName(constant_pool);
 261         } catch (ConstantPoolException e) {
 262             return report(e);
 263         }
 264     }
 265 
 266     public Void visitExceptions(Exceptions_attribute attr, Void ignore) {
 267         println("Exceptions:");
 268         indent(+1);
 269         print("throws ");
 270         for (int i = 0; i < attr.number_of_exceptions; i++) {
 271             if (i > 0)
 272                 print(", ");
 273             print(getJavaException(attr, i));
 274         }
 275         println();
 276         indent(-1);
 277         return null;
 278     }
 279 
 280     private String getJavaException(Exceptions_attribute attr, int index) {
 281         try {
 282             return getJavaName(attr.getException(index, constant_pool));
 283         } catch (ConstantPoolException e) {
 284             return report(e);
 285         }
 286     }
 287 
 288     public Void visitInnerClasses(InnerClasses_attribute attr, Void ignore) {
 289         boolean first = true;
 290         if (options.compat) {
 291             writeInnerClassHeader();
 292             first = false;
 293         }
 294         for (int i = 0 ; i < attr.classes.length; i++) {
 295             InnerClasses_attribute.Info info = attr.classes[i];
 296             //access
 297             AccessFlags access_flags = info.inner_class_access_flags;
 298             if (options.compat) {
 299                 // BUG 6622215: javap ignores certain relevant access flags
 300                 access_flags = access_flags.ignore(ACC_STATIC | ACC_PROTECTED | ACC_PRIVATE | ACC_INTERFACE | ACC_SYNTHETIC | ACC_ENUM);
 301                 // BUG 6622232: javap gets whitespace confused
 302                 print("   ");
 303             }
 304             if (options.checkAccess(access_flags)) {
 305                 if (first) {
 306                     writeInnerClassHeader();
 307                     first = false;
 308                 }
 309                 print("   ");
 310                 for (String name: access_flags.getInnerClassModifiers())
 311                     print(name + " ");
 312                 if (info.inner_name_index!=0) {
 313                     print("#" + info.inner_name_index + "= ");
 314                 }
 315                 print("#" + info.inner_class_info_index);
 316                 if (info.outer_class_info_index != 0) {
 317                     print(" of #" + info.outer_class_info_index);
 318                 }
 319                 print("; //");
 320                 if (info.inner_name_index != 0) {
 321                     print(getInnerName(constant_pool, info) + "=");
 322                 }
 323                 constantWriter.write(info.inner_class_info_index);
 324                 if (info.outer_class_info_index != 0) {
 325                     print(" of ");
 326                     constantWriter.write(info.outer_class_info_index);
 327                 }
 328                 println();
 329             }
 330         }
 331         if (!first)
 332             indent(-1);
 333         return null;
 334     }
 335 
 336     String getInnerName(ConstantPool constant_pool, InnerClasses_attribute.Info info) {
 337         try {
 338             return info.getInnerName(constant_pool);
 339         } catch (ConstantPoolException e) {
 340             return report(e);
 341         }
 342     }
 343 
 344     private void writeInnerClassHeader() {
 345         if (options.compat) // BUG 6622216: javap names some attributes incorrectly
 346             print("InnerClass");
 347         else
 348             print("InnerClasses");
 349         println(":");
 350         indent(+1);
 351     }
 352 
 353     public Void visitLineNumberTable(LineNumberTable_attribute attr, Void ignore) {
 354         println("LineNumberTable:");
 355         indent(+1);
 356         for (LineNumberTable_attribute.Entry entry: attr.line_number_table) {
 357             println("line " + entry.line_number + ": " + entry.start_pc);
 358         }
 359         indent(-1);
 360         return null;
 361     }
 362 
 363     public Void visitLocalVariableTable(LocalVariableTable_attribute attr, Void ignore) {
 364         println("LocalVariableTable:");
 365         indent(+1);
 366         println("Start  Length  Slot  Name   Signature");
 367         for (LocalVariableTable_attribute.Entry entry : attr.local_variable_table) {
 368             Formatter formatter = new Formatter();
 369             println(formatter.format("%8d %7d %5d %5s   %s",
 370                     entry.start_pc, entry.length, entry.index,
 371                     constantWriter.stringValue(entry.name_index),
 372                     constantWriter.stringValue(entry.descriptor_index)));
 373         }
 374         indent(-1);
 375         return null;
 376     }
 377 
 378     public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, Void ignore) {
 379         println("LocalVariableTypeTable:");
 380         indent(+1);
 381         println("Start  Length  Slot  Name   Signature");
 382         for (LocalVariableTypeTable_attribute.Entry entry : attr.local_variable_table) {
 383             println(String.format("%5d %7d %5d %5s   %s",
 384                     entry.start_pc, entry.length, entry.index,
 385                     constantWriter.stringValue(entry.name_index),
 386                     constantWriter.stringValue(entry.signature_index)));
 387         }
 388         indent(-1);
 389         return null;
 390     }
 391 
 392     private static final String format = "%-31s%s";
 393 
 394     public Void visitMethodParameters(MethodParameters_attribute attr,
 395                                       Void ignore) {
 396 
 397         final String header = String.format(format, "Name", "Flags");
 398         println("MethodParameters:");
 399         indent(+1);
 400         println(header);
 401         for (MethodParameters_attribute.Entry entry :
 402                  attr.method_parameter_table) {
 403             String flagstr =
 404                 (0 != (entry.flags & ACC_FINAL) ? " final" : "") +
 405                 (0 != (entry.flags & ACC_SYNTHETIC) ? " synthetic" : "");
 406             println(String.format(format,
 407                                   constantWriter.stringValue(entry.name_index),
 408                                   flagstr));
 409         }
 410         indent(-1);
 411         return null;
 412     }
 413 
 414     public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, Void ignore) {
 415         println("RuntimeVisibleAnnotations:");
 416         indent(+1);
 417         for (int i = 0; i < attr.annotations.length; i++) {
 418             print(i + ": ");
 419             annotationWriter.write(attr.annotations[i]);
 420             println();
 421         }
 422         indent(-1);
 423         return null;
 424     }
 425 
 426     public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, Void ignore) {
 427         println("RuntimeInvisibleAnnotations:");
 428         indent(+1);
 429         for (int i = 0; i < attr.annotations.length; i++) {
 430             print(i + ": ");
 431             annotationWriter.write(attr.annotations[i]);
 432             println();
 433         }
 434         indent(-1);
 435         return null;
 436     }
 437 
 438     public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, Void ignore) {
 439         println("RuntimeVisibleTypeAnnotations:");
 440         indent(+1);
 441         for (int i = 0; i < attr.annotations.length; i++) {
 442             print(i + ": ");
 443             annotationWriter.write(attr.annotations[i]);
 444             println();
 445         }
 446         indent(-1);
 447         return null;
 448     }
 449 
 450     public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, Void ignore) {
 451         println("RuntimeInvisibleTypeAnnotations:");
 452         indent(+1);
 453         for (int i = 0; i < attr.annotations.length; i++) {
 454             print(i + ": ");
 455             annotationWriter.write(attr.annotations[i]);
 456             println();
 457         }
 458         indent(-1);
 459         return null;
 460     }
 461 
 462     public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, Void ignore) {
 463         println("RuntimeVisibleParameterAnnotations:");
 464         indent(+1);
 465         for (int param = 0; param < attr.parameter_annotations.length; param++) {
 466             println("parameter " + param + ": ");
 467             indent(+1);
 468             for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
 469                 print(i + ": ");
 470                 annotationWriter.write(attr.parameter_annotations[param][i]);
 471                 println();
 472             }
 473             indent(-1);
 474         }
 475         indent(-1);
 476         return null;
 477     }
 478 
 479     public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, Void ignore) {
 480         println("RuntimeInvisibleParameterAnnotations:");
 481         indent(+1);
 482         for (int param = 0; param < attr.parameter_annotations.length; param++) {
 483             println(param + ": ");
 484             indent(+1);
 485             for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
 486                 print(i + ": ");
 487                 annotationWriter.write(attr.parameter_annotations[param][i]);
 488                 println();
 489             }
 490             indent(-1);
 491         }
 492         indent(-1);
 493         return null;
 494     }
 495 
 496     public Void visitSignature(Signature_attribute attr, Void ignore) {
 497         print("Signature: #" + attr.signature_index);
 498         tab();
 499         println("// " + getSignature(attr));
 500         return null;
 501     }
 502 
 503     String getSignature(Signature_attribute info) {
 504         try {
 505             return info.getSignature(constant_pool);
 506         } catch (ConstantPoolException e) {
 507             return report(e);
 508         }
 509     }
 510 
 511     public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, Void ignore) {
 512         println("SourceDebugExtension: " + attr.getValue());
 513         return null;
 514     }
 515 
 516     public Void visitSourceFile(SourceFile_attribute attr, Void ignore) {
 517         println("SourceFile: \"" + getSourceFile(attr) + "\"");
 518         return null;
 519     }
 520 
 521     private String getSourceFile(SourceFile_attribute attr) {
 522         try {
 523             return attr.getSourceFile(constant_pool);
 524         } catch (ConstantPoolException e) {
 525             return report(e);
 526         }
 527     }
 528 
 529     public Void visitSourceID(SourceID_attribute attr, Void ignore) {
 530         constantWriter.write(attr.sourceID_index);
 531         return null;
 532     }
 533 
 534     public Void visitStackMap(StackMap_attribute attr, Void ignore) {
 535         println("StackMap: number_of_entries = " + attr.number_of_entries);
 536         indent(+1);
 537         StackMapTableWriter w = new StackMapTableWriter();
 538         for (StackMapTable_attribute.stack_map_frame entry : attr.entries) {
 539             w.write(entry);
 540         }
 541         println();
 542         indent(-1);
 543         return null;
 544     }
 545 
 546     public Void visitStackMapTable(StackMapTable_attribute attr, Void ignore) {
 547         println("StackMapTable: number_of_entries = " + attr.number_of_entries);
 548         indent(+1);
 549         StackMapTableWriter w = new StackMapTableWriter();
 550         for (StackMapTable_attribute.stack_map_frame entry : attr.entries) {
 551             w.write(entry);
 552         }
 553         println();
 554         indent(-1);
 555         return null;
 556     }
 557 
 558     class StackMapTableWriter // also handles CLDC StackMap attributes
 559             implements StackMapTable_attribute.stack_map_frame.Visitor<Void,Void> {
 560         public void write(StackMapTable_attribute.stack_map_frame frame) {
 561             frame.accept(this, null);
 562         }
 563 
 564         public Void visit_same_frame(StackMapTable_attribute.same_frame frame, Void p) {
 565             printHeader(frame);
 566             println(" /* same */");
 567             return null;
 568         }
 569 
 570         public Void visit_same_locals_1_stack_item_frame(StackMapTable_attribute.same_locals_1_stack_item_frame frame, Void p) {
 571             printHeader(frame);
 572             println(" /* same_locals_1_stack_item */");
 573             indent(+1);
 574             printMap("stack", frame.stack);
 575             indent(-1);
 576             return null;
 577         }
 578 
 579         public Void visit_same_locals_1_stack_item_frame_extended(StackMapTable_attribute.same_locals_1_stack_item_frame_extended frame, Void p) {
 580             printHeader(frame);
 581             println(" /* same_locals_1_stack_item_frame_extended */");
 582             indent(+1);
 583             println("offset_delta = " + frame.offset_delta);
 584             printMap("stack", frame.stack);
 585             indent(-1);
 586             return null;
 587         }
 588 
 589         public Void visit_chop_frame(StackMapTable_attribute.chop_frame frame, Void p) {
 590             printHeader(frame);
 591             println(" /* chop */");
 592             indent(+1);
 593             println("offset_delta = " + frame.offset_delta);
 594             indent(-1);
 595             return null;
 596         }
 597 
 598         public Void visit_same_frame_extended(StackMapTable_attribute.same_frame_extended frame, Void p) {
 599             printHeader(frame);
 600             println(" /* same_frame_extended */");
 601             indent(+1);
 602             println("offset_delta = " + frame.offset_delta);
 603             indent(-1);
 604             return null;
 605         }
 606 
 607         public Void visit_append_frame(StackMapTable_attribute.append_frame frame, Void p) {
 608             printHeader(frame);
 609             println(" /* append */");
 610             println("     offset_delta = " + frame.offset_delta);
 611             printMap("locals", frame.locals);
 612             return null;
 613         }
 614 
 615         public Void visit_full_frame(StackMapTable_attribute.full_frame frame, Void p) {
 616             printHeader(frame);
 617             if (frame instanceof StackMap_attribute.stack_map_frame) {
 618                 indent(+1);
 619                 println(" offset = " + frame.offset_delta);
 620             } else {
 621                 println(" /* full_frame */");
 622                 indent(+1);
 623                 println("offset_delta = " + frame.offset_delta);
 624             }
 625             printMap("locals", frame.locals);
 626             printMap("stack", frame.stack);
 627             indent(-1);
 628             return null;
 629         }
 630 
 631         void printHeader(StackMapTable_attribute.stack_map_frame frame) {
 632             print("   frame_type = " + frame.frame_type);
 633         }
 634 
 635         void printMap(String name, StackMapTable_attribute.verification_type_info[] map) {
 636             print(name + " = [");
 637             for (int i = 0; i < map.length; i++) {
 638                 StackMapTable_attribute.verification_type_info info = map[i];
 639                 int tag = info.tag;
 640                 switch (tag) {
 641                     case StackMapTable_attribute.verification_type_info.ITEM_Object:
 642                         print(" ");
 643                         constantWriter.write(((StackMapTable_attribute.Object_variable_info) info).cpool_index);
 644                         break;
 645                     case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized:
 646                         print(" " + mapTypeName(tag));
 647                         print(" " + ((StackMapTable_attribute.Uninitialized_variable_info) info).offset);
 648                         break;
 649                     default:
 650                         print(" " + mapTypeName(tag));
 651                 }
 652                 print(i == (map.length - 1) ? " " : ",");
 653             }
 654             println("]");
 655         }
 656 
 657         String mapTypeName(int tag) {
 658             switch (tag) {
 659             case StackMapTable_attribute.verification_type_info.ITEM_Top:
 660                 return "top";
 661 
 662             case StackMapTable_attribute.verification_type_info.ITEM_Integer:
 663                 return "int";
 664 
 665             case StackMapTable_attribute.verification_type_info.ITEM_Float:
 666                 return "float";
 667 
 668             case StackMapTable_attribute.verification_type_info.ITEM_Long:
 669                 return "long";
 670 
 671             case StackMapTable_attribute.verification_type_info.ITEM_Double:
 672                 return "double";
 673 
 674             case StackMapTable_attribute.verification_type_info.ITEM_Null:
 675                 return "null";
 676 
 677             case StackMapTable_attribute.verification_type_info.ITEM_UninitializedThis:
 678                 return "this";
 679 
 680             case StackMapTable_attribute.verification_type_info.ITEM_Object:
 681                 return "CP";
 682 
 683             case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized:
 684                 return "uninitialized";
 685 
 686             default:
 687                 report("unrecognized verification_type_info tag: " + tag);
 688                 return "[tag:" + tag + "]";
 689             }
 690         }
 691     }
 692 
 693     public Void visitSynthetic(Synthetic_attribute attr, Void ignore) {
 694         println("Synthetic: true");
 695         return null;
 696     }
 697 
 698     static String getJavaName(String name) {
 699         return name.replace('/', '.');
 700     }
 701 
 702     String toHex(byte b, int w) {
 703         if (options.compat) // BUG 6622260: javap prints negative bytes incorrectly in hex
 704             return toHex((int) b, w);
 705         else
 706             return toHex(b & 0xff, w);
 707     }
 708 
 709     static String toHex(int i) {
 710         return Integer.toString(i, 16).toUpperCase();
 711     }
 712 
 713     static String toHex(int i, int w) {
 714         String s = Integer.toHexString(i).toUpperCase();
 715         while (s.length() < w)
 716             s = "0" + s;
 717         return s.toUpperCase();
 718     }
 719 
 720     private AnnotationWriter annotationWriter;
 721     private CodeWriter codeWriter;
 722     private ConstantWriter constantWriter;
 723     private Options options;
 724 
 725     private ConstantPool constant_pool;
 726     private Object owner;
 727 }