00001 package de.fub.bytecode.generic;
00002
00003 import de.fub.bytecode.Constants;
00004 import de.fub.bytecode.util.ByteSequence;
00005 import java.io.*;
00006 import java.util.Enumeration;
00007 import java.util.Hashtable;
00008 import java.util.Vector;
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 public class InstructionList implements Constants, Serializable {
00026 private InstructionHandle start = null, end = null;
00027 private int length = 0;
00028 private int[] byte_positions;
00029
00030
00031
00032 public InstructionList() {}
00033
00034
00035
00036
00037
00038 public InstructionList(byte[] code) {
00039 ByteSequence bytes = new ByteSequence(code);
00040 InstructionHandle[] ihs = new InstructionHandle[code.length];
00041 int[] pos = new int[code.length];
00042 int count = 0;
00043
00044
00045
00046
00047 try {
00048 while(bytes.available() > 0) {
00049
00050 int off = bytes.getIndex();
00051 pos[count] = off;
00052
00053
00054
00055
00056 Instruction i = Instruction.readInstruction(bytes);
00057 InstructionHandle ih;
00058 if(i instanceof BranchInstruction)
00059 ih = append((BranchInstruction)i);
00060 else
00061 ih = append(i);
00062
00063 ih.setPosition(off);
00064 ihs[count] = ih;
00065
00066 count++;
00067 }
00068 } catch(IOException e) { throw new ClassGenException(e.toString()); }
00069
00070 byte_positions = pos;
00071
00072
00073
00074
00075 for(int i=0; i < count; i++) {
00076 if(ihs[i] instanceof BranchHandle) {
00077 BranchInstruction bi = (BranchInstruction)ihs[i].instruction;
00078 int target = bi.position + bi.getIndex();
00079
00080
00081 InstructionHandle ih = findHandle(ihs, pos, count, target);
00082
00083 if(ih == null)
00084 throw new ClassGenException("Couldn't find target instruction: " + bi);
00085
00086 bi.setTarget(ih);
00087
00088
00089 if(bi instanceof Select) {
00090 Select s = (Select)bi;
00091 int[] indices = s.getIndices();
00092
00093 for(int j=0; j < indices.length; j++) {
00094 target = bi.position + indices[j];
00095 ih = findHandle(ihs, pos, count, target);
00096
00097 if(ih == null)
00098 throw new ClassGenException("Couldn't find instruction target: " + bi);
00099
00100 s.setTarget(j, ih);
00101 }
00102 }
00103 }
00104 }
00105 }
00106
00107
00108
00109
00110 public InstructionList(BranchInstruction i) {
00111 append(i);
00112 }
00113
00114
00115
00116
00117
00118
00119 public InstructionList(CompoundInstruction c) {
00120 append(c.getInstructionList());
00121 }
00122
00123
00124
00125
00126 public InstructionList(Instruction i) {
00127 append(i);
00128 }
00129
00130
00131
00132
00133
00134
00135 public BranchHandle append(BranchInstruction i) {
00136 BranchHandle ih = BranchHandle.getBranchHandle(i);
00137 append(ih);
00138
00139 return ih;
00140 }
00141
00142
00143
00144
00145
00146
00147 public InstructionHandle append(CompoundInstruction c) {
00148 return append(c.getInstructionList());
00149 }
00150
00151
00152
00153
00154
00155
00156 public InstructionHandle append(Instruction i) {
00157 InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
00158 append(ih);
00159
00160 return ih;
00161 }
00162
00163
00164
00165
00166
00167
00168
00169 public InstructionHandle append(Instruction i, CompoundInstruction c) {
00170 return append(i, c.getInstructionList());
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180 public InstructionHandle append(Instruction i, Instruction j) {
00181 return append(i, new InstructionList(j));
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191 public InstructionHandle append(Instruction i, InstructionList il) {
00192 InstructionHandle ih;
00193
00194 if((ih = findInstruction2(i)) == null)
00195 throw new ClassGenException("Instruction " + i +
00196 " is not contained in this list.");
00197
00198 return append(ih, il);
00199 }
00200
00201
00202
00203
00204
00205 private void append(InstructionHandle ih) {
00206 if(isEmpty()) {
00207 start = end = ih;
00208 ih.next = ih.prev = null;
00209 }
00210 else {
00211 end.next = ih;
00212 ih.prev = end;
00213 ih.next = null;
00214 end = ih;
00215 }
00216
00217 length++;
00218 }
00219
00220
00221
00222
00223
00224
00225
00226 public BranchHandle append(InstructionHandle ih, BranchInstruction i) {
00227 BranchHandle bh = BranchHandle.getBranchHandle(i);
00228 InstructionList il = new InstructionList();
00229 il.append(bh);
00230
00231 append(ih, il);
00232
00233 return bh;
00234 }
00235
00236
00237
00238
00239
00240
00241
00242 public InstructionHandle append(InstructionHandle ih, CompoundInstruction c) {
00243 return append(ih, c.getInstructionList());
00244 }
00245
00246
00247
00248
00249
00250
00251
00252 public InstructionHandle append(InstructionHandle ih, Instruction i) {
00253 return append(ih, new InstructionList(i));
00254 }
00255
00256
00257
00258
00259
00260
00261
00262
00263 public InstructionHandle append(InstructionHandle ih,
00264 InstructionList il) {
00265 if(il == null)
00266 throw new ClassGenException("Appending null InstructionList");
00267
00268 if(il.isEmpty())
00269 return ih;
00270
00271 InstructionHandle next = ih.next, ret = il.start;
00272
00273 ih.next = il.start;
00274 il.start.prev = ih;
00275
00276 il.end.next = next;
00277
00278 if(next != null)
00279 next.prev = il.end;
00280 else
00281 end = il.end;
00282
00283 length += il.length;
00284
00285 il.clear();
00286
00287 return ret;
00288 }
00289
00290
00291
00292
00293
00294
00295 public InstructionHandle append(InstructionList il) {
00296 if(il == null)
00297 throw new ClassGenException("Appending null InstructionList");
00298
00299 if(il.isEmpty())
00300 return null;
00301
00302 if(isEmpty()) {
00303 start = il.start;
00304 end = il.end;
00305 length = il.length;
00306
00307 il.clear();
00308
00309 return start;
00310 }
00311 else
00312 return append(end, il);
00313 }
00314 private void clear() {
00315 start = end = null;
00316 length = 0;
00317 }
00318 public boolean contains(Instruction i) {
00319 return findInstruction1(i) != null;
00320 }
00321 public boolean contains(InstructionHandle i) {
00322 for(InstructionHandle ih=start; ih != null; ih = ih.next)
00323 if(ih == i)
00324 return true;
00325
00326 return false;
00327 }
00328
00329
00330
00331 public InstructionList copy() {
00332 Hashtable map = new Hashtable();
00333 InstructionList il = new InstructionList();
00334
00335
00336
00337
00338
00339 for(InstructionHandle ih=start; ih != null; ih = ih.next) {
00340 Instruction i = ih.instruction;
00341 Instruction c = i.copy();
00342
00343 map.put(ih, il.append(c));
00344 }
00345
00346
00347
00348 InstructionHandle ih=start;
00349 InstructionHandle ch=il.start;
00350
00351 while(ih != null) {
00352 Instruction i = ih.instruction;
00353 Instruction c = ch.instruction;
00354
00355 if(i instanceof BranchInstruction) {
00356 BranchInstruction bi = (BranchInstruction)i;
00357 BranchInstruction bc = (BranchInstruction)c;
00358 InstructionHandle itarget = bi.getTarget();
00359
00360
00361 bc.setTarget((InstructionHandle)map.get(itarget));
00362
00363 if(bi instanceof Select) {
00364 InstructionHandle[] itargets = ((Select)bi).getTargets();
00365 InstructionHandle[] ctargets = ((Select)bc).getTargets();
00366
00367 for(int j=0; j < itargets.length; j++) {
00368 ctargets[j] = (InstructionHandle)map.get(itargets[j]);
00369 }
00370 }
00371 }
00372
00373 ih = ih.next;
00374 ch = ch.next;
00375 }
00376
00377 return il;
00378 }
00379
00380
00381
00382
00383
00384
00385 public void delete(Instruction i) throws TargetLostException {
00386 InstructionHandle ih;
00387
00388 if((ih = findInstruction1(i)) == null)
00389 throw new ClassGenException("Instruction " + i +
00390 " is not contained in this list.");
00391 delete(ih);
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401 public void delete(Instruction from, Instruction to) throws TargetLostException {
00402 InstructionHandle from_ih, to_ih;
00403
00404 if((from_ih = findInstruction1(from)) == null)
00405 throw new ClassGenException("Instruction " + from +
00406 " is not contained in this list.");
00407
00408 if((to_ih = findInstruction2(to)) == null)
00409 throw new ClassGenException("Instruction " + to +
00410 " is not contained in this list.");
00411 delete(from_ih, to_ih);
00412 }
00413
00414
00415
00416
00417
00418
00419 public void delete(InstructionHandle ih) throws TargetLostException {
00420 remove(ih.prev, ih.next);
00421 }
00422
00423
00424
00425
00426
00427
00428
00429
00430 public void delete(InstructionHandle from, InstructionHandle to)
00431 throws TargetLostException
00432 {
00433 remove(from.prev, to.next);
00434 }
00435
00436
00437
00438
00439
00440 public void dispose() {
00441
00442 for(InstructionHandle ih=end; ih != null; ih = ih.prev)
00443
00444
00445
00446 ih.dispose();
00447
00448 clear();
00449 }
00450
00451
00452
00453 public Enumeration elements() {
00454 return new Enumeration() {
00455 private InstructionHandle ih = start;
00456
00457 public Object nextElement() {
00458 InstructionHandle i = ih;
00459 ih = ih.next;
00460 return i;
00461 }
00462
00463 public boolean hasMoreElements() { return ih != null; }
00464 };
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 public static InstructionHandle findHandle(InstructionHandle[] ihs,
00477 int[] pos, int count,
00478 int target) {
00479 int l=0, r = count - 1;
00480
00481
00482
00483 do {
00484 int i = (l + r) / 2;
00485 int j = pos[i];
00486
00487 if(j == target)
00488 return ihs[i];
00489 else if(target < j)
00490 r = i - 1;
00491 else
00492 l = i + 1;
00493 } while(l <= r);
00494
00495 return null;
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505 public InstructionHandle findHandle(int pos) {
00506 InstructionHandle[] ihs = getInstructionHandles();
00507 return findHandle(ihs, byte_positions, length, pos);
00508 }
00509
00510
00511
00512
00513
00514
00515 private InstructionHandle findInstruction1(Instruction i) {
00516 for(InstructionHandle ih=start; ih != null; ih = ih.next)
00517 if(ih.instruction == i)
00518 return ih;
00519
00520 return null;
00521 }
00522
00523
00524
00525
00526
00527
00528 private InstructionHandle findInstruction2(Instruction i) {
00529 for(InstructionHandle ih=end; ih != null; ih = ih.prev)
00530 if(ih.instruction == i)
00531 return ih;
00532
00533 return null;
00534 }
00535
00536
00537
00538 public byte[] getByteCode() {
00539
00540 setPositions();
00541
00542 ByteArrayOutputStream b = new ByteArrayOutputStream();
00543 DataOutputStream out = new DataOutputStream(b);
00544
00545 try {
00546 for(InstructionHandle ih=start; ih != null; ih = ih.next) {
00547 Instruction i = ih.instruction;
00548 i.dump(out);
00549 }
00550 } catch(IOException e) {
00551 System.err.println(e);
00552 return null;
00553 }
00554
00555 return b.toByteArray();
00556 }
00557
00558
00559
00560 public InstructionHandle getEnd() { return end; }
00561
00562
00563
00564 public InstructionHandle[] getInstructionHandles() {
00565 InstructionHandle[] ihs = new InstructionHandle[length];
00566 InstructionHandle ih = start;
00567
00568 for(int i=0; i < length; i++) {
00569 ihs[i] = ih;
00570 ih = ih.next;
00571 }
00572
00573 return ihs;
00574 }
00575
00576
00577
00578
00579
00580
00581
00582 public int[] getInstructionPositions() { return byte_positions; }
00583
00584
00585
00586 public int getLength() { return length; }
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 public InstructionHandle getStart() { return start; }
00598
00599
00600
00601
00602
00603
00604 public BranchHandle insert(BranchInstruction i) {
00605 BranchHandle ih = BranchHandle.getBranchHandle(i);
00606 insert(ih);
00607 return ih;
00608 }
00609
00610
00611
00612
00613
00614
00615 public InstructionHandle insert(CompoundInstruction c) {
00616 return insert(c.getInstructionList());
00617 }
00618
00619
00620
00621
00622
00623
00624 public InstructionHandle insert(Instruction i) {
00625 InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
00626 insert(ih);
00627
00628 return ih;
00629 }
00630
00631
00632
00633
00634
00635
00636
00637 public InstructionHandle insert(Instruction i, CompoundInstruction c) {
00638 return insert(i, c.getInstructionList());
00639 }
00640
00641
00642
00643
00644
00645
00646
00647
00648 public InstructionHandle insert(Instruction i, Instruction j) {
00649 return insert(i, new InstructionList(j));
00650 }
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 public InstructionHandle insert(Instruction i, InstructionList il) {
00661 InstructionHandle ih;
00662
00663 if((ih = findInstruction1(i)) == null)
00664 throw new ClassGenException("Instruction " + i +
00665 " is not contained in this list.");
00666
00667 return insert(ih, il);
00668 }
00669
00670
00671
00672
00673
00674 private void insert(InstructionHandle ih) {
00675 if(isEmpty()) {
00676 start = end = ih;
00677 ih.next = ih.prev = null;
00678 }
00679 else {
00680 start.prev = ih;
00681 ih.next = start;
00682 ih.prev = null;
00683 start = ih;
00684 }
00685
00686 length++;
00687 }
00688
00689
00690
00691
00692
00693
00694
00695 public BranchHandle insert(InstructionHandle ih, BranchInstruction i) {
00696 BranchHandle bh = BranchHandle.getBranchHandle(i);
00697 InstructionList il = new InstructionList();
00698 il.append(bh);
00699
00700 insert(ih, il);
00701
00702 return bh;
00703 }
00704
00705
00706
00707
00708
00709
00710
00711 public InstructionHandle insert(InstructionHandle ih, CompoundInstruction c) {
00712 return insert(ih, c.getInstructionList());
00713 }
00714
00715
00716
00717
00718
00719
00720
00721 public InstructionHandle insert(InstructionHandle ih, Instruction i) {
00722 return insert(ih, new InstructionList(i));
00723 }
00724
00725
00726
00727
00728
00729
00730
00731
00732 public InstructionHandle insert(InstructionHandle ih, InstructionList il) {
00733 if(il == null)
00734 throw new ClassGenException("Inserting null InstructionList");
00735
00736 if(il.isEmpty())
00737 return ih;
00738
00739 InstructionHandle prev = ih.prev, ret = il.start;
00740
00741 ih.prev = il.end;
00742 il.end.next = ih;
00743
00744 il.start.prev = prev;
00745
00746 if(prev != null)
00747 prev.next = il.start;
00748 else
00749 start = il.start;
00750
00751 length += il.length;
00752
00753 il.clear();
00754
00755 return ret;
00756 }
00757
00758
00759
00760
00761
00762
00763 public InstructionHandle insert(InstructionList il) {
00764 if(isEmpty()) {
00765 append(il);
00766 return start;
00767 }
00768 else
00769 return insert(start, il);
00770 }
00771
00772
00773
00774 public boolean isEmpty() { return start == null; }
00775
00776
00777
00778
00779
00780
00781
00782 public void redirectBranches(InstructionHandle old_target,
00783 InstructionHandle new_target) {
00784 for(InstructionHandle ih = start; ih != null; ih = ih.next) {
00785 Instruction i = ih.getInstruction();
00786
00787 if(i instanceof BranchInstruction) {
00788 BranchInstruction b = (BranchInstruction)i;
00789 InstructionHandle target = b.getTarget();
00790
00791 if(target == old_target)
00792 b.setTarget(new_target);
00793
00794 if(b instanceof Select) {
00795 InstructionHandle[] targets = ((Select)b).getTargets();
00796
00797 for(int j=0; j < targets.length; j++)
00798 if(targets[j] == old_target)
00799 targets[j] = new_target;
00800 }
00801 }
00802 }
00803 }
00804
00805
00806
00807
00808
00809
00810
00811
00812 public void redirectExceptionHandlers(CodeExceptionGen[] exceptions,
00813 InstructionHandle old_target,
00814 InstructionHandle new_target) {
00815 for(int i=0; i < exceptions.length; i++) {
00816 if(exceptions[i].getStartPC() == old_target)
00817 exceptions[i].setStartPC(new_target);
00818
00819 if(exceptions[i].getEndPC() == old_target)
00820 exceptions[i].setEndPC(new_target);
00821
00822 if(exceptions[i].getHandlerPC() == old_target)
00823 exceptions[i].setHandlerPC(new_target);
00824 }
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834 public void redirectLocalVariables(LocalVariableGen[] lg,
00835 InstructionHandle old_target,
00836 InstructionHandle new_target) {
00837 for(int i=0; i < lg.length; i++) {
00838 InstructionHandle start = lg[i].getStart();
00839 InstructionHandle end = lg[i].getEnd();
00840
00841 if(start == old_target)
00842 lg[i].setStart(new_target);
00843
00844 if(end == old_target)
00845 lg[i].setEnd(new_target);
00846 }
00847 }
00848
00849
00850
00851
00852
00853
00854
00855
00856 private void remove(InstructionHandle prev, InstructionHandle next)
00857 throws TargetLostException
00858 {
00859 InstructionHandle first, last;
00860
00861 if((prev == null) && (next == null)) {
00862 first = last = start;
00863 start = end = null;
00864 } else {
00865 if(prev == null) {
00866 first = start;
00867 start = next;
00868 } else {
00869 first = prev.next;
00870 prev.next = next;
00871 }
00872
00873 if(next == null) {
00874 last = end;
00875 end = prev;
00876 } else {
00877 last = next.prev;
00878 next.prev = prev;
00879 }
00880 }
00881
00882 first.prev = null;
00883 last.next = null;
00884
00885 Vector target_vec = new Vector();
00886
00887 for(InstructionHandle ih=first; ih != null; ih = ih.next)
00888 ih.getInstruction().dispose();
00889
00890 StringBuffer buf = new StringBuffer("{ ");
00891 for(InstructionHandle ih=first; ih != null; ih = next) {
00892 next = ih.next;
00893 length--;
00894
00895 if(ih.hasTargeters()) {
00896 target_vec.addElement(ih);
00897 buf.append(ih.toString(true) + " ");
00898 ih.next = ih.prev = null;
00899 } else
00900 ih.dispose();
00901 }
00902
00903 buf.append("}");
00904
00905 if(!target_vec.isEmpty()) {
00906 InstructionHandle[] targeted = new InstructionHandle[target_vec.size()];
00907 target_vec.copyInto(targeted);
00908 throw new TargetLostException(targeted, buf.toString());
00909 }
00910 }
00911 public void setPositions() {
00912 setPositions(false);
00913 }
00914
00915
00916
00917
00918
00919
00920
00921 public void setPositions(boolean check) {
00922 int max_additional_bytes = 0, additional_bytes = 0;
00923 int index = 0, count = 0;
00924 int[] pos = new int[length];
00925
00926
00927
00928 if(check) {
00929 for(InstructionHandle ih=start; ih != null; ih = ih.next) {
00930 Instruction i = ih.instruction;
00931
00932 if(i instanceof BranchInstruction) {
00933 Instruction inst = ((BranchInstruction)i).getTarget().instruction;
00934 if(!contains(inst))
00935 throw new ClassGenException("Branch target of " + OPCODE_NAMES[i.tag] + ":" +
00936 inst + " not in instruction list");
00937
00938 if(i instanceof Select) {
00939 InstructionHandle[] targets = ((Select)i).getTargets();
00940
00941 for(int j=0; j < targets.length; j++) {
00942 inst = targets[j].instruction;
00943 if(!contains(inst))
00944 throw new ClassGenException("Branch target of " + OPCODE_NAMES[i.tag] + ":" +
00945 inst + " not in instruction list");
00946 }
00947 }
00948
00949 if(!(ih instanceof BranchHandle))
00950 throw new ClassGenException("Branch instruction " + OPCODE_NAMES[i.tag] + ":" +
00951 inst + " not contained in BranchHandle.");
00952
00953 }
00954 }
00955 }
00956
00957
00958
00959
00960 for(InstructionHandle ih=start; ih != null; ih = ih.next) {
00961 Instruction i = ih.instruction;
00962
00963 ih.setPosition(index);
00964 pos[count++] = index;
00965
00966
00967
00968
00969
00970
00971 switch(i.getTag()) {
00972 case JSR: case GOTO: max_additional_bytes += 2; break;
00973 case TABLESWITCH: case LOOKUPSWITCH: max_additional_bytes += 3; break;
00974 }
00975
00976 index += i.getLength();
00977 }
00978
00979
00980
00981
00982
00983 for(InstructionHandle ih=start; ih != null; ih = ih.next)
00984 additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes);
00985
00986
00987
00988
00989 index=count=0;
00990 for(InstructionHandle ih=start; ih != null; ih = ih.next) {
00991 Instruction i = ih.instruction;
00992
00993 ih.setPosition(index);
00994 pos[count++] = index;
00995 index += i.getLength();
00996 }
00997
00998 byte_positions = pos;
00999 }
01000
01001
01002
01003 public int size() { return length; }
01004 public String toString() {
01005 return toString(true);
01006 }
01007
01008
01009
01010
01011 public String toString(boolean verbose) {
01012 StringBuffer buf = new StringBuffer();
01013
01014 for(InstructionHandle ih=start; ih != null; ih = ih.next) {
01015 buf.append(ih.toString(verbose) + "\n");
01016 }
01017
01018 return buf.toString();
01019 }
01020 }