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