1 30 package net.sf.retrotranslator.runtime.asm; 31 32 40 class MethodWriter implements MethodVisitor { 41 42 45 MethodWriter next; 46 47 50 ClassWriter cw; 51 52 55 private int access; 56 57 61 private int name; 62 63 67 private int desc; 68 69 72 private String descriptor; 73 74 80 int classReaderOffset; 81 82 88 int classReaderLength; 89 90 93 String signature; 94 95 98 int exceptionCount; 99 100 105 int[] exceptions; 106 107 110 private ByteVector annd; 111 112 115 private AnnotationWriter anns; 116 117 120 private AnnotationWriter ianns; 121 122 126 private AnnotationWriter[] panns; 127 128 132 private AnnotationWriter[] ipanns; 133 134 137 private Attribute attrs; 138 139 142 private ByteVector code = new ByteVector(); 143 144 147 private int maxStack; 148 149 152 private int maxLocals; 153 154 157 private int catchCount; 158 159 162 private Handler catchTable; 163 164 167 private Handler lastHandler; 168 169 172 private int localVarCount; 173 174 177 private ByteVector localVar; 178 179 182 private int localVarTypeCount; 183 184 187 private ByteVector localVarType; 188 189 192 private int lineNumberCount; 193 194 197 private ByteVector lineNumber; 198 199 202 private Attribute cattrs; 203 204 207 private boolean resize; 208 209 218 219 223 private final boolean computeMaxs; 224 225 232 private int stackSize; 233 234 241 private int maxStackSize; 242 243 247 private Label currentBlock; 248 249 255 private Label blockStack; 256 257 262 private final static int[] SIZE; 263 264 268 271 static { 272 int i; 273 int[] b = new int[202]; 274 String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" 275 + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" 276 + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" 277 + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; 278 for (i = 0; i < b.length; ++i) { 279 b[i] = s.charAt(i) - 'E'; 280 } 281 SIZE = b; 282 283 } 496 497 501 514 MethodWriter( 515 final ClassWriter cw, 516 final int access, 517 final String name, 518 final String desc, 519 final String signature, 520 final String [] exceptions, 521 final boolean computeMaxs) 522 { 523 if (cw.firstMethod == null) { 524 cw.firstMethod = this; 525 } else { 526 cw.lastMethod.next = this; 527 } 528 cw.lastMethod = this; 529 this.cw = cw; 530 this.access = access; 531 this.name = cw.newUTF8(name); 532 this.desc = cw.newUTF8(desc); 533 this.descriptor = desc; 534 this.signature = signature; 535 if (exceptions != null && exceptions.length > 0) { 536 exceptionCount = exceptions.length; 537 this.exceptions = new int[exceptionCount]; 538 for (int i = 0; i < exceptionCount; ++i) { 539 this.exceptions[i] = cw.newClass(exceptions[i]); 540 } 541 } 542 this.computeMaxs = computeMaxs; 543 if (computeMaxs) { 544 int size = getArgumentsAndReturnSizes(desc) >> 2; 546 if ((access & Opcodes.ACC_STATIC) != 0) { 547 --size; 548 } 549 maxLocals = size; 550 currentBlock = new Label(); 552 currentBlock.pushed = true; 553 blockStack = currentBlock; 554 } 555 } 556 557 561 public AnnotationVisitor visitAnnotationDefault() { 562 annd = new ByteVector(); 563 return new AnnotationWriter(cw, false, annd, null, 0); 564 } 565 566 public AnnotationVisitor visitAnnotation( 567 final String desc, 568 final boolean visible) 569 { 570 ByteVector bv = new ByteVector(); 571 bv.putShort(cw.newUTF8(desc)).putShort(0); 573 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); 574 if (visible) { 575 aw.next = anns; 576 anns = aw; 577 } else { 578 aw.next = ianns; 579 ianns = aw; 580 } 581 return aw; 582 } 583 584 public AnnotationVisitor visitParameterAnnotation( 585 final int parameter, 586 final String desc, 587 final boolean visible) 588 { 589 ByteVector bv = new ByteVector(); 590 bv.putShort(cw.newUTF8(desc)).putShort(0); 592 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); 593 if (visible) { 594 if (panns == null) { 595 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; 596 } 597 aw.next = panns[parameter]; 598 panns[parameter] = aw; 599 } else { 600 if (ipanns == null) { 601 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; 602 } 603 aw.next = ipanns[parameter]; 604 ipanns[parameter] = aw; 605 } 606 return aw; 607 } 608 609 public void visitAttribute(final Attribute attr) { 610 if (attr.isCodeAttribute()) { 611 attr.next = cattrs; 612 cattrs = attr; 613 } else { 614 attr.next = attrs; 615 attrs = attr; 616 } 617 } 618 619 public void visitCode() { 620 } 621 622 public void visitInsn(final int opcode) { 623 if (computeMaxs) { 624 int size = stackSize + SIZE[opcode]; 626 if (size > maxStackSize) { 627 maxStackSize = size; 628 } 629 stackSize = size; 630 if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) 632 || opcode == Opcodes.ATHROW) 633 { 634 if (currentBlock != null) { 635 currentBlock.maxStackSize = maxStackSize; 636 currentBlock = null; 637 } 638 } 639 } 640 code.putByte(opcode); 642 } 643 644 public void visitIntInsn(final int opcode, final int operand) { 645 if (computeMaxs && opcode != Opcodes.NEWARRAY) { 646 int size = stackSize + 1; 649 if (size > maxStackSize) { 650 maxStackSize = size; 651 } 652 stackSize = size; 653 } 654 if (opcode == Opcodes.SIPUSH) { 656 code.put12(opcode, operand); 657 } else { code.put11(opcode, operand); 659 } 660 } 661 662 public void visitVarInsn(final int opcode, final int var) { 663 if (computeMaxs) { 664 if (opcode == Opcodes.RET) { 666 if (currentBlock != null) { 668 currentBlock.maxStackSize = maxStackSize; 669 currentBlock = null; 670 } 671 } else { int size = stackSize + SIZE[opcode]; 673 if (size > maxStackSize) { 674 maxStackSize = size; 675 } 676 stackSize = size; 677 } 678 int n; 680 if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD 681 || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) 682 { 683 n = var + 2; 684 } else { 685 n = var + 1; 686 } 687 if (n > maxLocals) { 688 maxLocals = n; 689 } 690 } 691 if (var < 4 && opcode != Opcodes.RET) { 693 int opt; 694 if (opcode < Opcodes.ISTORE) { 695 696 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; 697 } else { 698 699 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; 700 } 701 code.putByte(opt); 702 } else if (var >= 256) { 703 code.putByte(196 ).put12(opcode, var); 704 } else { 705 code.put11(opcode, var); 706 } 707 } 708 709 public void visitTypeInsn(final int opcode, final String desc) { 710 if (computeMaxs && opcode == Opcodes.NEW) { 711 int size = stackSize + 1; 714 if (size > maxStackSize) { 715 maxStackSize = size; 716 } 717 stackSize = size; 718 } 719 code.put12(opcode, cw.newClass(desc)); 721 } 722 723 public void visitFieldInsn( 724 final int opcode, 725 final String owner, 726 final String name, 727 final String desc) 728 { 729 if (computeMaxs) { 730 int size; 731 char c = desc.charAt(0); 733 switch (opcode) { 734 case Opcodes.GETSTATIC: 735 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); 736 break; 737 case Opcodes.PUTSTATIC: 738 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); 739 break; 740 case Opcodes.GETFIELD: 741 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); 742 break; 743 default: 745 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); 746 break; 747 } 748 if (size > maxStackSize) { 750 maxStackSize = size; 751 } 752 stackSize = size; 753 } 754 code.put12(opcode, cw.newField(owner, name, desc)); 756 } 757 758 public void visitMethodInsn( 759 final int opcode, 760 final String owner, 761 final String name, 762 final String desc) 763 { 764 boolean itf = opcode == Opcodes.INVOKEINTERFACE; 765 Item i = cw.newMethodItem(owner, name, desc, itf); 766 int argSize = i.intVal; 767 if (computeMaxs) { 768 775 if (argSize == 0) { 776 argSize = getArgumentsAndReturnSizes(desc); 779 i.intVal = argSize; 782 } 783 int size; 784 if (opcode == Opcodes.INVOKESTATIC) { 785 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; 786 } else { 787 size = stackSize - (argSize >> 2) + (argSize & 0x03); 788 } 789 if (size > maxStackSize) { 791 maxStackSize = size; 792 } 793 stackSize = size; 794 } 795 if (itf) { 797 if (!computeMaxs) { 798 if (argSize == 0) { 799 argSize = getArgumentsAndReturnSizes(desc); 800 i.intVal = argSize; 801 } 802 } 803 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); 804 } else { 805 code.put12(opcode, i.index); 806 } 807 } 808 809 public void visitJumpInsn(final int opcode, final Label label) { 810 if (computeMaxs) { 811 if (opcode == Opcodes.GOTO) { 812 if (currentBlock != null) { 815 currentBlock.maxStackSize = maxStackSize; 816 addSuccessor(stackSize, label); 817 currentBlock = null; 818 } 819 } else if (opcode == Opcodes.JSR) { 820 if (currentBlock != null) { 821 addSuccessor(stackSize + 1, label); 822 } 823 } else { 824 stackSize += SIZE[opcode]; 827 if (currentBlock != null) { 828 addSuccessor(stackSize, label); 829 } 830 } 831 } 832 if (label.resolved && label.position - code.length < Short.MIN_VALUE) { 834 841 if (opcode == Opcodes.GOTO) { 842 code.putByte(200); } else if (opcode == Opcodes.JSR) { 844 code.putByte(201); } else { 846 code.putByte(opcode <= 166 847 ? ((opcode + 1) ^ 1) - 1 848 : opcode ^ 1); 849 code.putShort(8); code.putByte(200); } 852 label.put(this, code, code.length - 1, true); 853 } else { 854 860 code.putByte(opcode); 861 label.put(this, code, code.length - 1, false); 862 } 863 } 864 865 public void visitLabel(final Label label) { 866 if (computeMaxs) { 867 if (currentBlock != null) { 868 currentBlock.maxStackSize = maxStackSize; 870 addSuccessor(stackSize, label); 871 } 872 currentBlock = label; 875 stackSize = 0; 876 maxStackSize = 0; 877 } 878 resize |= label.resolve(this, code.length, code.data); 880 } 881 882 public void visitLdcInsn(final Object cst) { 883 Item i = cw.newConstItem(cst); 884 if (computeMaxs) { 885 int size; 886 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { 888 size = stackSize + 2; 889 } else { 890 size = stackSize + 1; 891 } 892 if (size > maxStackSize) { 894 maxStackSize = size; 895 } 896 stackSize = size; 897 } 898 int index = i.index; 900 if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { 901 code.put12(20 , index); 902 } else if (index >= 256) { 903 code.put12(19 , index); 904 } else { 905 code.put11(Opcodes.LDC, index); 906 } 907 } 908 909 public void visitIincInsn(final int var, final int increment) { 910 if (computeMaxs) { 911 int n = var + 1; 913 if (n > maxLocals) { 914 maxLocals = n; 915 } 916 } 917 if ((var > 255) || (increment > 127) || (increment < -128)) { 919 code.putByte(196 ) 920 .put12(Opcodes.IINC, var) 921 .putShort(increment); 922 } else { 923 code.putByte(Opcodes.IINC).put11(var, increment); 924 } 925 } 926 927 public void visitTableSwitchInsn( 928 final int min, 929 final int max, 930 final Label dflt, 931 final Label labels[]) 932 { 933 if (computeMaxs) { 934 --stackSize; 936 if (currentBlock != null) { 938 currentBlock.maxStackSize = maxStackSize; 939 addSuccessor(stackSize, dflt); 940 for (int i = 0; i < labels.length; ++i) { 941 addSuccessor(stackSize, labels[i]); 942 } 943 currentBlock = null; 944 } 945 } 946 int source = code.length; 948 code.putByte(Opcodes.TABLESWITCH); 949 while (code.length % 4 != 0) { 950 code.putByte(0); 951 } 952 dflt.put(this, code, source, true); 953 code.putInt(min).putInt(max); 954 for (int i = 0; i < labels.length; ++i) { 955 labels[i].put(this, code, source, true); 956 } 957 } 958 959 public void visitLookupSwitchInsn( 960 final Label dflt, 961 final int keys[], 962 final Label labels[]) 963 { 964 if (computeMaxs) { 965 --stackSize; 967 if (currentBlock != null) { 969 currentBlock.maxStackSize = maxStackSize; 970 addSuccessor(stackSize, dflt); 971 for (int i = 0; i < labels.length; ++i) { 972 addSuccessor(stackSize, labels[i]); 973 } 974 currentBlock = null; 975 } 976 } 977 int source = code.length; 979 code.putByte(Opcodes.LOOKUPSWITCH); 980 while (code.length % 4 != 0) { 981 code.putByte(0); 982 } 983 dflt.put(this, code, source, true); 984 code.putInt(labels.length); 985 for (int i = 0; i < labels.length; ++i) { 986 code.putInt(keys[i]); 987 labels[i].put(this, code, source, true); 988 } 989 } 990 991 public void visitMultiANewArrayInsn(final String desc, final int dims) { 992 if (computeMaxs) { 993 stackSize += 1 - dims; 996 } 997 code.put12(Opcodes.MULTIANEWARRAY, cw.newClass(desc)).putByte(dims); 999 } 1000 1001 public void visitTryCatchBlock( 1002 final Label start, 1003 final Label end, 1004 final Label handler, 1005 final String type) 1006 { 1007 if (computeMaxs) { 1008 if (!handler.pushed) { 1010 handler.beginStackSize = 1; 1011 handler.pushed = true; 1012 handler.next = blockStack; 1013 blockStack = handler; 1014 } 1015 } 1016 ++catchCount; 1017 Handler h = new Handler(); 1018 h.start = start; 1019 h.end = end; 1020 h.handler = handler; 1021 h.desc = type; 1022 h.type = type != null ? cw.newClass(type) : 0; 1023 if (lastHandler == null) { 1024 catchTable = h; 1025 } else { 1026 lastHandler.next = h; 1027 } 1028 lastHandler = h; 1029 } 1030 1031 public void visitLocalVariable( 1032 final String name, 1033 final String desc, 1034 final String signature, 1035 final Label start, 1036 final Label end, 1037 final int index) 1038 { 1039 if (signature != null) { 1040 if (localVarType == null) { 1041 localVarType = new ByteVector(); 1042 } 1043 ++localVarTypeCount; 1044 localVarType.putShort(start.position) 1045 .putShort(end.position - start.position) 1046 .putShort(cw.newUTF8(name)) 1047 .putShort(cw.newUTF8(signature)) 1048 .putShort(index); 1049 } 1050 if (localVar == null) { 1051 localVar = new ByteVector(); 1052 } 1053 ++localVarCount; 1054 localVar.putShort(start.position) 1055 .putShort(end.position - start.position) 1056 .putShort(cw.newUTF8(name)) 1057 .putShort(cw.newUTF8(desc)) 1058 .putShort(index); 1059 1060 if(computeMaxs) { 1061 char c = desc.charAt(0); 1063 int n = index + ( c=='L' || c=='D' ? 2 : 1); 1064 if (n > maxLocals) { 1065 maxLocals = n; 1066 } 1067 } 1068 } 1069 1070 public void visitLineNumber(final int line, final Label start) { 1071 if (lineNumber == null) { 1072 lineNumber = new ByteVector(); 1073 } 1074 ++lineNumberCount; 1075 lineNumber.putShort(start.position); 1076 lineNumber.putShort(line); 1077 } 1078 1079 public void visitMaxs(final int maxStack, final int maxLocals) { 1080 if (computeMaxs) { 1081 int max = 0; 1083 1093 Label stack = blockStack; 1094 while (stack != null) { 1095 Label l = stack; 1097 stack = stack.next; 1098 int start = l.beginStackSize; 1100 int blockMax = start + l.maxStackSize; 1101 if (blockMax > max) { 1103 max = blockMax; 1104 } 1105 Edge b = l.successors; 1107 while (b != null) { 1108 l = b.successor; 1109 if (!l.pushed) { 1112 l.beginStackSize = start + b.stackSize; 1115 l.pushed = true; 1117 l.next = stack; 1118 stack = l; 1119 } 1120 b = b.next; 1121 } 1122 } 1123 this.maxStack = max; 1124 } else { 1125 this.maxStack = maxStack; 1126 this.maxLocals = maxLocals; 1127 } 1128 } 1129 1130 public void visitEnd() { 1131 } 1132 1133 1137 1147 private static int getArgumentsAndReturnSizes(final String desc) { 1148 int n = 1; 1149 int c = 1; 1150 while (true) { 1151 char car = desc.charAt(c++); 1152 if (car == ')') { 1153 car = desc.charAt(c); 1154 return n << 2 1155 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); 1156 } else if (car == 'L') { 1157 while (desc.charAt(c++) != ';') { 1158 } 1159 n += 1; 1160 } else if (car == '[') { 1161 while ((car = desc.charAt(c)) == '[') { 1162 ++c; 1163 } 1164 if (car == 'D' || car == 'J') { 1165 n -= 1; 1166 } 1167 } else if (car == 'D' || car == 'J') { 1168 n += 2; 1169 } else { 1170 n += 1; 1171 } 1172 } 1173 } 1174 1175 1181 private void addSuccessor(final int stackSize, final Label successor) { 1182 Edge b = new Edge(); 1183 b.stackSize = stackSize; 1185 b.successor = successor; 1186 b.next = currentBlock.successors; 1188 currentBlock.successors = b; 1189 } 1190 1191 1195 1200 final int getSize() { 1201 if (classReaderOffset != 0) { 1202 return 6 + classReaderLength; 1203 } 1204 if (resize) { 1205 resizeInstructions(new int[0], new int[0], 0); 1207 } 1208 int size = 8; 1209 if (code.length > 0) { 1210 cw.newUTF8("Code"); 1211 size += 18 + code.length + 8 * catchCount; 1212 if (localVar != null) { 1213 cw.newUTF8("LocalVariableTable"); 1214 size += 8 + localVar.length; 1215 } 1216 if (localVarType != null) { 1217 cw.newUTF8("LocalVariableTypeTable"); 1218 size += 8 + localVarType.length; 1219 } 1220 if (lineNumber != null) { 1221 cw.newUTF8("LineNumberTable"); 1222 size += 8 + lineNumber.length; 1223 } 1224 if (cattrs != null) { 1225 size += cattrs.getSize(cw, 1226 code.data, 1227 code.length, 1228 maxStack, 1229 maxLocals); 1230 } 1231 } 1232 if (exceptionCount > 0) { 1233 cw.newUTF8("Exceptions"); 1234 size += 8 + 2 * exceptionCount; 1235 } 1236 if ((access & Opcodes.ACC_SYNTHETIC) != 0 1237 && (cw.version & 0xffff) < Opcodes.V1_5) 1238 { 1239 cw.newUTF8("Synthetic"); 1240 size += 6; 1241 } 1242 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 1243 cw.newUTF8("Deprecated"); 1244 size += 6; 1245 } 1246 if (cw.version == Opcodes.V1_4) { 1247 if ((access & Opcodes.ACC_VARARGS) != 0) { 1248 cw.newUTF8("Varargs"); 1249 size += 6; 1250 } 1251 if ((access & Opcodes.ACC_BRIDGE) != 0) { 1252 cw.newUTF8("Bridge"); 1253 size += 6; 1254 } 1255 } 1256 if (signature != null) { 1257 cw.newUTF8("Signature"); 1258 cw.newUTF8(signature); 1259 size += 8; 1260 } 1261 if (annd != null) { 1262 cw.newUTF8("AnnotationDefault"); 1263 size += 6 + annd.length; 1264 } 1265 if (anns != null) { 1266 cw.newUTF8("RuntimeVisibleAnnotations"); 1267 size += 8 + anns.getSize(); 1268 } 1269 if (ianns != null) { 1270 cw.newUTF8("RuntimeInvisibleAnnotations"); 1271 size += 8 + ianns.getSize(); 1272 } 1273 if (panns != null) { 1274 cw.newUTF8("RuntimeVisibleParameterAnnotations"); 1275 size += 7 + 2 * panns.length; 1276 for (int i = panns.length - 1; i >= 0; --i) { 1277 size += panns[i] == null ? 0 : panns[i].getSize(); 1278 } 1279 } 1280 if (ipanns != null) { 1281 cw.newUTF8("RuntimeInvisibleParameterAnnotations"); 1282 size += 7 + 2 * ipanns.length; 1283 for (int i = ipanns.length - 1; i >= 0; --i) { 1284 size += ipanns[i] == null ? 0 : ipanns[i].getSize(); 1285 } 1286 } 1287 if (attrs != null) { 1288 size += attrs.getSize(cw, null, 0, -1, -1); 1289 } 1290 return size; 1291 } 1292 1293 1299 final void put(final ByteVector out, boolean dropTigerFlags) { 1300 int modifiers = access; 1301 if (dropTigerFlags) { 1302 modifiers &= ~(Opcodes.ACC_SYNTHETIC | Opcodes.ACC_VARARGS | Opcodes.ACC_BRIDGE); 1303 } 1304 out.putShort(modifiers).putShort(name).putShort(desc); 1305 if (classReaderOffset != 0) { 1306 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); 1307 return; 1308 } 1309 int attributeCount = 0; 1310 if (code.length > 0) { 1311 ++attributeCount; 1312 } 1313 if (exceptionCount > 0) { 1314 ++attributeCount; 1315 } 1316 if ((access & Opcodes.ACC_SYNTHETIC) != 0 1317 && (cw.version & 0xffff) < Opcodes.V1_5) 1318 { 1319 ++attributeCount; 1320 } 1321 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 1322 ++attributeCount; 1323 } 1324 if (cw.version == Opcodes.V1_4) { 1325 if ((access & Opcodes.ACC_VARARGS) != 0) { 1326 ++attributeCount; 1327 } 1328 if ((access & Opcodes.ACC_BRIDGE) != 0) { 1329 ++attributeCount; 1330 } 1331 } 1332 if (signature != null) { 1333 ++attributeCount; 1334 } 1335 if (annd != null) { 1336 ++attributeCount; 1337 } 1338 if (anns != null) { 1339 ++attributeCount; 1340 } 1341 if (ianns != null) { 1342 ++attributeCount; 1343 } 1344 if (panns != null) { 1345 ++attributeCount; 1346 } 1347 if (ipanns != null) { 1348 ++attributeCount; 1349 } 1350 if (attrs != null) { 1351 attributeCount += attrs.getCount(); 1352 } 1353 out.putShort(attributeCount); 1354 if (code.length > 0) { 1355 int size = 12 + code.length + 8 * catchCount; 1356 if (localVar != null) { 1357 size += 8 + localVar.length; 1358 } 1359 if (localVarType != null) { 1360 size += 8 + localVarType.length; 1361 } 1362 if (lineNumber != null) { 1363 size += 8 + lineNumber.length; 1364 } 1365 if (cattrs != null) { 1366 size += cattrs.getSize(cw, 1367 code.data, 1368 code.length, 1369 maxStack, 1370 maxLocals); 1371 } 1372 out.putShort(cw.newUTF8("Code")).putInt(size); 1373 out.putShort(maxStack).putShort(maxLocals); 1374 out.putInt(code.length).putByteArray(code.data, 0, code.length); 1375 out.putShort(catchCount); 1376 if (catchCount > 0) { 1377 Handler h = catchTable; 1378 while (h != null) { 1379 out.putShort(h.start.position) 1380 .putShort(h.end.position) 1381 .putShort(h.handler.position) 1382 .putShort(h.type); 1383 h = h.next; 1384 } 1385 } 1386 attributeCount = 0; 1387 if (localVar != null) { 1388 ++attributeCount; 1389 } 1390 if (localVarType != null) { 1391 ++attributeCount; 1392 } 1393 if (lineNumber != null) { 1394 ++attributeCount; 1395 } 1396 if (cattrs != null) { 1397 attributeCount += cattrs.getCount(); 1398 } 1399 out.putShort(attributeCount); 1400 if (localVar != null) { 1401 out.putShort(cw.newUTF8("LocalVariableTable")); 1402 out.putInt(localVar.length + 2).putShort(localVarCount); 1403 out.putByteArray(localVar.data, 0, localVar.length); 1404 } 1405 if (localVarType != null) { 1406 out.putShort(cw.newUTF8("LocalVariableTypeTable")); 1407 out.putInt(localVarType.length + 2).putShort(localVarTypeCount); 1408 out.putByteArray(localVarType.data, 0, localVarType.length); 1409 } 1410 if (lineNumber != null) { 1411 out.putShort(cw.newUTF8("LineNumberTable")); 1412 out.putInt(lineNumber.length + 2).putShort(lineNumberCount); 1413 out.putByteArray(lineNumber.data, 0, lineNumber.length); 1414 } 1415 if (cattrs != null) { 1416 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); 1417 } 1418 } 1419 if (exceptionCount > 0) { 1420 out.putShort(cw.newUTF8("Exceptions")) 1421 .putInt(2 * exceptionCount + 2); 1422 out.putShort(exceptionCount); 1423 for (int i = 0; i < exceptionCount; ++i) { 1424 out.putShort(exceptions[i]); 1425 } 1426 } 1427 if ((access & Opcodes.ACC_SYNTHETIC) != 0 1428 && (cw.version & 0xffff) < Opcodes.V1_5) 1429 { 1430 out.putShort(cw.newUTF8("Synthetic")).putInt(0); 1431 } 1432 if ((access & Opcodes.ACC_DEPRECATED) != 0) { 1433 out.putShort(cw.newUTF8("Deprecated")).putInt(0); 1434 } 1435 if (cw.version == Opcodes.V1_4) { 1436 if ((access & Opcodes.ACC_VARARGS) != 0) { 1437 out.putShort(cw.newUTF8("Varargs")).putInt(0); 1438 } 1439 if ((access & Opcodes.ACC_BRIDGE) != 0) { 1440 out.putShort(cw.newUTF8("Bridge")).putInt(0); 1441 } 1442 } 1443 if (signature != null) { 1444 out.putShort(cw.newUTF8("Signature")) 1445 .putInt(2) 1446 .putShort(cw.newUTF8(signature)); 1447 } 1448 if (annd != null) { 1449 out.putShort(cw.newUTF8("AnnotationDefault")); 1450 out.putInt(annd.length); 1451 out.putByteArray(annd.data, 0, annd.length); 1452 } 1453 if (anns != null) { 1454 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); 1455 anns.put(out); 1456 } 1457 if (ianns != null) { 1458 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); 1459 ianns.put(out); 1460 } 1461 if (panns != null) { 1462 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); 1463 AnnotationWriter.put(panns, out); 1464 } 1465 if (ipanns != null) { 1466 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); 1467 AnnotationWriter.put(ipanns, out); 1468 } 1469 if (attrs != null) { 1470 attrs.put(cw, null, 0, -1, -1, out); 1471 } 1472 } 1473 1474 1478 1510 private int[] resizeInstructions( 1511 final int[] indexes, 1512 final int[] sizes, 1513 final int len) 1514 { 1515 byte[] b = code.data; int u, v, label; int i, j; 1519 1544 int[] allIndexes = new int[len]; int[] allSizes = new int[len]; boolean[] resize; int newOffset; 1549 System.arraycopy(indexes, 0, allIndexes, 0, len); 1550 System.arraycopy(sizes, 0, allSizes, 0, len); 1551 resize = new boolean[code.length]; 1552 1553 int state = 3; 1555 do { 1556 if (state == 3) { 1557 state = 2; 1558 } 1559 u = 0; 1560 while (u < b.length) { 1561 int opcode = b[u] & 0xFF; int insert = 0; 1564 switch (ClassWriter.TYPE[opcode]) { 1565 case ClassWriter.NOARG_INSN: 1566 case ClassWriter.IMPLVAR_INSN: 1567 u += 1; 1568 break; 1569 case ClassWriter.LABEL_INSN: 1570 if (opcode > 201) { 1571 opcode = opcode < 218 ? opcode - 49 : opcode - 20; 1575 label = u + readUnsignedShort(b, u + 1); 1576 } else { 1577 label = u + readShort(b, u + 1); 1578 } 1579 newOffset = getNewOffset(allIndexes, allSizes, u, label); 1580 if (newOffset < Short.MIN_VALUE 1581 || newOffset > Short.MAX_VALUE) 1582 { 1583 if (!resize[u]) { 1584 if (opcode == Opcodes.GOTO 1585 || opcode == Opcodes.JSR) 1586 { 1587 insert = 2; 1591 } else { 1592 insert = 5; 1599 } 1600 resize[u] = true; 1601 } 1602 } 1603 u += 3; 1604 break; 1605 case ClassWriter.LABELW_INSN: 1606 u += 5; 1607 break; 1608 case ClassWriter.TABL_INSN: 1609 if (state == 1) { 1610 newOffset = getNewOffset(allIndexes, allSizes, 0, u); 1618 insert = -(newOffset & 3); 1619 } else if (!resize[u]) { 1620 insert = u & 3; 1624 resize[u] = true; 1625 } 1626 u = u + 4 - (u & 3); 1628 u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; 1629 break; 1630 case ClassWriter.LOOK_INSN: 1631 if (state == 1) { 1632 newOffset = getNewOffset(allIndexes, allSizes, 0, u); 1634 insert = -(newOffset & 3); 1635 } else if (!resize[u]) { 1636 insert = u & 3; 1638 resize[u] = true; 1639 } 1640 u = u + 4 - (u & 3); 1642 u += 8 * readInt(b, u + 4) + 8; 1643 break; 1644 case ClassWriter.WIDE_INSN: 1645 opcode = b[u + 1] & 0xFF; 1646 if (opcode == Opcodes.IINC) { 1647 u += 6; 1648 } else { 1649 u += 4; 1650 } 1651 break; 1652 case ClassWriter.VAR_INSN: 1653 case ClassWriter.SBYTE_INSN: 1654 case ClassWriter.LDC_INSN: 1655 u += 2; 1656 break; 1657 case ClassWriter.SHORT_INSN: 1658 case ClassWriter.LDCW_INSN: 1659 case ClassWriter.FIELDORMETH_INSN: 1660 case ClassWriter.TYPE_INSN: 1661 case ClassWriter.IINC_INSN: 1662 u += 3; 1663 break; 1664 case ClassWriter.ITFMETH_INSN: 1665 u += 5; 1666 break; 1667 default: 1669 u += 4; 1670 break; 1671 } 1672 if (insert != 0) { 1673 int[] newIndexes = new int[allIndexes.length + 1]; 1676 int[] newSizes = new int[allSizes.length + 1]; 1677 System.arraycopy(allIndexes, 1678 0, 1679 newIndexes, 1680 0, 1681 allIndexes.length); 1682 System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); 1683 newIndexes[allIndexes.length] = u; 1684 newSizes[allSizes.length] = insert; 1685 allIndexes = newIndexes; 1686 allSizes = newSizes; 1687 if (insert > 0) { 1688 state = 3; 1689 } 1690 } 1691 } 1692 if (state < 3) { 1693 --state; 1694 } 1695 } while (state != 0); 1696 1697 1701 ByteVector newCode = new ByteVector(code.length); 1702 1703 u = 0; 1704 while (u < code.length) { 1705 for (i = allIndexes.length - 1; i >= 0; --i) { 1706 if (allIndexes[i] == u) { 1707 if (i < len) { 1708 if (sizes[i] > 0) { 1709 newCode.putByteArray(null, 0, sizes[i]); 1710 } else { 1711 newCode.length += sizes[i]; 1712 } 1713 indexes[i] = newCode.length; 1714 } 1715 } 1716 } 1717 int opcode = b[u] & 0xFF; 1718 switch (ClassWriter.TYPE[opcode]) { 1719 case ClassWriter.NOARG_INSN: 1720 case ClassWriter.IMPLVAR_INSN: 1721 newCode.putByte(opcode); 1722 u += 1; 1723 break; 1724 case ClassWriter.LABEL_INSN: 1725 if (opcode > 201) { 1726 opcode = opcode < 218 ? opcode - 49 : opcode - 20; 1730 label = u + readUnsignedShort(b, u + 1); 1731 } else { 1732 label = u + readShort(b, u + 1); 1733 } 1734 newOffset = getNewOffset(allIndexes, allSizes, u, label); 1735 if (resize[u]) { 1736 if (opcode == Opcodes.GOTO) { 1742 newCode.putByte(200); } else if (opcode == Opcodes.JSR) { 1744 newCode.putByte(201); } else { 1746 newCode.putByte(opcode <= 166 1747 ? ((opcode + 1) ^ 1) - 1 1748 : opcode ^ 1); 1749 newCode.putShort(8); newCode.putByte(200); newOffset -= 3; 1753 } 1754 newCode.putInt(newOffset); 1755 } else { 1756 newCode.putByte(opcode); 1757 newCode.putShort(newOffset); 1758 } 1759 u += 3; 1760 break; 1761 case ClassWriter.LABELW_INSN: 1762 label = u + readInt(b, u + 1); 1763 newOffset = getNewOffset(allIndexes, allSizes, u, label); 1764 newCode.putByte(opcode); 1765 newCode.putInt(newOffset); 1766 u += 5; 1767 break; 1768 case ClassWriter.TABL_INSN: 1769 v = u; 1771 u = u + 4 - (v & 3); 1772 newCode.putByte(Opcodes.TABLESWITCH); 1774 while (newCode.length % 4 != 0) { 1775 newCode.putByte(0); 1776 } 1777 label = v + readInt(b, u); 1778 u += 4; 1779 newOffset = getNewOffset(allIndexes, allSizes, v, label); 1780 newCode.putInt(newOffset); 1781 j = readInt(b, u); 1782 u += 4; 1783 newCode.putInt(j); 1784 j = readInt(b, u) - j + 1; 1785 u += 4; 1786 newCode.putInt(readInt(b, u - 4)); 1787 for (; j > 0; --j) { 1788 label = v + readInt(b, u); 1789 u += 4; 1790 newOffset = getNewOffset(allIndexes, allSizes, v, label); 1791 newCode.putInt(newOffset); 1792 } 1793 break; 1794 case ClassWriter.LOOK_INSN: 1795 v = u; 1797 u = u + 4 - (v & 3); 1798 newCode.putByte(Opcodes.LOOKUPSWITCH); 1800 while (newCode.length % 4 != 0) { 1801 newCode.putByte(0); 1802 } 1803 label = v + readInt(b, u); 1804 u += 4; 1805 newOffset = getNewOffset(allIndexes, allSizes, v, label); 1806 newCode.putInt(newOffset); 1807 j = readInt(b, u); 1808 u += 4; 1809 newCode.putInt(j); 1810 for (; j > 0; --j) { 1811 newCode.putInt(readInt(b, u)); 1812 u += 4; 1813 label = v + readInt(b, u); 1814 u += 4; 1815 newOffset = getNewOffset(allIndexes, allSizes, v, label); 1816 newCode.putInt(newOffset); 1817 } 1818 break; 1819 case ClassWriter.WIDE_INSN: 1820 opcode = b[u + 1] & 0xFF; 1821 if (opcode == Opcodes.IINC) { 1822 newCode.putByteArray(b, u, 6); 1823 u += 6; 1824 } else { 1825 newCode.putByteArray(b, u, 4); 1826 u += 4; 1827 } 1828 break; 1829 case ClassWriter.VAR_INSN: 1830 case ClassWriter.SBYTE_INSN: 1831 case ClassWriter.LDC_INSN: 1832 newCode.putByteArray(b, u, 2); 1833 u += 2; 1834 break; 1835 case ClassWriter.SHORT_INSN: 1836 case ClassWriter.LDCW_INSN: 1837 case ClassWriter.FIELDORMETH_INSN: 1838 case ClassWriter.TYPE_INSN: 1839 case ClassWriter.IINC_INSN: 1840 newCode.putByteArray(b, u, 3); 1841 u += 3; 1842 break; 1843 case ClassWriter.ITFMETH_INSN: 1844 newCode.putByteArray(b, u, 5); 1845 u += 5; 1846 break; 1847 default: 1849 newCode.putByteArray(b, u, 4); 1850 u += 4; 1851 break; 1852 } 1853 } 1854 1855 Handler h = catchTable; 1857 while (h != null) { 1858 getNewOffset(allIndexes, allSizes, h.start); 1859 getNewOffset(allIndexes, allSizes, h.end); 1860 getNewOffset(allIndexes, allSizes, h.handler); 1861 h = h.next; 1862 } 1863 for (i = 0; i < 2; ++i) { 1864 ByteVector bv = i == 0 ? localVar : localVarType; 1865 if (bv != null) { 1866 b = bv.data; 1867 u = 0; 1868 while (u < bv.length) { 1869 label = readUnsignedShort(b, u); 1870 newOffset = getNewOffset(allIndexes, allSizes, 0, label); 1871 writeShort(b, u, newOffset); 1872 label += readUnsignedShort(b, u + 2); 1873 newOffset = getNewOffset(allIndexes, allSizes, 0, label) 1874 - newOffset; 1875 writeShort(b, u + 2, newOffset); 1876 u += 10; 1877 } 1878 } 1879 } 1880 if (lineNumber != null) { 1881 b = lineNumber.data; 1882 u = 0; 1883 while (u < lineNumber.length) { 1884 writeShort(b, u, getNewOffset(allIndexes, 1885 allSizes, 1886 0, 1887 readUnsignedShort(b, u))); 1888 u += 4; 1889 } 1890 } 1891 while (cattrs != null) { 1893 Label[] labels = cattrs.getLabels(); 1894 if (labels != null) { 1895 for (i = labels.length - 1; i >= 0; --i) { 1896 if (!labels[i].resized) { 1897 labels[i].position = getNewOffset(allIndexes, 1898 allSizes, 1899 0, 1900 labels[i].position); 1901 labels[i].resized = true; 1902 } 1903 } 1904 } 1905 } 1906 1907 code = newCode; 1909 1910 return indexes; 1912 } 1913 1914 1921 static int readUnsignedShort(final byte[] b, final int index) { 1922 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); 1923 } 1924 1925 1932 static short readShort(final byte[] b, final int index) { 1933 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); 1934 } 1935 1936 1943 static int readInt(final byte[] b, final int index) { 1944 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) 1945 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); 1946 } 1947 1948 1955 static void writeShort(final byte[] b, final int index, final int s) { 1956 b[index] = (byte) (s >>> 8); 1957 b[index + 1] = (byte) s; 1958 } 1959 1960 1981 static int getNewOffset( 1982 final int[] indexes, 1983 final int[] sizes, 1984 final int begin, 1985 final int end) 1986 { 1987 int offset = end - begin; 1988 for (int i = 0; i < indexes.length; ++i) { 1989 if (begin < indexes[i] && indexes[i] <= end) { 1990 offset += sizes[i]; 1992 } else if (end < indexes[i] && indexes[i] <= begin) { 1993 offset -= sizes[i]; 1995 } 1996 } 1997 return offset; 1998 } 1999 2000 2016 static void getNewOffset( 2017 final int[] indexes, 2018 final int[] sizes, 2019 final Label label) 2020 { 2021 if (!label.resized) { 2022 label.position = getNewOffset(indexes, sizes, 0, label.position); 2023 label.resized = true; 2024 } 2025 } 2026} 2027 | Popular Tags |