1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.NoSuchElementException;
29
30 import org.apache.bcel.Const;
31 import org.apache.bcel.classfile.Constant;
32 import org.apache.bcel.util.ByteSequence;
33 import org.apache.commons.lang3.ArrayUtils;
34 import org.apache.commons.lang3.stream.Streams;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class InstructionList implements Iterable<InstructionHandle> {
50
51
52
53
54
55
56
57
58
59
60 public static InstructionHandle findHandle(final InstructionHandle[] ihs, final int[] pos, final int count, final int target) {
61 if (ihs != null && pos != null) {
62 int l = 0;
63 int r = count - 1;
64
65
66
67 do {
68 final int i = l + r >>> 1;
69 final int j = pos[i];
70 if (j == target) {
71 return ihs[i];
72 }
73 if (target < j) {
74 r = i - 1;
75 } else {
76 l = i + 1;
77 }
78 } while (l <= r);
79 }
80 return null;
81 }
82
83 private InstructionHandle start;
84 private InstructionHandle end;
85 private int length;
86
87 private int[] bytePositions;
88
89 private List<InstructionListObserver> observers;
90
91
92
93
94 public InstructionList() {
95 }
96
97
98
99
100
101
102 public InstructionList(final BranchInstruction i) {
103 append(i);
104 }
105
106
107
108
109
110
111 public InstructionList(final byte[] code) {
112 int count = 0;
113 int[] pos;
114 InstructionHandle[] ihs;
115 try (ByteSequence bytes = new ByteSequence(code)) {
116 ihs = new InstructionHandle[code.length];
117 pos = new int[code.length];
118
119
120
121 while (bytes.available() > 0) {
122
123 final int off = bytes.getIndex();
124 pos[count] = off;
125
126
127
128 final Instruction i = Instruction.readInstruction(bytes);
129 InstructionHandle ih;
130 if (i instanceof BranchInstruction) {
131 ih = append((BranchInstruction) i);
132 } else {
133 ih = append(i);
134 }
135 ih.setPosition(off);
136 ihs[count] = ih;
137 count++;
138 }
139 } catch (final IOException e) {
140 throw new ClassGenException(e.toString(), e);
141 }
142 bytePositions = Arrays.copyOf(pos, count);
143
144
145
146 for (int i = 0; i < count; i++) {
147 if (ihs[i] instanceof BranchHandle) {
148 final BranchInstruction bi = (BranchInstruction) ihs[i].getInstruction();
149 int target = bi.getPosition() + bi.getIndex();
150
151
152
153 InstructionHandle ih = findHandle(ihs, pos, count, target);
154 if (ih == null) {
155 throw new ClassGenException("Couldn't find target for branch: " + bi);
156 }
157 bi.setTarget(ih);
158
159 if (bi instanceof Select) {
160 final Select s = (Select) bi;
161 final int[] indices = s.getIndices();
162 for (int j = 0; j < indices.length; j++) {
163 target = bi.getPosition() + indices[j];
164 ih = findHandle(ihs, pos, count, target);
165 if (ih == null) {
166 throw new ClassGenException("Couldn't find target for switch: " + bi);
167 }
168 s.setTarget(j, ih);
169 }
170 }
171 }
172 }
173 }
174
175
176
177
178
179
180 public InstructionList(final CompoundInstruction c) {
181 append(c.getInstructionList());
182 }
183
184
185
186
187
188
189 public InstructionList(final Instruction i) {
190 append(i);
191 }
192
193
194
195
196 public void addObserver(final InstructionListObserver o) {
197 if (observers == null) {
198 observers = new ArrayList<>();
199 }
200 observers.add(o);
201 }
202
203
204
205
206
207
208
209 public BranchHandle append(final BranchInstruction i) {
210 final BranchHandle ih = BranchHandle.getBranchHandle(i);
211 append(ih);
212 return ih;
213 }
214
215
216
217
218
219
220
221 public InstructionHandle append(final CompoundInstruction c) {
222 return append(c.getInstructionList());
223 }
224
225
226
227
228
229
230
231 public InstructionHandle append(final Instruction i) {
232 final InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
233 append(ih);
234 return ih;
235 }
236
237
238
239
240
241
242
243
244 public InstructionHandle append(final Instruction i, final CompoundInstruction c) {
245 return append(i, c.getInstructionList());
246 }
247
248
249
250
251
252
253
254
255 public InstructionHandle append(final Instruction i, final Instruction j) {
256 return append(i, new InstructionList(j));
257 }
258
259
260
261
262
263
264
265
266 public InstructionHandle append(final Instruction i, final InstructionList il) {
267 InstructionHandle ih;
268 if ((ih = findInstruction2(i)) == null) {
269 throw new ClassGenException("Instruction " + i + " is not contained in this list.");
270 }
271 return append(ih, il);
272 }
273
274
275
276
277
278
279 private void append(final InstructionHandle ih) {
280 if (isEmpty()) {
281 start = end = ih;
282 ih.setNext(ih.setPrev(null));
283 } else {
284 end.setNext(ih);
285 ih.setPrev(end);
286 ih.setNext(null);
287 end = ih;
288 }
289 length++;
290 }
291
292
293
294
295
296
297
298
299 public BranchHandle append(final InstructionHandle ih, final BranchInstruction i) {
300 final BranchHandle bh = BranchHandle.getBranchHandle(i);
301 final InstructionList il = new InstructionList();
302 il.append(bh);
303 append(ih, il);
304 return bh;
305 }
306
307
308
309
310
311
312
313
314 public InstructionHandle append(final InstructionHandle ih, final CompoundInstruction c) {
315 return append(ih, c.getInstructionList());
316 }
317
318
319
320
321
322
323
324
325 public InstructionHandle append(final InstructionHandle ih, final Instruction i) {
326 return append(ih, new InstructionList(i));
327 }
328
329
330
331
332
333
334
335
336
337 public InstructionHandle append(final InstructionHandle ih, final InstructionList il) {
338 if (il == null) {
339 throw new ClassGenException("Appending null InstructionList");
340 }
341 if (il.isEmpty()) {
342 return ih;
343 }
344 final InstructionHandle next = ih.getNext();
345 final InstructionHandle ret = il.start;
346 ih.setNext(il.start);
347 il.start.setPrev(ih);
348 il.end.setNext(next);
349 if (next != null) {
350 next.setPrev(il.end);
351 } else {
352 end = il.end;
353 }
354 length += il.length;
355 il.clear();
356 return ret;
357 }
358
359
360
361
362
363
364
365 public InstructionHandle append(final InstructionList il) {
366 if (il == null) {
367 throw new ClassGenException("Appending null InstructionList");
368 }
369 if (il.isEmpty()) {
370 return null;
371 }
372 if (isEmpty()) {
373 start = il.start;
374 end = il.end;
375 length = il.length;
376 il.clear();
377 return start;
378 }
379 return append(end, il);
380 }
381
382 private void clear() {
383 start = end = null;
384 length = 0;
385 }
386
387 public boolean contains(final Instruction i) {
388 return findInstruction1(i) != null;
389 }
390
391 public boolean contains(final InstructionHandle i) {
392 if (i == null) {
393 return false;
394 }
395 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
396 if (ih == i) {
397 return true;
398 }
399 }
400 return false;
401 }
402
403
404
405
406 public InstructionList copy() {
407 final Map<InstructionHandle, InstructionHandle> map = new HashMap<>();
408 final InstructionList il = new InstructionList();
409
410
411
412
413 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
414 final Instruction i = ih.getInstruction();
415 final Instruction c = i.copy();
416 if (c instanceof BranchInstruction) {
417 map.put(ih, il.append((BranchInstruction) c));
418 } else {
419 map.put(ih, il.append(c));
420 }
421 }
422
423
424
425 InstructionHandle ih = start;
426 InstructionHandle ch = il.start;
427 while (ih != null) {
428 final Instruction i = ih.getInstruction();
429 final Instruction c = ch.getInstruction();
430 if (i instanceof BranchInstruction) {
431 final BranchInstruction bi = (BranchInstruction) i;
432 final BranchInstruction bc = (BranchInstruction) c;
433 final InstructionHandle itarget = bi.getTarget();
434
435 bc.setTarget(map.get(itarget));
436 if (bi instanceof Select) {
437 final InstructionHandle[] itargets = ((Select) bi).getTargets();
438 final InstructionHandle[] ctargets = ((Select) bc).getTargets();
439 for (int j = 0; j < itargets.length; j++) {
440 ctargets[j] = map.get(itargets[j]);
441 }
442 }
443 }
444 ih = ih.getNext();
445 ch = ch.getNext();
446 }
447 return il;
448 }
449
450
451
452
453
454
455 public void delete(final Instruction i) throws TargetLostException {
456 InstructionHandle ih;
457 if ((ih = findInstruction1(i)) == null) {
458 throw new ClassGenException("Instruction " + i + " is not contained in this list.");
459 }
460 delete(ih);
461 }
462
463
464
465
466
467
468
469
470 public void delete(final Instruction from, final Instruction to) throws TargetLostException {
471 InstructionHandle fromIh;
472 InstructionHandle toIh;
473 if ((fromIh = findInstruction1(from)) == null) {
474 throw new ClassGenException("Instruction " + from + " is not contained in this list.");
475 }
476 if ((toIh = findInstruction2(to)) == null) {
477 throw new ClassGenException("Instruction " + to + " is not contained in this list.");
478 }
479 delete(fromIh, toIh);
480 }
481
482
483
484
485
486
487 public void delete(final InstructionHandle ih) throws TargetLostException {
488 remove(ih.getPrev(), ih.getNext());
489 }
490
491
492
493
494
495
496
497
498 public void delete(final InstructionHandle from, final InstructionHandle to) throws TargetLostException {
499 remove(from.getPrev(), to.getNext());
500 }
501
502
503
504
505
506 public void dispose() {
507
508 for (InstructionHandle ih = end; ih != null; ih = ih.getPrev()) {
509
510 ih.dispose();
511 }
512 clear();
513 }
514
515
516
517
518
519
520
521
522 public InstructionHandle findHandle(final int pos) {
523 final int[] positions = bytePositions;
524 InstructionHandle ih = start;
525 for (int i = 0; i < length; i++) {
526 if (positions[i] == pos) {
527 return ih;
528 }
529 ih = ih.getNext();
530 }
531 return null;
532 }
533
534
535
536
537
538
539
540 private InstructionHandle findInstruction1(final Instruction i) {
541 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
542 if (ih.getInstruction() == i) {
543 return ih;
544 }
545 }
546 return null;
547 }
548
549
550
551
552
553
554
555 private InstructionHandle findInstruction2(final Instruction i) {
556 for (InstructionHandle ih = end; ih != null; ih = ih.getPrev()) {
557 if (ih.getInstruction() == i) {
558 return ih;
559 }
560 }
561 return null;
562 }
563
564
565
566
567
568
569 public byte[] getByteCode() {
570
571 setPositions();
572 final ByteArrayOutputStream b = new ByteArrayOutputStream();
573 final DataOutputStream out = new DataOutputStream(b);
574 try {
575 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
576 final Instruction i = ih.getInstruction();
577 i.dump(out);
578 }
579 out.flush();
580 } catch (final IOException e) {
581 System.err.println(e);
582 return ArrayUtils.EMPTY_BYTE_ARRAY;
583 }
584 return b.toByteArray();
585 }
586
587
588
589
590 public InstructionHandle getEnd() {
591 return end;
592 }
593
594
595
596
597 public InstructionHandle[] getInstructionHandles() {
598 final InstructionHandle[] ihs = new InstructionHandle[length];
599 InstructionHandle ih = start;
600 for (int i = 0; i < length; i++) {
601 ihs[i] = ih;
602 ih = ih.getNext();
603 }
604 return ihs;
605 }
606
607
608
609
610
611
612
613 public int[] getInstructionPositions() {
614 return bytePositions;
615 }
616
617
618
619
620 public Instruction[] getInstructions() {
621 final List<Instruction> instructions = new ArrayList<>();
622 try (ByteSequence bytes = new ByteSequence(getByteCode())) {
623 while (bytes.available() > 0) {
624 instructions.add(Instruction.readInstruction(bytes));
625 }
626 } catch (final IOException e) {
627 throw new ClassGenException(e.toString(), e);
628 }
629 return instructions.toArray(Instruction.EMPTY_ARRAY);
630 }
631
632
633
634
635 public int getLength() {
636 return length;
637 }
638
639
640
641
642 public InstructionHandle getStart() {
643 return start;
644 }
645
646
647
648
649
650
651
652 public BranchHandle insert(final BranchInstruction i) {
653 final BranchHandle ih = BranchHandle.getBranchHandle(i);
654 insert(ih);
655 return ih;
656 }
657
658
659
660
661
662
663
664 public InstructionHandle insert(final CompoundInstruction c) {
665 return insert(c.getInstructionList());
666 }
667
668
669
670
671
672
673
674 public InstructionHandle insert(final Instruction i) {
675 final InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
676 insert(ih);
677 return ih;
678 }
679
680
681
682
683
684
685
686
687 public InstructionHandle insert(final Instruction i, final CompoundInstruction c) {
688 return insert(i, c.getInstructionList());
689 }
690
691
692
693
694
695
696
697
698 public InstructionHandle insert(final Instruction i, final Instruction j) {
699 return insert(i, new InstructionList(j));
700 }
701
702
703
704
705
706
707
708
709 public InstructionHandle insert(final Instruction i, final InstructionList il) {
710 InstructionHandle ih;
711 if ((ih = findInstruction1(i)) == null) {
712 throw new ClassGenException("Instruction " + i + " is not contained in this list.");
713 }
714 return insert(ih, il);
715 }
716
717
718
719
720
721
722 private void insert(final InstructionHandle ih) {
723 if (isEmpty()) {
724 start = end = ih;
725 ih.setNext(ih.setPrev(null));
726 } else {
727 start.setPrev(ih);
728 ih.setNext(start);
729 ih.setPrev(null);
730 start = ih;
731 }
732 length++;
733 }
734
735
736
737
738
739
740
741
742 public BranchHandle insert(final InstructionHandle ih, final BranchInstruction i) {
743 final BranchHandle bh = BranchHandle.getBranchHandle(i);
744 final InstructionList il = new InstructionList();
745 il.append(bh);
746 insert(ih, il);
747 return bh;
748 }
749
750
751
752
753
754
755
756
757 public InstructionHandle insert(final InstructionHandle ih, final CompoundInstruction c) {
758 return insert(ih, c.getInstructionList());
759 }
760
761
762
763
764
765
766
767
768 public InstructionHandle insert(final InstructionHandle ih, final Instruction i) {
769 return insert(ih, new InstructionList(i));
770 }
771
772
773
774
775
776
777
778
779
780 public InstructionHandle insert(final InstructionHandle ih, final InstructionList il) {
781 if (il == null) {
782 throw new ClassGenException("Inserting null InstructionList");
783 }
784 if (il.isEmpty()) {
785 return ih;
786 }
787 final InstructionHandle prev = ih.getPrev();
788 final InstructionHandle ret = il.start;
789 ih.setPrev(il.end);
790 il.end.setNext(ih);
791 il.start.setPrev(prev);
792 if (prev != null) {
793 prev.setNext(il.start);
794 } else {
795 start = il.start;
796 }
797 length += il.length;
798 il.clear();
799 return ret;
800 }
801
802
803
804
805
806
807
808 public InstructionHandle insert(final InstructionList il) {
809 if (isEmpty()) {
810 append(il);
811 return start;
812 }
813 return insert(start, il);
814 }
815
816
817
818
819 public boolean isEmpty() {
820 return start == null;
821 }
822
823
824
825
826 @Override
827 public Iterator<InstructionHandle> iterator() {
828 return new Iterator<InstructionHandle>() {
829
830 private InstructionHandle ih = start;
831
832 @Override
833 public boolean hasNext() {
834 return ih != null;
835 }
836
837 @Override
838 public InstructionHandle next() throws NoSuchElementException {
839 if (ih == null) {
840 throw new NoSuchElementException();
841 }
842 final InstructionHandle i = ih;
843 ih = ih.getNext();
844 return i;
845 }
846
847 @Override
848 public void remove() {
849 throw new UnsupportedOperationException();
850 }
851 };
852 }
853
854
855
856
857
858
859
860 public void move(final InstructionHandle ih, final InstructionHandle target) {
861 move(ih, ih, target);
862 }
863
864
865
866
867
868
869
870
871
872
873
874
875
876 public void move(final InstructionHandle start, final InstructionHandle end, final InstructionHandle target) {
877
878 if (start == null || end == null) {
879 throw new ClassGenException("Invalid null handle: From " + start + " to " + end);
880 }
881 if (target == start || target == end) {
882 throw new ClassGenException("Invalid range: From " + start + " to " + end + " contains target " + target);
883 }
884 for (InstructionHandle ih = start; ih != end.getNext(); ih = ih.getNext()) {
885 if (ih == null) {
886 throw new ClassGenException("Invalid range: From " + start + " to " + end);
887 }
888 if (ih == target) {
889 throw new ClassGenException("Invalid range: From " + start + " to " + end + " contains target " + target);
890 }
891 }
892
893 final InstructionHandle prev = start.getPrev();
894 InstructionHandle next = end.getNext();
895 if (prev != null) {
896 prev.setNext(next);
897 } else {
898 this.start = next;
899 }
900 if (next != null) {
901 next.setPrev(prev);
902 } else {
903 this.end = prev;
904 }
905 start.setPrev(end.setNext(null));
906
907 if (target == null) {
908 if (this.start != null) {
909 this.start.setPrev(end);
910 }
911 end.setNext(this.start);
912 this.start = start;
913 } else {
914 next = target.getNext();
915 target.setNext(start);
916 start.setPrev(target);
917 end.setNext(next);
918 if (next != null) {
919 next.setPrev(end);
920 } else {
921 this.end = end;
922 }
923 }
924 }
925
926
927
928
929
930
931
932 public void redirectBranches(final InstructionHandle oldTarget, final InstructionHandle newTarget) {
933 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
934 final Instruction i = ih.getInstruction();
935 if (i instanceof BranchInstruction) {
936 final BranchInstruction b = (BranchInstruction) i;
937 final InstructionHandle target = b.getTarget();
938 if (target == oldTarget) {
939 b.setTarget(newTarget);
940 }
941 if (b instanceof Select) {
942 final InstructionHandle[] targets = ((Select) b).getTargets();
943 for (int j = 0; j < targets.length; j++) {
944 if (targets[j] == oldTarget) {
945 ((Select) b).setTarget(j, newTarget);
946 }
947 }
948 }
949 }
950 }
951 }
952
953
954
955
956
957
958
959
960
961 public void redirectExceptionHandlers(final CodeExceptionGen[] exceptions, final InstructionHandle oldTarget, final InstructionHandle newTarget) {
962 Streams.of(exceptions).forEach(exception -> {
963 if (exception.getStartPC() == oldTarget) {
964 exception.setStartPC(newTarget);
965 }
966 if (exception.getEndPC() == oldTarget) {
967 exception.setEndPC(newTarget);
968 }
969 if (exception.getHandlerPC() == oldTarget) {
970 exception.setHandlerPC(newTarget);
971 }
972 });
973 }
974
975
976
977
978
979
980
981
982
983 public void redirectLocalVariables(final LocalVariableGen[] lg, final InstructionHandle oldTarget, final InstructionHandle newTarget) {
984 Streams.of(lg).forEach(element -> {
985 if (element.getStart() == oldTarget) {
986 element.setStart(newTarget);
987 }
988 if (element.getEnd() == oldTarget) {
989 element.setEnd(newTarget);
990 }
991 });
992 }
993
994
995
996
997
998
999
1000
1001 private void remove(final InstructionHandle prev, InstructionHandle next) throws TargetLostException {
1002 InstructionHandle first;
1003 InstructionHandle last;
1004 if (prev == null && next == null) {
1005 first = start;
1006 last = end;
1007 start = end = null;
1008 } else {
1009 if (prev == null) {
1010 first = start;
1011 start = next;
1012 } else {
1013 first = prev.getNext();
1014 prev.setNext(next);
1015 }
1016 if (next == null) {
1017 last = end;
1018 end = prev;
1019 } else {
1020 last = next.getPrev();
1021 next.setPrev(prev);
1022 }
1023 }
1024 first.setPrev(null);
1025 last.setNext(null);
1026 final List<InstructionHandle> targetList = new ArrayList<>();
1027 for (InstructionHandle ih = first; ih != null; ih = ih.getNext()) {
1028 ih.getInstruction().dispose();
1029 }
1030 final StringBuilder buf = new StringBuilder("{ ");
1031 for (InstructionHandle ih = first; ih != null; ih = next) {
1032 next = ih.getNext();
1033 length--;
1034 if (ih.hasTargeters()) {
1035 targetList.add(ih);
1036 buf.append(ih.toString(true)).append(" ");
1037 ih.setNext(ih.setPrev(null));
1038 } else {
1039 ih.dispose();
1040 }
1041 }
1042 buf.append("}");
1043 if (!targetList.isEmpty()) {
1044 throw new TargetLostException(targetList.toArray(InstructionHandle.EMPTY_ARRAY), buf.toString());
1045 }
1046 }
1047
1048
1049
1050
1051 public void removeObserver(final InstructionListObserver o) {
1052 if (observers != null) {
1053 observers.remove(o);
1054 }
1055 }
1056
1057
1058
1059
1060 public void replaceConstantPool(final ConstantPoolGen oldCp, final ConstantPoolGen newCp) {
1061 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
1062 final Instruction i = ih.getInstruction();
1063 if (i instanceof CPInstruction) {
1064 final CPInstruction ci = (CPInstruction) i;
1065 final Constant c = oldCp.getConstant(ci.getIndex());
1066 ci.setIndex(newCp.addConstant(c, oldCp));
1067 }
1068 }
1069 }
1070
1071 public void setPositions() {
1072 setPositions(false);
1073 }
1074
1075
1076
1077
1078
1079
1080 public void setPositions(final boolean check) {
1081 int maxAdditionalBytes = 0;
1082 int additionalBytes = 0;
1083 int index = 0;
1084 int count = 0;
1085 final int[] pos = new int[length];
1086
1087
1088
1089 if (check) {
1090 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
1091 final Instruction i = ih.getInstruction();
1092 if (i instanceof BranchInstruction) {
1093 Instruction inst = ((BranchInstruction) i).getTarget().getInstruction();
1094 if (!contains(inst)) {
1095 throw new ClassGenException("Branch target of " + Const.getOpcodeName(i.getOpcode()) + ":" + inst + " not in instruction list");
1096 }
1097 if (i instanceof Select) {
1098 final InstructionHandle[] targets = ((Select) i).getTargets();
1099 for (final InstructionHandle target : targets) {
1100 inst = target.getInstruction();
1101 if (!contains(inst)) {
1102 throw new ClassGenException("Branch target of " + Const.getOpcodeName(i.getOpcode()) + ":" + inst + " not in instruction list");
1103 }
1104 }
1105 }
1106 if (!(ih instanceof BranchHandle)) {
1107 throw new ClassGenException(
1108 "Branch instruction " + Const.getOpcodeName(i.getOpcode()) + ":" + inst + " not contained in BranchHandle.");
1109 }
1110 }
1111 }
1112 }
1113
1114
1115
1116 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
1117 final Instruction i = ih.getInstruction();
1118 ih.setPosition(index);
1119 pos[count++] = index;
1120
1121
1122
1123
1124 switch (i.getOpcode()) {
1125 case Const.JSR:
1126 case Const.GOTO:
1127 maxAdditionalBytes += 2;
1128 break;
1129 case Const.TABLESWITCH:
1130 case Const.LOOKUPSWITCH:
1131 maxAdditionalBytes += 3;
1132 break;
1133 default:
1134
1135 break;
1136 }
1137 index += i.getLength();
1138 }
1139
1140
1141
1142
1143 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
1144 additionalBytes += ih.updatePosition(additionalBytes, maxAdditionalBytes);
1145 }
1146
1147
1148
1149 index = count = 0;
1150 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
1151 final Instruction i = ih.getInstruction();
1152 ih.setPosition(index);
1153 pos[count++] = index;
1154 index += i.getLength();
1155 }
1156 bytePositions = Arrays.copyOfRange(pos, 0, count);
1157 }
1158
1159
1160
1161
1162 public int size() {
1163 return length;
1164 }
1165
1166 @Override
1167 public String toString() {
1168 return toString(true);
1169 }
1170
1171
1172
1173
1174
1175 public String toString(final boolean verbose) {
1176 final StringBuilder buf = new StringBuilder();
1177 for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
1178 buf.append(ih.toString(verbose)).append("\n");
1179 }
1180 return buf.toString();
1181 }
1182
1183
1184
1185
1186
1187 public void update() {
1188 if (observers != null) {
1189 for (final InstructionListObserver observer : observers) {
1190 observer.notify(this);
1191 }
1192 }
1193 }
1194 }