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