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("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 }