1 52 53 package com.go.trove.classfile; 54 55 import java.util.*; 56 import java.io.*; 57 58 67 class InstructionList implements CodeBuffer { 68 private static final boolean DEBUG = false; 69 70 Instruction mFirst; 71 Instruction mLast; 72 73 boolean mResolved = false; 74 75 private List mExceptionHandlers = new ArrayList(4); 76 private List mLocalVariables = new ArrayList(); 77 78 private int mMaxStack; 79 private int mMaxLocals; 80 81 private byte[] mByteCodes; 82 private int mBufferLength; 83 84 protected InstructionList() { 85 super(); 86 } 87 88 92 public Collection getInstructions() { 93 return new AbstractCollection() { 94 public Iterator iterator() { 95 return new Iterator() { 96 private Instruction mNext = mFirst; 97 98 public boolean hasNext() { 99 return mNext != null; 100 } 101 102 public Object next() { 103 if (mNext == null) { 104 throw new NoSuchElementException(); 105 } 106 107 Instruction current = mNext; 108 mNext = mNext.mNext; 109 return current; 110 } 111 112 public void remove() { 113 throw new UnsupportedOperationException (); 114 } 115 }; 116 } 117 118 public int size() { 119 int count = 0; 120 for (Instruction i = mFirst; i != null; i = i.mNext) { 121 count++; 122 } 123 return count; 124 } 125 }; 126 } 127 128 public int getMaxStackDepth() { 129 resolve(); 130 return mMaxStack; 131 } 132 133 public int getMaxLocals() { 134 resolve(); 135 return mMaxLocals; 136 } 137 138 public byte[] getByteCodes() { 139 resolve(); 140 return mByteCodes; 141 } 142 143 public ExceptionHandler[] getExceptionHandlers() { 144 resolve(); 145 146 ExceptionHandler[] handlers = 147 new ExceptionHandler[mExceptionHandlers.size()]; 148 return (ExceptionHandler[])mExceptionHandlers.toArray(handlers); 149 } 150 151 public void addExceptionHandler(ExceptionHandler handler) { 152 mExceptionHandlers.add(handler); 153 } 154 155 public LocalVariable createLocalVariable(String name, 156 TypeDescriptor type) { 157 LocalVariable var = new LocalVariableImpl(name, type, -1); 158 mLocalVariables.add(var); 159 return var; 160 } 161 162 public LocalVariable createLocalParameter(String name, 163 TypeDescriptor type, 164 int number) { 165 LocalVariableImpl var = new LocalVariableImpl(name, type, number); 166 mLocalVariables.add(var); 167 if (mFirst == null) { 168 LabelInstruction label = new LabelInstruction(); 170 label.setLocation(); 171 mFirst = label; 172 } 173 174 var.addStoreInstruction(mFirst); 177 178 return var; 179 } 180 181 private void resolve() { 182 if (mResolved) { 183 return; 184 } 185 186 if (!DEBUG) { 187 resolve0(); 188 } 189 else { 190 try { 191 resolve0(); 192 } 193 finally { 194 System.out.println("-- Instructions --"); 195 196 Iterator it = getInstructions().iterator(); 197 while (it.hasNext()) { 198 System.out.println(it.next()); 199 } 200 } 201 } 202 } 203 204 private void resolve0() { 205 mMaxStack = 0; 206 mMaxLocals = 0; 207 208 Instruction instr; 209 210 int instrCount = 0; 213 for (instr = mFirst; instr != null; instr = instr.mNext) { 214 instr.mStackDepth = -1; 215 instr.mLocation = instrCount++; 216 } 217 218 220 int size = mLocalVariables.size(); 221 List activeLocationBits = new ArrayList(size); 222 for (int i=0; i<size; i++) { 223 LocalVariableImpl var = (LocalVariableImpl)mLocalVariables.get(i); 224 if (var.getNumber() < 0) { 225 var.setNumber(mMaxLocals); 226 } 227 228 int max = var.getNumber() + (var.isDoubleWord() ? 2 : 1); 229 if (max > mMaxLocals) { 230 mMaxLocals = max; 231 } 232 } 233 234 318 319 321 Map subAdjustMap = new HashMap(11); 323 stackResolve(0, mFirst, subAdjustMap); 324 325 Iterator it = mExceptionHandlers.iterator(); 327 while (it.hasNext()) { 328 ExceptionHandler handler = (ExceptionHandler)it.next(); 329 Instruction enter = (Instruction)handler.getCatchLocation(); 330 stackResolve(1, enter, subAdjustMap); 331 } 332 333 339 boolean passAgain; 340 do { 341 passAgain = false; 342 343 mByteCodes = new byte[16]; 344 mBufferLength = 0; 345 346 for (instr = mFirst; instr != null; instr = instr.mNext) { 347 if (!instr.isResolved()) { 348 passAgain = true; 349 } 350 351 if (instr instanceof Label) { 352 if (instr.mLocation != mBufferLength) { 353 if (instr.mLocation >= 0) { 354 passAgain = true; 358 } 359 360 instr.mLocation = mBufferLength; 361 } 362 } 363 else { 364 instr.mLocation = mBufferLength; 365 366 byte[] bytes = instr.getBytes(); 367 if (bytes != null) { 368 if (passAgain) { 369 mBufferLength += bytes.length; 373 } 374 else { 375 addBytes(bytes); 376 } 377 } 378 } 379 } 380 } while (passAgain); 382 if (mBufferLength != mByteCodes.length) { 383 byte[] newBytes = new byte[mBufferLength]; 384 System.arraycopy(mByteCodes, 0, newBytes, 0, mBufferLength); 385 mByteCodes = newBytes; 386 } 387 388 mResolved = true; 392 } 393 394 private void addBytes(byte[] code) { 395 growBuffer(code.length); 396 System.arraycopy(code, 0, mByteCodes, mBufferLength, code.length); 397 mBufferLength += code.length; 398 } 399 400 private void growBuffer(int amount) { 401 if ((mBufferLength + amount) > mByteCodes.length) { 402 int newCapacity = mByteCodes.length * 2; 403 if ((mBufferLength + amount) > newCapacity) { 404 newCapacity = mBufferLength + amount; 405 } 406 407 byte[] newBuffer = new byte[newCapacity]; 408 System.arraycopy(mByteCodes, 0, newBuffer, 0, mBufferLength); 409 mByteCodes = newBuffer; 410 } 411 } 412 413 512 513 private int stackResolve(int stackDepth, 514 Instruction instr, 515 Map subAdjustMap) { 516 while (instr != null) { 517 if (instr.mStackDepth < 0) { 520 instr.mStackDepth = stackDepth; 521 } 522 else { 523 if (instr.mStackDepth != stackDepth) { 524 throw new RuntimeException 525 ("Stack depth different at previously visited " + 526 "instruction: " + instr.mStackDepth + 527 " != " + stackDepth); 528 } 529 530 break; 531 } 532 533 Instruction next = null; 535 536 if (instr.isFlowThrough()) { 537 if ((next = instr.mNext) == null) { 538 throw new RuntimeException 539 ("Execution flows through end of method"); 540 } 541 } 542 543 stackDepth += instr.getStackAdjustment(); 544 if (stackDepth > mMaxStack) { 545 mMaxStack = stackDepth; 546 } 547 else if (stackDepth < 0) { 548 throw new RuntimeException ("Stack depth is negative: " + 549 stackDepth); 550 } 551 552 Location[] targets = instr.getBranchTargets(); 553 if (targets != null) { 554 for (int i=0; i<targets.length; i++) { 555 LabelInstruction targetInstr = 556 (LabelInstruction)targets[i]; 557 558 if (i == 0 && next == null) { 559 next = targetInstr; 562 continue; 563 } 564 565 if (!instr.isSubroutineCall()) { 566 stackResolve 567 (stackDepth, targetInstr, subAdjustMap); 568 } 569 else { 570 Integer subAdjust = 571 (Integer )subAdjustMap.get(targetInstr); 572 573 if (subAdjust == null) { 574 int newDepth = 575 stackResolve(stackDepth, targetInstr, 576 subAdjustMap); 577 subAdjust = new Integer (newDepth - stackDepth); 578 subAdjustMap.put(targetInstr, subAdjust); 579 } 580 581 stackDepth += subAdjust.intValue(); 582 } 583 } 584 } 585 586 instr = next; 587 } 588 589 return stackDepth; 590 } 591 592 private class LocalVariableImpl implements LocalVariable { 593 private String mName; 594 private TypeDescriptor mType; 595 private boolean mIsDoubleWord; 596 597 private int mNumber; 598 private boolean mFixed; 599 600 private List mStoreInstructions; 601 private SortedSet mLocationRangeSet; 602 603 public LocalVariableImpl(String name, TypeDescriptor type, 604 int number) { 605 mName = name; 606 mType = type; 607 Class clazz = type.getClassArg(); 608 mIsDoubleWord = clazz == long.class || clazz == double.class; 609 mNumber = number; 610 if (number >= 0) { 611 mFixed = true; 612 } 613 mStoreInstructions = new ArrayList(); 614 } 615 616 619 public String getName() { 620 return mName; 621 } 622 623 public void setName(String name) { 624 mName = name; 625 } 626 627 public TypeDescriptor getType() { 628 return mType; 629 } 630 631 public boolean isDoubleWord() { 632 return mIsDoubleWord; 633 } 634 635 public int getNumber() { 636 return mNumber; 637 } 638 639 public void setNumber(int number) { 640 mNumber = number; 641 } 642 643 public SortedSet getLocationRangeSet() { 644 return mLocationRangeSet; 645 } 646 647 public void setLocations(Set locations) { 648 684 } 685 686 public boolean isFixedNumber() { 687 return mFixed; 688 } 689 690 public void addStoreInstruction(Instruction instr) { 691 mStoreInstructions.add(instr); 692 } 693 694 public Iterator iterateStoreInstructions() { 695 return mStoreInstructions.iterator(); 696 } 697 698 public String toString() { 699 if (getName() != null) { 700 return String.valueOf(getType()) + ' ' + getName(); 701 } 702 else { 703 return String.valueOf(getType()); 704 } 705 } 706 } 707 708 714 722 public abstract class Instruction implements Location { 723 private int mStackAdjust; 724 725 Instruction mPrev; 726 Instruction mNext; 727 728 int mStackDepth = -1; 731 732 int mLocation = -1; 734 735 739 public Instruction(int stackAdjust) { 740 mStackAdjust = stackAdjust; 741 add(); 742 } 743 744 748 protected Instruction(int stackAdjust, boolean addInstruction) { 749 mStackAdjust = stackAdjust; 750 751 if (addInstruction) { 752 add(); 753 } 754 } 755 756 760 protected void add() { 761 InstructionList.this.mResolved = false; 762 763 if (mPrev != null) { 764 mPrev.mNext = mNext; 765 } 766 767 if (mNext != null) { 768 mNext.mPrev = mPrev; 769 } 770 771 mNext = null; 772 773 if (InstructionList.this.mFirst == null) { 774 mPrev = null; 775 InstructionList.this.mFirst = this; 776 } 777 else { 778 mPrev = InstructionList.this.mLast; 779 InstructionList.this.mLast.mNext = this; 780 } 781 782 InstructionList.this.mLast = this; 783 } 784 785 788 public void insert(Instruction instr) { 789 InstructionList.this.mResolved = false; 790 791 instr.mPrev = this; 792 instr.mNext = mNext; 793 794 mNext = instr; 795 796 if (this == InstructionList.this.mLast) { 797 InstructionList.this.mLast = instr; 798 } 799 } 800 801 804 public void remove() { 805 InstructionList.this.mResolved = false; 806 807 if (mPrev != null) { 808 mPrev.mNext = mNext; 809 } 810 811 if (mNext != null) { 812 mNext.mPrev = mPrev; 813 } 814 815 if (this == InstructionList.this.mFirst) { 816 InstructionList.this.mFirst = mNext; 817 } 818 819 if (this == InstructionList.this.mLast) { 820 InstructionList.this.mLast = mPrev; 821 } 822 823 mPrev = null; 824 mNext = null; 825 } 826 827 830 public void replace(Instruction replacement) { 831 if (replacement == null) { 832 remove(); 833 return; 834 } 835 836 InstructionList.this.mResolved = false; 837 838 replacement.mPrev = mPrev; 839 replacement.mNext = mNext; 840 841 if (mPrev != null) { 842 mPrev.mNext = replacement; 843 } 844 845 if (mNext != null) { 846 mNext.mPrev = replacement; 847 } 848 849 if (this == InstructionList.this.mFirst) { 850 InstructionList.this.mFirst = replacement; 851 } 852 853 if (this == InstructionList.this.mLast) { 854 InstructionList.this.mLast = replacement; 855 } 856 } 857 858 862 public int getStackAdjustment() { 863 return mStackAdjust; 864 } 865 866 870 public int getStackDepth() { 871 return mStackDepth; 872 } 873 874 877 public int getLocation() { 878 return mLocation; 879 } 880 881 885 public Location[] getBranchTargets() { 886 return null; 887 } 888 889 894 public boolean isFlowThrough() { 895 return true; 896 } 897 898 public boolean isSubroutineCall() { 899 return false; 900 } 901 902 906 public abstract byte[] getBytes(); 907 908 912 public abstract boolean isResolved(); 913 914 public int compareTo(Object obj) { 915 if (this == obj) { 916 return 0; 917 } 918 Location other = (Location)obj; 919 920 int loca = getLocation(); 921 int locb = other.getLocation(); 922 923 if (loca < locb) { 924 return -1; 925 } 926 else if (loca > locb) { 927 return 1; 928 } 929 else { 930 return 0; 931 } 932 } 933 934 939 public String toString() { 940 String name = getClass().getName(); 941 int index = name.lastIndexOf('.'); 942 if (index >= 0) { 943 name = name.substring(index + 1); 944 } 945 index = name.lastIndexOf('$'); 946 if (index >= 0) { 947 name = name.substring(index + 1); 948 } 949 950 StringBuffer buf = new StringBuffer (name.length() + 20); 951 952 int adjust = getStackAdjustment(); 953 int depth = getStackDepth(); 954 955 if (depth >= 0) { 956 buf.append(' '); 957 } 958 else { 959 buf.append('*'); 960 } 961 962 buf.append('['); 963 buf.append(mLocation); 964 buf.append("] "); 965 966 buf.append(name); 967 buf.append(" ("); 968 969 if (depth >= 0) { 970 buf.append(depth); 971 buf.append(" + "); 972 buf.append(adjust); 973 buf.append(" = "); 974 buf.append(depth + adjust); 975 } 976 else { 977 buf.append(adjust); 978 } 979 980 buf.append(") "); 981 982 try { 983 byte[] bytes = getBytes(); 984 boolean wide = false; 985 if (bytes != null) { 986 for (int i=0; i<bytes.length; i++) { 987 if (i > 0) { 988 buf.append(','); 989 } 990 991 byte code = bytes[i]; 992 993 if (i == 0 || wide) { 994 buf.append(Opcode.getMnemonic(code)); 995 wide = code == Opcode.WIDE; 996 } 997 else { 998 buf.append(code & 0xff); 999 } 1000 } 1001 } 1002 } 1003 catch (Exception e) { 1004 } 1005 1006 return buf.toString(); 1007 } 1008 } 1009 1010 1018 public class LabelInstruction extends Instruction implements Label { 1019 public LabelInstruction() { 1020 super(0, false); 1021 } 1022 1023 1029 public Label setLocation() { 1030 add(); 1031 return this; 1032 } 1033 1034 1037 public int getLocation() throws IllegalStateException { 1038 int loc; 1039 if ((loc = mLocation) < 0) { 1040 if (mPrev == null && mNext == null) { 1041 throw new IllegalStateException 1042 ("Label location is not set"); 1043 } 1044 } 1045 1046 return loc; 1047 } 1048 1049 1052 public byte[] getBytes() { 1053 return null; 1054 } 1055 1056 public boolean isResolved() { 1057 return getLocation() >= 0; 1058 } 1059 } 1060 1061 1068 public class CodeInstruction extends Instruction { 1069 protected byte[] mBytes; 1070 1071 public CodeInstruction(int stackAdjust) { 1072 super(stackAdjust); 1073 } 1074 1075 protected CodeInstruction(int stackAdjust, boolean addInstruction) { 1076 super(stackAdjust, addInstruction); 1077 } 1078 1079 public CodeInstruction(int stackAdjust, byte b) { 1080 super(stackAdjust); 1081 mBytes = new byte[] {b}; 1082 } 1083 1084 public CodeInstruction(int stackAdjust, byte[] bytes) { 1085 super(stackAdjust); 1086 mBytes = bytes; 1087 } 1088 1089 public boolean isFlowThrough() { 1090 if (mBytes != null && mBytes.length > 0) { 1091 switch (mBytes[0]) { 1092 case Opcode.GOTO: 1093 case Opcode.GOTO_W: 1094 case Opcode.IRETURN: 1095 case Opcode.LRETURN: 1096 case Opcode.FRETURN: 1097 case Opcode.DRETURN: 1098 case Opcode.ARETURN: 1099 case Opcode.RETURN: 1100 case Opcode.ATHROW: 1101 return false; 1102 } 1103 } 1104 1105 return true; 1106 } 1107 1108 public byte[] getBytes() { 1109 return mBytes; 1110 } 1111 1112 public boolean isResolved() { 1113 return true; 1114 } 1115 } 1116 1117 1125 public class BranchInstruction extends CodeInstruction { 1126 private Location mTarget; 1127 private boolean mHasShortHop = false; 1128 private boolean mIsSub = false; 1129 1130 public BranchInstruction(int stackAdjust, 1131 byte opcode, Location target) { 1132 this(stackAdjust, true, opcode, target); 1133 } 1134 1135 private BranchInstruction(int stackAdjust, boolean addInstruction, 1136 byte opcode, Location target) { 1137 super(stackAdjust, addInstruction); 1138 1139 mTarget = target; 1140 1141 switch (opcode) { 1142 case Opcode.GOTO_W: 1143 case Opcode.JSR_W: 1144 mIsSub = true; 1145 mBytes = new byte[5]; 1146 mBytes[0] = opcode; 1147 break; 1148 case Opcode.JSR: 1149 mIsSub = true; 1150 case Opcode.GOTO: 1152 case Opcode.IF_ACMPEQ: 1153 case Opcode.IF_ACMPNE: 1154 case Opcode.IF_ICMPEQ: 1155 case Opcode.IF_ICMPNE: 1156 case Opcode.IF_ICMPLT: 1157 case Opcode.IF_ICMPGE: 1158 case Opcode.IF_ICMPGT: 1159 case Opcode.IF_ICMPLE: 1160 case Opcode.IFEQ: 1161 case Opcode.IFNE: 1162 case Opcode.IFLT: 1163 case Opcode.IFGE: 1164 case Opcode.IFGT: 1165 case Opcode.IFLE: 1166 case Opcode.IFNONNULL: 1167 case Opcode.IFNULL: 1168 mBytes = new byte[3]; 1169 mBytes[0] = opcode; 1170 break; 1171 default: 1172 throw new IllegalArgumentException 1173 ("Opcode not a branch instruction: " + 1174 Opcode.getMnemonic(opcode)); 1175 } 1176 } 1177 1178 public Location[] getBranchTargets() { 1179 return new Location[] {mTarget}; 1180 } 1181 1182 public boolean isSubroutineCall() { 1183 return mIsSub; 1184 } 1185 1186 public byte[] getBytes() { 1187 if (!isResolved() || mHasShortHop) { 1188 return mBytes; 1189 } 1190 1191 int offset = mTarget.getLocation() - mLocation; 1192 byte opcode = mBytes[0]; 1193 1194 if (opcode == Opcode.GOTO_W || opcode == Opcode.JSR_W) { 1195 mBytes[1] = (byte)(offset >> 24); 1196 mBytes[2] = (byte)(offset >> 16); 1197 mBytes[3] = (byte)(offset >> 8); 1198 mBytes[4] = (byte)(offset >> 0); 1199 } 1200 else if (-32768 <= offset && offset <= 32767) { 1201 mBytes[1] = (byte)(offset >> 8); 1202 mBytes[2] = (byte)(offset >> 0); 1203 } 1204 else if (opcode == Opcode.GOTO || opcode == Opcode.JSR) { 1205 mBytes = new byte[5]; 1206 if (opcode == Opcode.GOTO) { 1207 mBytes[0] = Opcode.GOTO_W; 1208 } 1209 else { 1210 mBytes[0] = Opcode.JSR_W; 1211 } 1212 mBytes[1] = (byte)(offset >> 24); 1213 mBytes[2] = (byte)(offset >> 16); 1214 mBytes[3] = (byte)(offset >> 8); 1215 mBytes[4] = (byte)(offset >> 0); 1216 } 1217 else { 1218 1220 1226 1233 mHasShortHop = true; 1234 1235 opcode = Opcode.reverseIfOpcode(opcode); 1236 1237 mBytes[0] = opcode; 1238 mBytes[1] = (byte)0; 1239 mBytes[2] = (byte)8; 1240 1241 insert 1243 (new BranchInstruction(0, false, Opcode.GOTO_W, mTarget)); 1244 } 1245 1246 return mBytes; 1247 } 1248 1249 public boolean isResolved() { 1250 return mTarget.getLocation() >= 0; 1251 } 1252 } 1253 1254 1262 public class ConstantOperandInstruction extends CodeInstruction { 1263 private ConstantInfo mInfo; 1264 1265 public ConstantOperandInstruction(int stackAdjust, 1266 byte[] bytes, 1267 ConstantInfo info) { 1268 super(stackAdjust, bytes); 1269 mInfo = info; 1270 } 1271 1272 public byte[] getBytes() { 1273 int index = mInfo.getIndex(); 1274 1275 if (index < 0) { 1276 throw new RuntimeException ("Constant pool index not resolved"); 1277 } 1278 1279 mBytes[1] = (byte)(index >> 8); 1280 mBytes[2] = (byte)index; 1281 1282 return mBytes; 1283 } 1284 1285 public boolean isResolved() { 1286 return mInfo.getIndex() >= 0; 1287 } 1288 } 1289 1290 1298 public class LoadConstantInstruction extends CodeInstruction { 1299 private ConstantInfo mInfo; 1300 private boolean mWideOnly; 1301 1302 public LoadConstantInstruction(int stackAdjust, 1303 ConstantInfo info) { 1304 this(stackAdjust, info, false); 1305 } 1306 1307 public LoadConstantInstruction(int stackAdjust, 1308 ConstantInfo info, 1309 boolean wideOnly) { 1310 super(stackAdjust); 1311 mInfo = info; 1312 mWideOnly = wideOnly; 1313 } 1314 1315 public boolean isFlowThrough() { 1316 return true; 1317 } 1318 1319 public byte[] getBytes() { 1320 int index = mInfo.getIndex(); 1321 1322 if (index < 0) { 1323 throw new RuntimeException ("Constant pool index not resolved"); 1324 } 1325 1326 if (mWideOnly) { 1327 byte[] bytes = new byte[3]; 1328 bytes[0] = Opcode.LDC2_W; 1329 bytes[1] = (byte)(index >> 8); 1330 bytes[2] = (byte)index; 1331 return bytes; 1332 } 1333 else if (index <= 255) { 1334 byte[] bytes = new byte[2]; 1335 bytes[0] = Opcode.LDC; 1336 bytes[1] = (byte)index; 1337 return bytes; 1338 } 1339 else { 1340 byte[] bytes = new byte[3]; 1341 bytes[0] = Opcode.LDC_W; 1342 bytes[1] = (byte)(index >> 8); 1343 bytes[2] = (byte)index; 1344 return bytes; 1345 } 1346 } 1347 1348 public boolean isResolved() { 1349 return mInfo.getIndex() >= 0; 1350 } 1351 } 1352 1353 1361 public class LocalOperandInstruction extends CodeInstruction { 1362 protected LocalVariable mLocal; 1363 1364 public LocalOperandInstruction(int stackAdjust, 1365 LocalVariable local) { 1366 super(stackAdjust); 1367 mLocal = local; 1368 } 1369 1370 public boolean isResolved() { 1371 return mLocal.getNumber() >= 0; 1372 } 1373 1374 public LocalVariable getLocalVariable() { 1375 return mLocal; 1376 } 1377 1378 public int getVariableNumber() { 1379 int varNum = mLocal.getNumber(); 1380 1381 if (varNum < 0) { 1382 throw new RuntimeException 1383 ("Local variable number not resolved"); 1384 } 1385 1386 return varNum; 1387 } 1388 } 1389 1390 1397 public class LoadLocalInstruction extends LocalOperandInstruction { 1398 public LoadLocalInstruction(int stackAdjust, 1399 LocalVariable local) { 1400 super(stackAdjust, local); 1401 } 1402 1403 public boolean isFlowThrough() { 1404 return true; 1405 } 1406 1407 public byte[] getBytes() { 1408 int varNum = getVariableNumber(); 1409 byte opcode; 1410 boolean writeIndex = false; 1411 1412 TypeDescriptor type = mLocal.getType(); 1413 Class clazz; 1414 if (type.getDimensions() > 0) { 1415 clazz = null; 1416 } 1417 else { 1418 clazz = type.getClassArg(); 1419 } 1420 1421 switch(varNum) { 1422 case 0: 1423 if (clazz == null || !clazz.isPrimitive()) { 1424 opcode = Opcode.ALOAD_0; 1425 } 1426 else if (clazz == long.class) { 1427 opcode = Opcode.LLOAD_0; 1428 } 1429 else if (clazz == float.class) { 1430 opcode = Opcode.FLOAD_0; 1431 } 1432 else if (clazz == double.class) { 1433 opcode = Opcode.DLOAD_0; 1434 } 1435 else { 1436 opcode = Opcode.ILOAD_0; 1437 } 1438 break; 1439 case 1: 1440 if (clazz == null || !clazz.isPrimitive()) { 1441 opcode = Opcode.ALOAD_1; 1442 } 1443 else if (clazz == long.class) { 1444 opcode = Opcode.LLOAD_1; 1445 } 1446 else if (clazz == float.class) { 1447 opcode = Opcode.FLOAD_1; 1448 } 1449 else if (clazz == double.class) { 1450 opcode = Opcode.DLOAD_1; 1451 } 1452 else { 1453 opcode = Opcode.ILOAD_1; 1454 } 1455 break; 1456 case 2: 1457 if (clazz == null || !clazz.isPrimitive()) { 1458 opcode = Opcode.ALOAD_2; 1459 } 1460 else if (clazz == long.class) { 1461 opcode = Opcode.LLOAD_2; 1462 } 1463 else if (clazz == float.class) { 1464 opcode = Opcode.FLOAD_2; 1465 } 1466 else if (clazz == double.class) { 1467 opcode = Opcode.DLOAD_2; 1468 } 1469 else { 1470 opcode = Opcode.ILOAD_2; 1471 } 1472 break; 1473 case 3: 1474 if (clazz == null || !clazz.isPrimitive()) { 1475 opcode = Opcode.ALOAD_3; 1476 } 1477 else if (clazz == long.class) { 1478 opcode = Opcode.LLOAD_3; 1479 } 1480 else if (clazz == float.class) { 1481 opcode = Opcode.FLOAD_3; 1482 } 1483 else if (clazz == double.class) { 1484 opcode = Opcode.DLOAD_3; 1485 } 1486 else { 1487 opcode = Opcode.ILOAD_3; 1488 } 1489 break; 1490 default: 1491 writeIndex = true; 1492 1493 if (clazz == null || !clazz.isPrimitive()) { 1494 opcode = Opcode.ALOAD; 1495 } 1496 else if (clazz == long.class) { 1497 opcode = Opcode.LLOAD; 1498 } 1499 else if (clazz == float.class) { 1500 opcode = Opcode.FLOAD; 1501 } 1502 else if (clazz == double.class) { 1503 opcode = Opcode.DLOAD; 1504 } 1505 else { 1506 opcode = Opcode.ILOAD; 1507 } 1508 break; 1509 } 1510 1511 if (!writeIndex) { 1512 mBytes = new byte[] { opcode }; 1513 } 1514 else { 1515 if (varNum <= 255) { 1516 mBytes = new byte[] { opcode, (byte)varNum }; 1517 } 1518 else { 1519 mBytes = new byte[] 1520 { 1521 Opcode.WIDE, 1522 opcode, 1523 (byte)(varNum >> 8), 1524 (byte)varNum 1525 }; 1526 } 1527 } 1528 1529 return mBytes; 1530 } 1531 } 1532 1533 1541 public class StoreLocalInstruction extends LocalOperandInstruction { 1542 public StoreLocalInstruction(int stackAdjust, 1543 LocalVariable local) { 1544 super(stackAdjust, local); 1545 ((LocalVariableImpl)local).addStoreInstruction(this); 1546 } 1547 1548 public boolean isFlowThrough() { 1549 return true; 1550 } 1551 1552 public byte[] getBytes() { 1553 int varNum = getVariableNumber(); 1554 byte opcode; 1555 boolean writeIndex = false; 1556 1557 TypeDescriptor type = mLocal.getType(); 1558 Class clazz; 1559 if (type.getDimensions() > 0) { 1560 clazz = null; 1561 } 1562 else { 1563 clazz = type.getClassArg(); 1564 } 1565 1566 switch(varNum) { 1567 case 0: 1568 if (clazz == null || !clazz.isPrimitive()) { 1569 opcode = Opcode.ASTORE_0; 1570 } 1571 else if (clazz == long.class) { 1572 opcode = Opcode.LSTORE_0; 1573 } 1574 else if (clazz == float.class) { 1575 opcode = Opcode.FSTORE_0; 1576 } 1577 else if (clazz == double.class) { 1578 opcode = Opcode.DSTORE_0; 1579 } 1580 else { 1581 opcode = Opcode.ISTORE_0; 1582 } 1583 break; 1584 case 1: 1585 if (clazz == null || !clazz.isPrimitive()) { 1586 opcode = Opcode.ASTORE_1; 1587 } 1588 else if (clazz == long.class) { 1589 opcode = Opcode.LSTORE_1; 1590 } 1591 else if (clazz == float.class) { 1592 opcode = Opcode.FSTORE_1; 1593 } 1594 else if (clazz == double.class) { 1595 opcode = Opcode.DSTORE_1; 1596 } 1597 else { 1598 opcode = Opcode.ISTORE_1; 1599 } 1600 break; 1601 case 2: 1602 if (clazz == null || !clazz.isPrimitive()) { 1603 opcode = Opcode.ASTORE_2; 1604 } 1605 else if (clazz == long.class) { 1606 opcode = Opcode.LSTORE_2; 1607 } 1608 else if (clazz == float.class) { 1609 opcode = Opcode.FSTORE_2; 1610 } 1611 else if (clazz == double.class) { 1612 opcode = Opcode.DSTORE_2; 1613 } 1614 else { 1615 opcode = Opcode.ISTORE_2; 1616 } 1617 break; 1618 case 3: 1619 if (clazz == null || !clazz.isPrimitive()) { 1620 opcode = Opcode.ASTORE_3; 1621 } 1622 else if (clazz == long.class) { 1623 opcode = Opcode.LSTORE_3; 1624 } 1625 else if (clazz == float.class) { 1626 opcode = Opcode.FSTORE_3; 1627 } 1628 else if (clazz == double.class) { 1629 opcode = Opcode.DSTORE_3; 1630 } 1631 else { 1632 opcode = Opcode.ISTORE_3; 1633 } 1634 break; 1635 default: 1636 writeIndex = true; 1637 1638 if (clazz == null || !clazz.isPrimitive()) { 1639 opcode = Opcode.ASTORE; 1640 } 1641 else if (clazz == long.class) { 1642 opcode = Opcode.LSTORE; 1643 } 1644 else if (clazz == float.class) { 1645 opcode = Opcode.FSTORE; 1646 } 1647 else if (clazz == double.class) { 1648 opcode = Opcode.DSTORE; 1649 } 1650 else { 1651 opcode = Opcode.ISTORE; 1652 } 1653 break; 1654 } 1655 1656 if (!writeIndex) { 1657 mBytes = new byte[] { opcode }; 1658 } 1659 else { 1660 if (varNum <= 255) { 1661 mBytes = new byte[] { opcode, (byte)varNum }; 1662 } 1663 else { 1664 mBytes = new byte[] 1665 { 1666 Opcode.WIDE, 1667 opcode, 1668 (byte)(varNum >> 8), 1669 (byte)varNum 1670 }; 1671 } 1672 } 1673 1674 return mBytes; 1675 } 1676 } 1677 1678 1685 public class RetInstruction extends LocalOperandInstruction { 1686 public RetInstruction(LocalVariable local) { 1687 super(0, local); 1688 } 1689 1690 public boolean isFlowThrough() { 1691 return false; 1692 } 1693 1694 public byte[] getBytes() { 1695 int varNum = getVariableNumber(); 1696 1697 if (varNum <= 255) { 1698 mBytes = new byte[] { Opcode.RET, (byte)varNum }; 1699 } 1700 else { 1701 mBytes = new byte[] 1702 { 1703 Opcode.WIDE, 1704 Opcode.RET, 1705 (byte)(varNum >> 8), 1706 (byte)varNum 1707 }; 1708 } 1709 1710 return mBytes; 1711 } 1712 } 1713 1714 1722 public class ShortIncrementInstruction extends LocalOperandInstruction { 1723 private short mAmount; 1724 1725 public ShortIncrementInstruction(LocalVariable local, short amount) { 1726 super(0, local); 1727 mAmount = amount; 1728 } 1729 1730 public boolean isFlowThrough() { 1731 return true; 1732 } 1733 1734 public byte[] getBytes() { 1735 int varNum = getVariableNumber(); 1736 1737 if ((-128 <= mAmount && mAmount <= 127) && varNum <= 255) { 1738 mBytes = new byte[] 1739 { Opcode.IINC, 1740 (byte)varNum, 1741 (byte)mAmount 1742 }; 1743 } 1744 else { 1745 mBytes = new byte[] 1746 { 1747 Opcode.WIDE, 1748 Opcode.IINC, 1749 (byte)(varNum >> 8), 1750 (byte)varNum, 1751 (byte)(mAmount >> 8), 1752 (byte)mAmount 1753 }; 1754 } 1755 1756 return mBytes; 1757 } 1758 } 1759 1760 1769 public class SwitchInstruction extends CodeInstruction { 1770 private int[] mCases; 1771 private Location[] mLocations; 1772 private Location mDefaultLocation; 1773 1774 private byte mOpcode; 1775 1776 private int mSmallest; 1777 private int mLargest; 1778 1779 public SwitchInstruction(int[] casesParam, 1780 Location[] locationsParam, 1781 Location defaultLocation) { 1782 super(-1); 1785 1786 if (casesParam.length != locationsParam.length) { 1787 throw new IllegalArgumentException 1788 ("Switch cases and locations sizes differ: " + 1789 casesParam.length + ", " + locationsParam.length); 1790 } 1791 1792 mCases = new int[casesParam.length]; 1793 System.arraycopy(casesParam, 0, mCases, 0, casesParam.length); 1794 1795 mLocations = new Location[locationsParam.length]; 1796 System.arraycopy(locationsParam, 0, mLocations, 1797 0, locationsParam.length); 1798 1799 mDefaultLocation = defaultLocation; 1800 1801 sort(0, mCases.length - 1); 1803 1804 int lastCase = 0; 1806 for (int i=0; i<mCases.length; i++) { 1807 if (i > 0 && mCases[i] == lastCase) { 1808 throw new RuntimeException ("Duplicate switch cases: " + 1809 lastCase); 1810 } 1811 lastCase = mCases[i]; 1812 } 1813 1814 1816 mSmallest = mCases[0]; 1817 mLargest = mCases[mCases.length - 1]; 1818 int tSize = 12 + 4 * (mLargest - mSmallest + 1); 1819 1820 int lSize = 8 + 8 * mCases.length; 1821 1822 if (tSize <= lSize) { 1823 mOpcode = Opcode.TABLESWITCH; 1824 } 1825 else { 1826 mOpcode = Opcode.LOOKUPSWITCH; 1827 } 1828 } 1829 1830 public Location[] getBranchTargets() { 1831 Location[] targets = new Location[mLocations.length + 1]; 1832 System.arraycopy(mLocations, 0, targets, 0, mLocations.length); 1833 targets[targets.length - 1] = mDefaultLocation; 1834 1835 return targets; 1836 } 1837 1838 public boolean isFlowThrough() { 1839 return false; 1840 } 1841 1842 public byte[] getBytes() { 1843 int length = 1; 1844 int pad = 3 - (mLocation & 3); 1845 length += pad; 1846 1847 if (mOpcode == Opcode.TABLESWITCH) { 1848 length += 12 + 4 * (mLargest - mSmallest + 1); 1849 } 1850 else { 1851 length += 8 + 8 * mCases.length; 1852 } 1853 1854 mBytes = new byte[length]; 1855 1856 if (!isResolved()) { 1857 return mBytes; 1858 } 1859 1860 mBytes[0] = mOpcode; 1861 int cursor = pad + 1; 1862 1863 int defaultOffset = mDefaultLocation.getLocation() - mLocation; 1864 mBytes[cursor++] = (byte)(defaultOffset >> 24); 1865 mBytes[cursor++] = (byte)(defaultOffset >> 16); 1866 mBytes[cursor++] = (byte)(defaultOffset >> 8); 1867 mBytes[cursor++] = (byte)(defaultOffset >> 0); 1868 1869 if (mOpcode == Opcode.TABLESWITCH) { 1870 mBytes[cursor++] = (byte)(mSmallest >> 24); 1871 mBytes[cursor++] = (byte)(mSmallest >> 16); 1872 mBytes[cursor++] = (byte)(mSmallest >> 8); 1873 mBytes[cursor++] = (byte)(mSmallest >> 0); 1874 1875 mBytes[cursor++] = (byte)(mLargest >> 24); 1876 mBytes[cursor++] = (byte)(mLargest >> 16); 1877 mBytes[cursor++] = (byte)(mLargest >> 8); 1878 mBytes[cursor++] = (byte)(mLargest >> 0); 1879 1880 int index = 0; 1881 for (int case_ = mSmallest; case_ <= mLargest; case_++) { 1882 if (case_ == mCases[index]) { 1883 int offset = 1884 mLocations[index].getLocation() - mLocation; 1885 mBytes[cursor++] = (byte)(offset >> 24); 1886 mBytes[cursor++] = (byte)(offset >> 16); 1887 mBytes[cursor++] = (byte)(offset >> 8); 1888 mBytes[cursor++] = (byte)(offset >> 0); 1889 1890 index++; 1891 } 1892 else { 1893 mBytes[cursor++] = (byte)(defaultOffset >> 24); 1894 mBytes[cursor++] = (byte)(defaultOffset >> 16); 1895 mBytes[cursor++] = (byte)(defaultOffset >> 8); 1896 mBytes[cursor++] = (byte)(defaultOffset >> 0); 1897 } 1898 } 1899 } 1900 else { 1901 mBytes[cursor++] = (byte)(mCases.length >> 24); 1902 mBytes[cursor++] = (byte)(mCases.length >> 16); 1903 mBytes[cursor++] = (byte)(mCases.length >> 8); 1904 mBytes[cursor++] = (byte)(mCases.length >> 0); 1905 1906 for (int index = 0; index < mCases.length; index++) { 1907 int case_ = mCases[index]; 1908 1909 mBytes[cursor++] = (byte)(case_ >> 24); 1910 mBytes[cursor++] = (byte)(case_ >> 16); 1911 mBytes[cursor++] = (byte)(case_ >> 8); 1912 mBytes[cursor++] = (byte)(case_ >> 0); 1913 1914 int offset = mLocations[index].getLocation() - mLocation; 1915 mBytes[cursor++] = (byte)(offset >> 24); 1916 mBytes[cursor++] = (byte)(offset >> 16); 1917 mBytes[cursor++] = (byte)(offset >> 8); 1918 mBytes[cursor++] = (byte)(offset >> 0); 1919 } 1920 } 1921 1922 return mBytes; 1923 } 1924 1925 public boolean isResolved() { 1926 if (mDefaultLocation.getLocation() >= 0) { 1927 for (int i=0; i<mLocations.length; i++) { 1928 if (mLocations[i].getLocation() < 0) { 1929 break; 1930 } 1931 } 1932 1933 return true; 1934 } 1935 1936 return false; 1937 } 1938 1939 private void sort(int left, int right) { 1940 if (left >= right) { 1941 return; 1942 } 1943 1944 swap(left, (left + right) / 2); 1946 int last = left; 1947 1948 for (int i = left + 1; i <= right; i++) { 1949 if (mCases[i] < mCases[left]) { 1950 swap(++last, i); 1951 } 1952 } 1953 1954 swap(left, last); 1955 sort(left, last-1); 1956 sort(last + 1, right); 1957 } 1958 1959 private void swap(int i, int j) { 1960 int tempInt = mCases[i]; 1961 mCases[i] = mCases[j]; 1962 mCases[j] = tempInt; 1963 1964 Location tempLocation = mLocations[i]; 1965 mLocations[i] = mLocations[j]; 1966 mLocations[j] = tempLocation; 1967 } 1968 } 1969} 1970 | Popular Tags |