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 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; 94 95 /** 96 * Constant used in {@link #appendDescriptor appendDescriptor} for field 97 * signatures, formatted in bytecode notation 98 */ 99 public static final int FIELD_SIGNATURE = 2; 100 101 /** 102 * Constant used in {@link #appendDescriptor appendDescriptor} for method 103 * descriptors, formatted in bytecode notation 104 */ 105 public static final int METHOD_DESCRIPTOR = 3; 106 107 /** 108 * Constant used in {@link #appendDescriptor appendDescriptor} for method 109 * signatures, formatted in bytecode notation 110 */ 111 public static final int METHOD_SIGNATURE = 4; 112 113 /** 114 * Constant used in {@link #appendDescriptor appendDescriptor} for class 115 * signatures, formatted in bytecode notation 116 */ 117 public static final int CLASS_SIGNATURE = 5; 118 119 /** 120 * Constant used in {@link #appendDescriptor appendDescriptor} for field or 121 * method return value signatures, formatted in default Java notation 122 * (non-bytecode) 123 */ 124 public static final int TYPE_DECLARATION = 6; 125 126 /** 127 * Constant used in {@link #appendDescriptor appendDescriptor} for class 128 * signatures, formatted in default Java notation (non-bytecode) 129 */ 130 public static final int CLASS_DECLARATION = 7; 131 132 /** 133 * Constant used in {@link #appendDescriptor appendDescriptor} for method 134 * parameter signatures, formatted in default Java notation (non-bytecode) 135 */ 136 public static final int PARAMETERS_DECLARATION = 8; 137 138 /** 139 * Constant used in {@link #appendDescriptor appendDescriptor} for handle 140 * descriptors, formatted in bytecode notation 141 */ 142 public static final int HANDLE_DESCRIPTOR = 9; 143 144 /** 145 * Tab for class members. 146 */ 147 protected String tab = " "; 148 149 /** 150 * Tab for bytecode instructions. 151 */ 152 protected String tab2 = " "; 153 154 /** 155 * Tab for table and lookup switch instructions. 156 */ 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 /** 170 * Class access flags 171 */ 172 private int access; 173 174 private int valueNumber = 0; 175 176 /** 177 * Constructs a new {@link Textifier}. <i>Subclasses must not use this 178 * constructor</i>. Instead, they must use the {@link #Textifier(int)} 179 * version. 180 * 181 * @throws IllegalStateException 182 * If a subclass calls this constructor. 183 */ 184 public Textifier() { 185 this(Opcodes.ASM5); 186 if (getClass() != Textifier.class) { 187 throw new IllegalStateException(); 188 } 189 } 190 191 /** 192 * Constructs a new {@link Textifier}. 193 * 194 * @param api 195 * the ASM API version implemented by this visitor. Must be one 196 * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. 197 */ 198 protected Textifier(final int api) { 199 super(api); 200 } 201 202 /** 203 * Prints a disassembled view of the given class to the standard output. 204 * <p> 205 * Usage: Textifier [-debug] <binary class name or class file name > 206 * 207 * @param args 208 * the command line arguments. 209 * 210 * @throws Exception 211 * if the class cannot be found, or if an IO exception occurs. 212 */ 213 public static void main(final String[] args) throws Exception { 214 int i = 0; 215 int flags = ClassReader.SKIP_DEBUG; 216 217 boolean ok = true; 218 if (args.length < 1 || args.length > 2) { 219 ok = false; 220 } 221 if (ok && "-debug".equals(args[0])) { 222 i = 1; 223 flags = 0; 224 if (args.length != 2) { 225 ok = false; 226 } 227 } 228 if (!ok) { 229 System.err 230 .println("Prints a disassembled view of the given class."); 231 System.err.println("Usage: Textifier [-debug] " 232 + "<fully qualified class name or class file name>"); 233 return; 234 } 235 ClassReader cr; 236 if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 237 || args[i].indexOf('/') > -1) { 238 cr = new ClassReader(new FileInputStream(args[i])); 239 } else { 240 cr = new ClassReader(args[i]); 241 } 242 cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), flags); 243 } 244 245 // ------------------------------------------------------------------------ 246 // Classes 247 // ------------------------------------------------------------------------ 248 249 @Override 250 public void visit(final int version, final int access, final String name, 251 final String signature, final String superName, 252 final String[] interfaces) { 253 this.access = access; 254 int major = version & 0xFFFF; 255 int minor = version >>> 16; 256 buf.setLength(0); 257 buf.append("// class version ").append(major).append('.').append(minor) 258 .append(" (").append(version).append(")\n"); 259 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 260 buf.append("// DEPRECATED\n"); 261 } 262 buf.append("// access flags 0x") 263 .append(Integer.toHexString(access).toUpperCase()).append('\n'); 264 265 appendDescriptor(CLASS_SIGNATURE, signature); 266 if (signature != null) { 267 TraceSignatureVisitor sv = new TraceSignatureVisitor(access); 268 SignatureReader r = new SignatureReader(signature); 269 r.accept(sv); 270 buf.append("// declaration: ").append(name) 271 .append(sv.getDeclaration()).append('\n'); 272 } 273 274 appendAccess(access & ~Opcodes.ACC_SUPER); 275 if ((access & Opcodes.ACC_ANNOTATION) != 0) { 276 buf.append("@interface "); 277 } else if ((access & Opcodes.ACC_INTERFACE) != 0) { 278 buf.append("interface "); 279 } else if ((access & Opcodes.ACC_ENUM) == 0) { 280 buf.append("class "); 281 } 282 appendDescriptor(INTERNAL_NAME, name); 283 284 if (superName != null && !"java/lang/Object".equals(superName)) { 285 buf.append(" extends "); 286 appendDescriptor(INTERNAL_NAME, superName); 287 buf.append(' '); 288 } 289 if (interfaces != null && interfaces.length > 0) { 290 buf.append(" implements "); 291 for (int i = 0; i < interfaces.length; ++i) { 292 appendDescriptor(INTERNAL_NAME, interfaces[i]); 293 buf.append(' '); 294 } 295 } 296 buf.append(" {\n\n"); 297 298 text.add(buf.toString()); 299 } 300 301 @Override 302 public void visitSource(final String file, final String debug) { 303 buf.setLength(0); 304 if (file != null) { 305 buf.append(tab).append("// compiled from: ").append(file) 306 .append('\n'); 307 } 308 if (debug != null) { 309 buf.append(tab).append("// debug info: ").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(final String owner, final String name, 319 final String desc) { 320 buf.setLength(0); 321 buf.append(tab).append("OUTERCLASS "); 322 appendDescriptor(INTERNAL_NAME, owner); 323 buf.append(' '); 324 if (name != null) { 325 buf.append(name).append(' '); 326 } 327 appendDescriptor(METHOD_DESCRIPTOR, desc); 328 buf.append('\n'); 329 text.add(buf.toString()); 330 } 331 332 @Override 333 public Textifier visitClassAnnotation(final String desc, 334 final boolean visible) { 335 text.add("\n"); 336 return visitAnnotation(desc, visible); 337 } 338 339 @Override 340 public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath, 341 String desc, boolean visible) { 342 text.add("\n"); 343 return visitTypeAnnotation(typeRef, typePath, desc, visible); 344 } 345 346 @Override 347 public void visitClassAttribute(final Attribute attr) { 348 text.add("\n"); 349 visitAttribute(attr); 350 } 351 352 @Override 353 public void visitInnerClass(final String name, final String outerName, 354 final String innerName, final int access) { 355 buf.setLength(0); 356 buf.append(tab).append("// access flags 0x"); 357 buf.append( 358 Integer.toHexString(access & ~Opcodes.ACC_SUPER).toUpperCase()) 359 .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(final int access, final String name, 374 final String desc, final String signature, final Object value) { 375 buf.setLength(0); 376 buf.append('\n'); 377 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 378 buf.append(tab).append("// DEPRECATED\n"); 379 } 380 buf.append(tab).append("// access flags 0x") 381 .append(Integer.toHexString(access).toUpperCase()).append('\n'); 382 if (signature != null) { 383 buf.append(tab); 384 appendDescriptor(FIELD_SIGNATURE, signature); 385 386 TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 387 SignatureReader r = new SignatureReader(signature); 388 r.acceptType(sv); 389 buf.append(tab).append("// declaration: ") 390 .append(sv.getDeclaration()).append('\n'); 391 } 392 393 buf.append(tab); 394 appendAccess(access); 395 396 appendDescriptor(FIELD_DESCRIPTOR, desc); 397 buf.append(' ').append(name); 398 if (value != null) { 399 buf.append(" = "); 400 if (value instanceof String) { 401 buf.append('\"').append(value).append('\"'); 402 } else { 403 buf.append(value); 404 } 405 } 406 407 buf.append('\n'); 408 text.add(buf.toString()); 409 410 Textifier t = createTextifier(); 411 text.add(t.getText()); 412 return t; 413 } 414 415 @Override 416 public Textifier visitMethod(final int access, final String name, 417 final String desc, final String signature, final String[] exceptions) { 418 buf.setLength(0); 419 buf.append('\n'); 420 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 421 buf.append(tab).append("// DEPRECATED\n"); 422 } 423 buf.append(tab).append("// access flags 0x") 424 .append(Integer.toHexString(access).toUpperCase()).append('\n'); 425 426 if (signature != null) { 427 buf.append(tab); 428 appendDescriptor(METHOD_SIGNATURE, signature); 429 430 TraceSignatureVisitor v = new TraceSignatureVisitor(0); 431 SignatureReader r = new SignatureReader(signature); 432 r.accept(v); 433 String genericDecl = v.getDeclaration(); 434 String genericReturn = v.getReturnType(); 435 String genericExceptions = v.getExceptions(); 436 437 buf.append(tab).append("// declaration: ").append(genericReturn) 438 .append(' ').append(name).append(genericDecl); 439 if (genericExceptions != null) { 440 buf.append(" throws ").append(genericExceptions); 441 } 442 buf.append('\n'); 443 } 444 445 buf.append(tab); 446 appendAccess(access & ~Opcodes.ACC_VOLATILE); 447 if ((access & Opcodes.ACC_NATIVE) != 0) { 448 buf.append("native "); 449 } 450 if ((access & Opcodes.ACC_VARARGS) != 0) { 451 buf.append("varargs "); 452 } 453 if ((access & Opcodes.ACC_BRIDGE) != 0) { 454 buf.append("bridge "); 455 } 456 if ((this.access & Opcodes.ACC_INTERFACE) != 0 457 && (access & Opcodes.ACC_ABSTRACT) == 0 458 && (access & Opcodes.ACC_STATIC) == 0) { 459 buf.append("default "); 460 } 461 462 buf.append(name); 463 appendDescriptor(METHOD_DESCRIPTOR, desc); 464 if (exceptions != null && exceptions.length > 0) { 465 buf.append(" throws "); 466 for (int i = 0; i < exceptions.length; ++i) { 467 appendDescriptor(INTERNAL_NAME, exceptions[i]); 468 buf.append(' '); 469 } 470 } 471 472 buf.append('\n'); 473 text.add(buf.toString()); 474 475 Textifier t = createTextifier(); 476 text.add(t.getText()); 477 return t; 478 } 479 480 @Override 481 public void visitClassEnd() { 482 text.add("}\n"); 483 } 484 485 // ------------------------------------------------------------------------ 486 // Annotations 487 // ------------------------------------------------------------------------ 488 489 @Override 490 public void visit(final String name, final Object value) { 491 buf.setLength(0); 492 appendComa(valueNumber++); 493 494 if (name != null) { 495 buf.append(name).append('='); 496 } 497 498 if (value instanceof String) { 499 visitString((String) value); 500 } else if (value instanceof Type) { 501 visitType((Type) value); 502 } else if (value instanceof Byte) { 503 visitByte(((Byte) value).byteValue()); 504 } else if (value instanceof Boolean) { 505 visitBoolean(((Boolean) value).booleanValue()); 506 } else if (value instanceof Short) { 507 visitShort(((Short) value).shortValue()); 508 } else if (value instanceof Character) { 509 visitChar(((Character) value).charValue()); 510 } else if (value instanceof Integer) { 511 visitInt(((Integer) value).intValue()); 512 } else if (value instanceof Float) { 513 visitFloat(((Float) value).floatValue()); 514 } else if (value instanceof Long) { 515 visitLong(((Long) value).longValue()); 516 } else if (value instanceof Double) { 517 visitDouble(((Double) value).doubleValue()); 518 } else if (value.getClass().isArray()) { 519 buf.append('{'); 520 if (value instanceof byte[]) { 521 byte[] v = (byte[]) value; 522 for (int i = 0; i < v.length; i++) { 523 appendComa(i); 524 visitByte(v[i]); 525 } 526 } else if (value instanceof boolean[]) { 527 boolean[] v = (boolean[]) value; 528 for (int i = 0; i < v.length; i++) { 529 appendComa(i); 530 visitBoolean(v[i]); 531 } 532 } else if (value instanceof short[]) { 533 short[] v = (short[]) value; 534 for (int i = 0; i < v.length; i++) { 535 appendComa(i); 536 visitShort(v[i]); 537 } 538 } else if (value instanceof char[]) { 539 char[] v = (char[]) value; 540 for (int i = 0; i < v.length; i++) { 541 appendComa(i); 542 visitChar(v[i]); 543 } 544 } else if (value instanceof int[]) { 545 int[] v = (int[]) value; 546 for (int i = 0; i < v.length; i++) { 547 appendComa(i); 548 visitInt(v[i]); 549 } 550 } else if (value instanceof long[]) { 551 long[] v = (long[]) value; 552 for (int i = 0; i < v.length; i++) { 553 appendComa(i); 554 visitLong(v[i]); 555 } 556 } else if (value instanceof float[]) { 557 float[] v = (float[]) value; 558 for (int i = 0; i < v.length; i++) { 559 appendComa(i); 560 visitFloat(v[i]); 561 } 562 } else if (value instanceof double[]) { 563 double[] v = (double[]) value; 564 for (int i = 0; i < v.length; i++) { 565 appendComa(i); 566 visitDouble(v[i]); 567 } 568 } 569 buf.append('}'); 570 } 571 572 text.add(buf.toString()); 573 } 574 575 private void visitInt(final int value) { 576 buf.append(value); 577 } 578 579 private void visitLong(final long value) { 580 buf.append(value).append('L'); 581 } 582 583 private void visitFloat(final float value) { 584 buf.append(value).append('F'); 585 } 586 587 private void visitDouble(final double value) { 588 buf.append(value).append('D'); 589 } 590 591 private void visitChar(final char value) { 592 buf.append("(char)").append((int) value); 593 } 594 595 private void visitShort(final short value) { 596 buf.append("(short)").append(value); 597 } 598 599 private void visitByte(final byte value) { 600 buf.append("(byte)").append(value); 601 } 602 603 private void visitBoolean(final boolean value) { 604 buf.append(value); 605 } 606 607 private void visitString(final String value) { 608 appendString(buf, value); 609 } 610 611 private void visitType(final Type value) { 612 buf.append(value.getClassName()).append(".class"); 613 } 614 615 @Override 616 public void visitEnum(final String name, final String desc, 617 final String value) { 618 buf.setLength(0); 619 appendComa(valueNumber++); 620 if (name != null) { 621 buf.append(name).append('='); 622 } 623 appendDescriptor(FIELD_DESCRIPTOR, desc); 624 buf.append('.').append(value); 625 text.add(buf.toString()); 626 } 627 628 @Override 629 public Textifier visitAnnotation(final String name, final String desc) { 630 buf.setLength(0); 631 appendComa(valueNumber++); 632 if (name != null) { 633 buf.append(name).append('='); 634 } 635 buf.append('@'); 636 appendDescriptor(FIELD_DESCRIPTOR, desc); 637 buf.append('('); 638 text.add(buf.toString()); 639 Textifier t = createTextifier(); 640 text.add(t.getText()); 641 text.add(")"); 642 return t; 643 } 644 645 @Override 646 public Textifier visitArray(final String name) { 647 buf.setLength(0); 648 appendComa(valueNumber++); 649 if (name != null) { 650 buf.append(name).append('='); 651 } 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 void visitAnnotationEnd() { 662 } 663 664 // ------------------------------------------------------------------------ 665 // Fields 666 // ------------------------------------------------------------------------ 667 668 @Override 669 public Textifier visitFieldAnnotation(final String desc, 670 final boolean visible) { 671 return visitAnnotation(desc, visible); 672 } 673 674 @Override 675 public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath, 676 String desc, boolean visible) { 677 return visitTypeAnnotation(typeRef, typePath, desc, visible); 678 } 679 680 @Override 681 public void visitFieldAttribute(final Attribute attr) { 682 visitAttribute(attr); 683 } 684 685 @Override 686 public void visitFieldEnd() { 687 } 688 689 // ------------------------------------------------------------------------ 690 // Methods 691 // ------------------------------------------------------------------------ 692 693 @Override 694 public void visitParameter(final String name, final int access) { 695 buf.setLength(0); 696 buf.append(tab2).append("// parameter "); 697 appendAccess(access); 698 buf.append(' ').append((name == null) ? "<no name>" : name) 699 .append('\n'); 700 text.add(buf.toString()); 701 } 702 703 @Override 704 public Textifier visitAnnotationDefault() { 705 text.add(tab2 + "default="); 706 Textifier t = createTextifier(); 707 text.add(t.getText()); 708 text.add("\n"); 709 return t; 710 } 711 712 @Override 713 public Textifier visitMethodAnnotation(final String desc, 714 final boolean visible) { 715 return visitAnnotation(desc, visible); 716 } 717 718 @Override 719 public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath, 720 String desc, boolean visible) { 721 return visitTypeAnnotation(typeRef, typePath, desc, visible); 722 } 723 724 @Override 725 public Textifier visitParameterAnnotation(final int parameter, 726 final String desc, final boolean visible) { 727 buf.setLength(0); 728 buf.append(tab2).append('@'); 729 appendDescriptor(FIELD_DESCRIPTOR, desc); 730 buf.append('('); 731 text.add(buf.toString()); 732 Textifier t = createTextifier(); 733 text.add(t.getText()); 734 text.add(visible ? ") // parameter " : ") // invisible, parameter "); 735 text.add(new Integer(parameter)); 736 text.add("\n"); 737 return t; 738 } 739 740 @Override 741 public void visitMethodAttribute(final Attribute attr) { 742 buf.setLength(0); 743 buf.append(tab).append("ATTRIBUTE "); 744 appendDescriptor(-1, attr.type); 745 746 if (attr instanceof Textifiable) { 747 ((Textifiable) attr).textify(buf, labelNames); 748 } else { 749 buf.append(" : unknown\n"); 750 } 751 752 text.add(buf.toString()); 753 } 754 755 @Override 756 public void visitCode() { 757 } 758 759 @Override 760 public void visitFrame(final int type, final int nLocal, 761 final Object[] local, final int nStack, final Object[] stack) { 762 buf.setLength(0); 763 buf.append(ltab); 764 buf.append("FRAME "); 765 switch (type) { 766 case Opcodes.F_NEW: 767 case Opcodes.F_FULL: 768 buf.append("FULL ["); 769 appendFrameTypes(nLocal, local); 770 buf.append("] ["); 771 appendFrameTypes(nStack, stack); 772 buf.append(']'); 773 break; 774 case Opcodes.F_APPEND: 775 buf.append("APPEND ["); 776 appendFrameTypes(nLocal, local); 777 buf.append(']'); 778 break; 779 case Opcodes.F_CHOP: 780 buf.append("CHOP ").append(nLocal); 781 break; 782 case Opcodes.F_SAME: 783 buf.append("SAME"); 784 break; 785 case Opcodes.F_SAME1: 786 buf.append("SAME1 "); 787 appendFrameTypes(1, stack); 788 break; 789 } 790 buf.append('\n'); 791 text.add(buf.toString()); 792 } 793 794 @Override 795 public void visitInsn(final int opcode) { 796 buf.setLength(0); 797 buf.append(tab2).append(OPCODES[opcode]).append('\n'); 798 text.add(buf.toString()); 799 } 800 801 @Override 802 public void visitIntInsn(final int opcode, final int operand) { 803 buf.setLength(0); 804 buf.append(tab2) 805 .append(OPCODES[opcode]) 806 .append(' ') 807 .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer 808 .toString(operand)).append('\n'); 809 text.add(buf.toString()); 810 } 811 812 @Override 813 public void visitVarInsn(final int opcode, final int var) { 814 buf.setLength(0); 815 buf.append(tab2).append(OPCODES[opcode]).append(' ').append(var) 816 .append('\n'); 817 text.add(buf.toString()); 818 } 819 820 @Override 821 public void visitTypeInsn(final int opcode, final String type) { 822 buf.setLength(0); 823 buf.append(tab2).append(OPCODES[opcode]).append(' '); 824 appendDescriptor(INTERNAL_NAME, type); 825 buf.append('\n'); 826 text.add(buf.toString()); 827 } 828 829 @Override 830 public void visitFieldInsn(final int opcode, final String owner, 831 final String name, final String desc) { 832 buf.setLength(0); 833 buf.append(tab2).append(OPCODES[opcode]).append(' '); 834 appendDescriptor(INTERNAL_NAME, owner); 835 buf.append('.').append(name).append(" : "); 836 appendDescriptor(FIELD_DESCRIPTOR, desc); 837 buf.append('\n'); 838 text.add(buf.toString()); 839 } 840 841 @Deprecated 842 @Override 843 public void visitMethodInsn(final int opcode, final String owner, 844 final String name, final String desc) { 845 if (api >= Opcodes.ASM5) { 846 super.visitMethodInsn(opcode, owner, name, desc); 847 return; 848 } 849 doVisitMethodInsn(opcode, owner, name, desc, 850 opcode == Opcodes.INVOKEINTERFACE); 851 } 852 853 @Override 854 public void visitMethodInsn(final int opcode, final String owner, 855 final String name, final String desc, final boolean itf) { 856 if (api < Opcodes.ASM5) { 857 super.visitMethodInsn(opcode, owner, name, desc, itf); 858 return; 859 } 860 doVisitMethodInsn(opcode, owner, name, desc, itf); 861 } 862 863 private void doVisitMethodInsn(final int opcode, final String owner, 864 final String name, final String desc, final boolean itf) { 865 buf.setLength(0); 866 buf.append(tab2).append(OPCODES[opcode]).append(' '); 867 appendDescriptor(INTERNAL_NAME, owner); 868 buf.append('.').append(name).append(' '); 869 appendDescriptor(METHOD_DESCRIPTOR, desc); 870 buf.append('\n'); 871 text.add(buf.toString()); 872 } 873 874 @Override 875 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, 876 Object... bsmArgs) { 877 buf.setLength(0); 878 buf.append(tab2).append("INVOKEDYNAMIC").append(' '); 879 buf.append(name); 880 appendDescriptor(METHOD_DESCRIPTOR, desc); 881 buf.append(" ["); 882 buf.append('\n'); 883 buf.append(tab3); 884 appendHandle(bsm); 885 buf.append('\n'); 886 buf.append(tab3).append("// arguments:"); 887 if (bsmArgs.length == 0) { 888 buf.append(" none"); 889 } else { 890 buf.append('\n'); 891 for (int i = 0; i < bsmArgs.length; i++) { 892 buf.append(tab3); 893 Object cst = bsmArgs[i]; 894 if (cst instanceof String) { 895 Printer.appendString(buf, (String) cst); 896 } else if (cst instanceof Type) { 897 Type type = (Type) cst; 898 if(type.getSort() == Type.METHOD){ 899 appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor()); 900 } else { 901 buf.append(type.getDescriptor()).append(".class"); 902 } 903 } else if (cst instanceof Handle) { 904 appendHandle((Handle) cst); 905 } else { 906 buf.append(cst); 907 } 908 buf.append(", \n"); 909 } 910 buf.setLength(buf.length() - 3); 911 } 912 buf.append('\n'); 913 buf.append(tab2).append("]\n"); 914 text.add(buf.toString()); 915 } 916 917 @Override 918 public void visitJumpInsn(final int opcode, final Label label) { 919 buf.setLength(0); 920 buf.append(tab2).append(OPCODES[opcode]).append(' '); 921 appendLabel(label); 922 buf.append('\n'); 923 text.add(buf.toString()); 924 } 925 926 @Override 927 public void visitLabel(final Label label) { 928 buf.setLength(0); 929 buf.append(ltab); 930 appendLabel(label); 931 buf.append('\n'); 932 text.add(buf.toString()); 933 } 934 935 @Override 936 public void visitLdcInsn(final Object cst) { 937 buf.setLength(0); 938 buf.append(tab2).append("LDC "); 939 if (cst instanceof String) { 940 Printer.appendString(buf, (String) cst); 941 } else if (cst instanceof Type) { 942 buf.append(((Type) cst).getDescriptor()).append(".class"); 943 } else { 944 buf.append(cst); 945 } 946 buf.append('\n'); 947 text.add(buf.toString()); 948 } 949 950 @Override 951 public void visitIincInsn(final int var, final int increment) { 952 buf.setLength(0); 953 buf.append(tab2).append("IINC ").append(var).append(' ') 954 .append(increment).append('\n'); 955 text.add(buf.toString()); 956 } 957 958 @Override 959 public void visitTableSwitchInsn(final int min, final int max, 960 final Label dflt, final Label... labels) { 961 buf.setLength(0); 962 buf.append(tab2).append("TABLESWITCH\n"); 963 for (int i = 0; i < labels.length; ++i) { 964 buf.append(tab3).append(min + i).append(": "); 965 appendLabel(labels[i]); 966 buf.append('\n'); 967 } 968 buf.append(tab3).append("default: "); 969 appendLabel(dflt); 970 buf.append('\n'); 971 text.add(buf.toString()); 972 } 973 974 @Override 975 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, 976 final Label[] labels) { 977 buf.setLength(0); 978 buf.append(tab2).append("LOOKUPSWITCH\n"); 979 for (int i = 0; i < labels.length; ++i) { 980 buf.append(tab3).append(keys[i]).append(": "); 981 appendLabel(labels[i]); 982 buf.append('\n'); 983 } 984 buf.append(tab3).append("default: "); 985 appendLabel(dflt); 986 buf.append('\n'); 987 text.add(buf.toString()); 988 } 989 990 @Override 991 public void visitMultiANewArrayInsn(final String desc, final int dims) { 992 buf.setLength(0); 993 buf.append(tab2).append("MULTIANEWARRAY "); 994 appendDescriptor(FIELD_DESCRIPTOR, desc); 995 buf.append(' ').append(dims).append('\n'); 996 text.add(buf.toString()); 997 } 998 999 @Override 1000 public Printer visitInsnAnnotation(int typeRef, TypePath typePath, 1001 String desc, boolean visible) { 1002 return visitTypeAnnotation(typeRef, typePath, desc, visible); 1003 } 1004 1005 @Override 1006 public void visitTryCatchBlock(final Label start, final Label end, 1007 final Label handler, final String type) { 1008 buf.setLength(0); 1009 buf.append(tab2).append("TRYCATCHBLOCK "); 1010 appendLabel(start); 1011 buf.append(' '); 1012 appendLabel(end); 1013 buf.append(' '); 1014 appendLabel(handler); 1015 buf.append(' '); 1016 appendDescriptor(INTERNAL_NAME, type); 1017 buf.append('\n'); 1018 text.add(buf.toString()); 1019 } 1020 1021 @Override 1022 public Printer visitTryCatchAnnotation(int typeRef, TypePath typePath, 1023 String desc, boolean visible) { 1024 buf.setLength(0); 1025 buf.append(tab2).append("TRYCATCHBLOCK @"); 1026 appendDescriptor(FIELD_DESCRIPTOR, desc); 1027 buf.append('('); 1028 text.add(buf.toString()); 1029 Textifier t = createTextifier(); 1030 text.add(t.getText()); 1031 buf.setLength(0); 1032 buf.append(") : "); 1033 appendTypeReference(typeRef); 1034 buf.append(", ").append(typePath); 1035 buf.append(visible ? "\n" : " // invisible\n"); 1036 text.add(buf.toString()); 1037 return t; 1038 } 1039 1040 @Override 1041 public void visitLocalVariable(final String name, final String desc, 1042 final String signature, final Label start, final Label end, 1043 final int index) { 1044 buf.setLength(0); 1045 buf.append(tab2).append("LOCALVARIABLE ").append(name).append(' '); 1046 appendDescriptor(FIELD_DESCRIPTOR, desc); 1047 buf.append(' '); 1048 appendLabel(start); 1049 buf.append(' '); 1050 appendLabel(end); 1051 buf.append(' ').append(index).append('\n'); 1052 1053 if (signature != null) { 1054 buf.append(tab2); 1055 appendDescriptor(FIELD_SIGNATURE, signature); 1056 1057 TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 1058 SignatureReader r = new SignatureReader(signature); 1059 r.acceptType(sv); 1060 buf.append(tab2).append("// declaration: ") 1061 .append(sv.getDeclaration()).append('\n'); 1062 } 1063 text.add(buf.toString()); 1064 } 1065 1066 @Override 1067 public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath, 1068 Label[] start, Label[] end, int[] index, String desc, 1069 boolean visible) { 1070 buf.setLength(0); 1071 buf.append(tab2).append("LOCALVARIABLE @"); 1072 appendDescriptor(FIELD_DESCRIPTOR, desc); 1073 buf.append('('); 1074 text.add(buf.toString()); 1075 Textifier t = createTextifier(); 1076 text.add(t.getText()); 1077 buf.setLength(0); 1078 buf.append(") : "); 1079 appendTypeReference(typeRef); 1080 buf.append(", ").append(typePath); 1081 for (int i = 0; i < start.length; ++i) { 1082 buf.append(" [ "); 1083 appendLabel(start[i]); 1084 buf.append(" - "); 1085 appendLabel(end[i]); 1086 buf.append(" - ").append(index[i]).append(" ]"); 1087 } 1088 buf.append(visible ? "\n" : " // invisible\n"); 1089 text.add(buf.toString()); 1090 return t; 1091 } 1092 1093 @Override 1094 public void visitLineNumber(final int line, final Label start) { 1095 buf.setLength(0); 1096 buf.append(tab2).append("LINENUMBER ").append(line).append(' '); 1097 appendLabel(start); 1098 buf.append('\n'); 1099 text.add(buf.toString()); 1100 } 1101 1102 @Override 1103 public void visitMaxs(final int maxStack, final int maxLocals) { 1104 buf.setLength(0); 1105 buf.append(tab2).append("MAXSTACK = ").append(maxStack).append('\n'); 1106 text.add(buf.toString()); 1107 1108 buf.setLength(0); 1109 buf.append(tab2).append("MAXLOCALS = ").append(maxLocals).append('\n'); 1110 text.add(buf.toString()); 1111 } 1112 1113 @Override 1114 public void visitMethodEnd() { 1115 } 1116 1117 // ------------------------------------------------------------------------ 1118 // Common methods 1119 // ------------------------------------------------------------------------ 1120 1121 /** 1122 * Prints a disassembled view of the given annotation. 1123 * 1124 * @param desc 1125 * the class descriptor of the annotation class. 1126 * @param visible 1127 * <tt>true</tt> if the annotation is visible at runtime. 1128 * @return a visitor to visit the annotation values. 1129 */ 1130 public Textifier visitAnnotation(final String desc, final boolean visible) { 1131 buf.setLength(0); 1132 buf.append(tab).append('@'); 1133 appendDescriptor(FIELD_DESCRIPTOR, desc); 1134 buf.append('('); 1135 text.add(buf.toString()); 1136 Textifier t = createTextifier(); 1137 text.add(t.getText()); 1138 text.add(visible ? ")\n" : ") // invisible\n"); 1139 return t; 1140 } 1141 1142 /** 1143 * Prints a disassembled view of the given type annotation. 1144 * 1145 * @param typeRef 1146 * a reference to the annotated type. See {@link TypeReference}. 1147 * @param typePath 1148 * the path to the annotated type argument, wildcard bound, array 1149 * element type, or static inner type within 'typeRef'. May be 1150 * <tt>null</tt> if the annotation targets 'typeRef' as a whole. 1151 * @param desc 1152 * the class descriptor of the annotation class. 1153 * @param visible 1154 * <tt>true</tt> if the annotation is visible at runtime. 1155 * @return a visitor to visit the annotation values. 1156 */ 1157 public Textifier visitTypeAnnotation(final int typeRef, 1158 final TypePath typePath, final String desc, final boolean visible) { 1159 buf.setLength(0); 1160 buf.append(tab).append('@'); 1161 appendDescriptor(FIELD_DESCRIPTOR, desc); 1162 buf.append('('); 1163 text.add(buf.toString()); 1164 Textifier t = createTextifier(); 1165 text.add(t.getText()); 1166 buf.setLength(0); 1167 buf.append(") : "); 1168 appendTypeReference(typeRef); 1169 buf.append(", ").append(typePath); 1170 buf.append(visible ? "\n" : " // invisible\n"); 1171 text.add(buf.toString()); 1172 return t; 1173 } 1174 1175 /** 1176 * Prints a disassembled view of the given attribute. 1177 * 1178 * @param attr 1179 * an attribute. 1180 */ 1181 public void visitAttribute(final Attribute attr) { 1182 buf.setLength(0); 1183 buf.append(tab).append("ATTRIBUTE "); 1184 appendDescriptor(-1, attr.type); 1185 1186 if (attr instanceof Textifiable) { 1187 ((Textifiable) attr).textify(buf, null); 1188 } else { 1189 buf.append(" : unknown\n"); 1190 } 1191 1192 text.add(buf.toString()); 1193 } 1194 1195 // ------------------------------------------------------------------------ 1196 // Utility methods 1197 // ------------------------------------------------------------------------ 1198 1199 /** 1200 * Creates a new TraceVisitor instance. 1201 * 1202 * @return a new TraceVisitor. 1203 */ 1204 protected Textifier createTextifier() { 1205 return new Textifier(); 1206 } 1207 1208 /** 1209 * Appends an internal name, a type descriptor or a type signature to 1210 * {@link #buf buf}. 1211 * 1212 * @param type 1213 * indicates if desc is an internal name, a field descriptor, a 1214 * method descriptor, a class signature, ... 1215 * @param desc 1216 * an internal name, type descriptor, or type signature. May be 1217 * <tt>null</tt>. 1218 */ 1219 protected void appendDescriptor(final int type, final String desc) { 1220 if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE 1221 || type == METHOD_SIGNATURE) { 1222 if (desc != null) { 1223 buf.append("// signature ").append(desc).append('\n'); 1224 } 1225 } else { 1226 buf.append(desc); 1227 } 1228 } 1229 1230 /** 1231 * Appends the name of the given label to {@link #buf buf}. Creates a new 1232 * label name if the given label does not yet have one. 1233 * 1234 * @param l 1235 * a label. 1236 */ 1237 protected void appendLabel(final Label l) { 1238 if (labelNames == null) { 1239 labelNames = new HashMap<Label, String>(); 1240 } 1241 String name = labelNames.get(l); 1242 if (name == null) { 1243 name = "L" + labelNames.size(); 1244 labelNames.put(l, name); 1245 } 1246 buf.append(name); 1247 } 1248 1249 /** 1250 * Appends the information about the given handle to {@link #buf buf}. 1251 * 1252 * @param h 1253 * a handle, non null. 1254 */ 1255 protected void appendHandle(final Handle h) { 1256 int tag = h.getTag(); 1257 buf.append("// handle kind 0x").append(Integer.toHexString(tag)) 1258 .append(" : "); 1259 boolean isMethodHandle = false; 1260 switch (tag) { 1261 case Opcodes.H_GETFIELD: 1262 buf.append("GETFIELD"); 1263 break; 1264 case Opcodes.H_GETSTATIC: 1265 buf.append("GETSTATIC"); 1266 break; 1267 case Opcodes.H_PUTFIELD: 1268 buf.append("PUTFIELD"); 1269 break; 1270 case Opcodes.H_PUTSTATIC: 1271 buf.append("PUTSTATIC"); 1272 break; 1273 case Opcodes.H_INVOKEINTERFACE: 1274 buf.append("INVOKEINTERFACE"); 1275 isMethodHandle = true; 1276 break; 1277 case Opcodes.H_INVOKESPECIAL: 1278 buf.append("INVOKESPECIAL"); 1279 isMethodHandle = true; 1280 break; 1281 case Opcodes.H_INVOKESTATIC: 1282 buf.append("INVOKESTATIC"); 1283 isMethodHandle = true; 1284 break; 1285 case Opcodes.H_INVOKEVIRTUAL: 1286 buf.append("INVOKEVIRTUAL"); 1287 isMethodHandle = true; 1288 break; 1289 case Opcodes.H_NEWINVOKESPECIAL: 1290 buf.append("NEWINVOKESPECIAL"); 1291 isMethodHandle = true; 1292 break; 1293 } 1294 buf.append('\n'); 1295 buf.append(tab3); 1296 appendDescriptor(INTERNAL_NAME, h.getOwner()); 1297 buf.append('.'); 1298 buf.append(h.getName()); 1299 if(!isMethodHandle){ 1300 buf.append('('); 1301 } 1302 appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc()); 1303 if(!isMethodHandle){ 1304 buf.append(')'); 1305 } 1306 } 1307 1308 /** 1309 * Appends a string representation of the given access modifiers to 1310 * {@link #buf buf}. 1311 * 1312 * @param access 1313 * some access modifiers. 1314 */ 1315 private void appendAccess(final int access) { 1316 if ((access & Opcodes.ACC_PUBLIC) != 0) { 1317 buf.append("public "); 1318 } 1319 if ((access & Opcodes.ACC_PRIVATE) != 0) { 1320 buf.append("private "); 1321 } 1322 if ((access & Opcodes.ACC_PROTECTED) != 0) { 1323 buf.append("protected "); 1324 } 1325 if ((access & Opcodes.ACC_FINAL) != 0) { 1326 buf.append("final "); 1327 } 1328 if ((access & Opcodes.ACC_STATIC) != 0) { 1329 buf.append("static "); 1330 } 1331 if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { 1332 buf.append("synchronized "); 1333 } 1334 if ((access & Opcodes.ACC_VOLATILE) != 0) { 1335 buf.append("volatile "); 1336 } 1337 if ((access & Opcodes.ACC_TRANSIENT) != 0) { 1338 buf.append("transient "); 1339 } 1340 if ((access & Opcodes.ACC_ABSTRACT) != 0) { 1341 buf.append("abstract "); 1342 } 1343 if ((access & Opcodes.ACC_STRICT) != 0) { 1344 buf.append("strictfp "); 1345 } 1346 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 1347 buf.append("synthetic "); 1348 } 1349 if ((access & Opcodes.ACC_MANDATED) != 0) { 1350 buf.append("mandated "); 1351 } 1352 if ((access & Opcodes.ACC_ENUM) != 0) { 1353 buf.append("enum "); 1354 } 1355 } 1356 1357 private void appendComa(final int i) { 1358 if (i != 0) { 1359 buf.append(", "); 1360 } 1361 } 1362 1363 private void appendTypeReference(final int typeRef) { 1364 TypeReference ref = new TypeReference(typeRef); 1365 switch (ref.getSort()) { 1366 case TypeReference.CLASS_TYPE_PARAMETER: 1367 buf.append("CLASS_TYPE_PARAMETER ").append( 1368 ref.getTypeParameterIndex()); 1369 break; 1370 case TypeReference.METHOD_TYPE_PARAMETER: 1371 buf.append("METHOD_TYPE_PARAMETER ").append( 1372 ref.getTypeParameterIndex()); 1373 break; 1374 case TypeReference.CLASS_EXTENDS: 1375 buf.append("CLASS_EXTENDS ").append(ref.getSuperTypeIndex()); 1376 break; 1377 case TypeReference.CLASS_TYPE_PARAMETER_BOUND: 1378 buf.append("CLASS_TYPE_PARAMETER_BOUND ") 1379 .append(ref.getTypeParameterIndex()).append(", ") 1380 .append(ref.getTypeParameterBoundIndex()); 1381 break; 1382 case TypeReference.METHOD_TYPE_PARAMETER_BOUND: 1383 buf.append("METHOD_TYPE_PARAMETER_BOUND ") 1384 .append(ref.getTypeParameterIndex()).append(", ") 1385 .append(ref.getTypeParameterBoundIndex()); 1386 break; 1387 case TypeReference.FIELD: 1388 buf.append("FIELD"); 1389 break; 1390 case TypeReference.METHOD_RETURN: 1391 buf.append("METHOD_RETURN"); 1392 break; 1393 case TypeReference.METHOD_RECEIVER: 1394 buf.append("METHOD_RECEIVER"); 1395 break; 1396 case TypeReference.METHOD_FORMAL_PARAMETER: 1397 buf.append("METHOD_FORMAL_PARAMETER ").append( 1398 ref.getFormalParameterIndex()); 1399 break; 1400 case TypeReference.THROWS: 1401 buf.append("THROWS ").append(ref.getExceptionIndex()); 1402 break; 1403 case TypeReference.LOCAL_VARIABLE: 1404 buf.append("LOCAL_VARIABLE"); 1405 break; 1406 case TypeReference.RESOURCE_VARIABLE: 1407 buf.append("RESOURCE_VARIABLE"); 1408 break; 1409 case TypeReference.EXCEPTION_PARAMETER: 1410 buf.append("EXCEPTION_PARAMETER ").append( 1411 ref.getTryCatchBlockIndex()); 1412 break; 1413 case TypeReference.INSTANCEOF: 1414 buf.append("INSTANCEOF"); 1415 break; 1416 case TypeReference.NEW: 1417 buf.append("NEW"); 1418 break; 1419 case TypeReference.CONSTRUCTOR_REFERENCE: 1420 buf.append("CONSTRUCTOR_REFERENCE"); 1421 break; 1422 case TypeReference.METHOD_REFERENCE: 1423 buf.append("METHOD_REFERENCE"); 1424 break; 1425 case TypeReference.CAST: 1426 buf.append("CAST ").append(ref.getTypeArgumentIndex()); 1427 break; 1428 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 1429 buf.append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ").append( 1430 ref.getTypeArgumentIndex()); 1431 break; 1432 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: 1433 buf.append("METHOD_INVOCATION_TYPE_ARGUMENT ").append( 1434 ref.getTypeArgumentIndex()); 1435 break; 1436 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 1437 buf.append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ").append( 1438 ref.getTypeArgumentIndex()); 1439 break; 1440 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: 1441 buf.append("METHOD_REFERENCE_TYPE_ARGUMENT ").append( 1442 ref.getTypeArgumentIndex()); 1443 break; 1444 } 1445 } 1446 1447 private void appendFrameTypes(final int n, final Object[] o) { 1448 for (int i = 0; i < n; ++i) { 1449 if (i > 0) { 1450 buf.append(' '); 1451 } 1452 if (o[i] instanceof String) { 1453 String desc = (String) o[i]; 1454 if (desc.startsWith("[")) { 1455 appendDescriptor(FIELD_DESCRIPTOR, desc); 1456 } else { 1457 appendDescriptor(INTERNAL_NAME, desc); 1458 } 1459 } else if (o[i] instanceof Integer) { 1460 switch (((Integer) o[i]).intValue()) { 1461 case 0: 1462 appendDescriptor(FIELD_DESCRIPTOR, "T"); 1463 break; 1464 case 1: 1465 appendDescriptor(FIELD_DESCRIPTOR, "I"); 1466 break; 1467 case 2: 1468 appendDescriptor(FIELD_DESCRIPTOR, "F"); 1469 break; 1470 case 3: 1471 appendDescriptor(FIELD_DESCRIPTOR, "D"); 1472 break; 1473 case 4: 1474 appendDescriptor(FIELD_DESCRIPTOR, "J"); 1475 break; 1476 case 5: 1477 appendDescriptor(FIELD_DESCRIPTOR, "N"); 1478 break; 1479 case 6: 1480 appendDescriptor(FIELD_DESCRIPTOR, "U"); 1481 break; 1482 } 1483 } else { 1484 appendLabel((Label) o[i]); 1485 } 1486 } 1487 } 1488 }