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.signature.SignatureReader; 73 74 /** 75 * A {@link Printer} that prints a disassembled view of the classes it visits. 76 * 77 * @author Eric Bruneton 78 */ 79 public class Textifier extends Printer { 80 81 /** 82 * Constant used in {@link #appendDescriptor appendDescriptor} for internal 83 * type names in bytecode notation. 84 */ 85 public static final int INTERNAL_NAME = 0; 86 87 /** 88 * Constant used in {@link #appendDescriptor appendDescriptor} for field 89 * descriptors, formatted in bytecode notation 90 */ 91 public static final int FIELD_DESCRIPTOR = 1; 155 protected String tab3 = " "; 156 157 /** 158 * Tab for labels. 159 */ 160 protected String ltab = " "; 161 162 /** 163 * The label names. This map associate String values to Label keys. 164 */ 165 protected Map<Label, String> labelNames; 166 167 private int valueNumber = 0; 168 169 /** 170 * Constructs a new {@link Textifier}. <i>Subclasses must not use this 171 * constructor</i>. Instead, they must use the {@link #Textifier(int)} 172 * version. 173 */ 174 public Textifier() { 175 this(Opcodes.ASM4); 176 } 177 178 /** 179 * Constructs a new {@link Textifier}. 180 * 181 * @param api the ASM API version implemented by this visitor. Must be one 182 * of {@link Opcodes#ASM4}. 183 */ 184 protected Textifier(final int api) { 185 super(api); 186 } 187 188 /** 189 * Prints a disassembled view of the given class to the standard output. <p> 190 * Usage: Textifier [-debug] <binary class name or class 191 * file name > 192 * 193 * @param args the command line arguments. 194 * 195 * @throws Exception if the class cannot be found, or if an IO exception 196 * occurs. 197 */ 198 public static void main(final String[] args) throws Exception { 199 int i = 0; 200 int flags = ClassReader.SKIP_DEBUG; 201 202 boolean ok = true; 203 if (args.length < 1 || args.length > 2) { 204 ok = false; 205 } 206 if (ok && "-debug".equals(args[0])) { 207 i = 1; 208 flags = 0; 209 if (args.length != 2) { 210 ok = false; 211 } 212 } 213 if (!ok) { 214 System.err.println("Prints a disassembled view of the given class."); 215 System.err.println("Usage: Textifier [-debug] " 216 + "<fully qualified class name or class file name>"); 217 return; 218 } 219 ClassReader cr; 220 if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 221 || args[i].indexOf('/') > -1) 222 { 223 cr = new ClassReader(new FileInputStream(args[i])); 224 } else { 225 cr = new ClassReader(args[i]); 226 } 227 cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), 228 flags); 229 } 230 231 // ------------------------------------------------------------------------ 232 // Classes 233 // ------------------------------------------------------------------------ 234 235 @Override 236 public void visit( 237 final int version, 238 final int access, 239 final String name, 240 final String signature, 241 final String superName, 242 final String[] interfaces) 243 { 244 int major = version & 0xFFFF; 245 int minor = version >>> 16; 246 buf.setLength(0); 247 buf.append("// class version ") 248 .append(major) 249 .append('.') 250 .append(minor) 251 .append(" (") 252 .append(version) 253 .append(")\n"); 254 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 255 buf.append("// DEPRECATED\n"); 256 } 257 buf.append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); 258 259 appendDescriptor(CLASS_SIGNATURE, signature); 260 if (signature != null) { 261 TraceSignatureVisitor sv = new TraceSignatureVisitor(access); 262 SignatureReader r = new SignatureReader(signature); 263 r.accept(sv); 264 buf.append("// declaration: ") 265 .append(name) 266 .append(sv.getDeclaration()) 267 .append('\n'); 268 } 269 270 appendAccess(access & ~Opcodes.ACC_SUPER); 271 if ((access & Opcodes.ACC_ANNOTATION) != 0) { 272 buf.append("@interface "); 273 } else if ((access & Opcodes.ACC_INTERFACE) != 0) { 274 buf.append("interface "); 275 } else if ((access & Opcodes.ACC_ENUM) == 0) { 276 buf.append("class "); 277 } 278 appendDescriptor(INTERNAL_NAME, name); 279 280 if (superName != null && !"java/lang/Object".equals(superName)) { 281 buf.append(" extends "); 282 appendDescriptor(INTERNAL_NAME, superName); 283 buf.append(' '); 284 } 285 if (interfaces != null && interfaces.length > 0) { 286 buf.append(" implements "); 287 for (int i = 0; i < interfaces.length; ++i) { 288 appendDescriptor(INTERNAL_NAME, interfaces[i]); 289 buf.append(' '); 290 } 291 } 292 buf.append(" {\n\n"); 293 294 text.add(buf.toString()); 295 } 296 297 @Override 298 public void visitSource(final String file, final String debug) { 299 buf.setLength(0); 300 if (file != null) { 301 buf.append(tab) 302 .append("// compiled from: ") 303 .append(file) 304 .append('\n'); 305 } 306 if (debug != null) { 307 buf.append(tab) 308 .append("// debug info: ") 309 .append(debug) 310 .append('\n'); 311 } 312 if (buf.length() > 0) { 313 text.add(buf.toString()); 314 } 315 } 316 317 @Override 318 public void visitOuterClass( 319 final String owner, 320 final String name, 321 final String desc) 322 { 323 buf.setLength(0); 324 buf.append(tab).append("OUTERCLASS "); 325 appendDescriptor(INTERNAL_NAME, owner); 326 buf.append(' '); 327 if (name != null) { 328 buf.append(name).append(' '); 329 } 330 appendDescriptor(METHOD_DESCRIPTOR, desc); 331 buf.append('\n'); 332 text.add(buf.toString()); 333 } 334 335 @Override 336 public Textifier visitClassAnnotation( 337 final String desc, 338 final boolean visible) 339 { 340 text.add("\n"); 341 return visitAnnotation(desc, visible); 342 } 343 344 @Override 345 public void visitClassAttribute(final Attribute attr) { 346 text.add("\n"); 347 visitAttribute(attr); 348 } 349 350 @Override 351 public void visitInnerClass( 352 final String name, 353 final String outerName, 354 final String innerName, 355 final int access) 356 { 357 buf.setLength(0); 358 buf.append(tab).append("// access flags 0x"); 359 buf.append(Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase()).append('\n'); 360 buf.append(tab); 361 appendAccess(access); 362 buf.append("INNERCLASS "); 363 appendDescriptor(INTERNAL_NAME, name); 364 buf.append(' '); 365 appendDescriptor(INTERNAL_NAME, outerName); 366 buf.append(' '); 367 appendDescriptor(INTERNAL_NAME, innerName); 368 buf.append('\n'); 369 text.add(buf.toString()); 370 } 371 372 @Override 373 public Textifier visitField( 374 final int access, 375 final String name, 376 final String desc, 377 final String signature, 378 final Object value) 379 { 380 buf.setLength(0); 381 buf.append('\n'); 382 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 383 buf.append(tab).append("// DEPRECATED\n"); 384 } 385 buf.append(tab).append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); 386 if (signature != null) { 387 buf.append(tab); 388 appendDescriptor(FIELD_SIGNATURE, signature); 389 390 TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 391 SignatureReader r = new SignatureReader(signature); 392 r.acceptType(sv); 393 buf.append(tab) 394 .append("// declaration: ") 395 .append(sv.getDeclaration()) 396 .append('\n'); 397 } 398 399 buf.append(tab); 400 appendAccess(access); 401 402 appendDescriptor(FIELD_DESCRIPTOR, desc); 403 buf.append(' ').append(name); 404 if (value != null) { 405 buf.append(" = "); 406 if (value instanceof String) { 407 buf.append('\"').append(value).append('\"'); 408 } else { 409 buf.append(value); 410 } 411 } 412 413 buf.append('\n'); 414 text.add(buf.toString()); 415 416 Textifier t = createTextifier(); 417 text.add(t.getText()); 418 return t; 419 } 420 421 @Override 422 public Textifier visitMethod( 423 final int access, 424 final String name, 425 final String desc, 426 final String signature, 427 final String[] exceptions) 428 { 429 buf.setLength(0); 430 buf.append('\n'); 431 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 432 buf.append(tab).append("// DEPRECATED\n"); 433 } 434 buf.append(tab).append("// access flags 0x").append(Integer.toHexString(access).toUpperCase()).append('\n'); 435 436 if (signature != null) { 437 buf.append(tab); 438 appendDescriptor(METHOD_SIGNATURE, signature); 439 440 TraceSignatureVisitor v = new TraceSignatureVisitor(0); 441 SignatureReader r = new SignatureReader(signature); 442 r.accept(v); 443 String genericDecl = v.getDeclaration(); 444 String genericReturn = v.getReturnType(); 445 String genericExceptions = v.getExceptions(); 446 447 buf.append(tab) 448 .append("// declaration: ") 449 .append(genericReturn) 450 .append(' ') 451 .append(name) 452 .append(genericDecl); 453 if (genericExceptions != null) { 454 buf.append(" throws ").append(genericExceptions); 455 } 456 buf.append('\n'); 457 } 458 459 buf.append(tab); 460 appendAccess(access); 461 if ((access & Opcodes.ACC_NATIVE) != 0) { 462 buf.append("native "); 463 } 464 if ((access & Opcodes.ACC_VARARGS) != 0) { 465 buf.append("varargs "); 466 } 467 if ((access & Opcodes.ACC_BRIDGE) != 0) { 468 buf.append("bridge "); 469 } 470 471 buf.append(name); 472 appendDescriptor(METHOD_DESCRIPTOR, desc); 605 buf.append("(short)").append(value); 606 } 607 608 private void visitByte(final byte value) { 609 buf.append("(byte)").append(value); 610 } 611 612 private void visitBoolean(final boolean value) { 613 buf.append(value); 614 } 615 616 private void visitString(final String value) { 617 appendString(buf, value); 618 } 619 620 private void visitType(final Type value) { 621 buf.append(value.getClassName()).append(".class"); 622 } 623 624 @Override 625 public void visitEnum( 626 final String name, 627 final String desc, 628 final String value) 629 { 630 buf.setLength(0); 631 appendComa(valueNumber++); 632 if (name != null) { 633 buf.append(name).append('='); 634 } 635 appendDescriptor(FIELD_DESCRIPTOR, desc); 636 buf.append('.').append(value); 637 text.add(buf.toString()); 638 } 639 640 @Override 641 public Textifier visitAnnotation( 642 final String name, 643 final String desc) 644 { 645 buf.setLength(0); 646 appendComa(valueNumber++); 647 if (name != null) { 648 buf.append(name).append('='); 649 } 650 buf.append('@'); 651 appendDescriptor(FIELD_DESCRIPTOR, desc); 652 buf.append('('); 653 text.add(buf.toString()); 654 Textifier t = createTextifier(); 655 text.add(t.getText()); 656 text.add(")"); 657 return t; 658 } 659 660 @Override 661 public Textifier visitArray( 662 final String name) 663 { 664 buf.setLength(0); 665 appendComa(valueNumber++); 666 if (name != null) { 667 buf.append(name).append('='); 668 } 669 buf.append('{'); 670 text.add(buf.toString()); 671 Textifier t = createTextifier(); 672 text.add(t.getText()); 673 text.add("}"); 674 return t; 675 } 676 677 @Override 678 public void visitAnnotationEnd() { 679 } 680 681 // ------------------------------------------------------------------------ 682 // Fields 683 // ------------------------------------------------------------------------ 684 685 @Override 686 public Textifier visitFieldAnnotation( 687 final String desc, 688 final boolean visible) 689 { 690 return visitAnnotation(desc, visible); 691 } 692 693 @Override 694 public void visitFieldAttribute(final Attribute attr) { 695 visitAttribute(attr); 696 } 697 698 @Override 699 public void visitFieldEnd() { 700 } 701 702 // ------------------------------------------------------------------------ 703 // Methods 704 // ------------------------------------------------------------------------ 705 706 @Override 707 public Textifier visitAnnotationDefault() { 708 text.add(tab2 + "default="); 709 Textifier t = createTextifier(); 710 text.add(t.getText()); 711 text.add("\n"); 712 return t; 713 } 714 715 @Override 716 public Textifier visitMethodAnnotation( 717 final String desc, 718 final boolean visible) 719 { 720 return visitAnnotation(desc, visible); 721 } 722 723 @Override 724 public Textifier visitParameterAnnotation( 725 final int parameter, 726 final String desc, 727 final boolean visible) 728 { 729 buf.setLength(0); 730 buf.append(tab2).append('@'); 731 appendDescriptor(FIELD_DESCRIPTOR, desc); 732 buf.append('('); 733 text.add(buf.toString()); 734 Textifier t = createTextifier(); 735 text.add(t.getText()); 736 text.add(visible ? ") // parameter " : ") // invisible, parameter "); 737 text.add(new Integer(parameter)); 738 text.add("\n"); 739 return t; 740 } 741 742 @Override 743 public void visitMethodAttribute(final Attribute attr) { 744 buf.setLength(0); 745 buf.append(tab).append("ATTRIBUTE "); 746 appendDescriptor(-1, attr.type); 747 748 if (attr instanceof Textifiable) { 749 ((Textifiable) attr).textify(buf, labelNames); 750 } else { 751 buf.append(" : unknown\n"); 752 } 753 754 text.add(buf.toString()); 755 } 756 757 @Override 758 public void visitCode() { 759 } 760 761 @Override 762 public void visitFrame( 763 final int type, 764 final int nLocal, 765 final Object[] local, 766 final int nStack, 767 final Object[] stack) 768 { 769 buf.setLength(0); 770 buf.append(ltab); 771 buf.append("FRAME "); 772 switch (type) { 773 case Opcodes.F_NEW: 774 case Opcodes.F_FULL: 775 buf.append("FULL ["); 776 appendFrameTypes(nLocal, local); 777 buf.append("] ["); 778 appendFrameTypes(nStack, stack); 779 buf.append(']'); 780 break; 781 case Opcodes.F_APPEND: 782 buf.append("APPEND ["); 783 appendFrameTypes(nLocal, local); 784 buf.append(']'); 785 break; 786 case Opcodes.F_CHOP: 787 buf.append("CHOP ").append(nLocal); 788 break; 794 appendFrameTypes(1, stack); 795 break; 796 } 797 buf.append('\n'); 798 text.add(buf.toString()); 799 } 800 801 @Override 802 public void visitInsn(final int opcode) { 803 buf.setLength(0); 804 buf.append(tab2).append(OPCODES[opcode]).append('\n'); 805 text.add(buf.toString()); 806 } 807 808 @Override 809 public void visitIntInsn(final int opcode, final int operand) { 810 buf.setLength(0); 811 buf.append(tab2) 812 .append(OPCODES[opcode]) 813 .append(' ') 814 .append(opcode == Opcodes.NEWARRAY 815 ? TYPES[operand] 816 : Integer.toString(operand)) 817 .append('\n'); 818 text.add(buf.toString()); 819 } 820 821 @Override 822 public void visitVarInsn(final int opcode, final int var) { 823 buf.setLength(0); 824 buf.append(tab2) 825 .append(OPCODES[opcode]) 826 .append(' ') 827 .append(var) 828 .append('\n'); 829 text.add(buf.toString()); 830 } 831 832 @Override 833 public void visitTypeInsn(final int opcode, final String type) { 834 buf.setLength(0); 835 buf.append(tab2).append(OPCODES[opcode]).append(' '); 836 appendDescriptor(INTERNAL_NAME, type); 837 buf.append('\n'); 838 text.add(buf.toString()); 839 } 840 841 @Override 842 public void visitFieldInsn( 843 final int opcode, 844 final String owner, 845 final String name, 846 final String desc) 847 { 848 buf.setLength(0); 849 buf.append(tab2).append(OPCODES[opcode]).append(' '); 850 appendDescriptor(INTERNAL_NAME, owner); 851 buf.append('.').append(name).append(" : "); 852 appendDescriptor(FIELD_DESCRIPTOR, desc); 853 buf.append('\n'); 854 text.add(buf.toString()); 855 } 856 857 @Override 858 public void visitMethodInsn( 859 final int opcode, 860 final String owner, 861 final String name, 862 final String desc) 863 { 864 buf.setLength(0); 865 buf.append(tab2).append(OPCODES[opcode]).append(' '); 866 appendDescriptor(INTERNAL_NAME, owner); 867 buf.append('.').append(name).append(' '); 868 appendDescriptor(METHOD_DESCRIPTOR, desc); 869 buf.append('\n'); 870 text.add(buf.toString()); 871 } 872 873 @Override 874 public void visitInvokeDynamicInsn( 875 String name, 876 String desc, 877 Handle bsm, 878 Object... bsmArgs) 879 { 880 buf.setLength(0); 881 buf.append(tab2).append("INVOKEDYNAMIC").append(' '); 882 buf.append(name); 883 appendDescriptor(METHOD_DESCRIPTOR, desc); 884 buf.append(" ["); 885 appendHandle(bsm); 886 buf.append(tab3).append("// arguments:"); 887 if(bsmArgs.length == 0) { 888 buf.append(" none"); 889 } else { 890 buf.append('\n').append(tab3); 891 for(int i = 0; i < bsmArgs.length; i++) { 892 Object cst = bsmArgs[i]; 893 if (cst instanceof String) { 894 Printer.appendString(buf, (String) cst); 895 } else if (cst instanceof Type) { 896 buf.append(((Type) cst).getDescriptor()).append(".class"); 897 } else if (cst instanceof Handle) { 898 appendHandle((Handle) cst); 899 } else { 900 buf.append(cst); 901 } 902 buf.append(", "); 903 } 904 buf.setLength(buf.length() - 2); 905 } 906 buf.append('\n'); 907 buf.append(tab2).append("]\n"); 908 text.add(buf.toString()); 909 } 910 911 @Override 927 } 928 929 @Override 930 public void visitLdcInsn(final Object cst) { 931 buf.setLength(0); 932 buf.append(tab2).append("LDC "); 933 if (cst instanceof String) { 934 Printer.appendString(buf, (String) cst); 935 } else if (cst instanceof Type) { 936 buf.append(((Type) cst).getDescriptor()).append(".class"); 937 } else { 938 buf.append(cst); 939 } 940 buf.append('\n'); 941 text.add(buf.toString()); 942 } 943 944 @Override 945 public void visitIincInsn(final int var, final int increment) { 946 buf.setLength(0); 947 buf.append(tab2) 948 .append("IINC ") 949 .append(var) 950 .append(' ') 951 .append(increment) 952 .append('\n'); 953 text.add(buf.toString()); 954 } 955 956 @Override 957 public void visitTableSwitchInsn( 958 final int min, 959 final int max, 960 final Label dflt, 961 final Label... labels) 962 { 963 buf.setLength(0); 964 buf.append(tab2).append("TABLESWITCH\n"); 965 for (int i = 0; i < labels.length; ++i) { 966 buf.append(tab3).append(min + i).append(": "); 967 appendLabel(labels[i]); 968 buf.append('\n'); 969 } 970 buf.append(tab3).append("default: "); 971 appendLabel(dflt); 972 buf.append('\n'); 973 text.add(buf.toString()); 974 } 975 976 @Override 977 public void visitLookupSwitchInsn( 978 final Label dflt, 979 final int[] keys, 980 final Label[] labels) 981 { 982 buf.setLength(0); 983 buf.append(tab2).append("LOOKUPSWITCH\n"); 984 for (int i = 0; i < labels.length; ++i) { 985 buf.append(tab3).append(keys[i]).append(": "); 986 appendLabel(labels[i]); 987 buf.append('\n'); 988 } 989 buf.append(tab3).append("default: "); 990 appendLabel(dflt); 991 buf.append('\n'); 992 text.add(buf.toString()); 993 } 994 995 @Override 996 public void visitMultiANewArrayInsn(final String desc, final int dims) { 997 buf.setLength(0); 998 buf.append(tab2).append("MULTIANEWARRAY "); 999 appendDescriptor(FIELD_DESCRIPTOR, desc); 1000 buf.append(' ').append(dims).append('\n'); 1001 text.add(buf.toString()); 1002 } 1003 1004 @Override 1005 public void visitTryCatchBlock( 1006 final Label start, 1007 final Label end, 1008 final Label handler, 1009 final String type) 1010 { 1011 buf.setLength(0); 1012 buf.append(tab2).append("TRYCATCHBLOCK "); 1013 appendLabel(start); 1014 buf.append(' '); 1015 appendLabel(end); 1016 buf.append(' '); 1017 appendLabel(handler); 1018 buf.append(' '); 1019 appendDescriptor(INTERNAL_NAME, type); 1020 buf.append('\n'); 1021 text.add(buf.toString()); 1022 } 1023 1024 @Override 1025 public void visitLocalVariable( 1026 final String name, 1027 final String desc, 1028 final String signature, 1029 final Label start, 1030 final Label end, 1031 final int index) 1032 { 1033 buf.setLength(0); 1034 buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' '); 1035 appendDescriptor(FIELD_DESCRIPTOR, desc); 1036 buf.append(' '); 1037 appendLabel(start); 1038 buf.append(' '); 1039 appendLabel(end); 1040 buf.append(' ').append(index).append('\n'); 1041 1042 if (signature != null) { 1043 buf.append(tab2); 1044 appendDescriptor(FIELD_SIGNATURE, signature); 1045 1046 TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 1047 SignatureReader r = new SignatureReader(signature); 1048 r.acceptType(sv); 1049 buf.append(tab2) 1050 .append("// declaration: ") 1051 .append(sv.getDeclaration()) 1052 .append('\n'); 1053 } 1054 text.add(buf.toString()); 1055 } 1056 1057 @Override 1058 public void visitLineNumber(final int line, final Label start) { 1059 buf.setLength(0); 1060 buf.append(tab2).append("LINENUMBER ").append(line).append(' '); 1061 appendLabel(start); 1062 buf.append('\n'); 1063 text.add(buf.toString()); 1064 } 1065 1066 @Override 1067 public void visitMaxs(final int maxStack, final int maxLocals) { 1068 buf.setLength(0); 1069 buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n'); 1070 text.add(buf.toString()); 1071 1072 buf.setLength(0); 1073 buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n'); 1074 text.add(buf.toString()); 1075 } 1076 1077 @Override 1078 public void visitMethodEnd() { 1079 } 1080 1081 // ------------------------------------------------------------------------ 1082 // Common methods 1083 // ------------------------------------------------------------------------ 1084 1085 /** 1086 * Prints a disassembled view of the given annotation. 1087 * 1088 * @param desc the class descriptor of the annotation class. 1089 * @param visible <tt>true</tt> if the annotation is visible at runtime. 1090 * @return a visitor to visit the annotation values. 1091 */ 1092 public Textifier visitAnnotation( 1093 final String desc, 1094 final boolean visible) 1095 { 1096 buf.setLength(0); 1097 buf.append(tab).append('@'); 1098 appendDescriptor(FIELD_DESCRIPTOR, desc); 1099 buf.append('('); 1100 text.add(buf.toString()); 1101 Textifier t = createTextifier(); 1102 text.add(t.getText()); 1103 text.add(visible ? ")\n" : ") // invisible\n"); 1104 return t; 1105 } 1106 1107 /** 1108 * Prints a disassembled view of the given attribute. 1109 * 1110 * @param attr an attribute. 1111 */ 1112 public void visitAttribute(final Attribute attr) { 1113 buf.setLength(0); 1114 buf.append(tab).append("ATTRIBUTE "); 1115 appendDescriptor(-1, attr.type); 1116 1117 if (attr instanceof Textifiable) { 1118 ((Textifiable) attr).textify(buf, null); 1119 } else { 1120 buf.append(" : unknown\n"); 1121 } 1122 1123 text.add(buf.toString()); 1124 } 1125 1126 // ------------------------------------------------------------------------ 1127 // Utility methods 1128 // ------------------------------------------------------------------------ 1129 1130 /** 1131 * Creates a new TraceVisitor instance. 1132 * 1133 * @return a new TraceVisitor. 1134 */ 1135 protected Textifier createTextifier() { 1136 return new Textifier(); 1137 } 1138 1139 /** 1140 * Appends an internal name, a type descriptor or a type signature to 1141 * {@link #buf buf}. 1142 * 1143 * @param type indicates if desc is an internal name, a field descriptor, a 1144 * method descriptor, a class signature, ... 1145 * @param desc an internal name, type descriptor, or type signature. May be 1146 * <tt>null</tt>. 1147 */ 1148 protected void appendDescriptor(final int type, final String desc) { 1149 if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE 1150 || type == METHOD_SIGNATURE) 1151 { 1152 if (desc != null) { 1153 buf.append("// signature ").append(desc).append('\n'); 1154 } 1155 } else { 1156 buf.append(desc); 1157 } 1158 } 1159 1160 /** 1161 * Appends the name of the given label to {@link #buf buf}. Creates a new 1162 * label name if the given label does not yet have one. 1163 * 1164 * @param l a label. 1165 */ 1166 protected void appendLabel(final Label l) { 1167 if (labelNames == null) { 1168 labelNames = new HashMap<Label, String>(); 1169 } 1170 String name = labelNames.get(l); 1171 if (name == null) { 1172 name = "L" + labelNames.size(); 1173 labelNames.put(l, name); 1174 } 1175 buf.append(name); 1176 } 1177 1178 /** 1179 * Appends the information about the given handle to {@link #buf buf}. 1180 * 1181 * @param h a handle, non null. 1182 */ 1183 protected void appendHandle(final Handle h) { 1184 buf.append('\n').append(tab3); 1185 int tag = h.getTag(); 1186 buf.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : "); 1187 switch (tag) { 1188 case Opcodes.H_GETFIELD: 1189 buf.append("GETFIELD"); 1190 break; 1191 case Opcodes.H_GETSTATIC: 1192 buf.append("GETSTATIC"); 1193 break; 1194 case Opcodes.H_PUTFIELD: 1195 buf.append("PUTFIELD"); 1196 break; 1197 case Opcodes.H_PUTSTATIC: 1198 buf.append("PUTSTATIC"); 1199 break; 1200 case Opcodes.H_INVOKEINTERFACE: 1201 buf.append("INVOKEINTERFACE"); 1202 break; 1203 case Opcodes.H_INVOKESPECIAL: 1204 buf.append("INVOKESPECIAL"); 1205 break; 1206 case Opcodes.H_INVOKESTATIC: 1207 buf.append("INVOKESTATIC"); 1208 break; 1209 case Opcodes.H_INVOKEVIRTUAL: 1210 buf.append("INVOKEVIRTUAL"); 1211 break; 1212 case Opcodes.H_NEWINVOKESPECIAL: 1213 buf.append("NEWINVOKESPECIAL"); 1214 break; 1215 } 1216 buf.append('\n'); 1217 buf.append(tab3); 1218 appendDescriptor(INTERNAL_NAME, h.getOwner()); 1219 buf.append('.'); 1220 buf.append(h.getName()); 1221 buf.append('('); 1222 appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc()); 1223 buf.append(')').append('\n'); 1224 } 1225 1226 /** 1227 * Appends a string representation of the given access modifiers to {@link 1228 * #buf buf}. 1229 * 1230 * @param access some access modifiers. 1231 */ 1232 private void appendAccess(final int access) { 1233 if ((access & Opcodes.ACC_PUBLIC) != 0) { 1234 buf.append("public "); 1235 } 1236 if ((access & Opcodes.ACC_PRIVATE) != 0) { 1237 buf.append("private "); 1238 } 1239 if ((access & Opcodes.ACC_PROTECTED) != 0) { 1240 buf.append("protected "); 1241 } 1242 if ((access & Opcodes.ACC_FINAL) != 0) { 1243 buf.append("final "); 1244 } 1245 if ((access & Opcodes.ACC_STATIC) != 0) { 1246 buf.append("static "); 1247 } 1248 if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { 1249 buf.append("synchronized "); 1250 } 1251 if ((access & Opcodes.ACC_VOLATILE) != 0) { 1252 buf.append("volatile "); 1253 } 1254 if ((access & Opcodes.ACC_TRANSIENT) != 0) { 1255 buf.append("transient "); 1256 } 1257 if ((access & Opcodes.ACC_ABSTRACT) != 0) { 1258 buf.append("abstract "); 1259 } 1260 if ((access & Opcodes.ACC_STRICT) != 0) { 1261 buf.append("strictfp "); 1262 } 1263 if ((access & Opcodes.ACC_ENUM) != 0) { 1264 buf.append("enum "); 1265 } 1266 } 1267 1268 private void appendComa(final int i) { 1269 if (i != 0) { 1270 buf.append(", "); 1271 } 1272 } 1273 1274 private void appendFrameTypes(final int n, final Object[] o) { 1275 for (int i = 0; i < n; ++i) { 1276 if (i > 0) { 1277 buf.append(' '); 1278 } 1279 if (o[i] instanceof String) { 1280 String desc = (String) o[i]; 1281 if (desc.startsWith("[")) { 1282 appendDescriptor(FIELD_DESCRIPTOR, desc); 1283 } else { 1284 appendDescriptor(INTERNAL_NAME, desc); 1285 } 1286 } else if (o[i] instanceof Integer) { 1287 switch (((Integer) o[i]).intValue()) { 1288 case 0: 1289 appendDescriptor(FIELD_DESCRIPTOR, "T"); 1290 break; 1291 case 1: 1292 appendDescriptor(FIELD_DESCRIPTOR, "I"); | 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 import jdk.internal.org.objectweb.asm.TypeReference; 74 import jdk.internal.org.objectweb.asm.signature.SignatureReader; 75 76 /** 77 * A {@link Printer} that prints a disassembled view of the classes it visits. 78 * 79 * @author Eric Bruneton 80 */ 81 public class Textifier extends Printer { 82 83 /** 84 * Constant used in {@link #appendDescriptor appendDescriptor} for internal 85 * type names in bytecode notation. 86 */ 87 public static final int INTERNAL_NAME = 0; 88 89 /** 90 * Constant used in {@link #appendDescriptor appendDescriptor} for field 91 * descriptors, formatted in bytecode notation 92 */ 93 public static final int FIELD_DESCRIPTOR = 1; 157 protected String tab3 = " "; 158 159 /** 160 * Tab for labels. 161 */ 162 protected String ltab = " "; 163 164 /** 165 * The label names. This map associate String values to Label keys. 166 */ 167 protected Map<Label, String> labelNames; 168 169 private int valueNumber = 0; 170 171 /** 172 * Constructs a new {@link Textifier}. <i>Subclasses must not use this 173 * constructor</i>. Instead, they must use the {@link #Textifier(int)} 174 * version. 175 */ 176 public Textifier() { 177 this(Opcodes.ASM5); 178 } 179 180 /** 181 * Constructs a new {@link Textifier}. 182 * 183 * @param api 184 * the ASM API version implemented by this visitor. Must be one 185 * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. 186 */ 187 protected Textifier(final int api) { 188 super(api); 189 } 190 191 /** 192 * Prints a disassembled view of the given class to the standard output. 193 * <p> 194 * Usage: Textifier [-debug] <binary class name or class file name > 195 * 196 * @param args 197 * the command line arguments. 198 * 199 * @throws Exception 200 * if the class cannot be found, or if an IO exception occurs. 201 */ 202 public static void main(final String[] args) throws Exception { 203 int i = 0; 204 int flags = ClassReader.SKIP_DEBUG; 205 206 boolean ok = true; 207 if (args.length < 1 || args.length > 2) { 208 ok = false; 209 } 210 if (ok && "-debug".equals(args[0])) { 211 i = 1; 212 flags = 0; 213 if (args.length != 2) { 214 ok = false; 215 } 216 } 217 if (!ok) { 218 System.err 219 .println("Prints a disassembled view of the given class."); 220 System.err.println("Usage: Textifier [-debug] " 221 + "<fully qualified class name or class file name>"); 222 return; 223 } 224 ClassReader cr; 225 if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 226 || args[i].indexOf('/') > -1) { 227 cr = new ClassReader(new FileInputStream(args[i])); 228 } else { 229 cr = new ClassReader(args[i]); 230 } 231 cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), flags); 232 } 233 234 // ------------------------------------------------------------------------ 235 // Classes 236 // ------------------------------------------------------------------------ 237 238 @Override 239 public void visit(final int version, final int access, final String name, 240 final String signature, final String superName, 241 final String[] interfaces) { 242 int major = version & 0xFFFF; 243 int minor = version >>> 16; 244 buf.setLength(0); 245 buf.append("// class version ").append(major).append('.').append(minor) 246 .append(" (").append(version).append(")\n"); 247 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 248 buf.append("// DEPRECATED\n"); 249 } 250 buf.append("// access flags 0x") 251 .append(Integer.toHexString(access).toUpperCase()).append('\n'); 252 253 appendDescriptor(CLASS_SIGNATURE, signature); 254 if (signature != null) { 255 TraceSignatureVisitor sv = new TraceSignatureVisitor(access); 256 SignatureReader r = new SignatureReader(signature); 257 r.accept(sv); 258 buf.append("// declaration: ").append(name) 259 .append(sv.getDeclaration()).append('\n'); 260 } 261 262 appendAccess(access & ~Opcodes.ACC_SUPER); 263 if ((access & Opcodes.ACC_ANNOTATION) != 0) { 264 buf.append("@interface "); 265 } else if ((access & Opcodes.ACC_INTERFACE) != 0) { 266 buf.append("interface "); 267 } else if ((access & Opcodes.ACC_ENUM) == 0) { 268 buf.append("class "); 269 } 270 appendDescriptor(INTERNAL_NAME, name); 271 272 if (superName != null && !"java/lang/Object".equals(superName)) { 273 buf.append(" extends "); 274 appendDescriptor(INTERNAL_NAME, superName); 275 buf.append(' '); 276 } 277 if (interfaces != null && interfaces.length > 0) { 278 buf.append(" implements "); 279 for (int i = 0; i < interfaces.length; ++i) { 280 appendDescriptor(INTERNAL_NAME, interfaces[i]); 281 buf.append(' '); 282 } 283 } 284 buf.append(" {\n\n"); 285 286 text.add(buf.toString()); 287 } 288 289 @Override 290 public void visitSource(final String file, final String debug) { 291 buf.setLength(0); 292 if (file != null) { 293 buf.append(tab).append("// compiled from: ").append(file) 294 .append('\n'); 295 } 296 if (debug != null) { 297 buf.append(tab).append("// debug info: ").append(debug) 298 .append('\n'); 299 } 300 if (buf.length() > 0) { 301 text.add(buf.toString()); 302 } 303 } 304 305 @Override 306 public void visitOuterClass(final String owner, final String name, 307 final String desc) { 308 buf.setLength(0); 309 buf.append(tab).append("OUTERCLASS "); 310 appendDescriptor(INTERNAL_NAME, owner); 311 buf.append(' '); 312 if (name != null) { 313 buf.append(name).append(' '); 314 } 315 appendDescriptor(METHOD_DESCRIPTOR, desc); 316 buf.append('\n'); 317 text.add(buf.toString()); 318 } 319 320 @Override 321 public Textifier visitClassAnnotation(final String desc, 322 final boolean visible) { 323 text.add("\n"); 324 return visitAnnotation(desc, visible); 325 } 326 327 @Override 328 public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath, 329 String desc, boolean visible) { 330 text.add("\n"); 331 return visitTypeAnnotation(typeRef, typePath, desc, visible); 332 } 333 334 @Override 335 public void visitClassAttribute(final Attribute attr) { 336 text.add("\n"); 337 visitAttribute(attr); 338 } 339 340 @Override 341 public void visitInnerClass(final String name, final String outerName, 342 final String innerName, final int access) { 343 buf.setLength(0); 344 buf.append(tab).append("// access flags 0x"); 345 buf.append( 346 Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase()) 347 .append('\n'); 348 buf.append(tab); 349 appendAccess(access); 350 buf.append("INNERCLASS "); 351 appendDescriptor(INTERNAL_NAME, name); 352 buf.append(' '); 353 appendDescriptor(INTERNAL_NAME, outerName); 354 buf.append(' '); 355 appendDescriptor(INTERNAL_NAME, innerName); 356 buf.append('\n'); 357 text.add(buf.toString()); 358 } 359 360 @Override 361 public Textifier visitField(final int access, final String name, 362 final String desc, final String signature, final Object value) { 363 buf.setLength(0); 364 buf.append('\n'); 365 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 366 buf.append(tab).append("// DEPRECATED\n"); 367 } 368 buf.append(tab).append("// access flags 0x") 369 .append(Integer.toHexString(access).toUpperCase()).append('\n'); 370 if (signature != null) { 371 buf.append(tab); 372 appendDescriptor(FIELD_SIGNATURE, signature); 373 374 TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 375 SignatureReader r = new SignatureReader(signature); 376 r.acceptType(sv); 377 buf.append(tab).append("// declaration: ") 378 .append(sv.getDeclaration()).append('\n'); 379 } 380 381 buf.append(tab); 382 appendAccess(access); 383 384 appendDescriptor(FIELD_DESCRIPTOR, desc); 385 buf.append(' ').append(name); 386 if (value != null) { 387 buf.append(" = "); 388 if (value instanceof String) { 389 buf.append('\"').append(value).append('\"'); 390 } else { 391 buf.append(value); 392 } 393 } 394 395 buf.append('\n'); 396 text.add(buf.toString()); 397 398 Textifier t = createTextifier(); 399 text.add(t.getText()); 400 return t; 401 } 402 403 @Override 404 public Textifier visitMethod(final int access, final String name, 405 final String desc, final String signature, final String[] exceptions) { 406 buf.setLength(0); 407 buf.append('\n'); 408 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 409 buf.append(tab).append("// DEPRECATED\n"); 410 } 411 buf.append(tab).append("// access flags 0x") 412 .append(Integer.toHexString(access).toUpperCase()).append('\n'); 413 414 if (signature != null) { 415 buf.append(tab); 416 appendDescriptor(METHOD_SIGNATURE, signature); 417 418 TraceSignatureVisitor v = new TraceSignatureVisitor(0); 419 SignatureReader r = new SignatureReader(signature); 420 r.accept(v); 421 String genericDecl = v.getDeclaration(); 422 String genericReturn = v.getReturnType(); 423 String genericExceptions = v.getExceptions(); 424 425 buf.append(tab).append("// declaration: ").append(genericReturn) 426 .append(' ').append(name).append(genericDecl); 427 if (genericExceptions != null) { 428 buf.append(" throws ").append(genericExceptions); 429 } 430 buf.append('\n'); 431 } 432 433 buf.append(tab); 434 appendAccess(access); 435 if ((access & Opcodes.ACC_NATIVE) != 0) { 436 buf.append("native "); 437 } 438 if ((access & Opcodes.ACC_VARARGS) != 0) { 439 buf.append("varargs "); 440 } 441 if ((access & Opcodes.ACC_BRIDGE) != 0) { 442 buf.append("bridge "); 443 } 444 445 buf.append(name); 446 appendDescriptor(METHOD_DESCRIPTOR, desc); 579 buf.append("(short)").append(value); 580 } 581 582 private void visitByte(final byte value) { 583 buf.append("(byte)").append(value); 584 } 585 586 private void visitBoolean(final boolean value) { 587 buf.append(value); 588 } 589 590 private void visitString(final String value) { 591 appendString(buf, value); 592 } 593 594 private void visitType(final Type value) { 595 buf.append(value.getClassName()).append(".class"); 596 } 597 598 @Override 599 public void visitEnum(final String name, final String desc, 600 final String value) { 601 buf.setLength(0); 602 appendComa(valueNumber++); 603 if (name != null) { 604 buf.append(name).append('='); 605 } 606 appendDescriptor(FIELD_DESCRIPTOR, desc); 607 buf.append('.').append(value); 608 text.add(buf.toString()); 609 } 610 611 @Override 612 public Textifier visitAnnotation(final String name, final String desc) { 613 buf.setLength(0); 614 appendComa(valueNumber++); 615 if (name != null) { 616 buf.append(name).append('='); 617 } 618 buf.append('@'); 619 appendDescriptor(FIELD_DESCRIPTOR, desc); 620 buf.append('('); 621 text.add(buf.toString()); 622 Textifier t = createTextifier(); 623 text.add(t.getText()); 624 text.add(")"); 625 return t; 626 } 627 628 @Override 629 public Textifier visitArray(final String name) { 630 buf.setLength(0); 631 appendComa(valueNumber++); 632 if (name != null) { 633 buf.append(name).append('='); 634 } 635 buf.append('{'); 636 text.add(buf.toString()); 637 Textifier t = createTextifier(); 638 text.add(t.getText()); 639 text.add("}"); 640 return t; 641 } 642 643 @Override 644 public void visitAnnotationEnd() { 645 } 646 647 // ------------------------------------------------------------------------ 648 // Fields 649 // ------------------------------------------------------------------------ 650 651 @Override 652 public Textifier visitFieldAnnotation(final String desc, 653 final boolean visible) { 654 return visitAnnotation(desc, visible); 655 } 656 657 @Override 658 public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath, 659 String desc, boolean visible) { 660 return visitTypeAnnotation(typeRef, typePath, desc, visible); 661 } 662 663 @Override 664 public void visitFieldAttribute(final Attribute attr) { 665 visitAttribute(attr); 666 } 667 668 @Override 669 public void visitFieldEnd() { 670 } 671 672 // ------------------------------------------------------------------------ 673 // Methods 674 // ------------------------------------------------------------------------ 675 676 @Override 677 public void visitParameter(final String name, final int access) { 678 buf.setLength(0); 679 buf.append(tab2).append("// parameter "); 680 appendAccess(access); 681 buf.append(' ').append((name == null) ? "<no name>" : name) 682 .append('\n'); 683 text.add(buf.toString()); 684 } 685 686 @Override 687 public Textifier visitAnnotationDefault() { 688 text.add(tab2 + "default="); 689 Textifier t = createTextifier(); 690 text.add(t.getText()); 691 text.add("\n"); 692 return t; 693 } 694 695 @Override 696 public Textifier visitMethodAnnotation(final String desc, 697 final boolean visible) { 698 return visitAnnotation(desc, visible); 699 } 700 701 @Override 702 public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath, 703 String desc, boolean visible) { 704 return visitTypeAnnotation(typeRef, typePath, desc, visible); 705 } 706 707 @Override 708 public Textifier visitParameterAnnotation(final int parameter, 709 final String desc, final boolean visible) { 710 buf.setLength(0); 711 buf.append(tab2).append('@'); 712 appendDescriptor(FIELD_DESCRIPTOR, desc); 713 buf.append('('); 714 text.add(buf.toString()); 715 Textifier t = createTextifier(); 716 text.add(t.getText()); 717 text.add(visible ? ") // parameter " : ") // invisible, parameter "); 718 text.add(new Integer(parameter)); 719 text.add("\n"); 720 return t; 721 } 722 723 @Override 724 public void visitMethodAttribute(final Attribute attr) { 725 buf.setLength(0); 726 buf.append(tab).append("ATTRIBUTE "); 727 appendDescriptor(-1, attr.type); 728 729 if (attr instanceof Textifiable) { 730 ((Textifiable) attr).textify(buf, labelNames); 731 } else { 732 buf.append(" : unknown\n"); 733 } 734 735 text.add(buf.toString()); 736 } 737 738 @Override 739 public void visitCode() { 740 } 741 742 @Override 743 public void visitFrame(final int type, final int nLocal, 744 final Object[] local, final int nStack, final Object[] stack) { 745 buf.setLength(0); 746 buf.append(ltab); 747 buf.append("FRAME "); 748 switch (type) { 749 case Opcodes.F_NEW: 750 case Opcodes.F_FULL: 751 buf.append("FULL ["); 752 appendFrameTypes(nLocal, local); 753 buf.append("] ["); 754 appendFrameTypes(nStack, stack); 755 buf.append(']'); 756 break; 757 case Opcodes.F_APPEND: 758 buf.append("APPEND ["); 759 appendFrameTypes(nLocal, local); 760 buf.append(']'); 761 break; 762 case Opcodes.F_CHOP: 763 buf.append("CHOP ").append(nLocal); 764 break; 770 appendFrameTypes(1, stack); 771 break; 772 } 773 buf.append('\n'); 774 text.add(buf.toString()); 775 } 776 777 @Override 778 public void visitInsn(final int opcode) { 779 buf.setLength(0); 780 buf.append(tab2).append(OPCODES[opcode]).append('\n'); 781 text.add(buf.toString()); 782 } 783 784 @Override 785 public void visitIntInsn(final int opcode, final int operand) { 786 buf.setLength(0); 787 buf.append(tab2) 788 .append(OPCODES[opcode]) 789 .append(' ') 790 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer 791 .toString(operand)).append('\n'); 792 text.add(buf.toString()); 793 } 794 795 @Override 796 public void visitVarInsn(final int opcode, final int var) { 797 buf.setLength(0); 798 buf.append(tab2).append(OPCODES[opcode]).append(' ').append(var) 799 .append('\n'); 800 text.add(buf.toString()); 801 } 802 803 @Override 804 public void visitTypeInsn(final int opcode, final String type) { 805 buf.setLength(0); 806 buf.append(tab2).append(OPCODES[opcode]).append(' '); 807 appendDescriptor(INTERNAL_NAME, type); 808 buf.append('\n'); 809 text.add(buf.toString()); 810 } 811 812 @Override 813 public void visitFieldInsn(final int opcode, final String owner, 814 final String name, final String desc) { 815 buf.setLength(0); 816 buf.append(tab2).append(OPCODES[opcode]).append(' '); 817 appendDescriptor(INTERNAL_NAME, owner); 818 buf.append('.').append(name).append(" : "); 819 appendDescriptor(FIELD_DESCRIPTOR, desc); 820 buf.append('\n'); 821 text.add(buf.toString()); 822 } 823 824 @Override 825 public void visitMethodInsn(final int opcode, final String owner, 826 final String name, final String desc) { 827 buf.setLength(0); 828 buf.append(tab2).append(OPCODES[opcode]).append(' '); 829 appendDescriptor(INTERNAL_NAME, owner); 830 buf.append('.').append(name).append(' '); 831 appendDescriptor(METHOD_DESCRIPTOR, desc); 832 buf.append('\n'); 833 text.add(buf.toString()); 834 } 835 836 @Override 837 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, 838 Object... bsmArgs) { 839 buf.setLength(0); 840 buf.append(tab2).append("INVOKEDYNAMIC").append(' '); 841 buf.append(name); 842 appendDescriptor(METHOD_DESCRIPTOR, desc); 843 buf.append(" ["); 844 appendHandle(bsm); 845 buf.append(tab3).append("// arguments:"); 846 if (bsmArgs.length == 0) { 847 buf.append(" none"); 848 } else { 849 buf.append('\n').append(tab3); 850 for (int i = 0; i < bsmArgs.length; i++) { 851 Object cst = bsmArgs[i]; 852 if (cst instanceof String) { 853 Printer.appendString(buf, (String) cst); 854 } else if (cst instanceof Type) { 855 buf.append(((Type) cst).getDescriptor()).append(".class"); 856 } else if (cst instanceof Handle) { 857 appendHandle((Handle) cst); 858 } else { 859 buf.append(cst); 860 } 861 buf.append(", "); 862 } 863 buf.setLength(buf.length() - 2); 864 } 865 buf.append('\n'); 866 buf.append(tab2).append("]\n"); 867 text.add(buf.toString()); 868 } 869 870 @Override 886 } 887 888 @Override 889 public void visitLdcInsn(final Object cst) { 890 buf.setLength(0); 891 buf.append(tab2).append("LDC "); 892 if (cst instanceof String) { 893 Printer.appendString(buf, (String) cst); 894 } else if (cst instanceof Type) { 895 buf.append(((Type) cst).getDescriptor()).append(".class"); 896 } else { 897 buf.append(cst); 898 } 899 buf.append('\n'); 900 text.add(buf.toString()); 901 } 902 903 @Override 904 public void visitIincInsn(final int var, final int increment) { 905 buf.setLength(0); 906 buf.append(tab2).append("IINC ").append(var).append(' ') 907 .append(increment).append('\n'); 908 text.add(buf.toString()); 909 } 910 911 @Override 912 public void visitTableSwitchInsn(final int min, final int max, 913 final Label dflt, final Label... labels) { 914 buf.setLength(0); 915 buf.append(tab2).append("TABLESWITCH\n"); 916 for (int i = 0; i < labels.length; ++i) { 917 buf.append(tab3).append(min + i).append(": "); 918 appendLabel(labels[i]); 919 buf.append('\n'); 920 } 921 buf.append(tab3).append("default: "); 922 appendLabel(dflt); 923 buf.append('\n'); 924 text.add(buf.toString()); 925 } 926 927 @Override 928 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, 929 final Label[] labels) { 930 buf.setLength(0); 931 buf.append(tab2).append("LOOKUPSWITCH\n"); 932 for (int i = 0; i < labels.length; ++i) { 933 buf.append(tab3).append(keys[i]).append(": "); 934 appendLabel(labels[i]); 935 buf.append('\n'); 936 } 937 buf.append(tab3).append("default: "); 938 appendLabel(dflt); 939 buf.append('\n'); 940 text.add(buf.toString()); 941 } 942 943 @Override 944 public void visitMultiANewArrayInsn(final String desc, final int dims) { 945 buf.setLength(0); 946 buf.append(tab2).append("MULTIANEWARRAY "); 947 appendDescriptor(FIELD_DESCRIPTOR, desc); 948 buf.append(' ').append(dims).append('\n'); 949 text.add(buf.toString()); 950 } 951 952 @Override 953 public Printer visitInsnAnnotation(int typeRef, TypePath typePath, 954 String desc, boolean visible) { 955 return visitTypeAnnotation(typeRef, typePath, desc, visible); 956 } 957 958 @Override 959 public void visitTryCatchBlock(final Label start, final Label end, 960 final Label handler, final String type) { 961 buf.setLength(0); 962 buf.append(tab2).append("TRYCATCHBLOCK "); 963 appendLabel(start); 964 buf.append(' '); 965 appendLabel(end); 966 buf.append(' '); 967 appendLabel(handler); 968 buf.append(' '); 969 appendDescriptor(INTERNAL_NAME, type); 970 buf.append('\n'); 971 text.add(buf.toString()); 972 } 973 974 @Override 975 public Printer visitTryCatchAnnotation(int typeRef, TypePath typePath, 976 String desc, boolean visible) { 977 buf.setLength(0); 978 buf.append(tab2).append("TRYCATCHBLOCK @"); 979 appendDescriptor(FIELD_DESCRIPTOR, desc); 980 buf.append('('); 981 text.add(buf.toString()); 982 Textifier t = createTextifier(); 983 text.add(t.getText()); 984 buf.setLength(0); 985 buf.append(") : "); 986 appendTypeReference(typeRef); 987 buf.append(", ").append(typePath); 988 buf.append(visible ? "\n" : " // invisible\n"); 989 text.add(buf.toString()); 990 return t; 991 } 992 993 @Override 994 public void visitLocalVariable(final String name, final String desc, 995 final String signature, final Label start, final Label end, 996 final int index) { 997 buf.setLength(0); 998 buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' '); 999 appendDescriptor(FIELD_DESCRIPTOR, desc); 1000 buf.append(' '); 1001 appendLabel(start); 1002 buf.append(' '); 1003 appendLabel(end); 1004 buf.append(' ').append(index).append('\n'); 1005 1006 if (signature != null) { 1007 buf.append(tab2); 1008 appendDescriptor(FIELD_SIGNATURE, signature); 1009 1010 TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 1011 SignatureReader r = new SignatureReader(signature); 1012 r.acceptType(sv); 1013 buf.append(tab2).append("// declaration: ") 1014 .append(sv.getDeclaration()).append('\n'); 1015 } 1016 text.add(buf.toString()); 1017 } 1018 1019 @Override 1020 public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath, 1021 Label[] start, Label[] end, int[] index, String desc, 1022 boolean visible) { 1023 buf.setLength(0); 1024 buf.append(tab2).append("LOCALVARIABLE @"); 1025 appendDescriptor(FIELD_DESCRIPTOR, desc); 1026 buf.append('('); 1027 text.add(buf.toString()); 1028 Textifier t = createTextifier(); 1029 text.add(t.getText()); 1030 buf.setLength(0); 1031 buf.append(") : "); 1032 appendTypeReference(typeRef); 1033 buf.append(", ").append(typePath); 1034 for (int i = 0; i < start.length; ++i) { 1035 buf.append(" [ "); 1036 appendLabel(start[i]); 1037 buf.append(" - "); 1038 appendLabel(end[i]); 1039 buf.append(" - ").append(index[i]).append(" ]"); 1040 } 1041 buf.append(visible ? "\n" : " // invisible\n"); 1042 text.add(buf.toString()); 1043 return t; 1044 } 1045 1046 @Override 1047 public void visitLineNumber(final int line, final Label start) { 1048 buf.setLength(0); 1049 buf.append(tab2).append("LINENUMBER ").append(line).append(' '); 1050 appendLabel(start); 1051 buf.append('\n'); 1052 text.add(buf.toString()); 1053 } 1054 1055 @Override 1056 public void visitMaxs(final int maxStack, final int maxLocals) { 1057 buf.setLength(0); 1058 buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n'); 1059 text.add(buf.toString()); 1060 1061 buf.setLength(0); 1062 buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n'); 1063 text.add(buf.toString()); 1064 } 1065 1066 @Override 1067 public void visitMethodEnd() { 1068 } 1069 1070 // ------------------------------------------------------------------------ 1071 // Common methods 1072 // ------------------------------------------------------------------------ 1073 1074 /** 1075 * Prints a disassembled view of the given annotation. 1076 * 1077 * @param desc 1078 * the class descriptor of the annotation class. 1079 * @param visible 1080 * <tt>true</tt> if the annotation is visible at runtime. 1081 * @return a visitor to visit the annotation values. 1082 */ 1083 public Textifier visitAnnotation(final String desc, final boolean visible) { 1084 buf.setLength(0); 1085 buf.append(tab).append('@'); 1086 appendDescriptor(FIELD_DESCRIPTOR, desc); 1087 buf.append('('); 1088 text.add(buf.toString()); 1089 Textifier t = createTextifier(); 1090 text.add(t.getText()); 1091 text.add(visible ? ")\n" : ") // invisible\n"); 1092 return t; 1093 } 1094 1095 /** 1096 * Prints a disassembled view of the given type annotation. 1097 * 1098 * @param typeRef 1099 * a reference to the annotated type. See {@link TypeReference}. 1100 * @param typePath 1101 * the path to the annotated type argument, wildcard bound, array 1102 * element type, or static inner type within 'typeRef'. May be 1103 * <tt>null</tt> if the annotation targets 'typeRef' as a whole. 1104 * @param desc 1105 * the class descriptor of the annotation class. 1106 * @param visible 1107 * <tt>true</tt> if the annotation is visible at runtime. 1108 * @return a visitor to visit the annotation values. 1109 */ 1110 public Textifier visitTypeAnnotation(final int typeRef, 1111 final TypePath typePath, final String desc, final boolean visible) { 1112 buf.setLength(0); 1113 buf.append(tab).append('@'); 1114 appendDescriptor(FIELD_DESCRIPTOR, desc); 1115 buf.append('('); 1116 text.add(buf.toString()); 1117 Textifier t = createTextifier(); 1118 text.add(t.getText()); 1119 buf.setLength(0); 1120 buf.append(") : "); 1121 appendTypeReference(typeRef); 1122 buf.append(", ").append(typePath); 1123 buf.append(visible ? "\n" : " // invisible\n"); 1124 text.add(buf.toString()); 1125 return t; 1126 } 1127 1128 /** 1129 * Prints a disassembled view of the given attribute. 1130 * 1131 * @param attr 1132 * an attribute. 1133 */ 1134 public void visitAttribute(final Attribute attr) { 1135 buf.setLength(0); 1136 buf.append(tab).append("ATTRIBUTE "); 1137 appendDescriptor(-1, attr.type); 1138 1139 if (attr instanceof Textifiable) { 1140 ((Textifiable) attr).textify(buf, null); 1141 } else { 1142 buf.append(" : unknown\n"); 1143 } 1144 1145 text.add(buf.toString()); 1146 } 1147 1148 // ------------------------------------------------------------------------ 1149 // Utility methods 1150 // ------------------------------------------------------------------------ 1151 1152 /** 1153 * Creates a new TraceVisitor instance. 1154 * 1155 * @return a new TraceVisitor. 1156 */ 1157 protected Textifier createTextifier() { 1158 return new Textifier(); 1159 } 1160 1161 /** 1162 * Appends an internal name, a type descriptor or a type signature to 1163 * {@link #buf buf}. 1164 * 1165 * @param type 1166 * indicates if desc is an internal name, a field descriptor, a 1167 * method descriptor, a class signature, ... 1168 * @param desc 1169 * an internal name, type descriptor, or type signature. May be 1170 * <tt>null</tt>. 1171 */ 1172 protected void appendDescriptor(final int type, final String desc) { 1173 if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE 1174 || type == METHOD_SIGNATURE) { 1175 if (desc != null) { 1176 buf.append("// signature ").append(desc).append('\n'); 1177 } 1178 } else { 1179 buf.append(desc); 1180 } 1181 } 1182 1183 /** 1184 * Appends the name of the given label to {@link #buf buf}. Creates a new 1185 * label name if the given label does not yet have one. 1186 * 1187 * @param l 1188 * a label. 1189 */ 1190 protected void appendLabel(final Label l) { 1191 if (labelNames == null) { 1192 labelNames = new HashMap<Label, String>(); 1193 } 1194 String name = labelNames.get(l); 1195 if (name == null) { 1196 name = "L" + labelNames.size(); 1197 labelNames.put(l, name); 1198 } 1199 buf.append(name); 1200 } 1201 1202 /** 1203 * Appends the information about the given handle to {@link #buf buf}. 1204 * 1205 * @param h 1206 * a handle, non null. 1207 */ 1208 protected void appendHandle(final Handle h) { 1209 buf.append('\n').append(tab3); 1210 int tag = h.getTag(); 1211 buf.append("// handle kind 0x").append(Integer.toHexString(tag)) 1212 .append(" : "); 1213 switch (tag) { 1214 case Opcodes.H_GETFIELD: 1215 buf.append("GETFIELD"); 1216 break; 1217 case Opcodes.H_GETSTATIC: 1218 buf.append("GETSTATIC"); 1219 break; 1220 case Opcodes.H_PUTFIELD: 1221 buf.append("PUTFIELD"); 1222 break; 1223 case Opcodes.H_PUTSTATIC: 1224 buf.append("PUTSTATIC"); 1225 break; 1226 case Opcodes.H_INVOKEINTERFACE: 1227 buf.append("INVOKEINTERFACE"); 1228 break; 1229 case Opcodes.H_INVOKESPECIAL: 1230 buf.append("INVOKESPECIAL"); 1231 break; 1232 case Opcodes.H_INVOKESTATIC: 1233 buf.append("INVOKESTATIC"); 1234 break; 1235 case Opcodes.H_INVOKEVIRTUAL: 1236 buf.append("INVOKEVIRTUAL"); 1237 break; 1238 case Opcodes.H_NEWINVOKESPECIAL: 1239 buf.append("NEWINVOKESPECIAL"); 1240 break; 1241 } 1242 buf.append('\n'); 1243 buf.append(tab3); 1244 appendDescriptor(INTERNAL_NAME, h.getOwner()); 1245 buf.append('.'); 1246 buf.append(h.getName()); 1247 buf.append('('); 1248 appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc()); 1249 buf.append(')').append('\n'); 1250 } 1251 1252 /** 1253 * Appends a string representation of the given access modifiers to 1254 * {@link #buf buf}. 1255 * 1256 * @param access 1257 * some access modifiers. 1258 */ 1259 private void appendAccess(final int access) { 1260 if ((access & Opcodes.ACC_PUBLIC) != 0) { 1261 buf.append("public "); 1262 } 1263 if ((access & Opcodes.ACC_PRIVATE) != 0) { 1264 buf.append("private "); 1265 } 1266 if ((access & Opcodes.ACC_PROTECTED) != 0) { 1267 buf.append("protected "); 1268 } 1269 if ((access & Opcodes.ACC_FINAL) != 0) { 1270 buf.append("final "); 1271 } 1272 if ((access & Opcodes.ACC_STATIC) != 0) { 1273 buf.append("static "); 1274 } 1275 if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { 1276 buf.append("synchronized "); 1277 } 1278 if ((access & Opcodes.ACC_VOLATILE) != 0) { 1279 buf.append("volatile "); 1280 } 1281 if ((access & Opcodes.ACC_TRANSIENT) != 0) { 1282 buf.append("transient "); 1283 } 1284 if ((access & Opcodes.ACC_ABSTRACT) != 0) { 1285 buf.append("abstract "); 1286 } 1287 if ((access & Opcodes.ACC_STRICT) != 0) { 1288 buf.append("strictfp "); 1289 } 1290 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 1291 buf.append("synthetic "); 1292 } 1293 if ((access & Opcodes.ACC_MANDATED) != 0) { 1294 buf.append("mandated "); 1295 } 1296 if ((access & Opcodes.ACC_ENUM) != 0) { 1297 buf.append("enum "); 1298 } 1299 } 1300 1301 private void appendComa(final int i) { 1302 if (i != 0) { 1303 buf.append(", "); 1304 } 1305 } 1306 1307 private void appendTypeReference(final int typeRef) { 1308 TypeReference ref = new TypeReference(typeRef); 1309 switch (ref.getSort()) { 1310 case TypeReference.CLASS_TYPE_PARAMETER: 1311 buf.append("CLASS_TYPE_PARAMETER ").append( 1312 ref.getTypeParameterIndex()); 1313 break; 1314 case TypeReference.METHOD_TYPE_PARAMETER: 1315 buf.append("METHOD_TYPE_PARAMETER ").append( 1316 ref.getTypeParameterIndex()); 1317 break; 1318 case TypeReference.CLASS_EXTENDS: 1319 buf.append("CLASS_EXTENDS ").append(ref.getSuperTypeIndex()); 1320 break; 1321 case TypeReference.CLASS_TYPE_PARAMETER_BOUND: 1322 buf.append("CLASS_TYPE_PARAMETER_BOUND ") 1323 .append(ref.getTypeParameterIndex()).append(", ") 1324 .append(ref.getTypeParameterBoundIndex()); 1325 break; 1326 case TypeReference.METHOD_TYPE_PARAMETER_BOUND: 1327 buf.append("METHOD_TYPE_PARAMETER_BOUND ") 1328 .append(ref.getTypeParameterIndex()).append(", ") 1329 .append(ref.getTypeParameterBoundIndex()); 1330 break; 1331 case TypeReference.FIELD: 1332 buf.append("FIELD"); 1333 break; 1334 case TypeReference.METHOD_RETURN: 1335 buf.append("METHOD_RETURN"); 1336 break; 1337 case TypeReference.METHOD_RECEIVER: 1338 buf.append("METHOD_RECEIVER"); 1339 break; 1340 case TypeReference.METHOD_FORMAL_PARAMETER: 1341 buf.append("METHOD_FORMAL_PARAMETER ").append( 1342 ref.getFormalParameterIndex()); 1343 break; 1344 case TypeReference.THROWS: 1345 buf.append("THROWS ").append(ref.getExceptionIndex()); 1346 break; 1347 case TypeReference.LOCAL_VARIABLE: 1348 buf.append("LOCAL_VARIABLE"); 1349 break; 1350 case TypeReference.RESOURCE_VARIABLE: 1351 buf.append("RESOURCE_VARIABLE"); 1352 break; 1353 case TypeReference.EXCEPTION_PARAMETER: 1354 buf.append("EXCEPTION_PARAMETER ").append( 1355 ref.getTryCatchBlockIndex()); 1356 break; 1357 case TypeReference.INSTANCEOF: 1358 buf.append("INSTANCEOF"); 1359 break; 1360 case TypeReference.NEW: 1361 buf.append("NEW"); 1362 break; 1363 case TypeReference.CONSTRUCTOR_REFERENCE: 1364 buf.append("CONSTRUCTOR_REFERENCE"); 1365 break; 1366 case TypeReference.METHOD_REFERENCE: 1367 buf.append("METHOD_REFERENCE"); 1368 break; 1369 case TypeReference.CAST: 1370 buf.append("CAST ").append(ref.getTypeArgumentIndex()); 1371 break; 1372 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 1373 buf.append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ").append( 1374 ref.getTypeArgumentIndex()); 1375 break; 1376 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: 1377 buf.append("METHOD_INVOCATION_TYPE_ARGUMENT ").append( 1378 ref.getTypeArgumentIndex()); 1379 break; 1380 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 1381 buf.append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ").append( 1382 ref.getTypeArgumentIndex()); 1383 break; 1384 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: 1385 buf.append("METHOD_REFERENCE_TYPE_ARGUMENT ").append( 1386 ref.getTypeArgumentIndex()); 1387 break; 1388 } 1389 } 1390 1391 private void appendFrameTypes(final int n, final Object[] o) { 1392 for (int i = 0; i < n; ++i) { 1393 if (i > 0) { 1394 buf.append(' '); 1395 } 1396 if (o[i] instanceof String) { 1397 String desc = (String) o[i]; 1398 if (desc.startsWith("[")) { 1399 appendDescriptor(FIELD_DESCRIPTOR, desc); 1400 } else { 1401 appendDescriptor(INTERNAL_NAME, desc); 1402 } 1403 } else if (o[i] instanceof Integer) { 1404 switch (((Integer) o[i]).intValue()) { 1405 case 0: 1406 appendDescriptor(FIELD_DESCRIPTOR, "T"); 1407 break; 1408 case 1: 1409 appendDescriptor(FIELD_DESCRIPTOR, "I"); |