rev 47452 : imported patch jdk-new-asmv6.patch

   1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * ASM: a very small and fast Java bytecode manipulation framework
  32  * Copyright (c) 2000-2011 INRIA, France Telecom
  33  * All rights reserved.
  34  *
  35  * Redistribution and use in source and binary forms, with or without
  36  * modification, are permitted provided that the following conditions
  37  * are met:
  38  * 1. Redistributions of source code must retain the above copyright
  39  *    notice, this list of conditions and the following disclaimer.
  40  * 2. Redistributions in binary form must reproduce the above copyright
  41  *    notice, this list of conditions and the following disclaimer in the
  42  *    documentation and/or other materials provided with the distribution.
  43  * 3. Neither the name of the copyright holders nor the names of its
  44  *    contributors may be used to endorse or promote products derived from
  45  *    this software without specific prior written permission.
  46  *
  47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  57  * THE POSSIBILITY OF SUCH DAMAGE.
  58  */
  59 package jdk.internal.org.objectweb.asm.util;
  60 
  61 import java.io.FileInputStream;
  62 import java.io.PrintWriter;
  63 import java.util.HashMap;
  64 import java.util.Map;
  65 
  66 import jdk.internal.org.objectweb.asm.Attribute;
  67 import jdk.internal.org.objectweb.asm.ClassReader;
  68 import jdk.internal.org.objectweb.asm.Handle;
  69 import jdk.internal.org.objectweb.asm.Label;
  70 import jdk.internal.org.objectweb.asm.Opcodes;
  71 import jdk.internal.org.objectweb.asm.Type;
  72 import jdk.internal.org.objectweb.asm.TypePath;
  73 import jdk.internal.org.objectweb.asm.TypeReference;
  74 import jdk.internal.org.objectweb.asm.signature.SignatureReader;
  75 
  76 /**
  77  * A {@link Printer} that prints a disassembled view of the classes it visits.
  78  *
  79  * @author Eric Bruneton
  80  */
  81 public class Textifier extends Printer {
  82 
  83     /**
  84      * Constant used in {@link #appendDescriptor appendDescriptor} for internal
  85      * type names in bytecode notation.
  86      */
  87     public static final int INTERNAL_NAME = 0;
  88 
  89     /**
  90      * Constant used in {@link #appendDescriptor appendDescriptor} for field
  91      * descriptors, formatted in bytecode notation
  92      */
  93     public static final int FIELD_DESCRIPTOR = 1;
  94 
  95     /**
  96      * Constant used in {@link #appendDescriptor appendDescriptor} for field
  97      * signatures, formatted in bytecode notation
  98      */
  99     public static final int FIELD_SIGNATURE = 2;
 100 
 101     /**
 102      * Constant used in {@link #appendDescriptor appendDescriptor} for method
 103      * descriptors, formatted in bytecode notation
 104      */
 105     public static final int METHOD_DESCRIPTOR = 3;
 106 
 107     /**
 108      * Constant used in {@link #appendDescriptor appendDescriptor} for method
 109      * signatures, formatted in bytecode notation
 110      */
 111     public static final int METHOD_SIGNATURE = 4;
 112 
 113     /**
 114      * Constant used in {@link #appendDescriptor appendDescriptor} for class
 115      * signatures, formatted in bytecode notation
 116      */
 117     public static final int CLASS_SIGNATURE = 5;
 118 
 119     /**
 120      * Constant used in {@link #appendDescriptor appendDescriptor} for field or
 121      * method return value signatures, formatted in default Java notation
 122      * (non-bytecode)
 123      */
 124     public static final int TYPE_DECLARATION = 6;
 125 
 126     /**
 127      * Constant used in {@link #appendDescriptor appendDescriptor} for class
 128      * signatures, formatted in default Java notation (non-bytecode)
 129      */
 130     public static final int CLASS_DECLARATION = 7;
 131 
 132     /**
 133      * Constant used in {@link #appendDescriptor appendDescriptor} for method
 134      * parameter signatures, formatted in default Java notation (non-bytecode)
 135      */
 136     public static final int PARAMETERS_DECLARATION = 8;
 137 
 138     /**
 139      * Constant used in {@link #appendDescriptor appendDescriptor} for handle
 140      * descriptors, formatted in bytecode notation
 141      */
 142     public static final int HANDLE_DESCRIPTOR = 9;
 143 
 144     /**
 145      * Tab for class members.
 146      */
 147     protected String tab = "  ";
 148 
 149     /**
 150      * Tab for bytecode instructions.
 151      */
 152     protected String tab2 = "    ";
 153 
 154     /**
 155      * Tab for table and lookup switch instructions.
 156      */
 157     protected String tab3 = "      ";
 158 
 159     /**
 160      * Tab for labels.
 161      */
 162     protected String ltab = "   ";
 163 
 164     /**
 165      * The label names. This map associate String values to Label keys.
 166      */
 167     protected Map<Label, String> labelNames;
 168 
 169     /**
 170      * Class access flags
 171      */
 172     private int access;
 173 
 174     private int valueNumber = 0;
 175 
 176     /**
 177      * Constructs a new {@link Textifier}. <i>Subclasses must not use this
 178      * constructor</i>. Instead, they must use the {@link #Textifier(int)}
 179      * version.
 180      *
 181      * @throws IllegalStateException
 182      *             If a subclass calls this constructor.
 183      */
 184     public Textifier() {
 185         this(Opcodes.ASM6);
 186         if (getClass() != Textifier.class) {
 187             throw new IllegalStateException();
 188         }
 189     }
 190 
 191     /**
 192      * Constructs a new {@link Textifier}.
 193      *
 194      * @param api
 195      *            the ASM API version implemented by this visitor. Must be one
 196      *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
 197      */
 198     protected Textifier(final int api) {
 199         super(api);
 200     }
 201 
 202     /**
 203      * Prints a disassembled view of the given class to the standard output.
 204      * <p>
 205      * Usage: Textifier [-debug] &lt;binary class name or class file name &gt;
 206      *
 207      * @param args
 208      *            the command line arguments.
 209      *
 210      * @throws Exception
 211      *             if the class cannot be found, or if an IO exception occurs.
 212      */
 213     public static void main(final String[] args) throws Exception {
 214         int i = 0;
 215         int flags = ClassReader.SKIP_DEBUG;
 216 
 217         boolean ok = true;
 218         if (args.length < 1 || args.length > 2) {
 219             ok = false;
 220         }
 221         if (ok && "-debug".equals(args[0])) {
 222             i = 1;
 223             flags = 0;
 224             if (args.length != 2) {
 225                 ok = false;
 226             }
 227         }
 228         if (!ok) {
 229             System.err
 230                     .println("Prints a disassembled view of the given class.");
 231             System.err.println("Usage: Textifier [-debug] "
 232                     + "<fully qualified class name or class file name>");
 233             return;
 234         }
 235         ClassReader cr;
 236         if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
 237                 || args[i].indexOf('/') > -1) {
 238             cr = new ClassReader(new FileInputStream(args[i]));
 239         } else {
 240             cr = new ClassReader(args[i]);
 241         }
 242         cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), flags);
 243     }
 244 
 245     // ------------------------------------------------------------------------
 246     // Classes
 247     // ------------------------------------------------------------------------
 248 
 249     @Override
 250     public void visit(final int version, final int access, final String name,
 251             final String signature, final String superName,
 252             final String[] interfaces) {
 253         if ((access & Opcodes.ACC_MODULE) != 0) {
 254             // visitModule will print the module
 255             return;
 256         }
 257         this.access = access;
 258         int major = version & 0xFFFF;
 259         int minor = version >>> 16;
 260         buf.setLength(0);
 261         buf.append("// class version ").append(major).append('.').append(minor)
 262                 .append(" (").append(version).append(")\n");
 263         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
 264             buf.append("// DEPRECATED\n");
 265         }
 266         buf.append("// access flags 0x")
 267                 .append(Integer.toHexString(access).toUpperCase()).append('\n');
 268 
 269         appendDescriptor(CLASS_SIGNATURE, signature);
 270         if (signature != null) {
 271             TraceSignatureVisitor sv = new TraceSignatureVisitor(access);
 272             SignatureReader r = new SignatureReader(signature);
 273             r.accept(sv);
 274             buf.append("// declaration: ").append(name)
 275                     .append(sv.getDeclaration()).append('\n');
 276         }
 277 
 278         appendAccess(access & ~(Opcodes.ACC_SUPER | Opcodes.ACC_MODULE));
 279         if ((access & Opcodes.ACC_ANNOTATION) != 0) {
 280             buf.append("@interface ");
 281         } else if ((access & Opcodes.ACC_INTERFACE) != 0) {
 282             buf.append("interface ");
 283         } else if ((access & Opcodes.ACC_ENUM) == 0) {
 284             buf.append("class ");
 285         }
 286         appendDescriptor(INTERNAL_NAME, name);
 287 
 288         if (superName != null && !"java/lang/Object".equals(superName)) {
 289             buf.append(" extends ");
 290             appendDescriptor(INTERNAL_NAME, superName);
 291             buf.append(' ');
 292         }
 293         if (interfaces != null && interfaces.length > 0) {
 294             buf.append(" implements ");
 295             for (int i = 0; i < interfaces.length; ++i) {
 296                 appendDescriptor(INTERNAL_NAME, interfaces[i]);
 297                 buf.append(' ');
 298             }
 299         }
 300         buf.append(" {\n\n");
 301 
 302         text.add(buf.toString());
 303     }
 304 
 305     @Override
 306     public void visitSource(final String file, final String debug) {
 307         buf.setLength(0);
 308         if (file != null) {
 309             buf.append(tab).append("// compiled from: ").append(file)
 310                     .append('\n');
 311         }
 312         if (debug != null) {
 313             buf.append(tab).append("// debug info: ").append(debug)
 314                     .append('\n');
 315         }
 316         if (buf.length() > 0) {
 317             text.add(buf.toString());
 318         }
 319     }
 320 
 321     @Override
 322     public Printer visitModule(final String name, final int access,
 323             final String version) {
 324         buf.setLength(0);
 325         if ((access & Opcodes.ACC_OPEN) != 0) {
 326             buf.append("open ");
 327         }
 328         buf.append("module ")
 329            .append(name)
 330            .append(" { ")
 331            .append(version == null ? "" : "// " + version)
 332            .append("\n\n");
 333         text.add(buf.toString());
 334         Textifier t = createTextifier();
 335         text.add(t.getText());
 336         return t;
 337     }
 338 
 339     @Override
 340     public void visitOuterClass(final String owner, final String name,
 341             final String desc) {
 342         buf.setLength(0);
 343         buf.append(tab).append("OUTERCLASS ");
 344         appendDescriptor(INTERNAL_NAME, owner);
 345         buf.append(' ');
 346         if (name != null) {
 347             buf.append(name).append(' ');
 348         }
 349         appendDescriptor(METHOD_DESCRIPTOR, desc);
 350         buf.append('\n');
 351         text.add(buf.toString());
 352     }
 353 
 354     @Override
 355     public Textifier visitClassAnnotation(final String desc,
 356             final boolean visible) {
 357         text.add("\n");
 358         return visitAnnotation(desc, visible);
 359     }
 360 
 361     @Override
 362     public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath,
 363             String desc, boolean visible) {
 364         text.add("\n");
 365         return visitTypeAnnotation(typeRef, typePath, desc, visible);
 366     }
 367 
 368     @Override
 369     public void visitClassAttribute(final Attribute attr) {
 370         text.add("\n");
 371         visitAttribute(attr);
 372     }
 373 
 374     @Override
 375     public void visitInnerClass(final String name, final String outerName,
 376             final String innerName, final int access) {
 377         buf.setLength(0);
 378         buf.append(tab).append("// access flags 0x");
 379         buf.append(
 380                 Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase())
 381                 .append('\n');
 382         buf.append(tab);
 383         appendAccess(access);
 384         buf.append("INNERCLASS ");
 385         appendDescriptor(INTERNAL_NAME, name);
 386         buf.append(' ');
 387         appendDescriptor(INTERNAL_NAME, outerName);
 388         buf.append(' ');
 389         appendDescriptor(INTERNAL_NAME, innerName);
 390         buf.append('\n');
 391         text.add(buf.toString());
 392     }
 393 
 394     @Override
 395     public Textifier visitField(final int access, final String name,
 396             final String desc, final String signature, final Object value) {
 397         buf.setLength(0);
 398         buf.append('\n');
 399         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
 400             buf.append(tab).append("// DEPRECATED\n");
 401         }
 402         buf.append(tab).append("// access flags 0x")
 403                 .append(Integer.toHexString(access).toUpperCase()).append('\n');
 404         if (signature != null) {
 405             buf.append(tab);
 406             appendDescriptor(FIELD_SIGNATURE, signature);
 407 
 408             TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
 409             SignatureReader r = new SignatureReader(signature);
 410             r.acceptType(sv);
 411             buf.append(tab).append("// declaration: ")
 412                     .append(sv.getDeclaration()).append('\n');
 413         }
 414 
 415         buf.append(tab);
 416         appendAccess(access);
 417 
 418         appendDescriptor(FIELD_DESCRIPTOR, desc);
 419         buf.append(' ').append(name);
 420         if (value != null) {
 421             buf.append(" = ");
 422             if (value instanceof String) {
 423                 buf.append('\"').append(value).append('\"');
 424             } else {
 425                 buf.append(value);
 426             }
 427         }
 428 
 429         buf.append('\n');
 430         text.add(buf.toString());
 431 
 432         Textifier t = createTextifier();
 433         text.add(t.getText());
 434         return t;
 435     }
 436 
 437     @Override
 438     public Textifier visitMethod(final int access, final String name,
 439             final String desc, final String signature, final String[] exceptions) {
 440         buf.setLength(0);
 441         buf.append('\n');
 442         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
 443             buf.append(tab).append("// DEPRECATED\n");
 444         }
 445         buf.append(tab).append("// access flags 0x")
 446                 .append(Integer.toHexString(access).toUpperCase()).append('\n');
 447 
 448         if (signature != null) {
 449             buf.append(tab);
 450             appendDescriptor(METHOD_SIGNATURE, signature);
 451 
 452             TraceSignatureVisitor v = new TraceSignatureVisitor(0);
 453             SignatureReader r = new SignatureReader(signature);
 454             r.accept(v);
 455             String genericDecl = v.getDeclaration();
 456             String genericReturn = v.getReturnType();
 457             String genericExceptions = v.getExceptions();
 458 
 459             buf.append(tab).append("// declaration: ").append(genericReturn)
 460                     .append(' ').append(name).append(genericDecl);
 461             if (genericExceptions != null) {
 462                 buf.append(" throws ").append(genericExceptions);
 463             }
 464             buf.append('\n');
 465         }
 466 
 467         buf.append(tab);
 468         appendAccess(access & ~(Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT));
 469         if ((access & Opcodes.ACC_NATIVE) != 0) {
 470             buf.append("native ");
 471         }
 472         if ((access & Opcodes.ACC_VARARGS) != 0) {
 473             buf.append("varargs ");
 474         }
 475         if ((access & Opcodes.ACC_BRIDGE) != 0) {
 476             buf.append("bridge ");
 477         }
 478         if ((this.access & Opcodes.ACC_INTERFACE) != 0
 479                 && (access & Opcodes.ACC_ABSTRACT) == 0
 480                 && (access & Opcodes.ACC_STATIC) == 0) {
 481             buf.append("default ");
 482         }
 483 
 484         buf.append(name);
 485         appendDescriptor(METHOD_DESCRIPTOR, desc);
 486         if (exceptions != null && exceptions.length > 0) {
 487             buf.append(" throws ");
 488             for (int i = 0; i < exceptions.length; ++i) {
 489                 appendDescriptor(INTERNAL_NAME, exceptions[i]);
 490                 buf.append(' ');
 491             }
 492         }
 493 
 494         buf.append('\n');
 495         text.add(buf.toString());
 496 
 497         Textifier t = createTextifier();
 498         text.add(t.getText());
 499         return t;
 500     }
 501 
 502     @Override
 503     public void visitClassEnd() {
 504         text.add("}\n");
 505     }
 506 
 507     // ------------------------------------------------------------------------
 508     // Module
 509     // ------------------------------------------------------------------------
 510 
 511     @Override
 512     public void visitMainClass(String mainClass) {
 513         buf.setLength(0);
 514         buf.append("  // main class ").append(mainClass).append('\n');
 515         text.add(buf.toString());
 516     }
 517 
 518     @Override
 519     public void visitPackage(String packaze) {
 520         buf.setLength(0);
 521         buf.append("  // package ").append(packaze).append('\n');
 522         text.add(buf.toString());
 523     }
 524 
 525     @Override
 526     public void visitRequire(String require, int access, String version) {
 527         buf.setLength(0);
 528         buf.append(tab).append("requires ");
 529         if ((access & Opcodes.ACC_TRANSITIVE) != 0) {
 530             buf.append("transitive ");
 531         }
 532         if ((access & Opcodes.ACC_STATIC_PHASE) != 0) {
 533             buf.append("static ");
 534         }
 535         buf.append(require)
 536            .append(";  // access flags 0x")
 537            .append(Integer.toHexString(access).toUpperCase())
 538            .append('\n');
 539         if (version != null) {
 540             buf.append("  // version ")
 541                .append(version)
 542                .append('\n');
 543         }
 544         text.add(buf.toString());
 545     }
 546 
 547     @Override
 548     public void visitExport(String export, int access, String... modules) {
 549         buf.setLength(0);
 550         buf.append(tab).append("exports ");
 551         buf.append(export);
 552         if (modules != null && modules.length > 0) {
 553             buf.append(" to");
 554         } else {
 555             buf.append(';');
 556         }
 557         buf.append("  // access flags 0x")
 558            .append(Integer.toHexString(access).toUpperCase())
 559            .append('\n');
 560         if (modules != null && modules.length > 0) {
 561             for (int i = 0; i < modules.length; ++i) {
 562                 buf.append(tab2).append(modules[i]);
 563                 buf.append(i != modules.length - 1 ? ",\n": ";\n");
 564             }
 565         }
 566         text.add(buf.toString());
 567     }
 568 
 569     @Override
 570     public void visitOpen(String export, int access, String... modules) {
 571         buf.setLength(0);
 572         buf.append(tab).append("opens ");
 573         buf.append(export);
 574         if (modules != null && modules.length > 0) {
 575             buf.append(" to");
 576         } else {
 577             buf.append(';');
 578         }
 579         buf.append("  // access flags 0x")
 580            .append(Integer.toHexString(access).toUpperCase())
 581            .append('\n');
 582         if (modules != null && modules.length > 0) {
 583             for (int i = 0; i < modules.length; ++i) {
 584                 buf.append(tab2).append(modules[i]);
 585                 buf.append(i != modules.length - 1 ? ",\n": ";\n");
 586             }
 587         }
 588         text.add(buf.toString());
 589     }
 590 
 591     @Override
 592     public void visitUse(String use) {
 593         buf.setLength(0);
 594         buf.append(tab).append("uses ");
 595         appendDescriptor(INTERNAL_NAME, use);
 596         buf.append(";\n");
 597         text.add(buf.toString());
 598     }
 599 
 600     @Override
 601     public void visitProvide(String provide, String... providers) {
 602         buf.setLength(0);
 603         buf.append(tab).append("provides ");
 604         appendDescriptor(INTERNAL_NAME, provide);
 605         buf.append(" with\n");
 606         for (int i = 0; i < providers.length; ++i) {
 607             buf.append(tab2);
 608             appendDescriptor(INTERNAL_NAME, providers[i]);
 609             buf.append(i != providers.length - 1 ? ",\n": ";\n");
 610         }
 611         text.add(buf.toString());
 612     }
 613 
 614     @Override
 615     public void visitModuleEnd() {
 616         // empty
 617     }
 618 
 619     // ------------------------------------------------------------------------
 620     // Annotations
 621     // ------------------------------------------------------------------------
 622 
 623     @Override
 624     public void visit(final String name, final Object value) {
 625         buf.setLength(0);
 626         appendComa(valueNumber++);
 627 
 628         if (name != null) {
 629             buf.append(name).append('=');
 630         }
 631 
 632         if (value instanceof String) {
 633             visitString((String) value);
 634         } else if (value instanceof Type) {
 635             visitType((Type) value);
 636         } else if (value instanceof Byte) {
 637             visitByte(((Byte) value).byteValue());
 638         } else if (value instanceof Boolean) {
 639             visitBoolean(((Boolean) value).booleanValue());
 640         } else if (value instanceof Short) {
 641             visitShort(((Short) value).shortValue());
 642         } else if (value instanceof Character) {
 643             visitChar(((Character) value).charValue());
 644         } else if (value instanceof Integer) {
 645             visitInt(((Integer) value).intValue());
 646         } else if (value instanceof Float) {
 647             visitFloat(((Float) value).floatValue());
 648         } else if (value instanceof Long) {
 649             visitLong(((Long) value).longValue());
 650         } else if (value instanceof Double) {
 651             visitDouble(((Double) value).doubleValue());
 652         } else if (value.getClass().isArray()) {
 653             buf.append('{');
 654             if (value instanceof byte[]) {
 655                 byte[] v = (byte[]) value;
 656                 for (int i = 0; i < v.length; i++) {
 657                     appendComa(i);
 658                     visitByte(v[i]);
 659                 }
 660             } else if (value instanceof boolean[]) {
 661                 boolean[] v = (boolean[]) value;
 662                 for (int i = 0; i < v.length; i++) {
 663                     appendComa(i);
 664                     visitBoolean(v[i]);
 665                 }
 666             } else if (value instanceof short[]) {
 667                 short[] v = (short[]) value;
 668                 for (int i = 0; i < v.length; i++) {
 669                     appendComa(i);
 670                     visitShort(v[i]);
 671                 }
 672             } else if (value instanceof char[]) {
 673                 char[] v = (char[]) value;
 674                 for (int i = 0; i < v.length; i++) {
 675                     appendComa(i);
 676                     visitChar(v[i]);
 677                 }
 678             } else if (value instanceof int[]) {
 679                 int[] v = (int[]) value;
 680                 for (int i = 0; i < v.length; i++) {
 681                     appendComa(i);
 682                     visitInt(v[i]);
 683                 }
 684             } else if (value instanceof long[]) {
 685                 long[] v = (long[]) value;
 686                 for (int i = 0; i < v.length; i++) {
 687                     appendComa(i);
 688                     visitLong(v[i]);
 689                 }
 690             } else if (value instanceof float[]) {
 691                 float[] v = (float[]) value;
 692                 for (int i = 0; i < v.length; i++) {
 693                     appendComa(i);
 694                     visitFloat(v[i]);
 695                 }
 696             } else if (value instanceof double[]) {
 697                 double[] v = (double[]) value;
 698                 for (int i = 0; i < v.length; i++) {
 699                     appendComa(i);
 700                     visitDouble(v[i]);
 701                 }
 702             }
 703             buf.append('}');
 704         }
 705 
 706         text.add(buf.toString());
 707     }
 708 
 709     private void visitInt(final int value) {
 710         buf.append(value);
 711     }
 712 
 713     private void visitLong(final long value) {
 714         buf.append(value).append('L');
 715     }
 716 
 717     private void visitFloat(final float value) {
 718         buf.append(value).append('F');
 719     }
 720 
 721     private void visitDouble(final double value) {
 722         buf.append(value).append('D');
 723     }
 724 
 725     private void visitChar(final char value) {
 726         buf.append("(char)").append((int) value);
 727     }
 728 
 729     private void visitShort(final short value) {
 730         buf.append("(short)").append(value);
 731     }
 732 
 733     private void visitByte(final byte value) {
 734         buf.append("(byte)").append(value);
 735     }
 736 
 737     private void visitBoolean(final boolean value) {
 738         buf.append(value);
 739     }
 740 
 741     private void visitString(final String value) {
 742         appendString(buf, value);
 743     }
 744 
 745     private void visitType(final Type value) {
 746         buf.append(value.getClassName()).append(".class");
 747     }
 748 
 749     @Override
 750     public void visitEnum(final String name, final String desc,
 751             final String value) {
 752         buf.setLength(0);
 753         appendComa(valueNumber++);
 754         if (name != null) {
 755             buf.append(name).append('=');
 756         }
 757         appendDescriptor(FIELD_DESCRIPTOR, desc);
 758         buf.append('.').append(value);
 759         text.add(buf.toString());
 760     }
 761 
 762     @Override
 763     public Textifier visitAnnotation(final String name, final String desc) {
 764         buf.setLength(0);
 765         appendComa(valueNumber++);
 766         if (name != null) {
 767             buf.append(name).append('=');
 768         }
 769         buf.append('@');
 770         appendDescriptor(FIELD_DESCRIPTOR, desc);
 771         buf.append('(');
 772         text.add(buf.toString());
 773         Textifier t = createTextifier();
 774         text.add(t.getText());
 775         text.add(")");
 776         return t;
 777     }
 778 
 779     @Override
 780     public Textifier visitArray(final String name) {
 781         buf.setLength(0);
 782         appendComa(valueNumber++);
 783         if (name != null) {
 784             buf.append(name).append('=');
 785         }
 786         buf.append('{');
 787         text.add(buf.toString());
 788         Textifier t = createTextifier();
 789         text.add(t.getText());
 790         text.add("}");
 791         return t;
 792     }
 793 
 794     @Override
 795     public void visitAnnotationEnd() {
 796     }
 797 
 798     // ------------------------------------------------------------------------
 799     // Fields
 800     // ------------------------------------------------------------------------
 801 
 802     @Override
 803     public Textifier visitFieldAnnotation(final String desc,
 804             final boolean visible) {
 805         return visitAnnotation(desc, visible);
 806     }
 807 
 808     @Override
 809     public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath,
 810             String desc, boolean visible) {
 811         return visitTypeAnnotation(typeRef, typePath, desc, visible);
 812     }
 813 
 814     @Override
 815     public void visitFieldAttribute(final Attribute attr) {
 816         visitAttribute(attr);
 817     }
 818 
 819     @Override
 820     public void visitFieldEnd() {
 821     }
 822 
 823     // ------------------------------------------------------------------------
 824     // Methods
 825     // ------------------------------------------------------------------------
 826 
 827     @Override
 828     public void visitParameter(final String name, final int access) {
 829         buf.setLength(0);
 830         buf.append(tab2).append("// parameter ");
 831         appendAccess(access);
 832         buf.append(' ').append((name == null) ? "<no name>" : name)
 833                 .append('\n');
 834         text.add(buf.toString());
 835     }
 836 
 837     @Override
 838     public Textifier visitAnnotationDefault() {
 839         text.add(tab2 + "default=");
 840         Textifier t = createTextifier();
 841         text.add(t.getText());
 842         text.add("\n");
 843         return t;
 844     }
 845 
 846     @Override
 847     public Textifier visitMethodAnnotation(final String desc,
 848             final boolean visible) {
 849         return visitAnnotation(desc, visible);
 850     }
 851 
 852     @Override
 853     public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath,
 854             String desc, boolean visible) {
 855         return visitTypeAnnotation(typeRef, typePath, desc, visible);
 856     }
 857 
 858     @Override
 859     public Textifier visitParameterAnnotation(final int parameter,
 860             final String desc, final boolean visible) {
 861         buf.setLength(0);
 862         buf.append(tab2).append('@');
 863         appendDescriptor(FIELD_DESCRIPTOR, desc);
 864         buf.append('(');
 865         text.add(buf.toString());
 866         Textifier t = createTextifier();
 867         text.add(t.getText());
 868         text.add(visible ? ") // parameter " : ") // invisible, parameter ");
 869         text.add(parameter);
 870         text.add("\n");
 871         return t;
 872     }
 873 
 874     @Override
 875     public void visitMethodAttribute(final Attribute attr) {
 876         buf.setLength(0);
 877         buf.append(tab).append("ATTRIBUTE ");
 878         appendDescriptor(-1, attr.type);
 879 
 880         if (attr instanceof Textifiable) {
 881             ((Textifiable) attr).textify(buf, labelNames);
 882         } else {
 883             buf.append(" : unknown\n");
 884         }
 885 
 886         text.add(buf.toString());
 887     }
 888 
 889     @Override
 890     public void visitCode() {
 891     }
 892 
 893     @Override
 894     public void visitFrame(final int type, final int nLocal,
 895             final Object[] local, final int nStack, final Object[] stack) {
 896         buf.setLength(0);
 897         buf.append(ltab);
 898         buf.append("FRAME ");
 899         switch (type) {
 900         case Opcodes.F_NEW:
 901         case Opcodes.F_FULL:
 902             buf.append("FULL [");
 903             appendFrameTypes(nLocal, local);
 904             buf.append("] [");
 905             appendFrameTypes(nStack, stack);
 906             buf.append(']');
 907             break;
 908         case Opcodes.F_APPEND:
 909             buf.append("APPEND [");
 910             appendFrameTypes(nLocal, local);
 911             buf.append(']');
 912             break;
 913         case Opcodes.F_CHOP:
 914             buf.append("CHOP ").append(nLocal);
 915             break;
 916         case Opcodes.F_SAME:
 917             buf.append("SAME");
 918             break;
 919         case Opcodes.F_SAME1:
 920             buf.append("SAME1 ");
 921             appendFrameTypes(1, stack);
 922             break;
 923         }
 924         buf.append('\n');
 925         text.add(buf.toString());
 926     }
 927 
 928     @Override
 929     public void visitInsn(final int opcode) {
 930         buf.setLength(0);
 931         buf.append(tab2).append(OPCODES[opcode]).append('\n');
 932         text.add(buf.toString());
 933     }
 934 
 935     @Override
 936     public void visitIntInsn(final int opcode, final int operand) {
 937         buf.setLength(0);
 938         buf.append(tab2)
 939                 .append(OPCODES[opcode])
 940                 .append(' ')
 941                 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer
 942                         .toString(operand)).append('\n');
 943         text.add(buf.toString());
 944     }
 945 
 946     @Override
 947     public void visitVarInsn(final int opcode, final int var) {
 948         buf.setLength(0);
 949         buf.append(tab2).append(OPCODES[opcode]).append(' ').append(var)
 950                 .append('\n');
 951         text.add(buf.toString());
 952     }
 953 
 954     @Override
 955     public void visitTypeInsn(final int opcode, final String type) {
 956         buf.setLength(0);
 957         buf.append(tab2).append(OPCODES[opcode]).append(' ');
 958         appendDescriptor(INTERNAL_NAME, type);
 959         buf.append('\n');
 960         text.add(buf.toString());
 961     }
 962 
 963     @Override
 964     public void visitFieldInsn(final int opcode, final String owner,
 965             final String name, final String desc) {
 966         buf.setLength(0);
 967         buf.append(tab2).append(OPCODES[opcode]).append(' ');
 968         appendDescriptor(INTERNAL_NAME, owner);
 969         buf.append('.').append(name).append(" : ");
 970         appendDescriptor(FIELD_DESCRIPTOR, desc);
 971         buf.append('\n');
 972         text.add(buf.toString());
 973     }
 974 
 975     @Deprecated
 976     @Override
 977     public void visitMethodInsn(final int opcode, final String owner,
 978             final String name, final String desc) {
 979         if (api >= Opcodes.ASM5) {
 980             super.visitMethodInsn(opcode, owner, name, desc);
 981             return;
 982         }
 983         doVisitMethodInsn(opcode, owner, name, desc,
 984                 opcode == Opcodes.INVOKEINTERFACE);
 985     }
 986 
 987     @Override
 988     public void visitMethodInsn(final int opcode, final String owner,
 989             final String name, final String desc, final boolean itf) {
 990         if (api < Opcodes.ASM5) {
 991             super.visitMethodInsn(opcode, owner, name, desc, itf);
 992             return;
 993         }
 994         doVisitMethodInsn(opcode, owner, name, desc, itf);
 995     }
 996 
 997     private void doVisitMethodInsn(final int opcode, final String owner,
 998             final String name, final String desc, final boolean itf) {
 999         buf.setLength(0);
1000         buf.append(tab2).append(OPCODES[opcode]).append(' ');
1001         appendDescriptor(INTERNAL_NAME, owner);
1002         buf.append('.').append(name).append(' ');
1003         appendDescriptor(METHOD_DESCRIPTOR, desc);
1004         buf.append('\n');
1005         text.add(buf.toString());
1006     }
1007 
1008     @Override
1009     public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
1010             Object... bsmArgs) {
1011         buf.setLength(0);
1012         buf.append(tab2).append("INVOKEDYNAMIC").append(' ');
1013         buf.append(name);
1014         appendDescriptor(METHOD_DESCRIPTOR, desc);
1015         buf.append(" [");
1016         buf.append('\n');
1017         buf.append(tab3);
1018         appendHandle(bsm);
1019         buf.append('\n');
1020         buf.append(tab3).append("// arguments:");
1021         if (bsmArgs.length == 0) {
1022             buf.append(" none");
1023         } else {
1024             buf.append('\n');
1025             for (int i = 0; i < bsmArgs.length; i++) {
1026                 buf.append(tab3);
1027                 Object cst = bsmArgs[i];
1028                 if (cst instanceof String) {
1029                     Printer.appendString(buf, (String) cst);
1030                 } else if (cst instanceof Type) {
1031                     Type type = (Type) cst;
1032                     if(type.getSort() == Type.METHOD){
1033                         appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
1034                     } else {
1035                         buf.append(type.getDescriptor()).append(".class");
1036                     }
1037                 } else if (cst instanceof Handle) {
1038                     appendHandle((Handle) cst);
1039                 } else {
1040                     buf.append(cst);
1041                 }
1042                 buf.append(", \n");
1043             }
1044             buf.setLength(buf.length() - 3);
1045         }
1046         buf.append('\n');
1047         buf.append(tab2).append("]\n");
1048         text.add(buf.toString());
1049     }
1050 
1051     @Override
1052     public void visitJumpInsn(final int opcode, final Label label) {
1053         buf.setLength(0);
1054         buf.append(tab2).append(OPCODES[opcode]).append(' ');
1055         appendLabel(label);
1056         buf.append('\n');
1057         text.add(buf.toString());
1058     }
1059 
1060     @Override
1061     public void visitLabel(final Label label) {
1062         buf.setLength(0);
1063         buf.append(ltab);
1064         appendLabel(label);
1065         buf.append('\n');
1066         text.add(buf.toString());
1067     }
1068 
1069     @Override
1070     public void visitLdcInsn(final Object cst) {
1071         buf.setLength(0);
1072         buf.append(tab2).append("LDC ");
1073         if (cst instanceof String) {
1074             Printer.appendString(buf, (String) cst);
1075         } else if (cst instanceof Type) {
1076             buf.append(((Type) cst).getDescriptor()).append(".class");
1077         } else {
1078             buf.append(cst);
1079         }
1080         buf.append('\n');
1081         text.add(buf.toString());
1082     }
1083 
1084     @Override
1085     public void visitIincInsn(final int var, final int increment) {
1086         buf.setLength(0);
1087         buf.append(tab2).append("IINC ").append(var).append(' ')
1088                 .append(increment).append('\n');
1089         text.add(buf.toString());
1090     }
1091 
1092     @Override
1093     public void visitTableSwitchInsn(final int min, final int max,
1094             final Label dflt, final Label... labels) {
1095         buf.setLength(0);
1096         buf.append(tab2).append("TABLESWITCH\n");
1097         for (int i = 0; i < labels.length; ++i) {
1098             buf.append(tab3).append(min + i).append(": ");
1099             appendLabel(labels[i]);
1100             buf.append('\n');
1101         }
1102         buf.append(tab3).append("default: ");
1103         appendLabel(dflt);
1104         buf.append('\n');
1105         text.add(buf.toString());
1106     }
1107 
1108     @Override
1109     public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
1110             final Label[] labels) {
1111         buf.setLength(0);
1112         buf.append(tab2).append("LOOKUPSWITCH\n");
1113         for (int i = 0; i < labels.length; ++i) {
1114             buf.append(tab3).append(keys[i]).append(": ");
1115             appendLabel(labels[i]);
1116             buf.append('\n');
1117         }
1118         buf.append(tab3).append("default: ");
1119         appendLabel(dflt);
1120         buf.append('\n');
1121         text.add(buf.toString());
1122     }
1123 
1124     @Override
1125     public void visitMultiANewArrayInsn(final String desc, final int dims) {
1126         buf.setLength(0);
1127         buf.append(tab2).append("MULTIANEWARRAY ");
1128         appendDescriptor(FIELD_DESCRIPTOR, desc);
1129         buf.append(' ').append(dims).append('\n');
1130         text.add(buf.toString());
1131     }
1132 
1133     @Override
1134     public Printer visitInsnAnnotation(int typeRef, TypePath typePath,
1135             String desc, boolean visible) {
1136         return visitTypeAnnotation(typeRef, typePath, desc, visible);
1137     }
1138 
1139     @Override
1140     public void visitTryCatchBlock(final Label start, final Label end,
1141             final Label handler, final String type) {
1142         buf.setLength(0);
1143         buf.append(tab2).append("TRYCATCHBLOCK ");
1144         appendLabel(start);
1145         buf.append(' ');
1146         appendLabel(end);
1147         buf.append(' ');
1148         appendLabel(handler);
1149         buf.append(' ');
1150         appendDescriptor(INTERNAL_NAME, type);
1151         buf.append('\n');
1152         text.add(buf.toString());
1153     }
1154 
1155     @Override
1156     public Printer visitTryCatchAnnotation(int typeRef, TypePath typePath,
1157             String desc, boolean visible) {
1158         buf.setLength(0);
1159         buf.append(tab2).append("TRYCATCHBLOCK @");
1160         appendDescriptor(FIELD_DESCRIPTOR, desc);
1161         buf.append('(');
1162         text.add(buf.toString());
1163         Textifier t = createTextifier();
1164         text.add(t.getText());
1165         buf.setLength(0);
1166         buf.append(") : ");
1167         appendTypeReference(typeRef);
1168         buf.append(", ").append(typePath);
1169         buf.append(visible ? "\n" : " // invisible\n");
1170         text.add(buf.toString());
1171         return t;
1172     }
1173 
1174     @Override
1175     public void visitLocalVariable(final String name, final String desc,
1176             final String signature, final Label start, final Label end,
1177             final int index) {
1178         buf.setLength(0);
1179         buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' ');
1180         appendDescriptor(FIELD_DESCRIPTOR, desc);
1181         buf.append(' ');
1182         appendLabel(start);
1183         buf.append(' ');
1184         appendLabel(end);
1185         buf.append(' ').append(index).append('\n');
1186 
1187         if (signature != null) {
1188             buf.append(tab2);
1189             appendDescriptor(FIELD_SIGNATURE, signature);
1190 
1191             TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
1192             SignatureReader r = new SignatureReader(signature);
1193             r.acceptType(sv);
1194             buf.append(tab2).append("// declaration: ")
1195                     .append(sv.getDeclaration()).append('\n');
1196         }
1197         text.add(buf.toString());
1198     }
1199 
1200     @Override
1201     public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
1202             Label[] start, Label[] end, int[] index, String desc,
1203             boolean visible) {
1204         buf.setLength(0);
1205         buf.append(tab2).append("LOCALVARIABLE @");
1206         appendDescriptor(FIELD_DESCRIPTOR, desc);
1207         buf.append('(');
1208         text.add(buf.toString());
1209         Textifier t = createTextifier();
1210         text.add(t.getText());
1211         buf.setLength(0);
1212         buf.append(") : ");
1213         appendTypeReference(typeRef);
1214         buf.append(", ").append(typePath);
1215         for (int i = 0; i < start.length; ++i) {
1216             buf.append(" [ ");
1217             appendLabel(start[i]);
1218             buf.append(" - ");
1219             appendLabel(end[i]);
1220             buf.append(" - ").append(index[i]).append(" ]");
1221         }
1222         buf.append(visible ? "\n" : " // invisible\n");
1223         text.add(buf.toString());
1224         return t;
1225     }
1226 
1227     @Override
1228     public void visitLineNumber(final int line, final Label start) {
1229         buf.setLength(0);
1230         buf.append(tab2).append("LINENUMBER ").append(line).append(' ');
1231         appendLabel(start);
1232         buf.append('\n');
1233         text.add(buf.toString());
1234     }
1235 
1236     @Override
1237     public void visitMaxs(final int maxStack, final int maxLocals) {
1238         buf.setLength(0);
1239         buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n');
1240         text.add(buf.toString());
1241 
1242         buf.setLength(0);
1243         buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n');
1244         text.add(buf.toString());
1245     }
1246 
1247     @Override
1248     public void visitMethodEnd() {
1249     }
1250 
1251     // ------------------------------------------------------------------------
1252     // Common methods
1253     // ------------------------------------------------------------------------
1254 
1255     /**
1256      * Prints a disassembled view of the given annotation.
1257      *
1258      * @param desc
1259      *            the class descriptor of the annotation class.
1260      * @param visible
1261      *            <tt>true</tt> if the annotation is visible at runtime.
1262      * @return a visitor to visit the annotation values.
1263      */
1264     public Textifier visitAnnotation(final String desc, final boolean visible) {
1265         buf.setLength(0);
1266         buf.append(tab).append('@');
1267         appendDescriptor(FIELD_DESCRIPTOR, desc);
1268         buf.append('(');
1269         text.add(buf.toString());
1270         Textifier t = createTextifier();
1271         text.add(t.getText());
1272         text.add(visible ? ")\n" : ") // invisible\n");
1273         return t;
1274     }
1275 
1276     /**
1277      * Prints a disassembled view of the given type annotation.
1278      *
1279      * @param typeRef
1280      *            a reference to the annotated type. See {@link TypeReference}.
1281      * @param typePath
1282      *            the path to the annotated type argument, wildcard bound, array
1283      *            element type, or static inner type within 'typeRef'. May be
1284      *            <tt>null</tt> if the annotation targets 'typeRef' as a whole.
1285      * @param desc
1286      *            the class descriptor of the annotation class.
1287      * @param visible
1288      *            <tt>true</tt> if the annotation is visible at runtime.
1289      * @return a visitor to visit the annotation values.
1290      */
1291     public Textifier visitTypeAnnotation(final int typeRef,
1292             final TypePath typePath, final String desc, final boolean visible) {
1293         buf.setLength(0);
1294         buf.append(tab).append('@');
1295         appendDescriptor(FIELD_DESCRIPTOR, desc);
1296         buf.append('(');
1297         text.add(buf.toString());
1298         Textifier t = createTextifier();
1299         text.add(t.getText());
1300         buf.setLength(0);
1301         buf.append(") : ");
1302         appendTypeReference(typeRef);
1303         buf.append(", ").append(typePath);
1304         buf.append(visible ? "\n" : " // invisible\n");
1305         text.add(buf.toString());
1306         return t;
1307     }
1308 
1309     /**
1310      * Prints a disassembled view of the given attribute.
1311      *
1312      * @param attr
1313      *            an attribute.
1314      */
1315     public void visitAttribute(final Attribute attr) {
1316         buf.setLength(0);
1317         buf.append(tab).append("ATTRIBUTE ");
1318         appendDescriptor(-1, attr.type);
1319 
1320         if (attr instanceof Textifiable) {
1321             ((Textifiable) attr).textify(buf, null);
1322         } else {
1323             buf.append(" : unknown\n");
1324         }
1325 
1326         text.add(buf.toString());
1327     }
1328 
1329     // ------------------------------------------------------------------------
1330     // Utility methods
1331     // ------------------------------------------------------------------------
1332 
1333     /**
1334      * Creates a new TraceVisitor instance.
1335      *
1336      * @return a new TraceVisitor.
1337      */
1338     protected Textifier createTextifier() {
1339         return new Textifier();
1340     }
1341 
1342     /**
1343      * Appends an internal name, a type descriptor or a type signature to
1344      * {@link #buf buf}.
1345      *
1346      * @param type
1347      *            indicates if desc is an internal name, a field descriptor, a
1348      *            method descriptor, a class signature, ...
1349      * @param desc
1350      *            an internal name, type descriptor, or type signature. May be
1351      *            <tt>null</tt>.
1352      */
1353     protected void appendDescriptor(final int type, final String desc) {
1354         if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE
1355                 || type == METHOD_SIGNATURE) {
1356             if (desc != null) {
1357                 buf.append("// signature ").append(desc).append('\n');
1358             }
1359         } else {
1360             buf.append(desc);
1361         }
1362     }
1363 
1364     /**
1365      * Appends the name of the given label to {@link #buf buf}. Creates a new
1366      * label name if the given label does not yet have one.
1367      *
1368      * @param l
1369      *            a label.
1370      */
1371     protected void appendLabel(final Label l) {
1372         if (labelNames == null) {
1373             labelNames = new HashMap<Label, String>();
1374         }
1375         String name = labelNames.get(l);
1376         if (name == null) {
1377             name = "L" + labelNames.size();
1378             labelNames.put(l, name);
1379         }
1380         buf.append(name);
1381     }
1382 
1383     /**
1384      * Appends the information about the given handle to {@link #buf buf}.
1385      *
1386      * @param h
1387      *            a handle, non null.
1388      */
1389     protected void appendHandle(final Handle h) {
1390         int tag = h.getTag();
1391         buf.append("// handle kind 0x").append(Integer.toHexString(tag))
1392                 .append(" : ");
1393         boolean isMethodHandle = false;
1394         switch (tag) {
1395         case Opcodes.H_GETFIELD:
1396             buf.append("GETFIELD");
1397             break;
1398         case Opcodes.H_GETSTATIC:
1399             buf.append("GETSTATIC");
1400             break;
1401         case Opcodes.H_PUTFIELD:
1402             buf.append("PUTFIELD");
1403             break;
1404         case Opcodes.H_PUTSTATIC:
1405             buf.append("PUTSTATIC");
1406             break;
1407         case Opcodes.H_INVOKEINTERFACE:
1408             buf.append("INVOKEINTERFACE");
1409             isMethodHandle = true;
1410             break;
1411         case Opcodes.H_INVOKESPECIAL:
1412             buf.append("INVOKESPECIAL");
1413             isMethodHandle = true;
1414             break;
1415         case Opcodes.H_INVOKESTATIC:
1416             buf.append("INVOKESTATIC");
1417             isMethodHandle = true;
1418             break;
1419         case Opcodes.H_INVOKEVIRTUAL:
1420             buf.append("INVOKEVIRTUAL");
1421             isMethodHandle = true;
1422             break;
1423         case Opcodes.H_NEWINVOKESPECIAL:
1424             buf.append("NEWINVOKESPECIAL");
1425             isMethodHandle = true;
1426             break;
1427         }
1428         buf.append('\n');
1429         buf.append(tab3);
1430         appendDescriptor(INTERNAL_NAME, h.getOwner());
1431         buf.append('.');
1432         buf.append(h.getName());
1433         if (!isMethodHandle) {
1434             buf.append('(');
1435         }
1436         appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc());
1437         if (!isMethodHandle) {
1438             buf.append(')');
1439         }
1440         if (h.isInterface()) {
1441             buf.append(" itf");
1442         }
1443     }
1444 
1445     /**
1446      * Appends a string representation of the given access modifiers to
1447      * {@link #buf buf}.
1448      *
1449      * @param access
1450      *            some access modifiers.
1451      */
1452     private void appendAccess(final int access) {
1453         if ((access & Opcodes.ACC_PUBLIC) != 0) {
1454             buf.append("public ");
1455         }
1456         if ((access & Opcodes.ACC_PRIVATE) != 0) {
1457             buf.append("private ");
1458         }
1459         if ((access & Opcodes.ACC_PROTECTED) != 0) {
1460             buf.append("protected ");
1461         }
1462         if ((access & Opcodes.ACC_FINAL) != 0) {
1463             buf.append("final ");
1464         }
1465         if ((access & Opcodes.ACC_STATIC) != 0) {
1466             buf.append("static ");
1467         }
1468         if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
1469             buf.append("synchronized ");
1470         }
1471         if ((access & Opcodes.ACC_VOLATILE) != 0) {
1472             buf.append("volatile ");
1473         }
1474         if ((access & Opcodes.ACC_TRANSIENT) != 0) {
1475             buf.append("transient ");
1476         }
1477         if ((access & Opcodes.ACC_ABSTRACT) != 0) {
1478             buf.append("abstract ");
1479         }
1480         if ((access & Opcodes.ACC_STRICT) != 0) {
1481             buf.append("strictfp ");
1482         }
1483         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
1484             buf.append("synthetic ");
1485         }
1486         if ((access & Opcodes.ACC_MANDATED) != 0) {
1487             buf.append("mandated ");
1488         }
1489         if ((access & Opcodes.ACC_ENUM) != 0) {
1490             buf.append("enum ");
1491         }
1492     }
1493 
1494     private void appendComa(final int i) {
1495         if (i != 0) {
1496             buf.append(", ");
1497         }
1498     }
1499 
1500     private void appendTypeReference(final int typeRef) {
1501         TypeReference ref = new TypeReference(typeRef);
1502         switch (ref.getSort()) {
1503         case TypeReference.CLASS_TYPE_PARAMETER:
1504             buf.append("CLASS_TYPE_PARAMETER ").append(
1505                     ref.getTypeParameterIndex());
1506             break;
1507         case TypeReference.METHOD_TYPE_PARAMETER:
1508             buf.append("METHOD_TYPE_PARAMETER ").append(
1509                     ref.getTypeParameterIndex());
1510             break;
1511         case TypeReference.CLASS_EXTENDS:
1512             buf.append("CLASS_EXTENDS ").append(ref.getSuperTypeIndex());
1513             break;
1514         case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
1515             buf.append("CLASS_TYPE_PARAMETER_BOUND ")
1516                     .append(ref.getTypeParameterIndex()).append(", ")
1517                     .append(ref.getTypeParameterBoundIndex());
1518             break;
1519         case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
1520             buf.append("METHOD_TYPE_PARAMETER_BOUND ")
1521                     .append(ref.getTypeParameterIndex()).append(", ")
1522                     .append(ref.getTypeParameterBoundIndex());
1523             break;
1524         case TypeReference.FIELD:
1525             buf.append("FIELD");
1526             break;
1527         case TypeReference.METHOD_RETURN:
1528             buf.append("METHOD_RETURN");
1529             break;
1530         case TypeReference.METHOD_RECEIVER:
1531             buf.append("METHOD_RECEIVER");
1532             break;
1533         case TypeReference.METHOD_FORMAL_PARAMETER:
1534             buf.append("METHOD_FORMAL_PARAMETER ").append(
1535                     ref.getFormalParameterIndex());
1536             break;
1537         case TypeReference.THROWS:
1538             buf.append("THROWS ").append(ref.getExceptionIndex());
1539             break;
1540         case TypeReference.LOCAL_VARIABLE:
1541             buf.append("LOCAL_VARIABLE");
1542             break;
1543         case TypeReference.RESOURCE_VARIABLE:
1544             buf.append("RESOURCE_VARIABLE");
1545             break;
1546         case TypeReference.EXCEPTION_PARAMETER:
1547             buf.append("EXCEPTION_PARAMETER ").append(
1548                     ref.getTryCatchBlockIndex());
1549             break;
1550         case TypeReference.INSTANCEOF:
1551             buf.append("INSTANCEOF");
1552             break;
1553         case TypeReference.NEW:
1554             buf.append("NEW");
1555             break;
1556         case TypeReference.CONSTRUCTOR_REFERENCE:
1557             buf.append("CONSTRUCTOR_REFERENCE");
1558             break;
1559         case TypeReference.METHOD_REFERENCE:
1560             buf.append("METHOD_REFERENCE");
1561             break;
1562         case TypeReference.CAST:
1563             buf.append("CAST ").append(ref.getTypeArgumentIndex());
1564             break;
1565         case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
1566             buf.append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ").append(
1567                     ref.getTypeArgumentIndex());
1568             break;
1569         case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
1570             buf.append("METHOD_INVOCATION_TYPE_ARGUMENT ").append(
1571                     ref.getTypeArgumentIndex());
1572             break;
1573         case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
1574             buf.append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ").append(
1575                     ref.getTypeArgumentIndex());
1576             break;
1577         case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
1578             buf.append("METHOD_REFERENCE_TYPE_ARGUMENT ").append(
1579                     ref.getTypeArgumentIndex());
1580             break;
1581         }
1582     }
1583 
1584     private void appendFrameTypes(final int n, final Object[] o) {
1585         for (int i = 0; i < n; ++i) {
1586             if (i > 0) {
1587                 buf.append(' ');
1588             }
1589             if (o[i] instanceof String) {
1590                 String desc = (String) o[i];
1591                 if (desc.startsWith("[")) {
1592                     appendDescriptor(FIELD_DESCRIPTOR, desc);
1593                 } else {
1594                     appendDescriptor(INTERNAL_NAME, desc);
1595                 }
1596             } else if (o[i] instanceof Integer) {
1597                 switch (((Integer) o[i]).intValue()) {
1598                 case 0:
1599                     appendDescriptor(FIELD_DESCRIPTOR, "T");
1600                     break;
1601                 case 1:
1602                     appendDescriptor(FIELD_DESCRIPTOR, "I");
1603                     break;
1604                 case 2:
1605                     appendDescriptor(FIELD_DESCRIPTOR, "F");
1606                     break;
1607                 case 3:
1608                     appendDescriptor(FIELD_DESCRIPTOR, "D");
1609                     break;
1610                 case 4:
1611                     appendDescriptor(FIELD_DESCRIPTOR, "J");
1612                     break;
1613                 case 5:
1614                     appendDescriptor(FIELD_DESCRIPTOR, "N");
1615                     break;
1616                 case 6:
1617                     appendDescriptor(FIELD_DESCRIPTOR, "U");
1618                     break;
1619                 }
1620             } else {
1621                 appendLabel((Label) o[i]);
1622             }
1623         }
1624     }
1625 }
--- EOF ---