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 namestr =
 404                 entry.name_index != 0 ?
 405                 constantWriter.stringValue(entry.name_index) : "<no name>";
 406             String flagstr =
 407                 (0 != (entry.flags & ACC_FINAL) ? "final " : "") +
 408                 (0 != (entry.flags & ACC_MANDATED) ? "mandated " : "") +
 409                 (0 != (entry.flags & ACC_SYNTHETIC) ? "synthetic" : "");
 410             println(String.format(format, namestr, flagstr));
 411         }
 412         indent(-1);
 413         return null;
 414     }
 415 
 416     public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, Void ignore) {
 417         println("RuntimeVisibleAnnotations:");
 418         indent(+1);
 419         for (int i = 0; i < attr.annotations.length; i++) {
 420             print(i + ": ");
 421             annotationWriter.write(attr.annotations[i]);
 422             println();
 423         }
 424         indent(-1);
 425         return null;
 426     }
 427 
 428     public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, Void ignore) {
 429         println("RuntimeInvisibleAnnotations:");
 430         indent(+1);
 431         for (int i = 0; i < attr.annotations.length; i++) {
 432             print(i + ": ");
 433             annotationWriter.write(attr.annotations[i]);
 434             println();
 435         }
 436         indent(-1);
 437         return null;
 438     }
 439 
 440     public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, Void ignore) {
 441         println("RuntimeVisibleTypeAnnotations:");
 442         indent(+1);
 443         for (int i = 0; i < attr.annotations.length; i++) {
 444             print(i + ": ");
 445             annotationWriter.write(attr.annotations[i]);
 446             println();
 447         }
 448         indent(-1);
 449         return null;
 450     }
 451 
 452     public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, Void ignore) {
 453         println("RuntimeInvisibleTypeAnnotations:");
 454         indent(+1);
 455         for (int i = 0; i < attr.annotations.length; i++) {
 456             print(i + ": ");
 457             annotationWriter.write(attr.annotations[i]);
 458             println();
 459         }
 460         indent(-1);
 461         return null;
 462     }
 463 
 464     public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, Void ignore) {
 465         println("RuntimeVisibleParameterAnnotations:");
 466         indent(+1);
 467         for (int param = 0; param < attr.parameter_annotations.length; param++) {
 468             println("parameter " + param + ": ");
 469             indent(+1);
 470             for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
 471                 print(i + ": ");
 472                 annotationWriter.write(attr.parameter_annotations[param][i]);
 473                 println();
 474             }
 475             indent(-1);
 476         }
 477         indent(-1);
 478         return null;
 479     }
 480 
 481     public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, Void ignore) {
 482         println("RuntimeInvisibleParameterAnnotations:");
 483         indent(+1);
 484         for (int param = 0; param < attr.parameter_annotations.length; param++) {
 485             println(param + ": ");
 486             indent(+1);
 487             for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
 488                 print(i + ": ");
 489                 annotationWriter.write(attr.parameter_annotations[param][i]);
 490                 println();
 491             }
 492             indent(-1);
 493         }
 494         indent(-1);
 495         return null;
 496     }
 497 
 498     public Void visitSignature(Signature_attribute attr, Void ignore) {
 499         print("Signature: #" + attr.signature_index);
 500         tab();
 501         println("// " + getSignature(attr));
 502         return null;
 503     }
 504 
 505     String getSignature(Signature_attribute info) {
 506         try {
 507             return info.getSignature(constant_pool);
 508         } catch (ConstantPoolException e) {
 509             return report(e);
 510         }
 511     }
 512 
 513     public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, Void ignore) {
 514         println("SourceDebugExtension: " + attr.getValue());
 515         return null;
 516     }
 517 
 518     public Void visitSourceFile(SourceFile_attribute attr, Void ignore) {
 519         println("SourceFile: \"" + getSourceFile(attr) + "\"");
 520         return null;
 521     }
 522 
 523     private String getSourceFile(SourceFile_attribute attr) {
 524         try {
 525             return attr.getSourceFile(constant_pool);
 526         } catch (ConstantPoolException e) {
 527             return report(e);
 528         }
 529     }
 530 
 531     public Void visitSourceID(SourceID_attribute attr, Void ignore) {
 532         constantWriter.write(attr.sourceID_index);
 533         return null;
 534     }
 535 
 536     public Void visitStackMap(StackMap_attribute attr, Void ignore) {
 537         println("StackMap: number_of_entries = " + attr.number_of_entries);
 538         indent(+1);
 539         StackMapTableWriter w = new StackMapTableWriter();
 540         for (StackMapTable_attribute.stack_map_frame entry : attr.entries) {
 541             w.write(entry);
 542         }
 543         println();
 544         indent(-1);
 545         return null;
 546     }
 547 
 548     public Void visitStackMapTable(StackMapTable_attribute attr, Void ignore) {
 549         println("StackMapTable: number_of_entries = " + attr.number_of_entries);
 550         indent(+1);
 551         StackMapTableWriter w = new StackMapTableWriter();
 552         for (StackMapTable_attribute.stack_map_frame entry : attr.entries) {
 553             w.write(entry);
 554         }
 555         println();
 556         indent(-1);
 557         return null;
 558     }
 559 
 560     class StackMapTableWriter // also handles CLDC StackMap attributes
 561             implements StackMapTable_attribute.stack_map_frame.Visitor<Void,Void> {
 562         public void write(StackMapTable_attribute.stack_map_frame frame) {
 563             frame.accept(this, null);
 564         }
 565 
 566         public Void visit_same_frame(StackMapTable_attribute.same_frame frame, Void p) {
 567             printHeader(frame);
 568             println(" /* same */");
 569             return null;
 570         }
 571 
 572         public Void visit_same_locals_1_stack_item_frame(StackMapTable_attribute.same_locals_1_stack_item_frame frame, Void p) {
 573             printHeader(frame);
 574             println(" /* same_locals_1_stack_item */");
 575             indent(+1);
 576             printMap("stack", frame.stack);
 577             indent(-1);
 578             return null;
 579         }
 580 
 581         public Void visit_same_locals_1_stack_item_frame_extended(StackMapTable_attribute.same_locals_1_stack_item_frame_extended frame, Void p) {
 582             printHeader(frame);
 583             println(" /* same_locals_1_stack_item_frame_extended */");
 584             indent(+1);
 585             println("offset_delta = " + frame.offset_delta);
 586             printMap("stack", frame.stack);
 587             indent(-1);
 588             return null;
 589         }
 590 
 591         public Void visit_chop_frame(StackMapTable_attribute.chop_frame frame, Void p) {
 592             printHeader(frame);
 593             println(" /* chop */");
 594             indent(+1);
 595             println("offset_delta = " + frame.offset_delta);
 596             indent(-1);
 597             return null;
 598         }
 599 
 600         public Void visit_same_frame_extended(StackMapTable_attribute.same_frame_extended frame, Void p) {
 601             printHeader(frame);
 602             println(" /* same_frame_extended */");
 603             indent(+1);
 604             println("offset_delta = " + frame.offset_delta);
 605             indent(-1);
 606             return null;
 607         }
 608 
 609         public Void visit_append_frame(StackMapTable_attribute.append_frame frame, Void p) {
 610             printHeader(frame);
 611             println(" /* append */");
 612             println("     offset_delta = " + frame.offset_delta);
 613             printMap("locals", frame.locals);
 614             return null;
 615         }
 616 
 617         public Void visit_full_frame(StackMapTable_attribute.full_frame frame, Void p) {
 618             printHeader(frame);
 619             if (frame instanceof StackMap_attribute.stack_map_frame) {
 620                 indent(+1);
 621                 println(" offset = " + frame.offset_delta);
 622             } else {
 623                 println(" /* full_frame */");
 624                 indent(+1);
 625                 println("offset_delta = " + frame.offset_delta);
 626             }
 627             printMap("locals", frame.locals);
 628             printMap("stack", frame.stack);
 629             indent(-1);
 630             return null;
 631         }
 632 
 633         void printHeader(StackMapTable_attribute.stack_map_frame frame) {
 634             print("   frame_type = " + frame.frame_type);
 635         }
 636 
 637         void printMap(String name, StackMapTable_attribute.verification_type_info[] map) {
 638             print(name + " = [");
 639             for (int i = 0; i < map.length; i++) {
 640                 StackMapTable_attribute.verification_type_info info = map[i];
 641                 int tag = info.tag;
 642                 switch (tag) {
 643                     case StackMapTable_attribute.verification_type_info.ITEM_Object:
 644                         print(" ");
 645                         constantWriter.write(((StackMapTable_attribute.Object_variable_info) info).cpool_index);
 646                         break;
 647                     case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized:
 648                         print(" " + mapTypeName(tag));
 649                         print(" " + ((StackMapTable_attribute.Uninitialized_variable_info) info).offset);
 650                         break;
 651                     default:
 652                         print(" " + mapTypeName(tag));
 653                 }
 654                 print(i == (map.length - 1) ? " " : ",");
 655             }
 656             println("]");
 657         }
 658 
 659         String mapTypeName(int tag) {
 660             switch (tag) {
 661             case StackMapTable_attribute.verification_type_info.ITEM_Top:
 662                 return "top";
 663 
 664             case StackMapTable_attribute.verification_type_info.ITEM_Integer:
 665                 return "int";
 666 
 667             case StackMapTable_attribute.verification_type_info.ITEM_Float:
 668                 return "float";
 669 
 670             case StackMapTable_attribute.verification_type_info.ITEM_Long:
 671                 return "long";
 672 
 673             case StackMapTable_attribute.verification_type_info.ITEM_Double:
 674                 return "double";
 675 
 676             case StackMapTable_attribute.verification_type_info.ITEM_Null:
 677                 return "null";
 678 
 679             case StackMapTable_attribute.verification_type_info.ITEM_UninitializedThis:
 680                 return "this";
 681 
 682             case StackMapTable_attribute.verification_type_info.ITEM_Object:
 683                 return "CP";
 684 
 685             case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized:
 686                 return "uninitialized";
 687 
 688             default:
 689                 report("unrecognized verification_type_info tag: " + tag);
 690                 return "[tag:" + tag + "]";
 691             }
 692         }
 693     }
 694 
 695     public Void visitSynthetic(Synthetic_attribute attr, Void ignore) {
 696         println("Synthetic: true");
 697         return null;
 698     }
 699 
 700     static String getJavaName(String name) {
 701         return name.replace('/', '.');
 702     }
 703 
 704     String toHex(byte b, int w) {
 705         if (options.compat) // BUG 6622260: javap prints negative bytes incorrectly in hex
 706             return toHex((int) b, w);
 707         else
 708             return toHex(b & 0xff, w);
 709     }
 710 
 711     static String toHex(int i) {
 712         return Integer.toString(i, 16).toUpperCase();
 713     }
 714 
 715     static String toHex(int i, int w) {
 716         String s = Integer.toHexString(i).toUpperCase();
 717         while (s.length() < w)
 718             s = "0" + s;
 719         return s.toUpperCase();
 720     }
 721 
 722     private AnnotationWriter annotationWriter;
 723     private CodeWriter codeWriter;
 724     private ConstantWriter constantWriter;
 725     private Options options;
 726 
 727     private ConstantPool constant_pool;
 728     private Object owner;
 729 }