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         buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
 860         buf.append("new Label[] {");
 861         for (int i = 0; i < start.length; ++i) {
 862             buf.append(i == 0 ? " " : ", ");
 863             appendLabel(start[i]);
 864         }
 865         buf.append(" }, new Label[] {");
 866         for (int i = 0; i < end.length; ++i) {
 867             buf.append(i == 0 ? " " : ", ");
 868             appendLabel(end[i]);
 869         }
 870         buf.append(" }, new int[] {");
 871         for (int i = 0; i < index.length; ++i) {
 872             buf.append(i == 0 ? " " : ", ").append(index[i]);
 873         }
 874         buf.append(" }, ");
 875         appendConstant(desc);
 876         buf.append(", ").append(visible).append(");\n");
 877         text.add(buf.toString());
 878         ASMifier a = createASMifier("av", 0);
 879         text.add(a.getText());
 880         text.add("}\n");
 881         return a;
 882     }
 883 
 884     @Override
 885     public void visitLineNumber(final int line, final Label start) {
 886         buf.setLength(0);
 887         buf.append(name).append(".visitLineNumber(").append(line).append(", ");
 888         appendLabel(start);
 889         buf.append(");\n");
 890         text.add(buf.toString());
 891     }
 892 
 893     @Override
 894     public void visitMaxs(final int maxStack, final int maxLocals) {
 895         buf.setLength(0);
 896         buf.append(name).append(".visitMaxs(").append(maxStack).append(", ")
 897                 .append(maxLocals).append(");\n");
 898         text.add(buf.toString());
 899     }
 900 
 901     @Override
 902     public void visitMethodEnd() {
 903         buf.setLength(0);
 904         buf.append(name).append(".visitEnd();\n");
 905         text.add(buf.toString());
 906     }
 907 
 908     // ------------------------------------------------------------------------
 909     // Common methods
 910     // ------------------------------------------------------------------------
 911 
 912     public ASMifier visitAnnotation(final String desc, final boolean visible) {
 913         buf.setLength(0);
 914         buf.append("{\n").append("av0 = ").append(name)
 915                 .append(".visitAnnotation(");
 916         appendConstant(desc);
 917         buf.append(", ").append(visible).append(");\n");
 918         text.add(buf.toString());
 919         ASMifier a = createASMifier("av", 0);
 920         text.add(a.getText());
 921         text.add("}\n");
 922         return a;
 923     }
 924 
 925     public ASMifier visitTypeAnnotation(final int typeRef,
 926             final TypePath typePath, final String desc, final boolean visible) {
 927         return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath,
 928                 desc, visible);
 929     }
 930 
 931     public ASMifier visitTypeAnnotation(final String method, final int typeRef,
 932             final TypePath typePath, final String desc, final boolean visible) {
 933         buf.setLength(0);
 934         buf.append("{\n").append("av0 = ").append(name).append(".")
 935                 .append(method).append("(");
 936         buf.append(typeRef);
 937         buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
 938         appendConstant(desc);
 939         buf.append(", ").append(visible).append(");\n");
 940         text.add(buf.toString());
 941         ASMifier a = createASMifier("av", 0);
 942         text.add(a.getText());
 943         text.add("}\n");
 944         return a;
 945     }
 946 
 947     public void visitAttribute(final Attribute attr) {
 948         buf.setLength(0);
 949         buf.append("// ATTRIBUTE ").append(attr.type).append('\n');
 950         if (attr instanceof ASMifiable) {
 951             if (labelNames == null) {
 952                 labelNames = new HashMap<Label, String>();
 953             }
 954             buf.append("{\n");
 955             ((ASMifiable) attr).asmify(buf, "attr", labelNames);
 956             buf.append(name).append(".visitAttribute(attr);\n");
 957             buf.append("}\n");
 958         }
 959         text.add(buf.toString());
 960     }
 961 
 962     // ------------------------------------------------------------------------
 963     // Utility methods
 964     // ------------------------------------------------------------------------
 965 
 966     protected ASMifier createASMifier(final String name, final int id) {
 967         return new ASMifier(Opcodes.ASM5, name, id);
 968     }
 969 
 970     /**
 971      * Appends a string representation of the given access modifiers to
 972      * {@link #buf buf}.
 973      *
 974      * @param access
 975      *            some access modifiers.
 976      */
 977     void appendAccess(final int access) {
 978         boolean first = true;
 979         if ((access & Opcodes.ACC_PUBLIC) != 0) {
 980             buf.append("ACC_PUBLIC");
 981             first = false;
 982         }
 983         if ((access & Opcodes.ACC_PRIVATE) != 0) {
 984             buf.append("ACC_PRIVATE");
 985             first = false;
 986         }
 987         if ((access & Opcodes.ACC_PROTECTED) != 0) {
 988             buf.append("ACC_PROTECTED");
 989             first = false;
 990         }
 991         if ((access & Opcodes.ACC_FINAL) != 0) {
 992             if (!first) {
 993                 buf.append(" + ");
 994             }
 995             buf.append("ACC_FINAL");
 996             first = false;
 997         }
 998         if ((access & Opcodes.ACC_STATIC) != 0) {
 999             if (!first) {
1000                 buf.append(" + ");
1001             }
1002             buf.append("ACC_STATIC");
1003             first = false;
1004         }
1005         if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
1006             if (!first) {
1007                 buf.append(" + ");
1008             }
1009             if ((access & ACCESS_CLASS) == 0) {
1010                 buf.append("ACC_SYNCHRONIZED");
1011             } else {
1012                 buf.append("ACC_SUPER");
1013             }
1014             first = false;
1015         }
1016         if ((access & Opcodes.ACC_VOLATILE) != 0
1017                 && (access & ACCESS_FIELD) != 0) {
1018             if (!first) {
1019                 buf.append(" + ");
1020             }
1021             buf.append("ACC_VOLATILE");
1022             first = false;
1023         }
1024         if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0
1025                 && (access & ACCESS_FIELD) == 0) {
1026             if (!first) {
1027                 buf.append(" + ");
1028             }
1029             buf.append("ACC_BRIDGE");
1030             first = false;
1031         }
1032         if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0
1033                 && (access & ACCESS_FIELD) == 0) {
1034             if (!first) {
1035                 buf.append(" + ");
1036             }
1037             buf.append("ACC_VARARGS");
1038             first = false;
1039         }
1040         if ((access & Opcodes.ACC_TRANSIENT) != 0
1041                 && (access & ACCESS_FIELD) != 0) {
1042             if (!first) {
1043                 buf.append(" + ");
1044             }
1045             buf.append("ACC_TRANSIENT");
1046             first = false;
1047         }
1048         if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0
1049                 && (access & ACCESS_FIELD) == 0) {
1050             if (!first) {
1051                 buf.append(" + ");
1052             }
1053             buf.append("ACC_NATIVE");
1054             first = false;
1055         }
1056         if ((access & Opcodes.ACC_ENUM) != 0
1057                 && ((access & ACCESS_CLASS) != 0
1058                         || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) {
1059             if (!first) {
1060                 buf.append(" + ");
1061             }
1062             buf.append("ACC_ENUM");
1063             first = false;
1064         }
1065         if ((access & Opcodes.ACC_ANNOTATION) != 0
1066                 && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_INNER) != 0)) {
1067             if (!first) {
1068                 buf.append(" + ");
1069             }
1070             buf.append("ACC_ANNOTATION");
1071             first = false;
1072         }
1073         if ((access & Opcodes.ACC_ABSTRACT) != 0) {
1074             if (!first) {
1075                 buf.append(" + ");
1076             }
1077             buf.append("ACC_ABSTRACT");
1078             first = false;
1079         }
1080         if ((access & Opcodes.ACC_INTERFACE) != 0) {
1081             if (!first) {
1082                 buf.append(" + ");
1083             }
1084             buf.append("ACC_INTERFACE");
1085             first = false;
1086         }
1087         if ((access & Opcodes.ACC_STRICT) != 0) {
1088             if (!first) {
1089                 buf.append(" + ");
1090             }
1091             buf.append("ACC_STRICT");
1092             first = false;
1093         }
1094         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
1095             if (!first) {
1096                 buf.append(" + ");
1097             }
1098             buf.append("ACC_SYNTHETIC");
1099             first = false;
1100         }
1101         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1102             if (!first) {
1103                 buf.append(" + ");
1104             }
1105             buf.append("ACC_DEPRECATED");
1106             first = false;
1107         }
1108         if ((access & Opcodes.ACC_MANDATED) != 0) {
1109             if (!first) {
1110                 buf.append(" + ");
1111             }
1112             buf.append("ACC_MANDATED");
1113             first = false;
1114         }
1115         if (first) {
1116             buf.append('0');
1117         }
1118     }
1119 
1120     /**
1121      * Appends a string representation of the given constant to the given
1122      * buffer.
1123      *
1124      * @param cst
1125      *            an {@link Integer}, {@link Float}, {@link Long},
1126      *            {@link Double} or {@link String} object. May be <tt>null</tt>.
1127      */
1128     protected void appendConstant(final Object cst) {
1129         appendConstant(buf, cst);
1130     }
1131 
1132     /**
1133      * Appends a string representation of the given constant to the given
1134      * buffer.
1135      *
1136      * @param buf
1137      *            a string buffer.
1138      * @param cst
1139      *            an {@link Integer}, {@link Float}, {@link Long},
1140      *            {@link Double} or {@link String} object. May be <tt>null</tt>.
1141      */
1142     static void appendConstant(final StringBuffer buf, final Object cst) {
1143         if (cst == null) {
1144             buf.append("null");
1145         } else if (cst instanceof String) {
1146             appendString(buf, (String) cst);
1147         } else if (cst instanceof Type) {
1148             buf.append("Type.getType(\"");
1149             buf.append(((Type) cst).getDescriptor());
1150             buf.append("\")");
1151         } else if (cst instanceof Handle) {
1152             buf.append("new Handle(");
1153             Handle h = (Handle) cst;
1154             buf.append("Opcodes.").append(HANDLE_TAG[h.getTag()])
1155                     .append(", \"");
1156             buf.append(h.getOwner()).append("\", \"");
1157             buf.append(h.getName()).append("\", \"");
1158             buf.append(h.getDesc()).append("\")");
1159         } else if (cst instanceof Byte) {
1160             buf.append("new Byte((byte)").append(cst).append(')');
1161         } else if (cst instanceof Boolean) {
1162             buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE"
1163                     : "Boolean.FALSE");
1164         } else if (cst instanceof Short) {
1165             buf.append("new Short((short)").append(cst).append(')');
1166         } else if (cst instanceof Character) {
1167             int c = ((Character) cst).charValue();
1168             buf.append("new Character((char)").append(c).append(')');
1169         } else if (cst instanceof Integer) {
1170             buf.append("new Integer(").append(cst).append(')');
1171         } else if (cst instanceof Float) {
1172             buf.append("new Float(\"").append(cst).append("\")");
1173         } else if (cst instanceof Long) {
1174             buf.append("new Long(").append(cst).append("L)");
1175         } else if (cst instanceof Double) {
1176             buf.append("new Double(\"").append(cst).append("\")");
1177         } else if (cst instanceof byte[]) {
1178             byte[] v = (byte[]) cst;
1179             buf.append("new byte[] {");
1180             for (int i = 0; i < v.length; i++) {
1181                 buf.append(i == 0 ? "" : ",").append(v[i]);
1182             }
1183             buf.append('}');
1184         } else if (cst instanceof boolean[]) {
1185             boolean[] v = (boolean[]) cst;
1186             buf.append("new boolean[] {");
1187             for (int i = 0; i < v.length; i++) {
1188                 buf.append(i == 0 ? "" : ",").append(v[i]);
1189             }
1190             buf.append('}');
1191         } else if (cst instanceof short[]) {
1192             short[] v = (short[]) cst;
1193             buf.append("new short[] {");
1194             for (int i = 0; i < v.length; i++) {
1195                 buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]);
1196             }
1197             buf.append('}');
1198         } else if (cst instanceof char[]) {
1199             char[] v = (char[]) cst;
1200             buf.append("new char[] {");
1201             for (int i = 0; i < v.length; i++) {
1202                 buf.append(i == 0 ? "" : ",").append("(char)")
1203                         .append((int) v[i]);
1204             }
1205             buf.append('}');
1206         } else if (cst instanceof int[]) {
1207             int[] v = (int[]) cst;
1208             buf.append("new int[] {");
1209             for (int i = 0; i < v.length; i++) {
1210                 buf.append(i == 0 ? "" : ",").append(v[i]);
1211             }
1212             buf.append('}');
1213         } else if (cst instanceof long[]) {
1214             long[] v = (long[]) cst;
1215             buf.append("new long[] {");
1216             for (int i = 0; i < v.length; i++) {
1217                 buf.append(i == 0 ? "" : ",").append(v[i]).append('L');
1218             }
1219             buf.append('}');
1220         } else if (cst instanceof float[]) {
1221             float[] v = (float[]) cst;
1222             buf.append("new float[] {");
1223             for (int i = 0; i < v.length; i++) {
1224                 buf.append(i == 0 ? "" : ",").append(v[i]).append('f');
1225             }
1226             buf.append('}');
1227         } else if (cst instanceof double[]) {
1228             double[] v = (double[]) cst;
1229             buf.append("new double[] {");
1230             for (int i = 0; i < v.length; i++) {
1231                 buf.append(i == 0 ? "" : ",").append(v[i]).append('d');
1232             }
1233             buf.append('}');
1234         }
1235     }
1236 
1237     private void declareFrameTypes(final int n, final Object[] o) {
1238         for (int i = 0; i < n; ++i) {
1239             if (o[i] instanceof Label) {
1240                 declareLabel((Label) o[i]);
1241             }
1242         }
1243     }
1244 
1245     private void appendFrameTypes(final int n, final Object[] o) {
1246         for (int i = 0; i < n; ++i) {
1247             if (i > 0) {
1248                 buf.append(", ");
1249             }
1250             if (o[i] instanceof String) {
1251                 appendConstant(o[i]);
1252             } else if (o[i] instanceof Integer) {
1253                 switch (((Integer) o[i]).intValue()) {
1254                 case 0:
1255                     buf.append("Opcodes.TOP");
1256                     break;
1257                 case 1:
1258                     buf.append("Opcodes.INTEGER");
1259                     break;
1260                 case 2:
1261                     buf.append("Opcodes.FLOAT");
1262                     break;
1263                 case 3:
1264                     buf.append("Opcodes.DOUBLE");
1265                     break;
1266                 case 4:
1267                     buf.append("Opcodes.LONG");
1268                     break;
1269                 case 5:
1270                     buf.append("Opcodes.NULL");
1271                     break;
1272                 case 6:
1273                     buf.append("Opcodes.UNINITIALIZED_THIS");
1274                     break;
1275                 }
1276             } else {
1277                 appendLabel((Label) o[i]);
1278             }
1279         }
1280     }
1281 
1282     /**
1283      * Appends a declaration of the given label to {@link #buf buf}. This
1284      * declaration is of the form "Label lXXX = new Label();". Does nothing if
1285      * the given label has already been declared.
1286      *
1287      * @param l
1288      *            a label.
1289      */
1290     protected void declareLabel(final Label l) {
1291         if (labelNames == null) {
1292             labelNames = new HashMap<Label, String>();
1293         }
1294         String name = labelNames.get(l);
1295         if (name == null) {
1296             name = "l" + labelNames.size();
1297             labelNames.put(l, name);
1298             buf.append("Label ").append(name).append(" = new Label();\n");
1299         }
1300     }
1301 
1302     /**
1303      * Appends the name of the given label to {@link #buf buf}. The given label
1304      * <i>must</i> already have a name. One way to ensure this is to always call
1305      * {@link #declareLabel declared} before calling this method.
1306      *
1307      * @param l
1308      *            a label.
1309      */
1310     protected void appendLabel(final Label l) {
1311         buf.append(labelNames.get(l));
1312     }
1313 }