1 30 package org.objectweb.asm.attrs; 31 32 import java.util.ArrayList ; 33 import java.util.Collections ; 34 import java.util.List ; 35 36 import org.objectweb.asm.Attribute; 37 import org.objectweb.asm.ByteVector; 38 import org.objectweb.asm.ClassReader; 39 import org.objectweb.asm.ClassWriter; 40 import org.objectweb.asm.Label; 41 import org.objectweb.asm.Opcodes; 42 import org.objectweb.asm.Type; 43 44 354 public class StackMapTableAttribute extends Attribute { 355 359 public static final int SAME_FRAME = 0; 361 365 public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; 367 369 372 public static final int RESERVED = 128; 373 374 378 public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; 380 385 public static final int CHOP_FRAME = 248; 387 391 public static final int SAME_FRAME_EXTENDED = 251; 393 398 public static final int APPEND_FRAME = 252; 400 403 public static final int FULL_FRAME = 255; 405 private static final int MAX_SHORT = 65535; 406 407 410 private List frames; 411 412 public StackMapTableAttribute() { 413 super("StackMapTable"); 414 } 415 416 public StackMapTableAttribute(List frames) { 417 this(); 418 this.frames = frames; 419 } 420 421 public List getFrames() { 422 return frames; 423 } 424 425 public StackMapFrame getFrame(Label label) { 426 for (int i = 0; i < frames.size(); i++) { 427 StackMapFrame frame = (StackMapFrame) frames.get(i); 428 if (frame.label == label) { 429 return frame; 430 } 431 } 432 return null; 433 } 434 435 public boolean isUnknown() { 436 return false; 437 } 438 439 public boolean isCodeAttribute() { 440 return true; 441 } 442 443 protected Attribute read( 444 ClassReader cr, 445 int off, 446 int len, 447 char[] buf, 448 int codeOff, 449 Label[] labels) 450 { 451 452 ArrayList frames = new ArrayList (); 453 454 boolean isExtCodeSize = cr.readInt(codeOff + 4) > MAX_SHORT; 456 boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > MAX_SHORT; 457 boolean isExtStack = cr.readUnsignedShort(codeOff) > MAX_SHORT; 458 459 int offset = 0; 460 461 int methodOff = getMethodOff(cr, codeOff, buf); 462 StackMapFrame frame = new StackMapFrame(getLabel(offset, labels), 463 calculateLocals(cr.readClass(cr.header + 2, buf), cr.readUnsignedShort(methodOff), cr.readUTF8(methodOff + 2, buf), cr.readUTF8(methodOff + 4, buf)), Collections.EMPTY_LIST); 468 frames.add(frame); 469 470 473 int size; 474 if (isExtCodeSize) { 475 size = cr.readInt(off); 476 off += 4; 477 } else { 478 size = cr.readUnsignedShort(off); 479 off += 2; 480 } 481 482 for (; size > 0; size--) { 483 int tag = cr.readByte(off); off++; 485 486 List stack; 487 List locals; 488 489 int offsetDelta; 490 int frameType; 491 if (tag < SAME_LOCALS_1_STACK_ITEM_FRAME) { 492 frameType = SAME_FRAME; 493 offsetDelta = tag; 494 495 locals = new ArrayList (frame.locals); 496 stack = Collections.EMPTY_LIST; 497 498 } else if (tag < RESERVED) { 499 frameType = SAME_LOCALS_1_STACK_ITEM_FRAME; 500 offsetDelta = tag - SAME_LOCALS_1_STACK_ITEM_FRAME; 501 502 locals = new ArrayList (frame.locals); 503 stack = new ArrayList (); 504 off = readType(stack, isExtCodeSize, cr, off, labels, buf); 506 507 } else { 508 if (isExtCodeSize) { 509 offsetDelta = cr.readInt(off); 510 off += 4; 511 } else { 512 offsetDelta = cr.readUnsignedShort(off); 513 off += 2; 514 } 515 516 if (tag == SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 517 frameType = SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 518 locals = new ArrayList (frame.locals); 519 stack = new ArrayList (); 520 off = readType(stack, isExtCodeSize, cr, off, labels, buf); 522 523 } else if (tag >= CHOP_FRAME && tag < SAME_FRAME_EXTENDED) { 524 frameType = CHOP_FRAME; 525 stack = Collections.EMPTY_LIST; 526 527 int k = SAME_FRAME_EXTENDED - tag; 528 locals = new ArrayList (frame.locals.subList(0, 530 frame.locals.size() - k)); 531 532 } else if (tag == SAME_FRAME_EXTENDED) { 533 frameType = SAME_FRAME_EXTENDED; 534 stack = Collections.EMPTY_LIST; 535 locals = new ArrayList (frame.locals); 536 537 } else if ( tag < FULL_FRAME) { 538 frameType = APPEND_FRAME; 539 stack = Collections.EMPTY_LIST; 540 541 locals = new ArrayList (frame.locals); 543 for (int k = tag - SAME_FRAME_EXTENDED; k > 0; k--) { 544 off = readType(locals, 545 isExtCodeSize, 546 cr, 547 off, 548 labels, 549 buf); 550 } 551 552 } else if (tag == FULL_FRAME) { 553 frameType = FULL_FRAME; 554 555 locals = new ArrayList (); 557 off = readTypes(locals, 558 isExtLocals, 559 isExtCodeSize, 560 cr, 561 off, 562 labels, 563 buf); 564 565 stack = new ArrayList (); 567 off = readTypes(stack, 568 isExtStack, 569 isExtCodeSize, 570 cr, 571 off, 572 labels, 573 buf); 574 575 } else { 576 throw new RuntimeException ("Unknown frame type " + tag 577 + " after offset " + offset); 578 579 } 580 } 581 582 offset += offsetDelta; 583 584 Label offsetLabel = getLabel(offset, labels); 585 586 frame = new StackMapFrame(offsetLabel, locals, stack); 587 frames.add(frame); 588 591 offset++; 592 } 593 594 return new StackMapTableAttribute(frames); 595 } 596 597 protected ByteVector write( 598 ClassWriter cw, 599 byte[] code, 600 int len, 601 int maxStack, 602 int maxLocals) 603 { 604 ByteVector bv = new ByteVector(); 605 boolean isExtCodeSize = code != null && code.length > MAX_SHORT; 607 writeSize(frames.size() - 1, bv, isExtCodeSize); 608 609 if (frames.size() < 2) { 610 return bv; 611 } 612 613 boolean isExtLocals = maxLocals > MAX_SHORT; 614 boolean isExtStack = maxStack > MAX_SHORT; 615 616 StackMapFrame frame = (StackMapFrame) frames.get(0); 618 List locals = frame.locals; 619 List stack = frame.stack; 620 int offset = frame.label.getOffset(); 621 622 for (int i = 1; i < frames.size(); i++) { 623 frame = (StackMapFrame) frames.get(i); 624 625 List clocals = frame.locals; 626 List cstack = frame.stack; 627 int coffset = frame.label.getOffset(); 628 629 int clocalsSize = clocals.size(); 630 int cstackSize = cstack.size(); 631 632 int localsSize = locals.size(); 633 int stackSize = stack.size(); 634 635 int delta = coffset - offset; 636 637 int type = FULL_FRAME; 638 int k = 0; 639 if (cstackSize == 0) { 640 k = clocalsSize - localsSize; 641 switch (k) { 642 case -3: 643 case -2: 644 case -1: 645 type = CHOP_FRAME; localsSize = clocalsSize; break; 648 649 case 0: 650 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; 652 break; 653 654 case 1: 655 case 2: 656 case 3: 657 type = APPEND_FRAME; break; 659 } 660 } else if (localsSize == clocalsSize && cstackSize == 1) { 661 type = delta < 63 663 ? SAME_LOCALS_1_STACK_ITEM_FRAME 664 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 665 } 666 667 if (type != FULL_FRAME) { 668 for (int j = 0; j < localsSize && type != FULL_FRAME; j++) { 670 if (!locals.get(j).equals(clocals.get(j))) 671 type = FULL_FRAME; 672 } 673 } 674 675 switch (type) { 676 case SAME_FRAME: 677 bv.putByte(delta); 678 break; 679 680 case SAME_LOCALS_1_STACK_ITEM_FRAME: 681 bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); 682 writeTypeInfos(bv, cw, cstack, 0, 1); 683 break; 684 685 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: 686 bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED); 687 writeSize(delta, bv, isExtCodeSize); 688 writeTypeInfos(bv, cw, cstack, 0, 1); 689 break; 690 691 case SAME_FRAME_EXTENDED: 692 bv.putByte(SAME_FRAME_EXTENDED); 693 writeSize(delta, bv, isExtCodeSize); 694 break; 695 696 case CHOP_FRAME: 697 bv.putByte(SAME_FRAME_EXTENDED + k); writeSize(delta, bv, isExtCodeSize); 699 break; 700 701 case APPEND_FRAME: 702 bv.putByte(SAME_FRAME_EXTENDED + k); writeSize(delta, bv, isExtCodeSize); 704 writeTypeInfos(bv, 705 cw, 706 clocals, 707 clocalsSize - 1, 708 clocalsSize); 709 break; 710 711 case FULL_FRAME: 712 bv.putByte(FULL_FRAME); 713 writeSize(delta, bv, isExtCodeSize); 714 writeSize(clocalsSize, bv, isExtLocals); 715 writeTypeInfos(bv, cw, clocals, 0, clocalsSize); 716 writeSize(cstackSize, bv, isExtStack); 717 writeTypeInfos(bv, cw, cstack, 0, cstackSize); 718 break; 719 720 default: 721 throw new RuntimeException (); 722 } 723 offset = coffset + 1; locals = clocals; 725 stack = cstack; 726 } 727 return bv; 728 } 729 730 private void writeSize(int delta, ByteVector bv, boolean isExt) { 731 if (isExt) { 732 bv.putInt(delta); 733 } else { 734 bv.putShort(delta); 735 } 736 } 737 738 private void writeTypeInfos( 739 ByteVector bv, 740 ClassWriter cw, 741 List info, 742 int start, 743 int end) 744 { 745 for (int j = start; j < end; j++) { 746 StackMapType typeInfo = (StackMapType) info.get(j); 747 bv.putByte(typeInfo.getType()); 748 749 switch (typeInfo.getType()) { 750 case StackMapType.ITEM_Object: bv.putShort(cw.newClass(typeInfo.getObject())); 752 break; 753 754 case StackMapType.ITEM_Uninitialized: bv.putShort(typeInfo.getLabel().getOffset()); 756 break; 757 758 } 759 } 760 } 761 762 public static int getMethodOff(ClassReader cr, int codeOff, char[] buf) { 763 int off = cr.header + 6; 764 765 int interfacesCount = cr.readUnsignedShort(off); 766 off += 2 + interfacesCount * 2; 767 768 int fieldsCount = cr.readUnsignedShort(off); 769 off += 2; 770 for (; fieldsCount > 0; --fieldsCount) { 771 int attrCount = cr.readUnsignedShort(off + 6); off += 8; 773 for (; attrCount > 0; --attrCount) { 774 off += 6 + cr.readInt(off + 2); 775 } 776 } 777 778 int methodsCount = cr.readUnsignedShort(off); 779 off += 2; 780 for (; methodsCount > 0; --methodsCount) { 781 int methodOff = off; 782 int attrCount = cr.readUnsignedShort(off + 6); off += 8; 784 for (; attrCount > 0; --attrCount) { 785 String attrName = cr.readUTF8(off, buf); 786 off += 6; 787 if (attrName.equals("Code")) { 788 if (codeOff == off) { 789 return methodOff; 790 } 791 } 792 off += cr.readInt(off - 4); 793 } 794 } 795 796 return -1; 797 } 798 799 805 public static List calculateLocals( 806 String className, 807 int access, 808 String methodName, 809 String methodDesc) 810 { 811 List locals = new ArrayList (); 812 813 if ("<init>".equals(methodName) 815 && !className.equals("java/lang/Object")) 816 { 817 StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_UninitializedThis); 818 typeInfo.setObject(className); locals.add(typeInfo); 820 } else if ((access & Opcodes.ACC_STATIC) == 0) { 821 StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_Object); 822 typeInfo.setObject(className); locals.add(typeInfo); 824 } 825 826 Type[] types = Type.getArgumentTypes(methodDesc); 827 for (int i = 0; i < types.length; i++) { 828 Type t = types[i]; 829 StackMapType smt; 830 switch (t.getSort()) { 831 case Type.LONG: 832 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Long); 833 break; 834 case Type.DOUBLE: 835 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Double); 836 break; 837 838 case Type.FLOAT: 839 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Float); 840 break; 841 842 case Type.ARRAY: 843 case Type.OBJECT: 844 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Object); 845 smt.setObject(t.getDescriptor()); break; 847 848 default: 849 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Integer); 850 break; 851 } 852 } 853 854 return locals; 855 } 856 857 private int readTypes( 858 List info, 859 boolean isExt, 860 boolean isExtCodeSize, 861 ClassReader cr, 862 int off, 863 Label[] labels, 864 char[] buf) 865 { 866 int n = 0; 867 if (isExt) { 868 n = cr.readInt(off); 869 off += 4; 870 } else { 871 n = cr.readUnsignedShort(off); 872 off += 2; 873 } 874 875 for (; n > 0; n--) { 876 off = readType(info, isExtCodeSize, cr, off, labels, buf); 877 } 878 return off; 879 } 880 881 private int readType( 882 List info, 883 boolean isExtCodeSize, 884 ClassReader cr, 885 int off, 886 Label[] labels, 887 char[] buf) 888 { 889 int itemType = cr.readByte(off++); 890 StackMapType typeInfo = StackMapType.getTypeInfo(itemType); 891 info.add(typeInfo); 892 switch (itemType) { 893 898 case StackMapType.ITEM_Object: typeInfo.setObject(cr.readClass(off, buf)); 900 off += 2; 901 break; 902 903 case StackMapType.ITEM_Uninitialized: int offset; 905 if (isExtCodeSize) { 906 offset = cr.readInt(off); 907 off += 4; 908 } else { 909 offset = cr.readUnsignedShort(off); 910 off += 2; 911 } 912 913 typeInfo.setLabel(getLabel(offset, labels)); 914 break; 915 } 916 return off; 917 } 918 919 private Label getLabel(int offset, Label[] labels) { 920 Label l = labels[offset]; 921 if (l != null) { 922 return l; 923 } 924 return labels[offset] = new Label(); 925 } 926 927 public String toString() { 928 StringBuffer sb = new StringBuffer ("StackMapTable["); 929 for (int i = 0; i < frames.size(); i++) { 930 sb.append('\n').append('[').append(frames.get(i)).append(']'); 931 } 932 sb.append("\n]"); 933 return sb.toString(); 934 } 935 } 936 | Popular Tags |