1 30 package com.tc.asm.attrs; 31 32 import java.util.ArrayList ; 33 import java.util.Collections ; 34 import java.util.List ; 35 36 import com.tc.asm.Attribute; 37 import com.tc.asm.ByteVector; 38 import com.tc.asm.ClassReader; 39 import com.tc.asm.ClassWriter; 40 import com.tc.asm.Label; 41 import com.tc.asm.Opcodes; 42 import com.tc.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 if (tag < SAME_LOCALS_1_STACK_ITEM_FRAME) { offsetDelta = tag; 492 493 locals = new ArrayList (frame.locals); 494 stack = Collections.EMPTY_LIST; 495 496 } else if (tag < RESERVED) { offsetDelta = tag - SAME_LOCALS_1_STACK_ITEM_FRAME; 498 499 locals = new ArrayList (frame.locals); 500 stack = new ArrayList (); 501 off = readType(stack, isExtCodeSize, cr, off, labels, buf); 503 504 } else { 505 if (isExtCodeSize) { 506 offsetDelta = cr.readInt(off); 507 off += 4; 508 } else { 509 offsetDelta = cr.readUnsignedShort(off); 510 off += 2; 511 } 512 513 if (tag == SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { locals = new ArrayList (frame.locals); 515 stack = new ArrayList (); 516 off = readType(stack, isExtCodeSize, cr, off, labels, buf); 518 519 } else if (tag >= CHOP_FRAME && tag < SAME_FRAME_EXTENDED) { stack = Collections.EMPTY_LIST; 521 522 int k = SAME_FRAME_EXTENDED - tag; 523 locals = new ArrayList (frame.locals.subList(0, 525 frame.locals.size() - k)); 526 527 } else if (tag == SAME_FRAME_EXTENDED) { stack = Collections.EMPTY_LIST; 529 locals = new ArrayList (frame.locals); 530 531 } else if ( tag < FULL_FRAME) { stack = Collections.EMPTY_LIST; 533 534 locals = new ArrayList (frame.locals); 536 for (int k = tag - SAME_FRAME_EXTENDED; k > 0; k--) { 537 off = readType(locals, 538 isExtCodeSize, 539 cr, 540 off, 541 labels, 542 buf); 543 } 544 545 } else if (tag == FULL_FRAME) { locals = new ArrayList (); 548 off = readTypes(locals, 549 isExtLocals, 550 isExtCodeSize, 551 cr, 552 off, 553 labels, 554 buf); 555 556 stack = new ArrayList (); 558 off = readTypes(stack, 559 isExtStack, 560 isExtCodeSize, 561 cr, 562 off, 563 labels, 564 buf); 565 566 } else { 567 throw new RuntimeException ("Unknown frame type " + tag 568 + " after offset " + offset); 569 570 } 571 } 572 573 offset += offsetDelta; 574 575 Label offsetLabel = getLabel(offset, labels); 576 577 frame = new StackMapFrame(offsetLabel, locals, stack); 578 frames.add(frame); 579 582 offset++; 583 } 584 585 return new StackMapTableAttribute(frames); 586 } 587 588 protected ByteVector write( 589 ClassWriter cw, 590 byte[] code, 591 int len, 592 int maxStack, 593 int maxLocals) 594 { 595 ByteVector bv = new ByteVector(); 596 boolean isExtCodeSize = code != null && code.length > MAX_SHORT; 598 writeSize(frames.size() - 1, bv, isExtCodeSize); 599 600 if (frames.size() < 2) { 601 return bv; 602 } 603 604 boolean isExtLocals = maxLocals > MAX_SHORT; 605 boolean isExtStack = maxStack > MAX_SHORT; 606 607 StackMapFrame frame = (StackMapFrame) frames.get(0); 609 List locals = frame.locals; 610 int offset = frame.label.getOffset(); 611 612 for (int i = 1; i < frames.size(); i++) { 613 frame = (StackMapFrame) frames.get(i); 614 615 List clocals = frame.locals; 616 List cstack = frame.stack; 617 int coffset = frame.label.getOffset(); 618 619 int clocalsSize = clocals.size(); 620 int cstackSize = cstack.size(); 621 622 int localsSize = locals.size(); 623 624 int delta = coffset - offset; 625 626 int type = FULL_FRAME; 627 int k = 0; 628 if (cstackSize == 0) { 629 k = clocalsSize - localsSize; 630 switch (k) { 631 case -3: 632 case -2: 633 case -1: 634 type = CHOP_FRAME; localsSize = clocalsSize; break; 637 638 case 0: 639 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; 641 break; 642 643 case 1: 644 case 2: 645 case 3: 646 type = APPEND_FRAME; break; 648 } 649 } else if (localsSize == clocalsSize && cstackSize == 1) { 650 type = delta < 63 652 ? SAME_LOCALS_1_STACK_ITEM_FRAME 653 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 654 } 655 656 if (type != FULL_FRAME) { 657 for (int j = 0; j < localsSize && type != FULL_FRAME; j++) { 659 if (!locals.get(j).equals(clocals.get(j))) 660 type = FULL_FRAME; 661 } 662 } 663 664 switch (type) { 665 case SAME_FRAME: 666 bv.putByte(delta); 667 break; 668 669 case SAME_LOCALS_1_STACK_ITEM_FRAME: 670 bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); 671 writeTypeInfos(bv, cw, cstack, 0, 1); 672 break; 673 674 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: 675 bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED); 676 writeSize(delta, bv, isExtCodeSize); 677 writeTypeInfos(bv, cw, cstack, 0, 1); 678 break; 679 680 case SAME_FRAME_EXTENDED: 681 bv.putByte(SAME_FRAME_EXTENDED); 682 writeSize(delta, bv, isExtCodeSize); 683 break; 684 685 case CHOP_FRAME: 686 bv.putByte(SAME_FRAME_EXTENDED + k); writeSize(delta, bv, isExtCodeSize); 688 break; 689 690 case APPEND_FRAME: 691 bv.putByte(SAME_FRAME_EXTENDED + k); writeSize(delta, bv, isExtCodeSize); 693 writeTypeInfos(bv, 694 cw, 695 clocals, 696 clocalsSize - 1, 697 clocalsSize); 698 break; 699 700 case FULL_FRAME: 701 bv.putByte(FULL_FRAME); 702 writeSize(delta, bv, isExtCodeSize); 703 writeSize(clocalsSize, bv, isExtLocals); 704 writeTypeInfos(bv, cw, clocals, 0, clocalsSize); 705 writeSize(cstackSize, bv, isExtStack); 706 writeTypeInfos(bv, cw, cstack, 0, cstackSize); 707 break; 708 709 default: 710 throw new RuntimeException (); 711 } 712 offset = coffset + 1; locals = clocals; 714 } 715 return bv; 716 } 717 718 private void writeSize(int delta, ByteVector bv, boolean isExt) { 719 if (isExt) { 720 bv.putInt(delta); 721 } else { 722 bv.putShort(delta); 723 } 724 } 725 726 private void writeTypeInfos( 727 ByteVector bv, 728 ClassWriter cw, 729 List info, 730 int start, 731 int end) 732 { 733 for (int j = start; j < end; j++) { 734 StackMapType typeInfo = (StackMapType) info.get(j); 735 bv.putByte(typeInfo.getType()); 736 737 switch (typeInfo.getType()) { 738 case StackMapType.ITEM_Object: bv.putShort(cw.newClass(typeInfo.getObject())); 740 break; 741 742 case StackMapType.ITEM_Uninitialized: bv.putShort(typeInfo.getLabel().getOffset()); 744 break; 745 746 } 747 } 748 } 749 750 public static int getMethodOff(ClassReader cr, int codeOff, char[] buf) { 751 int off = cr.header + 6; 752 753 int interfacesCount = cr.readUnsignedShort(off); 754 off += 2 + interfacesCount * 2; 755 756 int fieldsCount = cr.readUnsignedShort(off); 757 off += 2; 758 for (; fieldsCount > 0; --fieldsCount) { 759 int attrCount = cr.readUnsignedShort(off + 6); off += 8; 761 for (; attrCount > 0; --attrCount) { 762 off += 6 + cr.readInt(off + 2); 763 } 764 } 765 766 int methodsCount = cr.readUnsignedShort(off); 767 off += 2; 768 for (; methodsCount > 0; --methodsCount) { 769 int methodOff = off; 770 int attrCount = cr.readUnsignedShort(off + 6); off += 8; 772 for (; attrCount > 0; --attrCount) { 773 String attrName = cr.readUTF8(off, buf); 774 off += 6; 775 if (attrName.equals("Code")) { 776 if (codeOff == off) { 777 return methodOff; 778 } 779 } 780 off += cr.readInt(off - 4); 781 } 782 } 783 784 return -1; 785 } 786 787 797 public static List calculateLocals( 798 String className, 799 int access, 800 String methodName, 801 String methodDesc) 802 { 803 List locals = new ArrayList (); 804 805 if ("<init>".equals(methodName) 807 && !className.equals("java/lang/Object")) 808 { 809 StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_UninitializedThis); 810 typeInfo.setObject(className); locals.add(typeInfo); 812 } else if ((access & Opcodes.ACC_STATIC) == 0) { 813 StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_Object); 814 typeInfo.setObject(className); locals.add(typeInfo); 816 } 817 818 Type[] types = Type.getArgumentTypes(methodDesc); 819 for (int i = 0; i < types.length; i++) { 820 Type t = types[i]; 821 StackMapType smt; 822 switch (t.getSort()) { 823 case Type.LONG: 824 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Long); 825 break; 826 case Type.DOUBLE: 827 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Double); 828 break; 829 830 case Type.FLOAT: 831 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Float); 832 break; 833 834 case Type.ARRAY: 835 case Type.OBJECT: 836 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Object); 837 smt.setObject(t.getDescriptor()); break; 839 840 default: 841 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Integer); 842 break; 843 } 844 } 845 846 return locals; 847 } 848 849 private int readTypes( 850 List info, 851 boolean isExt, 852 boolean isExtCodeSize, 853 ClassReader cr, 854 int off, 855 Label[] labels, 856 char[] buf) 857 { 858 int n = 0; 859 if (isExt) { 860 n = cr.readInt(off); 861 off += 4; 862 } else { 863 n = cr.readUnsignedShort(off); 864 off += 2; 865 } 866 867 for (; n > 0; n--) { 868 off = readType(info, isExtCodeSize, cr, off, labels, buf); 869 } 870 return off; 871 } 872 873 private int readType( 874 List info, 875 boolean isExtCodeSize, 876 ClassReader cr, 877 int off, 878 Label[] labels, 879 char[] buf) 880 { 881 int itemType = cr.readByte(off++); 882 StackMapType typeInfo = StackMapType.getTypeInfo(itemType); 883 info.add(typeInfo); 884 switch (itemType) { 885 890 case StackMapType.ITEM_Object: typeInfo.setObject(cr.readClass(off, buf)); 892 off += 2; 893 break; 894 895 case StackMapType.ITEM_Uninitialized: int offset; 897 if (isExtCodeSize) { 898 offset = cr.readInt(off); 899 off += 4; 900 } else { 901 offset = cr.readUnsignedShort(off); 902 off += 2; 903 } 904 905 typeInfo.setLabel(getLabel(offset, labels)); 906 break; 907 } 908 return off; 909 } 910 911 private Label getLabel(int offset, Label[] labels) { 912 Label l = labels[offset]; 913 if (l != null) { 914 return l; 915 } 916 return labels[offset] = new Label(); 917 } 918 919 public String toString() { 920 StringBuffer sb = new StringBuffer ("StackMapTable["); 921 for (int i = 0; i < frames.size(); i++) { 922 sb.append('\n').append('[').append(frames.get(i)).append(']'); 923 } 924 sb.append("\n]"); 925 return sb.toString(); 926 } 927 } 928 | Popular Tags |