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 
  74 /**
  75  * A {@link Printer} that prints the ASM code to generate the classes if visits.
  76  *
  77  * @author Eric Bruneton
  78  */
  79 public class ASMifier extends Printer {
  80 
  81     /**
  82      * The name of the visitor variable in the produced code.
  83      */
  84     protected final String name;
  85 
  86     /**
  87      * Identifier of the annotation visitor variable in the produced code.
  88      */
  89     protected final int id;
  90 
  91     /**
  92      * The label names. This map associates String values to Label keys. It is
  93      * used only in ASMifierMethodVisitor.
  94      */
  95     protected Map<Label, String> labelNames;
  96 
  97     /**
  98      * Pseudo access flag used to distinguish class access flags.
  99      */
 100     private static final int ACCESS_CLASS = 262144;
 101 
 102     /**
 103      * Pseudo access flag used to distinguish field access flags.
 104      */
 105     private static final int ACCESS_FIELD = 524288;
 106 
 107     /**
 108      * Pseudo access flag used to distinguish inner class flags.
 109      */
 110     private static final int ACCESS_INNER = 1048576;
 111 
 112     /**
 113      * Pseudo access flag used to distinguish module requires/exports flags.
 114      */
 115     private static final int ACCESS_MODULE = 2097152;
 116 
 117     /**
 118      * Constructs a new {@link ASMifier}. <i>Subclasses must not use this
 119      * constructor</i>. Instead, they must use the
 120      * {@link #ASMifier(int, String, int)} version.
 121      *
 122      * @throws IllegalStateException
 123      *             If a subclass calls this constructor.
 124      */
 125     public ASMifier() {
 126         this(Opcodes.ASM6, "cw", 0);
 127         if (getClass() != ASMifier.class) {
 128             throw new IllegalStateException();
 129         }
 130     }
 131 
 132     /**
 133      * Constructs a new {@link ASMifier}.
 134      *
 135      * @param api
 136      *            the ASM API version implemented by this class. Must be one of
 137      *            {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
 138      * @param name
 139      *            the name of the visitor variable in the produced code.
 140      * @param id
 141      *            identifier of the annotation visitor variable in the produced
 142      *            code.
 143      */
 144     protected ASMifier(final int api, final String name, final int id) {
 145         super(api);
 146         this.name = name;
 147         this.id = id;
 148     }
 149 
 150     /**
 151      * Prints the ASM source code to generate the given class to the standard
 152      * output.
 153      * <p>
 154      * Usage: ASMifier [-debug] &lt;binary class name or class file name&gt;
 155      *
 156      * @param args
 157      *            the command line arguments.
 158      *
 159      * @throws Exception
 160      *             if the class cannot be found, or if an IO exception occurs.
 161      */
 162     public static void main(final String[] args) throws Exception {
 163         int i = 0;
 164         int flags = ClassReader.SKIP_DEBUG;
 165 
 166         boolean ok = true;
 167         if (args.length < 1 || args.length > 2) {
 168             ok = false;
 169         }
 170         if (ok && "-debug".equals(args[0])) {
 171             i = 1;
 172             flags = 0;
 173             if (args.length != 2) {
 174                 ok = false;
 175             }
 176         }
 177         if (!ok) {
 178             System.err
 179                     .println("Prints the ASM code to generate the given class.");
 180             System.err.println("Usage: ASMifier [-debug] "
 181                     + "<fully qualified class name or class file name>");
 182             return;
 183         }
 184         ClassReader cr;
 185         if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
 186                 || args[i].indexOf('/') > -1) {
 187             cr = new ClassReader(new FileInputStream(args[i]));
 188         } else {
 189             cr = new ClassReader(args[i]);
 190         }
 191         cr.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(
 192                 System.out)), flags);
 193     }
 194 
 195     // ------------------------------------------------------------------------
 196     // Classes
 197     // ------------------------------------------------------------------------
 198 
 199     @Override
 200     public void visit(final int version, final int access, final String name,
 201             final String signature, final String superName,
 202             final String[] interfaces) {
 203         String simpleName;
 204         if (name == null) {
 205             simpleName = "module-info";
 206         } else {
 207             int n = name.lastIndexOf('/');
 208             if (n == -1) {
 209                 simpleName = name;
 210             } else {
 211                 text.add("package asm." + name.substring(0, n).replace('/', '.')
 212                         + ";\n");
 213                 simpleName = name.substring(n + 1).replace('-', '_');
 214             }
 215         }
 216         text.add("import java.util.*;\n");
 217         text.add("import jdk.internal.org.objectweb.asm.*;\n");
 218         text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
 219         text.add("public static byte[] dump () throws Exception {\n\n");
 220         text.add("ClassWriter cw = new ClassWriter(0);\n");
 221         text.add("FieldVisitor fv;\n");
 222         text.add("MethodVisitor mv;\n");
 223         text.add("AnnotationVisitor av0;\n\n");
 224 
 225         buf.setLength(0);
 226         buf.append("cw.visit(");
 227         switch (version) {
 228         case Opcodes.V1_1:
 229             buf.append("V1_1");
 230             break;
 231         case Opcodes.V1_2:
 232             buf.append("V1_2");
 233             break;
 234         case Opcodes.V1_3:
 235             buf.append("V1_3");
 236             break;
 237         case Opcodes.V1_4:
 238             buf.append("V1_4");
 239             break;
 240         case Opcodes.V1_5:
 241             buf.append("V1_5");
 242             break;
 243         case Opcodes.V1_6:
 244             buf.append("V1_6");
 245             break;
 246         case Opcodes.V1_7:
 247             buf.append("V1_7");
 248             break;
 249         case Opcodes.V1_8:
 250             buf.append("V1_8");
 251             break;
 252         case Opcodes.V9:
 253             buf.append("V9");
 254             break;
 255         default:
 256             buf.append(version);
 257             break;
 258         }
 259         buf.append(", ");
 260         appendAccess(access | ACCESS_CLASS);
 261         buf.append(", ");
 262         appendConstant(name);
 263         buf.append(", ");
 264         appendConstant(signature);
 265         buf.append(", ");
 266         appendConstant(superName);
 267         buf.append(", ");
 268         if (interfaces != null && interfaces.length > 0) {
 269             buf.append("new String[] {");
 270             for (int i = 0; i < interfaces.length; ++i) {
 271                 buf.append(i == 0 ? " " : ", ");
 272                 appendConstant(interfaces[i]);
 273             }
 274             buf.append(" }");
 275         } else {
 276             buf.append("null");
 277         }
 278         buf.append(");\n\n");
 279         text.add(buf.toString());
 280     }
 281 
 282     @Override
 283     public void visitSource(final String file, final String debug) {
 284         buf.setLength(0);
 285         buf.append("cw.visitSource(");
 286         appendConstant(file);
 287         buf.append(", ");
 288         appendConstant(debug);
 289         buf.append(");\n\n");
 290         text.add(buf.toString());
 291     }
 292 
 293     @Override
 294     public Printer visitModule(final String name, final int flags,
 295             final String version) {
 296         buf.setLength(0);
 297         buf.append("ModuleVisitor mdv = cw.visitModule(");
 298         appendConstant(name);
 299         buf.append(", ");
 300         appendAccess(flags | ACCESS_MODULE);
 301         buf.append(", ");
 302         appendConstant(version);
 303         buf.append(");\n\n");
 304         text.add(buf.toString());
 305         ASMifier a = createASMifier("mdv", 0);
 306         text.add(a.getText());
 307         text.add("}\n");
 308         return a;
 309     }
 310 
 311     @Override
 312     public void visitOuterClass(final String owner, final String name,
 313             final String desc) {
 314         buf.setLength(0);
 315         buf.append("cw.visitOuterClass(");
 316         appendConstant(owner);
 317         buf.append(", ");
 318         appendConstant(name);
 319         buf.append(", ");
 320         appendConstant(desc);
 321         buf.append(");\n\n");
 322         text.add(buf.toString());
 323     }
 324 
 325     @Override
 326     public ASMifier visitClassAnnotation(final String desc,
 327             final boolean visible) {
 328         return visitAnnotation(desc, visible);
 329     }
 330 
 331     @Override
 332     public ASMifier visitClassTypeAnnotation(final int typeRef,
 333             final TypePath typePath, final String desc, final boolean visible) {
 334         return visitTypeAnnotation(typeRef, typePath, desc, visible);
 335     }
 336 
 337     @Override
 338     public void visitClassAttribute(final Attribute attr) {
 339         visitAttribute(attr);
 340     }
 341 
 342     @Override
 343     public void visitInnerClass(final String name, final String outerName,
 344             final String innerName, final int access) {
 345         buf.setLength(0);
 346         buf.append("cw.visitInnerClass(");
 347         appendConstant(name);
 348         buf.append(", ");
 349         appendConstant(outerName);
 350         buf.append(", ");
 351         appendConstant(innerName);
 352         buf.append(", ");
 353         appendAccess(access | ACCESS_INNER);
 354         buf.append(");\n\n");
 355         text.add(buf.toString());
 356     }
 357 
 358     @Override
 359     public ASMifier visitField(final int access, final String name,
 360             final String desc, final String signature, final Object value) {
 361         buf.setLength(0);
 362         buf.append("{\n");
 363         buf.append("fv = cw.visitField(");
 364         appendAccess(access | ACCESS_FIELD);
 365         buf.append(", ");
 366         appendConstant(name);
 367         buf.append(", ");
 368         appendConstant(desc);
 369         buf.append(", ");
 370         appendConstant(signature);
 371         buf.append(", ");
 372         appendConstant(value);
 373         buf.append(");\n");
 374         text.add(buf.toString());
 375         ASMifier a = createASMifier("fv", 0);
 376         text.add(a.getText());
 377         text.add("}\n");
 378         return a;
 379     }
 380 
 381     @Override
 382     public ASMifier visitMethod(final int access, final String name,
 383             final String desc, final String signature, final String[] exceptions) {
 384         buf.setLength(0);
 385         buf.append("{\n");
 386         buf.append("mv = cw.visitMethod(");
 387         appendAccess(access);
 388         buf.append(", ");
 389         appendConstant(name);
 390         buf.append(", ");
 391         appendConstant(desc);
 392         buf.append(", ");
 393         appendConstant(signature);
 394         buf.append(", ");
 395         if (exceptions != null && exceptions.length > 0) {
 396             buf.append("new String[] {");
 397             for (int i = 0; i < exceptions.length; ++i) {
 398                 buf.append(i == 0 ? " " : ", ");
 399                 appendConstant(exceptions[i]);
 400             }
 401             buf.append(" }");
 402         } else {
 403             buf.append("null");
 404         }
 405         buf.append(");\n");
 406         text.add(buf.toString());
 407         ASMifier a = createASMifier("mv", 0);
 408         text.add(a.getText());
 409         text.add("}\n");
 410         return a;
 411     }
 412 
 413     @Override
 414     public void visitClassEnd() {
 415         text.add("cw.visitEnd();\n\n");
 416         text.add("return cw.toByteArray();\n");
 417         text.add("}\n");
 418         text.add("}\n");
 419     }
 420 
 421     // ------------------------------------------------------------------------
 422     // Module
 423     // ------------------------------------------------------------------------
 424 
 425     @Override
 426     public void visitMainClass(String mainClass) {
 427         buf.setLength(0);
 428         buf.append("mdv.visitMainClass(");
 429         appendConstant(buf, mainClass);
 430         buf.append(");\n");
 431         text.add(buf.toString());
 432     }
 433 
 434     @Override
 435     public void visitPackage(String packaze) {
 436         buf.setLength(0);
 437         buf.append("mdv.visitPackage(");
 438         appendConstant(buf, packaze);
 439         buf.append(");\n");
 440         text.add(buf.toString());
 441     }
 442 
 443     @Override
 444     public void visitRequire(String module, int access, String version) {
 445         buf.setLength(0);
 446         buf.append("mdv.visitRequire(");
 447         appendConstant(buf, module);
 448         buf.append(", ");
 449         appendAccess(access | ACCESS_MODULE);
 450         buf.append(", ");
 451         appendConstant(buf, version);
 452         buf.append(");\n");
 453         text.add(buf.toString());
 454     }
 455 
 456     @Override
 457     public void visitExport(String packaze, int access, String... modules) {
 458         buf.setLength(0);
 459         buf.append("mdv.visitExport(");
 460         appendConstant(buf, packaze);
 461         buf.append(", ");
 462         appendAccess(access | ACCESS_MODULE);
 463         if (modules != null && modules.length > 0) {
 464             buf.append(", new String[] {");
 465             for (int i = 0; i < modules.length; ++i) {
 466                 buf.append(i == 0 ? " " : ", ");
 467                 appendConstant(modules[i]);
 468             }
 469             buf.append(" }");
 470         }
 471         buf.append(");\n");
 472         text.add(buf.toString());
 473     }
 474 
 475     @Override
 476     public void visitOpen(String packaze, int access, String... modules) {
 477         buf.setLength(0);
 478         buf.append("mdv.visitOpen(");
 479         appendConstant(buf, packaze);
 480         buf.append(", ");
 481         appendAccess(access | ACCESS_MODULE);
 482         if (modules != null && modules.length > 0) {
 483             buf.append(", new String[] {");
 484             for (int i = 0; i < modules.length; ++i) {
 485                 buf.append(i == 0 ? " " : ", ");
 486                 appendConstant(modules[i]);
 487             }
 488             buf.append(" }");
 489         }
 490         buf.append(");\n");
 491         text.add(buf.toString());
 492     }
 493 
 494     @Override
 495     public void visitUse(String service) {
 496         buf.setLength(0);
 497         buf.append("mdv.visitUse(");
 498         appendConstant(buf, service);
 499         buf.append(");\n");
 500         text.add(buf.toString());
 501     }
 502 
 503     @Override
 504     public void visitProvide(String service, String... providers) {
 505         buf.setLength(0);
 506         buf.append("mdv.visitProvide(");
 507         appendConstant(buf, service);
 508         buf.append(",  new String[] {");
 509         for (int i = 0; i < providers.length; ++i) {
 510             buf.append(i == 0 ? " " : ", ");
 511             appendConstant(providers[i]);
 512         }
 513         buf.append(" });\n");
 514         text.add(buf.toString());
 515     }
 516 
 517     @Override
 518     public void visitModuleEnd() {
 519         text.add("mdv.visitEnd();\n");
 520     }
 521 
 522 
 523     // ------------------------------------------------------------------------
 524     // Annotations
 525     // ------------------------------------------------------------------------
 526 
 527     @Override
 528     public void visit(final String name, final Object value) {
 529         buf.setLength(0);
 530         buf.append("av").append(id).append(".visit(");
 531         appendConstant(buf, name);
 532         buf.append(", ");
 533         appendConstant(buf, value);
 534         buf.append(");\n");
 535         text.add(buf.toString());
 536     }
 537 
 538     @Override
 539     public void visitEnum(final String name, final String desc,
 540             final String value) {
 541         buf.setLength(0);
 542         buf.append("av").append(id).append(".visitEnum(");
 543         appendConstant(buf, name);
 544         buf.append(", ");
 545         appendConstant(buf, desc);
 546         buf.append(", ");
 547         appendConstant(buf, value);
 548         buf.append(");\n");
 549         text.add(buf.toString());
 550     }
 551 
 552     @Override
 553     public ASMifier visitAnnotation(final String name, final String desc) {
 554         buf.setLength(0);
 555         buf.append("{\n");
 556         buf.append("AnnotationVisitor av").append(id + 1).append(" = av");
 557         buf.append(id).append(".visitAnnotation(");
 558         appendConstant(buf, name);
 559         buf.append(", ");
 560         appendConstant(buf, desc);
 561         buf.append(");\n");
 562         text.add(buf.toString());
 563         ASMifier a = createASMifier("av", id + 1);
 564         text.add(a.getText());
 565         text.add("}\n");
 566         return a;
 567     }
 568 
 569     @Override
 570     public ASMifier visitArray(final String name) {
 571         buf.setLength(0);
 572         buf.append("{\n");
 573         buf.append("AnnotationVisitor av").append(id + 1).append(" = av");
 574         buf.append(id).append(".visitArray(");
 575         appendConstant(buf, name);
 576         buf.append(");\n");
 577         text.add(buf.toString());
 578         ASMifier a = createASMifier("av", id + 1);
 579         text.add(a.getText());
 580         text.add("}\n");
 581         return a;
 582     }
 583 
 584     @Override
 585     public void visitAnnotationEnd() {
 586         buf.setLength(0);
 587         buf.append("av").append(id).append(".visitEnd();\n");
 588         text.add(buf.toString());
 589     }
 590 
 591     // ------------------------------------------------------------------------
 592     // Fields
 593     // ------------------------------------------------------------------------
 594 
 595     @Override
 596     public ASMifier visitFieldAnnotation(final String desc,
 597             final boolean visible) {
 598         return visitAnnotation(desc, visible);
 599     }
 600 
 601     @Override
 602     public ASMifier visitFieldTypeAnnotation(final int typeRef,
 603             final TypePath typePath, final String desc, final boolean visible) {
 604         return visitTypeAnnotation(typeRef, typePath, desc, visible);
 605     }
 606 
 607     @Override
 608     public void visitFieldAttribute(final Attribute attr) {
 609         visitAttribute(attr);
 610     }
 611 
 612     @Override
 613     public void visitFieldEnd() {
 614         buf.setLength(0);
 615         buf.append(name).append(".visitEnd();\n");
 616         text.add(buf.toString());
 617     }
 618 
 619     // ------------------------------------------------------------------------
 620     // Methods
 621     // ------------------------------------------------------------------------
 622 
 623     @Override
 624     public void visitParameter(String parameterName, int access) {
 625         buf.setLength(0);
 626         buf.append(name).append(".visitParameter(");
 627         appendString(buf, parameterName);
 628         buf.append(", ");
 629         appendAccess(access);
 630         text.add(buf.append(");\n").toString());
 631     }
 632 
 633     @Override
 634     public ASMifier visitAnnotationDefault() {
 635         buf.setLength(0);
 636         buf.append("{\n").append("av0 = ").append(name)
 637                 .append(".visitAnnotationDefault();\n");
 638         text.add(buf.toString());
 639         ASMifier a = createASMifier("av", 0);
 640         text.add(a.getText());
 641         text.add("}\n");
 642         return a;
 643     }
 644 
 645     @Override
 646     public ASMifier visitMethodAnnotation(final String desc,
 647             final boolean visible) {
 648         return visitAnnotation(desc, visible);
 649     }
 650 
 651     @Override
 652     public ASMifier visitMethodTypeAnnotation(final int typeRef,
 653             final TypePath typePath, final String desc, final boolean visible) {
 654         return visitTypeAnnotation(typeRef, typePath, desc, visible);
 655     }
 656 
 657     @Override
 658     public ASMifier visitParameterAnnotation(final int parameter,
 659             final String desc, final boolean visible) {
 660         buf.setLength(0);
 661         buf.append("{\n").append("av0 = ").append(name)
 662                 .append(".visitParameterAnnotation(").append(parameter)
 663                 .append(", ");
 664         appendConstant(desc);
 665         buf.append(", ").append(visible).append(");\n");
 666         text.add(buf.toString());
 667         ASMifier a = createASMifier("av", 0);
 668         text.add(a.getText());
 669         text.add("}\n");
 670         return a;
 671     }
 672 
 673     @Override
 674     public void visitMethodAttribute(final Attribute attr) {
 675         visitAttribute(attr);
 676     }
 677 
 678     @Override
 679     public void visitCode() {
 680         text.add(name + ".visitCode();\n");
 681     }
 682 
 683     @Override
 684     public void visitFrame(final int type, final int nLocal,
 685             final Object[] local, final int nStack, final Object[] stack) {
 686         buf.setLength(0);
 687         switch (type) {
 688         case Opcodes.F_NEW:
 689         case Opcodes.F_FULL:
 690             declareFrameTypes(nLocal, local);
 691             declareFrameTypes(nStack, stack);
 692             if (type == Opcodes.F_NEW) {
 693                 buf.append(name).append(".visitFrame(Opcodes.F_NEW, ");
 694             } else {
 695                 buf.append(name).append(".visitFrame(Opcodes.F_FULL, ");
 696             }
 697             buf.append(nLocal).append(", new Object[] {");
 698             appendFrameTypes(nLocal, local);
 699             buf.append("}, ").append(nStack).append(", new Object[] {");
 700             appendFrameTypes(nStack, stack);
 701             buf.append('}');
 702             break;
 703         case Opcodes.F_APPEND:
 704             declareFrameTypes(nLocal, local);
 705             buf.append(name).append(".visitFrame(Opcodes.F_APPEND,")
 706                     .append(nLocal).append(", new Object[] {");
 707             appendFrameTypes(nLocal, local);
 708             buf.append("}, 0, null");
 709             break;
 710         case Opcodes.F_CHOP:
 711             buf.append(name).append(".visitFrame(Opcodes.F_CHOP,")
 712                     .append(nLocal).append(", null, 0, null");
 713             break;
 714         case Opcodes.F_SAME:
 715             buf.append(name).append(
 716                     ".visitFrame(Opcodes.F_SAME, 0, null, 0, null");
 717             break;
 718         case Opcodes.F_SAME1:
 719             declareFrameTypes(1, stack);
 720             buf.append(name).append(
 721                     ".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
 722             appendFrameTypes(1, stack);
 723             buf.append('}');
 724             break;
 725         }
 726         buf.append(");\n");
 727         text.add(buf.toString());
 728     }
 729 
 730     @Override
 731     public void visitInsn(final int opcode) {
 732         buf.setLength(0);
 733         buf.append(name).append(".visitInsn(").append(OPCODES[opcode])
 734                 .append(");\n");
 735         text.add(buf.toString());
 736     }
 737 
 738     @Override
 739     public void visitIntInsn(final int opcode, final int operand) {
 740         buf.setLength(0);
 741         buf.append(name)
 742                 .append(".visitIntInsn(")
 743                 .append(OPCODES[opcode])
 744                 .append(", ")
 745                 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer
 746                         .toString(operand)).append(");\n");
 747         text.add(buf.toString());
 748     }
 749 
 750     @Override
 751     public void visitVarInsn(final int opcode, final int var) {
 752         buf.setLength(0);
 753         buf.append(name).append(".visitVarInsn(").append(OPCODES[opcode])
 754                 .append(", ").append(var).append(");\n");
 755         text.add(buf.toString());
 756     }
 757 
 758     @Override
 759     public void visitTypeInsn(final int opcode, final String type) {
 760         buf.setLength(0);
 761         buf.append(name).append(".visitTypeInsn(").append(OPCODES[opcode])
 762                 .append(", ");
 763         appendConstant(type);
 764         buf.append(");\n");
 765         text.add(buf.toString());
 766     }
 767 
 768     @Override
 769     public void visitFieldInsn(final int opcode, final String owner,
 770             final String name, final String desc) {
 771         buf.setLength(0);
 772         buf.append(this.name).append(".visitFieldInsn(")
 773                 .append(OPCODES[opcode]).append(", ");
 774         appendConstant(owner);
 775         buf.append(", ");
 776         appendConstant(name);
 777         buf.append(", ");
 778         appendConstant(desc);
 779         buf.append(");\n");
 780         text.add(buf.toString());
 781     }
 782 
 783     @Deprecated
 784     @Override
 785     public void visitMethodInsn(final int opcode, final String owner,
 786             final String name, final String desc) {
 787         if (api >= Opcodes.ASM5) {
 788             super.visitMethodInsn(opcode, owner, name, desc);
 789             return;
 790         }
 791         doVisitMethodInsn(opcode, owner, name, desc,
 792                 opcode == Opcodes.INVOKEINTERFACE);
 793     }
 794 
 795     @Override
 796     public void visitMethodInsn(final int opcode, final String owner,
 797             final String name, final String desc, final boolean itf) {
 798         if (api < Opcodes.ASM5) {
 799             super.visitMethodInsn(opcode, owner, name, desc, itf);
 800             return;
 801         }
 802         doVisitMethodInsn(opcode, owner, name, desc, itf);
 803     }
 804 
 805     private void doVisitMethodInsn(final int opcode, final String owner,
 806             final String name, final String desc, final boolean itf) {
 807         buf.setLength(0);
 808         buf.append(this.name).append(".visitMethodInsn(")
 809                 .append(OPCODES[opcode]).append(", ");
 810         appendConstant(owner);
 811         buf.append(", ");
 812         appendConstant(name);
 813         buf.append(", ");
 814         appendConstant(desc);
 815         buf.append(", ");
 816         buf.append(itf ? "true" : "false");
 817         buf.append(");\n");
 818         text.add(buf.toString());
 819     }
 820 
 821     @Override
 822     public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
 823             Object... bsmArgs) {
 824         buf.setLength(0);
 825         buf.append(this.name).append(".visitInvokeDynamicInsn(");
 826         appendConstant(name);
 827         buf.append(", ");
 828         appendConstant(desc);
 829         buf.append(", ");
 830         appendConstant(bsm);
 831         buf.append(", new Object[]{");
 832         for (int i = 0; i < bsmArgs.length; ++i) {
 833             appendConstant(bsmArgs[i]);
 834             if (i != bsmArgs.length - 1) {
 835                 buf.append(", ");
 836             }
 837         }
 838         buf.append("});\n");
 839         text.add(buf.toString());
 840     }
 841 
 842     @Override
 843     public void visitJumpInsn(final int opcode, final Label label) {
 844         buf.setLength(0);
 845         declareLabel(label);
 846         buf.append(name).append(".visitJumpInsn(").append(OPCODES[opcode])
 847                 .append(", ");
 848         appendLabel(label);
 849         buf.append(");\n");
 850         text.add(buf.toString());
 851     }
 852 
 853     @Override
 854     public void visitLabel(final Label label) {
 855         buf.setLength(0);
 856         declareLabel(label);
 857         buf.append(name).append(".visitLabel(");
 858         appendLabel(label);
 859         buf.append(");\n");
 860         text.add(buf.toString());
 861     }
 862 
 863     @Override
 864     public void visitLdcInsn(final Object cst) {
 865         buf.setLength(0);
 866         buf.append(name).append(".visitLdcInsn(");
 867         appendConstant(cst);
 868         buf.append(");\n");
 869         text.add(buf.toString());
 870     }
 871 
 872     @Override
 873     public void visitIincInsn(final int var, final int increment) {
 874         buf.setLength(0);
 875         buf.append(name).append(".visitIincInsn(").append(var).append(", ")
 876                 .append(increment).append(");\n");
 877         text.add(buf.toString());
 878     }
 879 
 880     @Override
 881     public void visitTableSwitchInsn(final int min, final int max,
 882             final Label dflt, final Label... labels) {
 883         buf.setLength(0);
 884         for (int i = 0; i < labels.length; ++i) {
 885             declareLabel(labels[i]);
 886         }
 887         declareLabel(dflt);
 888 
 889         buf.append(name).append(".visitTableSwitchInsn(").append(min)
 890                 .append(", ").append(max).append(", ");
 891         appendLabel(dflt);
 892         buf.append(", new Label[] {");
 893         for (int i = 0; i < labels.length; ++i) {
 894             buf.append(i == 0 ? " " : ", ");
 895             appendLabel(labels[i]);
 896         }
 897         buf.append(" });\n");
 898         text.add(buf.toString());
 899     }
 900 
 901     @Override
 902     public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
 903             final Label[] labels) {
 904         buf.setLength(0);
 905         for (int i = 0; i < labels.length; ++i) {
 906             declareLabel(labels[i]);
 907         }
 908         declareLabel(dflt);
 909 
 910         buf.append(name).append(".visitLookupSwitchInsn(");
 911         appendLabel(dflt);
 912         buf.append(", new int[] {");
 913         for (int i = 0; i < keys.length; ++i) {
 914             buf.append(i == 0 ? " " : ", ").append(keys[i]);
 915         }
 916         buf.append(" }, new Label[] {");
 917         for (int i = 0; i < labels.length; ++i) {
 918             buf.append(i == 0 ? " " : ", ");
 919             appendLabel(labels[i]);
 920         }
 921         buf.append(" });\n");
 922         text.add(buf.toString());
 923     }
 924 
 925     @Override
 926     public void visitMultiANewArrayInsn(final String desc, final int dims) {
 927         buf.setLength(0);
 928         buf.append(name).append(".visitMultiANewArrayInsn(");
 929         appendConstant(desc);
 930         buf.append(", ").append(dims).append(");\n");
 931         text.add(buf.toString());
 932     }
 933 
 934     @Override
 935     public ASMifier visitInsnAnnotation(final int typeRef,
 936             final TypePath typePath, final String desc, final boolean visible) {
 937         return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath,
 938                 desc, visible);
 939     }
 940 
 941     @Override
 942     public void visitTryCatchBlock(final Label start, final Label end,
 943             final Label handler, final String type) {
 944         buf.setLength(0);
 945         declareLabel(start);
 946         declareLabel(end);
 947         declareLabel(handler);
 948         buf.append(name).append(".visitTryCatchBlock(");
 949         appendLabel(start);
 950         buf.append(", ");
 951         appendLabel(end);
 952         buf.append(", ");
 953         appendLabel(handler);
 954         buf.append(", ");
 955         appendConstant(type);
 956         buf.append(");\n");
 957         text.add(buf.toString());
 958     }
 959 
 960     @Override
 961     public ASMifier visitTryCatchAnnotation(final int typeRef,
 962             final TypePath typePath, final String desc, final boolean visible) {
 963         return visitTypeAnnotation("visitTryCatchAnnotation", typeRef,
 964                 typePath, desc, visible);
 965     }
 966 
 967     @Override
 968     public void visitLocalVariable(final String name, final String desc,
 969             final String signature, final Label start, final Label end,
 970             final int index) {
 971         buf.setLength(0);
 972         buf.append(this.name).append(".visitLocalVariable(");
 973         appendConstant(name);
 974         buf.append(", ");
 975         appendConstant(desc);
 976         buf.append(", ");
 977         appendConstant(signature);
 978         buf.append(", ");
 979         appendLabel(start);
 980         buf.append(", ");
 981         appendLabel(end);
 982         buf.append(", ").append(index).append(");\n");
 983         text.add(buf.toString());
 984     }
 985 
 986     @Override
 987     public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
 988             Label[] start, Label[] end, int[] index, String desc,
 989             boolean visible) {
 990         buf.setLength(0);
 991         buf.append("{\n").append("av0 = ").append(name)
 992                 .append(".visitLocalVariableAnnotation(");
 993         buf.append(typeRef);
 994         if (typePath == null) {
 995             buf.append(", null, ");
 996         } else {
 997             buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
 998         }
 999         buf.append("new Label[] {");
1000         for (int i = 0; i < start.length; ++i) {
1001             buf.append(i == 0 ? " " : ", ");
1002             appendLabel(start[i]);
1003         }
1004         buf.append(" }, new Label[] {");
1005         for (int i = 0; i < end.length; ++i) {
1006             buf.append(i == 0 ? " " : ", ");
1007             appendLabel(end[i]);
1008         }
1009         buf.append(" }, new int[] {");
1010         for (int i = 0; i < index.length; ++i) {
1011             buf.append(i == 0 ? " " : ", ").append(index[i]);
1012         }
1013         buf.append(" }, ");
1014         appendConstant(desc);
1015         buf.append(", ").append(visible).append(");\n");
1016         text.add(buf.toString());
1017         ASMifier a = createASMifier("av", 0);
1018         text.add(a.getText());
1019         text.add("}\n");
1020         return a;
1021     }
1022 
1023     @Override
1024     public void visitLineNumber(final int line, final Label start) {
1025         buf.setLength(0);
1026         buf.append(name).append(".visitLineNumber(").append(line).append(", ");
1027         appendLabel(start);
1028         buf.append(");\n");
1029         text.add(buf.toString());
1030     }
1031 
1032     @Override
1033     public void visitMaxs(final int maxStack, final int maxLocals) {
1034         buf.setLength(0);
1035         buf.append(name).append(".visitMaxs(").append(maxStack).append(", ")
1036                 .append(maxLocals).append(");\n");
1037         text.add(buf.toString());
1038     }
1039 
1040     @Override
1041     public void visitMethodEnd() {
1042         buf.setLength(0);
1043         buf.append(name).append(".visitEnd();\n");
1044         text.add(buf.toString());
1045     }
1046 
1047     // ------------------------------------------------------------------------
1048     // Common methods
1049     // ------------------------------------------------------------------------
1050 
1051     public ASMifier visitAnnotation(final String desc, final boolean visible) {
1052         buf.setLength(0);
1053         buf.append("{\n").append("av0 = ").append(name)
1054                 .append(".visitAnnotation(");
1055         appendConstant(desc);
1056         buf.append(", ").append(visible).append(");\n");
1057         text.add(buf.toString());
1058         ASMifier a = createASMifier("av", 0);
1059         text.add(a.getText());
1060         text.add("}\n");
1061         return a;
1062     }
1063 
1064     public ASMifier visitTypeAnnotation(final int typeRef,
1065             final TypePath typePath, final String desc, final boolean visible) {
1066         return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath,
1067                 desc, visible);
1068     }
1069 
1070     public ASMifier visitTypeAnnotation(final String method, final int typeRef,
1071             final TypePath typePath, final String desc, final boolean visible) {
1072         buf.setLength(0);
1073         buf.append("{\n").append("av0 = ").append(name).append(".")
1074                 .append(method).append("(");
1075         buf.append(typeRef);
1076         if (typePath == null) {
1077             buf.append(", null, ");
1078         } else {
1079             buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
1080         }
1081         appendConstant(desc);
1082         buf.append(", ").append(visible).append(");\n");
1083         text.add(buf.toString());
1084         ASMifier a = createASMifier("av", 0);
1085         text.add(a.getText());
1086         text.add("}\n");
1087         return a;
1088     }
1089 
1090     public void visitAttribute(final Attribute attr) {
1091         buf.setLength(0);
1092         buf.append("// ATTRIBUTE ").append(attr.type).append('\n');
1093         if (attr instanceof ASMifiable) {
1094             if (labelNames == null) {
1095                 labelNames = new HashMap<Label, String>();
1096             }
1097             buf.append("{\n");
1098             ((ASMifiable) attr).asmify(buf, "attr", labelNames);
1099             buf.append(name).append(".visitAttribute(attr);\n");
1100             buf.append("}\n");
1101         }
1102         text.add(buf.toString());
1103     }
1104 
1105     // ------------------------------------------------------------------------
1106     // Utility methods
1107     // ------------------------------------------------------------------------
1108 
1109     protected ASMifier createASMifier(final String name, final int id) {
1110         return new ASMifier(Opcodes.ASM6, name, id);
1111     }
1112 
1113     /**
1114      * Appends a string representation of the given access modifiers to
1115      * {@link #buf buf}.
1116      *
1117      * @param access
1118      *            some access modifiers.
1119      */
1120     void appendAccess(final int access) {
1121         boolean first = true;
1122         if ((access & Opcodes.ACC_PUBLIC) != 0) {
1123             buf.append("ACC_PUBLIC");
1124             first = false;
1125         }
1126         if ((access & Opcodes.ACC_PRIVATE) != 0) {
1127             buf.append("ACC_PRIVATE");
1128             first = false;
1129         }
1130         if ((access & Opcodes.ACC_PROTECTED) != 0) {
1131             buf.append("ACC_PROTECTED");
1132             first = false;
1133         }
1134         if ((access & Opcodes.ACC_FINAL) != 0) {
1135             if (!first) {
1136                 buf.append(" + ");
1137             }
1138             if ((access & ACCESS_MODULE) == 0) {
1139                 buf.append("ACC_FINAL");
1140             } else {
1141                 buf.append("ACC_TRANSITIVE");
1142             }
1143             first = false;
1144         }
1145         if ((access & Opcodes.ACC_STATIC) != 0) {
1146             if (!first) {
1147                 buf.append(" + ");
1148             }
1149             buf.append("ACC_STATIC");
1150             first = false;
1151         }
1152         if ((access & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE)) != 0) {
1153             if (!first) {
1154                 buf.append(" + ");
1155             }
1156             if ((access & ACCESS_CLASS) == 0) {
1157                 if ((access & ACCESS_MODULE) == 0) {
1158                     buf.append("ACC_SYNCHRONIZED");
1159                 } else {
1160                     buf.append("ACC_TRANSITIVE");
1161                 }
1162             } else {
1163                 buf.append("ACC_SUPER");
1164             }
1165             first = false;
1166         }
1167         if ((access & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE)) != 0) {
1168             if (!first) {
1169                 buf.append(" + ");
1170             }
1171             if ((access & ACCESS_FIELD) == 0) {
1172                 if ((access & ACCESS_MODULE) == 0) {
1173                     buf.append("ACC_BRIDGE");
1174                 } else {
1175                     buf.append("ACC_STATIC_PHASE");
1176                 }
1177             } else {
1178                 buf.append("ACC_VOLATILE");
1179             }
1180 
1181             first = false;
1182         }
1183         if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0
1184                 && (access & ACCESS_FIELD) == 0) {
1185             if (!first) {
1186                 buf.append(" + ");
1187             }
1188             buf.append("ACC_VARARGS");
1189             first = false;
1190         }
1191         if ((access & Opcodes.ACC_TRANSIENT) != 0
1192                 && (access & ACCESS_FIELD) != 0) {
1193             if (!first) {
1194                 buf.append(" + ");
1195             }
1196             buf.append("ACC_TRANSIENT");
1197             first = false;
1198         }
1199         if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0
1200                 && (access & ACCESS_FIELD) == 0) {
1201             if (!first) {
1202                 buf.append(" + ");
1203             }
1204             buf.append("ACC_NATIVE");
1205             first = false;
1206         }
1207         if ((access & Opcodes.ACC_ENUM) != 0
1208                 && ((access & ACCESS_CLASS) != 0
1209                         || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) {
1210             if (!first) {
1211                 buf.append(" + ");
1212             }
1213             buf.append("ACC_ENUM");
1214             first = false;
1215         }
1216         if ((access & Opcodes.ACC_ANNOTATION) != 0
1217                 && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_INNER) != 0)) {
1218             if (!first) {
1219                 buf.append(" + ");
1220             }
1221             buf.append("ACC_ANNOTATION");
1222             first = false;
1223         }
1224         if ((access & Opcodes.ACC_ABSTRACT) != 0) {
1225             if (!first) {
1226                 buf.append(" + ");
1227             }
1228             buf.append("ACC_ABSTRACT");
1229             first = false;
1230         }
1231         if ((access & Opcodes.ACC_INTERFACE) != 0) {
1232             if (!first) {
1233                 buf.append(" + ");
1234             }
1235             buf.append("ACC_INTERFACE");
1236             first = false;
1237         }
1238         if ((access & Opcodes.ACC_STRICT) != 0) {
1239             if (!first) {
1240                 buf.append(" + ");
1241             }
1242             buf.append("ACC_STRICT");
1243             first = false;
1244         }
1245         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
1246             if (!first) {
1247                 buf.append(" + ");
1248             }
1249             buf.append("ACC_SYNTHETIC");
1250             first = false;
1251         }
1252         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1253             if (!first) {
1254                 buf.append(" + ");
1255             }
1256             buf.append("ACC_DEPRECATED");
1257             first = false;
1258         }
1259         if ((access & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
1260             if (!first) {
1261                 buf.append(" + ");
1262             }
1263             if ((access & ACCESS_CLASS) == 0) {
1264                 buf.append("ACC_MANDATED");
1265             } else {
1266                 buf.append("ACC_MODULE");
1267             }
1268             first = false;
1269         }
1270         if (first) {
1271             buf.append('0');
1272         }
1273     }
1274 
1275     /**
1276      * Appends a string representation of the given constant to the given
1277      * buffer.
1278      *
1279      * @param cst
1280      *            an {@link Integer}, {@link Float}, {@link Long},
1281      *            {@link Double} or {@link String} object. May be <tt>null</tt>.
1282      */
1283     protected void appendConstant(final Object cst) {
1284         appendConstant(buf, cst);
1285     }
1286 
1287     /**
1288      * Appends a string representation of the given constant to the given
1289      * buffer.
1290      *
1291      * @param buf
1292      *            a string buffer.
1293      * @param cst
1294      *            an {@link Integer}, {@link Float}, {@link Long},
1295      *            {@link Double} or {@link String} object. May be <tt>null</tt>.
1296      */
1297     static void appendConstant(final StringBuffer buf, final Object cst) {
1298         if (cst == null) {
1299             buf.append("null");
1300         } else if (cst instanceof String) {
1301             appendString(buf, (String) cst);
1302         } else if (cst instanceof Type) {
1303             buf.append("Type.getType(\"");
1304             buf.append(((Type) cst).getDescriptor());
1305             buf.append("\")");
1306         } else if (cst instanceof Handle) {
1307             buf.append("new Handle(");
1308             Handle h = (Handle) cst;
1309             buf.append("Opcodes.").append(HANDLE_TAG[h.getTag()])
1310                     .append(", \"");
1311             buf.append(h.getOwner()).append("\", \"");
1312             buf.append(h.getName()).append("\", \"");
1313             buf.append(h.getDesc()).append("\", ");
1314             buf.append(h.isInterface()).append(")");
1315         } else if (cst instanceof Byte) {
1316             buf.append("new Byte((byte)").append(cst).append(')');
1317         } else if (cst instanceof Boolean) {
1318             buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE"
1319                     : "Boolean.FALSE");
1320         } else if (cst instanceof Short) {
1321             buf.append("new Short((short)").append(cst).append(')');
1322         } else if (cst instanceof Character) {
1323             int c = ((Character) cst).charValue();
1324             buf.append("new Character((char)").append(c).append(')');
1325         } else if (cst instanceof Integer) {
1326             buf.append("new Integer(").append(cst).append(')');
1327         } else if (cst instanceof Float) {
1328             buf.append("new Float(\"").append(cst).append("\")");
1329         } else if (cst instanceof Long) {
1330             buf.append("new Long(").append(cst).append("L)");
1331         } else if (cst instanceof Double) {
1332             buf.append("new Double(\"").append(cst).append("\")");
1333         } else if (cst instanceof byte[]) {
1334             byte[] v = (byte[]) cst;
1335             buf.append("new byte[] {");
1336             for (int i = 0; i < v.length; i++) {
1337                 buf.append(i == 0 ? "" : ",").append(v[i]);
1338             }
1339             buf.append('}');
1340         } else if (cst instanceof boolean[]) {
1341             boolean[] v = (boolean[]) cst;
1342             buf.append("new boolean[] {");
1343             for (int i = 0; i < v.length; i++) {
1344                 buf.append(i == 0 ? "" : ",").append(v[i]);
1345             }
1346             buf.append('}');
1347         } else if (cst instanceof short[]) {
1348             short[] v = (short[]) cst;
1349             buf.append("new short[] {");
1350             for (int i = 0; i < v.length; i++) {
1351                 buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]);
1352             }
1353             buf.append('}');
1354         } else if (cst instanceof char[]) {
1355             char[] v = (char[]) cst;
1356             buf.append("new char[] {");
1357             for (int i = 0; i < v.length; i++) {
1358                 buf.append(i == 0 ? "" : ",").append("(char)")
1359                         .append((int) v[i]);
1360             }
1361             buf.append('}');
1362         } else if (cst instanceof int[]) {
1363             int[] v = (int[]) cst;
1364             buf.append("new int[] {");
1365             for (int i = 0; i < v.length; i++) {
1366                 buf.append(i == 0 ? "" : ",").append(v[i]);
1367             }
1368             buf.append('}');
1369         } else if (cst instanceof long[]) {
1370             long[] v = (long[]) cst;
1371             buf.append("new long[] {");
1372             for (int i = 0; i < v.length; i++) {
1373                 buf.append(i == 0 ? "" : ",").append(v[i]).append('L');
1374             }
1375             buf.append('}');
1376         } else if (cst instanceof float[]) {
1377             float[] v = (float[]) cst;
1378             buf.append("new float[] {");
1379             for (int i = 0; i < v.length; i++) {
1380                 buf.append(i == 0 ? "" : ",").append(v[i]).append('f');
1381             }
1382             buf.append('}');
1383         } else if (cst instanceof double[]) {
1384             double[] v = (double[]) cst;
1385             buf.append("new double[] {");
1386             for (int i = 0; i < v.length; i++) {
1387                 buf.append(i == 0 ? "" : ",").append(v[i]).append('d');
1388             }
1389             buf.append('}');
1390         }
1391     }
1392 
1393     private void declareFrameTypes(final int n, final Object[] o) {
1394         for (int i = 0; i < n; ++i) {
1395             if (o[i] instanceof Label) {
1396                 declareLabel((Label) o[i]);
1397             }
1398         }
1399     }
1400 
1401     private void appendFrameTypes(final int n, final Object[] o) {
1402         for (int i = 0; i < n; ++i) {
1403             if (i > 0) {
1404                 buf.append(", ");
1405             }
1406             if (o[i] instanceof String) {
1407                 appendConstant(o[i]);
1408             } else if (o[i] instanceof Integer) {
1409                 switch (((Integer) o[i]).intValue()) {
1410                 case 0:
1411                     buf.append("Opcodes.TOP");
1412                     break;
1413                 case 1:
1414                     buf.append("Opcodes.INTEGER");
1415                     break;
1416                 case 2:
1417                     buf.append("Opcodes.FLOAT");
1418                     break;
1419                 case 3:
1420                     buf.append("Opcodes.DOUBLE");
1421                     break;
1422                 case 4:
1423                     buf.append("Opcodes.LONG");
1424                     break;
1425                 case 5:
1426                     buf.append("Opcodes.NULL");
1427                     break;
1428                 case 6:
1429                     buf.append("Opcodes.UNINITIALIZED_THIS");
1430                     break;
1431                 }
1432             } else {
1433                 appendLabel((Label) o[i]);
1434             }
1435         }
1436     }
1437 
1438     /**
1439      * Appends a declaration of the given label to {@link #buf buf}. This
1440      * declaration is of the form "Label lXXX = new Label();". Does nothing if
1441      * the given label has already been declared.
1442      *
1443      * @param l
1444      *            a label.
1445      */
1446     protected void declareLabel(final Label l) {
1447         if (labelNames == null) {
1448             labelNames = new HashMap<Label, String>();
1449         }
1450         String name = labelNames.get(l);
1451         if (name == null) {
1452             name = "l" + labelNames.size();
1453             labelNames.put(l, name);
1454             buf.append("Label ").append(name).append(" = new Label();\n");
1455         }
1456     }
1457 
1458     /**
1459      * Appends the name of the given label to {@link #buf buf}. The given label
1460      * <i>must</i> already have a name. One way to ensure this is to always call
1461      * {@link #declareLabel declared} before calling this method.
1462      *
1463      * @param l
1464      *            a label.
1465      */
1466     protected void appendLabel(final Label l) {
1467         buf.append(labelNames.get(l));
1468     }
1469 }