1 17 package org.apache.bcel.generic; 18 19 import java.io.ByteArrayOutputStream ; 20 import java.io.DataOutputStream ; 21 import java.io.IOException ; 22 import java.io.Serializable ; 23 import java.util.ArrayList ; 24 import java.util.HashMap ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.Map ; 28 import org.apache.bcel.Constants; 29 import org.apache.bcel.classfile.Constant; 30 import org.apache.bcel.util.ByteSequence; 31 32 51 public class InstructionList implements Serializable { 52 53 private InstructionHandle start = null, end = null; 54 private int length = 0; private int[] byte_positions; 57 58 61 public InstructionList() { 62 } 63 64 65 69 public InstructionList(Instruction i) { 70 append(i); 71 } 72 73 74 78 public InstructionList(BranchInstruction i) { 79 append(i); 80 } 81 82 83 89 public InstructionList(CompoundInstruction c) { 90 append(c.getInstructionList()); 91 } 92 93 94 97 public boolean isEmpty() { 98 return start == null; 99 } 101 102 112 public static InstructionHandle findHandle( InstructionHandle[] ihs, int[] pos, int count, 113 int target ) { 114 int l = 0, r = count - 1; 115 117 do { 118 int i = (l + r) / 2; 119 int j = pos[i]; 120 if (j == target) { 121 return ihs[i]; 122 } else if (target < j) { 123 r = i - 1; 124 } else { 125 l = i + 1; 126 } 127 } while (l <= r); 128 return null; 129 } 130 131 132 140 public InstructionHandle findHandle( int pos ) { 141 InstructionHandle[] ihs = getInstructionHandles(); 142 return findHandle(ihs, byte_positions, length, pos); 143 } 144 145 146 151 public InstructionList(byte[] code) { 152 ByteSequence bytes = new ByteSequence(code); 153 InstructionHandle[] ihs = new InstructionHandle[code.length]; 154 int[] pos = new int[code.length]; int count = 0; 159 try { 160 while (bytes.available() > 0) { 161 int off = bytes.getIndex(); 163 pos[count] = off; 164 167 Instruction i = Instruction.readInstruction(bytes); 168 InstructionHandle ih; 169 if (i instanceof BranchInstruction) { 170 ih = append((BranchInstruction) i); 171 } else { 172 ih = append(i); 173 } 174 ih.setPosition(off); 175 ihs[count] = ih; 176 count++; 177 } 178 } catch (IOException e) { 179 throw new ClassGenException(e.toString()); 180 } 181 byte_positions = new int[count]; System.arraycopy(pos, 0, byte_positions, 0, count); 183 186 for (int i = 0; i < count; i++) { 187 if (ihs[i] instanceof BranchHandle) { 188 BranchInstruction bi = (BranchInstruction) ihs[i].instruction; 189 int target = bi.position + bi.getIndex(); 191 InstructionHandle ih = findHandle(ihs, pos, count, target); 193 if (ih == null) { 194 throw new ClassGenException("Couldn't find target for branch: " + bi); 195 } 196 bi.setTarget(ih); if (bi instanceof Select) { Select s = (Select) bi; 200 int[] indices = s.getIndices(); 201 for (int j = 0; j < indices.length; j++) { 202 target = bi.position + indices[j]; 203 ih = findHandle(ihs, pos, count, target); 204 if (ih == null) { 205 throw new ClassGenException("Couldn't find target for switch: " + bi); 206 } 207 s.setTarget(j, ih); } 209 } 210 } 211 } 212 } 213 214 215 223 public InstructionHandle append( InstructionHandle ih, InstructionList il ) { 224 if (il == null) { 225 throw new ClassGenException("Appending null InstructionList"); 226 } 227 if (il.isEmpty()) { 228 return ih; 229 } 230 InstructionHandle next = ih.next, ret = il.start; 231 ih.next = il.start; 232 il.start.prev = ih; 233 il.end.next = next; 234 if (next != null) { 235 next.prev = il.end; 236 } else { 237 end = il.end; } 239 length += il.length; il.clear(); 241 return ret; 242 } 243 244 245 253 public InstructionHandle append( Instruction i, InstructionList il ) { 254 InstructionHandle ih; 255 if ((ih = findInstruction2(i)) == null) { 256 throw new ClassGenException("Instruction " + i + " is not contained in this list."); 257 } 258 return append(ih, il); 259 } 260 261 262 269 public InstructionHandle append( InstructionList il ) { 270 if (il == null) { 271 throw new ClassGenException("Appending null InstructionList"); 272 } 273 if (il.isEmpty()) { 274 return null; 275 } 276 if (isEmpty()) { 277 start = il.start; 278 end = il.end; 279 length = il.length; 280 il.clear(); 281 return start; 282 } else { 283 return append(end, il); } 285 } 286 287 288 293 private void append( InstructionHandle ih ) { 294 if (isEmpty()) { 295 start = end = ih; 296 ih.next = ih.prev = null; 297 } else { 298 end.next = ih; 299 ih.prev = end; 300 ih.next = null; 301 end = ih; 302 } 303 length++; } 305 306 307 313 public InstructionHandle append( Instruction i ) { 314 InstructionHandle ih = InstructionHandle.getInstructionHandle(i); 315 append(ih); 316 return ih; 317 } 318 319 320 326 public BranchHandle append( BranchInstruction i ) { 327 BranchHandle ih = BranchHandle.getBranchHandle(i); 328 append(ih); 329 return ih; 330 } 331 332 333 341 public InstructionHandle append( Instruction i, Instruction j ) { 342 return append(i, new InstructionList(j)); 343 } 344 345 346 353 public InstructionHandle append( Instruction i, CompoundInstruction c ) { 354 return append(i, c.getInstructionList()); 355 } 356 357 358 364 public InstructionHandle append( CompoundInstruction c ) { 365 return append(c.getInstructionList()); 366 } 367 368 369 376 public InstructionHandle append( InstructionHandle ih, CompoundInstruction c ) { 377 return append(ih, c.getInstructionList()); 378 } 379 380 381 388 public InstructionHandle append( InstructionHandle ih, Instruction i ) { 389 return append(ih, new InstructionList(i)); 390 } 391 392 393 400 public BranchHandle append( InstructionHandle ih, BranchInstruction i ) { 401 BranchHandle bh = BranchHandle.getBranchHandle(i); 402 InstructionList il = new InstructionList(); 403 il.append(bh); 404 append(ih, il); 405 return bh; 406 } 407 408 409 417 public InstructionHandle insert( InstructionHandle ih, InstructionList il ) { 418 if (il == null) { 419 throw new ClassGenException("Inserting null InstructionList"); 420 } 421 if (il.isEmpty()) { 422 return ih; 423 } 424 InstructionHandle prev = ih.prev, ret = il.start; 425 ih.prev = il.end; 426 il.end.next = ih; 427 il.start.prev = prev; 428 if (prev != null) { 429 prev.next = il.start; 430 } else { 431 start = il.start; } 433 length += il.length; il.clear(); 435 return ret; 436 } 437 438 439 445 public InstructionHandle insert( InstructionList il ) { 446 if (isEmpty()) { 447 append(il); return start; 449 } else { 450 return insert(start, il); 451 } 452 } 453 454 455 460 private void insert( InstructionHandle ih ) { 461 if (isEmpty()) { 462 start = end = ih; 463 ih.next = ih.prev = null; 464 } else { 465 start.prev = ih; 466 ih.next = start; 467 ih.prev = null; 468 start = ih; 469 } 470 length++; 471 } 472 473 474 483 public InstructionHandle insert( Instruction i, InstructionList il ) { 484 InstructionHandle ih; 485 if ((ih = findInstruction1(i)) == null) { 486 throw new ClassGenException("Instruction " + i + " is not contained in this list."); 487 } 488 return insert(ih, il); 489 } 490 491 492 498 public InstructionHandle insert( Instruction i ) { 499 InstructionHandle ih = InstructionHandle.getInstructionHandle(i); 500 insert(ih); 501 return ih; 502 } 503 504 505 511 public BranchHandle insert( BranchInstruction i ) { 512 BranchHandle ih = BranchHandle.getBranchHandle(i); 513 insert(ih); 514 return ih; 515 } 516 517 518 526 public InstructionHandle insert( Instruction i, Instruction j ) { 527 return insert(i, new InstructionList(j)); 528 } 529 530 531 538 public InstructionHandle insert( Instruction i, CompoundInstruction c ) { 539 return insert(i, c.getInstructionList()); 540 } 541 542 543 549 public InstructionHandle insert( CompoundInstruction c ) { 550 return insert(c.getInstructionList()); 551 } 552 553 554 561 public InstructionHandle insert( InstructionHandle ih, Instruction i ) { 562 return insert(ih, new InstructionList(i)); 563 } 564 565 566 573 public InstructionHandle insert( InstructionHandle ih, CompoundInstruction c ) { 574 return insert(ih, c.getInstructionList()); 575 } 576 577 578 585 public BranchHandle insert( InstructionHandle ih, BranchInstruction i ) { 586 BranchHandle bh = BranchHandle.getBranchHandle(i); 587 InstructionList il = new InstructionList(); 588 il.append(bh); 589 insert(ih, il); 590 return bh; 591 } 592 593 594 605 public void move( InstructionHandle start, InstructionHandle end, InstructionHandle target ) { 606 if ((start == null) || (end == null)) { 608 throw new ClassGenException("Invalid null handle: From " + start + " to " + end); 609 } 610 if ((target == start) || (target == end)) { 611 throw new ClassGenException("Invalid range: From " + start + " to " + end 612 + " contains target " + target); 613 } 614 for (InstructionHandle ih = start; ih != end.next; ih = ih.next) { 615 if (ih == null) { 616 throw new ClassGenException("Invalid range: From " + start + " to " + end); 617 } else if (ih == target) { 618 throw new ClassGenException("Invalid range: From " + start + " to " + end 619 + " contains target " + target); 620 } 621 } 622 InstructionHandle prev = start.prev, next = end.next; 624 if (prev != null) { 625 prev.next = next; 626 } else { 627 this.start = next; 628 } 629 if (next != null) { 630 next.prev = prev; 631 } else { 632 this.end = prev; 633 } 634 start.prev = end.next = null; 635 if (target == null) { if (this.start != null) { 638 this.start.prev = end; 639 } 640 end.next = this.start; 641 this.start = start; 642 } else { 643 next = target.next; 644 target.next = start; 645 start.prev = target; 646 end.next = next; 647 if (next != null) { 648 next.prev = end; 649 } else { 650 this.end = end; 651 } 652 } 653 } 654 655 656 662 public void move( InstructionHandle ih, InstructionHandle target ) { 663 move(ih, ih, target); 664 } 665 666 667 675 private void remove( InstructionHandle prev, InstructionHandle next ) 676 throws TargetLostException { 677 InstructionHandle first, last; if ((prev == null) && (next == null)) { first = last = start; 680 start = end = null; 681 } else { 682 if (prev == null) { first = start; 684 start = next; 685 } else { 686 first = prev.next; 687 prev.next = next; 688 } 689 if (next == null) { last = end; 691 end = prev; 692 } else { 693 last = next.prev; 694 next.prev = prev; 695 } 696 } 697 first.prev = null; last.next = null; 699 List target_vec = new ArrayList (); 700 for (InstructionHandle ih = first; ih != null; ih = ih.next) { 701 ih.getInstruction().dispose(); } 703 StringBuffer buf = new StringBuffer ("{ "); 704 for (InstructionHandle ih = first; ih != null; ih = next) { 705 next = ih.next; 706 length--; 707 if (ih.hasTargeters()) { target_vec.add(ih); 709 buf.append(ih.toString(true) + " "); 710 ih.next = ih.prev = null; 711 } else { 712 ih.dispose(); 713 } 714 } 715 buf.append("}"); 716 if (!target_vec.isEmpty()) { 717 InstructionHandle[] targeted = new InstructionHandle[target_vec.size()]; 718 target_vec.toArray(targeted); 719 throw new TargetLostException(targeted, buf.toString()); 720 } 721 } 722 723 724 730 public void delete( InstructionHandle ih ) throws TargetLostException { 731 remove(ih.prev, ih.next); 732 } 733 734 735 741 public void delete( Instruction i ) throws TargetLostException { 742 InstructionHandle ih; 743 if ((ih = findInstruction1(i)) == null) { 744 throw new ClassGenException("Instruction " + i + " is not contained in this list."); 745 } 746 delete(ih); 747 } 748 749 750 758 public void delete( InstructionHandle from, InstructionHandle to ) throws TargetLostException { 759 remove(from.prev, to.next); 760 } 761 762 763 771 public void delete( Instruction from, Instruction to ) throws TargetLostException { 772 InstructionHandle from_ih, to_ih; 773 if ((from_ih = findInstruction1(from)) == null) { 774 throw new ClassGenException("Instruction " + from + " is not contained in this list."); 775 } 776 if ((to_ih = findInstruction2(to)) == null) { 777 throw new ClassGenException("Instruction " + to + " is not contained in this list."); 778 } 779 delete(from_ih, to_ih); 780 } 781 782 783 789 private InstructionHandle findInstruction1( Instruction i ) { 790 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 791 if (ih.instruction == i) { 792 return ih; 793 } 794 } 795 return null; 796 } 797 798 799 805 private InstructionHandle findInstruction2( Instruction i ) { 806 for (InstructionHandle ih = end; ih != null; ih = ih.prev) { 807 if (ih.instruction == i) { 808 return ih; 809 } 810 } 811 return null; 812 } 813 814 815 public boolean contains( InstructionHandle i ) { 816 if (i == null) { 817 return false; 818 } 819 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 820 if (ih == i) { 821 return true; 822 } 823 } 824 return false; 825 } 826 827 828 public boolean contains( Instruction i ) { 829 return findInstruction1(i) != null; 830 } 831 832 833 public void setPositions() { 834 setPositions(false); 835 } 836 837 838 845 public void setPositions( boolean check ) { 846 int max_additional_bytes = 0, additional_bytes = 0; 847 int index = 0, count = 0; 848 int[] pos = new int[length]; 849 851 if (check) { 852 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 853 Instruction i = ih.instruction; 854 if (i instanceof BranchInstruction) { Instruction inst = ((BranchInstruction) i).getTarget().instruction; 856 if (!contains(inst)) { 857 throw new ClassGenException("Branch target of " 858 + Constants.OPCODE_NAMES[i.opcode] + ":" + inst 859 + " not in instruction list"); 860 } 861 if (i instanceof Select) { 862 InstructionHandle[] targets = ((Select) i).getTargets(); 863 for (int j = 0; j < targets.length; j++) { 864 inst = targets[j].instruction; 865 if (!contains(inst)) { 866 throw new ClassGenException("Branch target of " 867 + Constants.OPCODE_NAMES[i.opcode] + ":" + inst 868 + " not in instruction list"); 869 } 870 } 871 } 872 if (!(ih instanceof BranchHandle)) { 873 throw new ClassGenException("Branch instruction " 874 + Constants.OPCODE_NAMES[i.opcode] + ":" + inst 875 + " not contained in BranchHandle."); 876 } 877 } 878 } 879 } 880 883 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 884 Instruction i = ih.instruction; 885 ih.setPosition(index); 886 pos[count++] = index; 887 892 switch (i.getOpcode()) { 893 case Constants.JSR: 894 case Constants.GOTO: 895 max_additional_bytes += 2; 896 break; 897 case Constants.TABLESWITCH: 898 case Constants.LOOKUPSWITCH: 899 max_additional_bytes += 3; 900 break; 901 } 902 index += i.getLength(); 903 } 904 908 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 909 additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes); 910 } 911 914 index = count = 0; 915 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 916 Instruction i = ih.instruction; 917 ih.setPosition(index); 918 pos[count++] = index; 919 index += i.getLength(); 920 } 921 byte_positions = new int[count]; System.arraycopy(pos, 0, byte_positions, 0, count); 923 } 924 925 926 932 public byte[] getByteCode() { 933 setPositions(); 935 ByteArrayOutputStream b = new ByteArrayOutputStream (); 936 DataOutputStream out = new DataOutputStream (b); 937 try { 938 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 939 Instruction i = ih.instruction; 940 i.dump(out); } 942 } catch (IOException e) { 943 System.err.println(e); 944 return null; 945 } 946 return b.toByteArray(); 947 } 948 949 950 953 public Instruction[] getInstructions() { 954 ByteSequence bytes = new ByteSequence(getByteCode()); 955 List instructions = new ArrayList (); 956 try { 957 while (bytes.available() > 0) { 958 instructions.add(Instruction.readInstruction(bytes)); 959 } 960 } catch (IOException e) { 961 throw new ClassGenException(e.toString()); 962 } 963 return (Instruction[]) instructions.toArray(new Instruction[instructions.size()]); 964 } 965 966 967 public String toString() { 968 return toString(true); 969 } 970 971 972 976 public String toString( boolean verbose ) { 977 StringBuffer buf = new StringBuffer (); 978 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 979 buf.append(ih.toString(verbose)).append("\n"); 980 } 981 return buf.toString(); 982 } 983 984 985 988 public Iterator iterator() { 989 return new Iterator () { 990 991 private InstructionHandle ih = start; 992 993 994 public Object next() { 995 InstructionHandle i = ih; 996 ih = ih.next; 997 return i; 998 } 999 1000 1001 public void remove() { 1002 throw new UnsupportedOperationException (); 1003 } 1004 1005 1006 public boolean hasNext() { 1007 return ih != null; 1008 } 1009 }; 1010 } 1011 1012 1013 1016 public InstructionHandle[] getInstructionHandles() { 1017 InstructionHandle[] ihs = new InstructionHandle[length]; 1018 InstructionHandle ih = start; 1019 for (int i = 0; i < length; i++) { 1020 ihs[i] = ih; 1021 ih = ih.next; 1022 } 1023 return ihs; 1024 } 1025 1026 1027 1034 public int[] getInstructionPositions() { 1035 return byte_positions; 1036 } 1037 1038 1039 1042 public InstructionList copy() { 1043 Map map = new HashMap (); 1044 InstructionList il = new InstructionList(); 1045 1049 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 1050 Instruction i = ih.instruction; 1051 Instruction c = i.copy(); if (c instanceof BranchInstruction) { 1053 map.put(ih, il.append((BranchInstruction) c)); 1054 } else { 1055 map.put(ih, il.append(c)); 1056 } 1057 } 1058 1060 InstructionHandle ih = start; 1061 InstructionHandle ch = il.start; 1062 while (ih != null) { 1063 Instruction i = ih.instruction; 1064 Instruction c = ch.instruction; 1065 if (i instanceof BranchInstruction) { 1066 BranchInstruction bi = (BranchInstruction) i; 1067 BranchInstruction bc = (BranchInstruction) c; 1068 InstructionHandle itarget = bi.getTarget(); bc.setTarget((InstructionHandle) map.get(itarget)); 1071 if (bi instanceof Select) { InstructionHandle[] itargets = ((Select) bi).getTargets(); 1073 InstructionHandle[] ctargets = ((Select) bc).getTargets(); 1074 for (int j = 0; j < itargets.length; j++) { ctargets[j] = (InstructionHandle) map.get(itargets[j]); 1076 } 1077 } 1078 } 1079 ih = ih.next; 1080 ch = ch.next; 1081 } 1082 return il; 1083 } 1084 1085 1086 1089 public void replaceConstantPool( ConstantPoolGen old_cp, ConstantPoolGen new_cp ) { 1090 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 1091 Instruction i = ih.instruction; 1092 if (i instanceof CPInstruction) { 1093 CPInstruction ci = (CPInstruction) i; 1094 Constant c = old_cp.getConstant(ci.getIndex()); 1095 ci.setIndex(new_cp.addConstant(c, old_cp)); 1096 } 1097 } 1098 } 1099 1100 1101 private void clear() { 1102 start = end = null; 1103 length = 0; 1104 } 1105 1106 1107 1113 public void dispose() { 1114 for (InstructionHandle ih = end; ih != null; ih = ih.prev) { 1116 1119 ih.dispose(); 1120 } 1121 clear(); 1122 } 1123 1124 1125 1128 public InstructionHandle getStart() { 1129 return start; 1130 } 1131 1132 1133 1136 public InstructionHandle getEnd() { 1137 return end; 1138 } 1139 1140 1141 1144 public int getLength() { 1145 return length; 1146 } 1147 1148 1149 1152 public int size() { 1153 return length; 1154 } 1155 1156 1157 1164 public void redirectBranches( InstructionHandle old_target, InstructionHandle new_target ) { 1165 for (InstructionHandle ih = start; ih != null; ih = ih.next) { 1166 Instruction i = ih.getInstruction(); 1167 if (i instanceof BranchInstruction) { 1168 BranchInstruction b = (BranchInstruction) i; 1169 InstructionHandle target = b.getTarget(); 1170 if (target == old_target) { 1171 b.setTarget(new_target); 1172 } 1173 if (b instanceof Select) { InstructionHandle[] targets = ((Select) b).getTargets(); 1175 for (int j = 0; j < targets.length; j++) { 1176 if (targets[j] == old_target) { 1177 ((Select) b).setTarget(j, new_target); 1178 } 1179 } 1180 } 1181 } 1182 } 1183 } 1184 1185 1186 1194 public void redirectLocalVariables( LocalVariableGen[] lg, InstructionHandle old_target, 1195 InstructionHandle new_target ) { 1196 for (int i = 0; i < lg.length; i++) { 1197 InstructionHandle start = lg[i].getStart(); 1198 InstructionHandle end = lg[i].getEnd(); 1199 if (start == old_target) { 1200 lg[i].setStart(new_target); 1201 } 1202 if (end == old_target) { 1203 lg[i].setEnd(new_target); 1204 } 1205 } 1206 } 1207 1208 1209 1217 public void redirectExceptionHandlers( CodeExceptionGen[] exceptions, 1218 InstructionHandle old_target, InstructionHandle new_target ) { 1219 for (int i = 0; i < exceptions.length; i++) { 1220 if (exceptions[i].getStartPC() == old_target) { 1221 exceptions[i].setStartPC(new_target); 1222 } 1223 if (exceptions[i].getEndPC() == old_target) { 1224 exceptions[i].setEndPC(new_target); 1225 } 1226 if (exceptions[i].getHandlerPC() == old_target) { 1227 exceptions[i].setHandlerPC(new_target); 1228 } 1229 } 1230 } 1231 1232 private List observers; 1233 1234 1235 1237 public void addObserver( InstructionListObserver o ) { 1238 if (observers == null) { 1239 observers = new ArrayList (); 1240 } 1241 observers.add(o); 1242 } 1243 1244 1245 1247 public void removeObserver( InstructionListObserver o ) { 1248 if (observers != null) { 1249 observers.remove(o); 1250 } 1251 } 1252 1253 1254 1258 public void update() { 1259 if (observers != null) { 1260 for (Iterator e = observers.iterator(); e.hasNext();) { 1261 ((InstructionListObserver) e.next()).notify(this); 1262 } 1263 } 1264 } 1265} 1266 | Popular Tags |