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