View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License. 
16   *
17   */
18  package org.apache.bcel.generic;
19  
20  import java.io.ByteArrayOutputStream;
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  import java.io.Serializable;
24  import java.util.ArrayList;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.NoSuchElementException;
30  
31  import org.apache.bcel.Constants;
32  import org.apache.bcel.classfile.Constant;
33  import org.apache.bcel.util.ByteSequence;
34  
35  /** 
36   * This class is a container for a list of <a
37   * href="Instruction.html">Instruction</a> objects. Instructions can
38   * be appended, inserted, moved, deleted, etc.. Instructions are being
39   * wrapped into <a
40   * href="InstructionHandle.html">InstructionHandles</a> objects that
41   * are returned upon append/insert operations. They give the user
42   * (read only) access to the list structure, such that it can be traversed and
43   * manipulated in a controlled way.
44   *
45   * A list is finally dumped to a byte code array with <a
46   * href="#getByteCode()">getByteCode</a>.
47   *
48   * @version $Id: InstructionList.java 1152077 2011-07-29 02:29:42Z dbrosius $
49   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
50   * @see     Instruction
51   * @see     InstructionHandle
52   * @see BranchHandle
53   */
54  public class InstructionList implements Serializable {
55  
56      private static final long serialVersionUID = 2651389055345707857L;
57      private InstructionHandle start = null, end = null;
58      private int length = 0; // number of elements in list
59      private int[] byte_positions; // byte code offsets corresponding to instructions
60  
61  
62      /**
63       * Create (empty) instruction list.
64       */
65      public InstructionList() {
66      }
67  
68  
69      /**
70       * Create instruction list containing one instruction.
71       * @param i initial instruction
72       */
73      public InstructionList(Instruction i) {
74          append(i);
75      }
76  
77  
78      /**
79       * Create instruction list containing one instruction.
80       * @param i initial instruction
81       */
82      public InstructionList(BranchInstruction i) {
83          append(i);
84      }
85  
86  
87      /**
88       * Initialize list with (nonnull) compound instruction. Consumes argument
89       * list, i.e., it becomes empty.
90       *
91       * @param c compound instruction (list)
92       */
93      public InstructionList(CompoundInstruction c) {
94          append(c.getInstructionList());
95      }
96  
97  
98      /**
99       * Test for empty list.
100      */
101     public boolean isEmpty() {
102         return start == null;
103     } // && end == null
104 
105 
106     /**
107      * Find the target instruction (handle) that corresponds to the given target
108      * position (byte code offset).
109      *
110      * @param ihs array of instruction handles, i.e. il.getInstructionHandles()
111      * @param pos array of positions corresponding to ihs, i.e. il.getInstructionPositions()
112      * @param count length of arrays
113      * @param target target position to search for
114      * @return target position's instruction handle if available
115      */
116     public static InstructionHandle findHandle( InstructionHandle[] ihs, int[] pos, int count,
117             int target ) {
118         int l = 0, r = count - 1;
119         /* Do a binary search since the pos array is orderd.
120          */
121         do {
122             int i = (l + r) / 2;
123             int j = pos[i];
124             if (j == target) {
125                 return ihs[i];
126             } else if (target < j) {
127                 r = i - 1;
128             } else {
129                 l = i + 1;
130             }
131         } while (l <= r);
132         return null;
133     }
134 
135 
136     /**
137      * Get instruction handle for instruction at byte code position pos.
138      * This only works properly, if the list is freshly initialized from a byte array or
139      * setPositions() has been called before this method.
140      *
141      * @param pos byte code position to search for
142      * @return target position's instruction handle if available
143      */
144     public InstructionHandle findHandle( int pos ) {
145     	int[] positions = byte_positions;
146         InstructionHandle ih = start;
147         for (int i = 0; i < length; i++) { 
148             if(positions[i] == pos) {
149                 return ih;
150             }
151             ih = ih.next;
152         }
153         return null;
154     }
155 
156 
157     /**
158      * Initialize instruction list from byte array.
159      *
160      * @param code byte array containing the instructions
161      */
162     public InstructionList(byte[] code) {
163         ByteSequence bytes = new ByteSequence(code);
164         InstructionHandle[] ihs = new InstructionHandle[code.length];
165         int[] pos = new int[code.length]; // Can't be more than that
166         int count = 0; // Contains actual length
167         /* Pass 1: Create an object for each byte code and append them
168          * to the list.
169          */
170         try {
171             while (bytes.available() > 0) {
172                 // Remember byte offset and associate it with the instruction
173                 int off = bytes.getIndex();
174                 pos[count] = off;
175                 /* Read one instruction from the byte stream, the byte position is set
176                  * accordingly.
177                  */
178                 Instruction i = Instruction.readInstruction(bytes);
179                 InstructionHandle ih;
180                 if (i instanceof BranchInstruction) {
181                     ih = append((BranchInstruction) i);
182                 } else {
183                     ih = append(i);
184                 }
185                 ih.setPosition(off);
186                 ihs[count] = ih;
187                 count++;
188             }
189         } catch (IOException e) {
190             throw new ClassGenException(e.toString(), e);
191         }
192         byte_positions = new int[count]; // Trim to proper size
193         System.arraycopy(pos, 0, byte_positions, 0, count);
194         /* Pass 2: Look for BranchInstruction and update their targets, i.e.,
195          * convert offsets to instruction handles.
196          */
197         for (int i = 0; i < count; i++) {
198             if (ihs[i] instanceof BranchHandle) {
199                 BranchInstruction bi = (BranchInstruction) ihs[i].instruction;
200                 int target = bi.position + bi.getIndex(); /* Byte code position:
201                  * relative -> absolute. */
202                 // Search for target position
203                 InstructionHandle ih = findHandle(ihs, pos, count, target);
204                 if (ih == null) {
205                     throw new ClassGenException("Couldn't find target for branch: " + bi);
206                 }
207                 bi.setTarget(ih); // Update target
208                 // If it is a Select instruction, update all branch targets
209                 if (bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
210                     Select s = (Select) bi;
211                     int[] indices = s.getIndices();
212                     for (int j = 0; j < indices.length; j++) {
213                         target = bi.position + indices[j];
214                         ih = findHandle(ihs, pos, count, target);
215                         if (ih == null) {
216                             throw new ClassGenException("Couldn't find target for switch: " + bi);
217                         }
218                         s.setTarget(j, ih); // Update target      
219                     }
220                 }
221             }
222         }
223     }
224 
225 
226     /**
227      * Append another list after instruction (handle) ih contained in this list.
228      * Consumes argument list, i.e., it becomes empty.
229      *
230      * @param ih where to append the instruction list 
231      * @param il Instruction list to append to this one
232      * @return instruction handle pointing to the <B>first</B> appended instruction
233      */
234     public InstructionHandle append( InstructionHandle ih, InstructionList il ) {
235         if (il == null) {
236             throw new ClassGenException("Appending null InstructionList");
237         }
238         if (il.isEmpty()) {
239             return ih;
240         }
241         InstructionHandle next = ih.next, ret = il.start;
242         ih.next = il.start;
243         il.start.prev = ih;
244         il.end.next = next;
245         if (next != null) {
246             next.prev = il.end;
247         } else {
248             end = il.end; // Update end ...
249         }
250         length += il.length; // Update length
251         il.clear();
252         return ret;
253     }
254 
255 
256     /**
257      * Append another list after instruction i contained in this list.
258      * Consumes argument list, i.e., it becomes empty.
259      *
260      * @param i  where to append the instruction list 
261      * @param il Instruction list to append to this one
262      * @return instruction handle pointing to the <B>first</B> appended instruction
263      */
264     public InstructionHandle append( Instruction i, InstructionList il ) {
265         InstructionHandle ih;
266         if ((ih = findInstruction2(i)) == null) {
267             throw new ClassGenException("Instruction " + i + " is not contained in this list.");
268         }
269         return append(ih, il);
270     }
271 
272 
273     /**
274      * Append another list to this one.
275      * Consumes argument list, i.e., it becomes empty.
276      *
277      * @param il list to append to end of this list
278      * @return instruction handle of the <B>first</B> appended instruction
279      */
280     public InstructionHandle append( InstructionList il ) {
281         if (il == null) {
282             throw new ClassGenException("Appending null InstructionList");
283         }
284         if (il.isEmpty()) {
285             return null;
286         }
287         if (isEmpty()) {
288             start = il.start;
289             end = il.end;
290             length = il.length;
291             il.clear();
292             return start;
293         } else {
294             return append(end, il); // was end.instruction
295         }
296     }
297 
298 
299     /**
300      * Append an instruction to the end of this list.
301      *
302      * @param ih instruction to append
303      */
304     private void append( InstructionHandle ih ) {
305         if (isEmpty()) {
306             start = end = ih;
307             ih.next = ih.prev = null;
308         } else {
309             end.next = ih;
310             ih.prev = end;
311             ih.next = null;
312             end = ih;
313         }
314         length++; // Update length
315     }
316 
317 
318     /**
319      * Append an instruction to the end of this list.
320      *
321      * @param i instruction to append
322      * @return instruction handle of the appended instruction
323      */
324     public InstructionHandle append( Instruction i ) {
325         InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
326         append(ih);
327         return ih;
328     }
329 
330 
331     /**
332      * Append a branch instruction to the end of this list.
333      *
334      * @param i branch instruction to append
335      * @return branch instruction handle of the appended instruction
336      */
337     public BranchHandle append( BranchInstruction i ) {
338         BranchHandle ih = BranchHandle.getBranchHandle(i);
339         append(ih);
340         return ih;
341     }
342 
343 
344     /**
345      * Append a single instruction j after another instruction i, which
346      * must be in this list of course!
347      *
348      * @param i Instruction in list
349      * @param j Instruction to append after i in list
350      * @return instruction handle of the first appended instruction
351      */
352     public InstructionHandle append( Instruction i, Instruction j ) {
353         return append(i, new InstructionList(j));
354     }
355 
356 
357     /**
358      * Append a compound instruction, after instruction i.
359      *
360      * @param i Instruction in list
361      * @param c The composite instruction (containing an InstructionList)
362      * @return instruction handle of the first appended instruction
363      */
364     public InstructionHandle append( Instruction i, CompoundInstruction c ) {
365         return append(i, c.getInstructionList());
366     }
367 
368 
369     /**
370      * Append a compound instruction.
371      *
372      * @param c The composite instruction (containing an InstructionList)
373      * @return instruction handle of the first appended instruction
374      */
375     public InstructionHandle append( CompoundInstruction c ) {
376         return append(c.getInstructionList());
377     }
378 
379 
380     /**
381      * Append a compound instruction.
382      *
383      * @param ih where to append the instruction list 
384      * @param c The composite instruction (containing an InstructionList)
385      * @return instruction handle of the first appended instruction
386      */
387     public InstructionHandle append( InstructionHandle ih, CompoundInstruction c ) {
388         return append(ih, c.getInstructionList());
389     }
390 
391 
392     /**
393      * Append an instruction after instruction (handle) ih contained in this list.
394      *
395      * @param ih where to append the instruction list 
396      * @param i Instruction to append
397      * @return instruction handle pointing to the <B>first</B> appended instruction
398      */
399     public InstructionHandle append( InstructionHandle ih, Instruction i ) {
400         return append(ih, new InstructionList(i));
401     }
402 
403 
404     /**
405      * Append an instruction after instruction (handle) ih contained in this list.
406      *
407      * @param ih where to append the instruction list 
408      * @param i Instruction to append
409      * @return instruction handle pointing to the <B>first</B> appended instruction
410      */
411     public BranchHandle append( InstructionHandle ih, BranchInstruction i ) {
412         BranchHandle bh = BranchHandle.getBranchHandle(i);
413         InstructionList il = new InstructionList();
414         il.append(bh);
415         append(ih, il);
416         return bh;
417     }
418 
419 
420     /**
421      * Insert another list before Instruction handle ih contained in this list.
422      * Consumes argument list, i.e., it becomes empty.
423      *
424      * @param ih  where to append the instruction list 
425      * @param il Instruction list to insert
426      * @return instruction handle of the first inserted instruction
427      */
428     public InstructionHandle insert( InstructionHandle ih, InstructionList il ) {
429         if (il == null) {
430             throw new ClassGenException("Inserting null InstructionList");
431         }
432         if (il.isEmpty()) {
433             return ih;
434         }
435         InstructionHandle prev = ih.prev, ret = il.start;
436         ih.prev = il.end;
437         il.end.next = ih;
438         il.start.prev = prev;
439         if (prev != null) {
440             prev.next = il.start;
441         } else {
442             start = il.start; // Update start ...
443         }
444         length += il.length; // Update length
445         il.clear();
446         return ret;
447     }
448 
449 
450     /**
451      * Insert another list.   
452      *
453      * @param il list to insert before start of this list
454      * @return instruction handle of the first inserted instruction
455      */
456     public InstructionHandle insert( InstructionList il ) {
457         if (isEmpty()) {
458             append(il); // Code is identical for this case
459             return start;
460         } else {
461             return insert(start, il);
462         }
463     }
464 
465 
466     /**
467      * Insert an instruction at start of this list.
468      *
469      * @param ih instruction to insert
470      */
471     private void insert( InstructionHandle ih ) {
472         if (isEmpty()) {
473             start = end = ih;
474             ih.next = ih.prev = null;
475         } else {
476             start.prev = ih;
477             ih.next = start;
478             ih.prev = null;
479             start = ih;
480         }
481         length++;
482     }
483 
484 
485     /**
486      * Insert another list before Instruction i contained in this list.
487      * Consumes argument list, i.e., it becomes empty.
488      *
489      * @param i  where to append the instruction list 
490      * @param il Instruction list to insert
491      * @return instruction handle pointing to the first inserted instruction,
492      * i.e., il.getStart()
493      */
494     public InstructionHandle insert( Instruction i, InstructionList il ) {
495         InstructionHandle ih;
496         if ((ih = findInstruction1(i)) == null) {
497             throw new ClassGenException("Instruction " + i + " is not contained in this list.");
498         }
499         return insert(ih, il);
500     }
501 
502 
503     /**
504      * Insert an instruction at start of this list.
505      *
506      * @param i instruction to insert
507      * @return instruction handle of the inserted instruction
508      */
509     public InstructionHandle insert( Instruction i ) {
510         InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
511         insert(ih);
512         return ih;
513     }
514 
515 
516     /**
517      * Insert a branch instruction at start of this list.
518      *
519      * @param i branch instruction to insert
520      * @return branch instruction handle of the appended instruction
521      */
522     public BranchHandle insert( BranchInstruction i ) {
523         BranchHandle ih = BranchHandle.getBranchHandle(i);
524         insert(ih);
525         return ih;
526     }
527 
528 
529     /**
530      * Insert a single instruction j before another instruction i, which
531      * must be in this list of course!
532      *
533      * @param i Instruction in list
534      * @param j Instruction to insert before i in list
535      * @return instruction handle of the first inserted instruction
536      */
537     public InstructionHandle insert( Instruction i, Instruction j ) {
538         return insert(i, new InstructionList(j));
539     }
540 
541 
542     /**
543      * Insert a compound instruction before instruction i.
544      *
545      * @param i Instruction in list
546      * @param c The composite instruction (containing an InstructionList)
547      * @return instruction handle of the first inserted instruction
548      */
549     public InstructionHandle insert( Instruction i, CompoundInstruction c ) {
550         return insert(i, c.getInstructionList());
551     }
552 
553 
554     /**
555      * Insert a compound instruction.
556      *
557      * @param c The composite instruction (containing an InstructionList)
558      * @return instruction handle of the first inserted instruction
559      */
560     public InstructionHandle insert( CompoundInstruction c ) {
561         return insert(c.getInstructionList());
562     }
563 
564 
565     /**
566      * Insert an instruction before instruction (handle) ih contained in this list.
567      *
568      * @param ih where to insert to the instruction list 
569      * @param i Instruction to insert
570      * @return instruction handle of the first inserted instruction
571      */
572     public InstructionHandle insert( InstructionHandle ih, Instruction i ) {
573         return insert(ih, new InstructionList(i));
574     }
575 
576 
577     /**
578      * Insert a compound instruction.
579      *
580      * @param ih where to insert the instruction list 
581      * @param c The composite instruction (containing an InstructionList)
582      * @return instruction handle of the first inserted instruction
583      */
584     public InstructionHandle insert( InstructionHandle ih, CompoundInstruction c ) {
585         return insert(ih, c.getInstructionList());
586     }
587 
588 
589     /**
590      * Insert an instruction before instruction (handle) ih contained in this list.
591      *
592      * @param ih where to insert to the instruction list 
593      * @param i Instruction to insert
594      * @return instruction handle of the first inserted instruction
595      */
596     public BranchHandle insert( InstructionHandle ih, BranchInstruction i ) {
597         BranchHandle bh = BranchHandle.getBranchHandle(i);
598         InstructionList il = new InstructionList();
599         il.append(bh);
600         insert(ih, il);
601         return bh;
602     }
603 
604 
605     /**
606      * Take all instructions (handles) from "start" to "end" and append them after the
607      * new location "target". Of course, "end" must be after "start" and target must
608      * not be located withing this range. If you want to move something to the start of
609      * the list use null as value for target.<br>
610      * Any instruction targeters pointing to handles within the block, keep their targets.
611      *
612      * @param start  of moved block
613      * @param end    of moved block
614      * @param target of moved block
615      */
616     public void move( InstructionHandle start, InstructionHandle end, InstructionHandle target ) {
617         // Step 1: Check constraints
618         if ((start == null) || (end == null)) {
619             throw new ClassGenException("Invalid null handle: From " + start + " to " + end);
620         }
621         if ((target == start) || (target == end)) {
622             throw new ClassGenException("Invalid range: From " + start + " to " + end
623                     + " contains target " + target);
624         }
625         for (InstructionHandle ih = start; ih != end.next; ih = ih.next) {
626             if (ih == null) {
627                 throw new ClassGenException("Invalid range: From " + start + " to " + end);
628             } else if (ih == target) {
629                 throw new ClassGenException("Invalid range: From " + start + " to " + end
630                         + " contains target " + target);
631             }
632         }
633         // Step 2: Temporarily remove the given instructions from the list
634         InstructionHandle prev = start.prev, next = end.next;
635         if (prev != null) {
636             prev.next = next;
637         } else {
638             this.start = next;
639         }
640         if (next != null) {
641             next.prev = prev;
642         } else {
643             this.end = prev;
644         }
645         start.prev = end.next = null;
646         // Step 3: append after target
647         if (target == null) { // append to start of list
648             if (this.start != null) {
649                 this.start.prev = end;
650             }
651             end.next = this.start;
652             this.start = start;
653         } else {
654             next = target.next;
655             target.next = start;
656             start.prev = target;
657             end.next = next;
658             if (next != null) {
659                 next.prev = end;
660             } else {
661                 this.end = end;
662             }
663         }
664     }
665 
666 
667     /**
668      * Move a single instruction (handle) to a new location.
669      *
670      * @param ih     moved instruction
671      * @param target new location of moved instruction
672      */
673     public void move( InstructionHandle ih, InstructionHandle target ) {
674         move(ih, ih, target);
675     }
676 
677 
678     /**
679      * Remove from instruction `prev' to instruction `next' both contained
680      * in this list. Throws TargetLostException when one of the removed instruction handles
681      * is still being targeted.
682      *
683      * @param prev where to start deleting (predecessor, exclusive)
684      * @param next where to end deleting (successor, exclusive)
685      */
686     private void remove( InstructionHandle prev, InstructionHandle next )
687             throws TargetLostException {
688         InstructionHandle first, last; // First and last deleted instruction
689         if ((prev == null) && (next == null)) {
690             first = start;
691             last = end;
692             start = end = null;
693         } else {
694             if (prev == null) { // At start of list
695                 first = start;
696                 start = next;
697             } else {
698                 first = prev.next;
699                 prev.next = next;
700             }
701             if (next == null) { // At end of list
702                 last = end;
703                 end = prev;
704             } else {
705                 last = next.prev;
706                 next.prev = prev;
707             }
708         }
709         first.prev = null; // Completely separated from rest of list
710         last.next = null;
711         List<InstructionHandle> target_vec = new ArrayList<InstructionHandle>();
712         for (InstructionHandle ih = first; ih != null; ih = ih.next) {
713             ih.getInstruction().dispose(); // e.g. BranchInstructions release their targets
714         }
715         StringBuilder buf = new StringBuilder("{ ");
716         for (InstructionHandle ih = first; ih != null; ih = next) {
717             next = ih.next;
718             length--;
719             if (ih.hasTargeters()) { // Still got targeters?
720                 target_vec.add(ih);
721                 buf.append(ih.toString(true) + " ");
722                 ih.next = ih.prev = null;
723             } else {
724                 ih.dispose();
725             }
726         }
727         buf.append("}");
728         if (!target_vec.isEmpty()) {
729             InstructionHandle[] targeted = new InstructionHandle[target_vec.size()];
730             target_vec.toArray(targeted);
731             throw new TargetLostException(targeted, buf.toString());
732         }
733     }
734 
735 
736     /**
737      * Remove instruction from this list. The corresponding Instruction
738      * handles must not be reused!
739      *
740      * @param ih instruction (handle) to remove 
741      */
742     public void delete( InstructionHandle ih ) throws TargetLostException {
743         remove(ih.prev, ih.next);
744     }
745 
746 
747     /**
748      * Remove instruction from this list. The corresponding Instruction
749      * handles must not be reused!
750      *
751      * @param i instruction to remove
752      */
753     public void delete( Instruction i ) throws TargetLostException {
754         InstructionHandle ih;
755         if ((ih = findInstruction1(i)) == null) {
756             throw new ClassGenException("Instruction " + i + " is not contained in this list.");
757         }
758         delete(ih);
759     }
760 
761 
762     /**
763      * Remove instructions from instruction `from' to instruction `to' contained
764      * in this list. The user must ensure that `from' is an instruction before
765      * `to', or risk havoc. The corresponding Instruction handles must not be reused!
766      *
767      * @param from where to start deleting (inclusive)
768      * @param to   where to end deleting (inclusive)
769      */
770     public void delete( InstructionHandle from, InstructionHandle to ) throws TargetLostException {
771         remove(from.prev, to.next);
772     }
773 
774 
775     /**
776      * Remove instructions from instruction `from' to instruction `to' contained
777      * in this list. The user must ensure that `from' is an instruction before
778      * `to', or risk havoc. The corresponding Instruction handles must not be reused!
779      *
780      * @param from where to start deleting (inclusive)
781      * @param to   where to end deleting (inclusive)
782      */
783     public void delete( Instruction from, Instruction to ) throws TargetLostException {
784         InstructionHandle from_ih, to_ih;
785         if ((from_ih = findInstruction1(from)) == null) {
786             throw new ClassGenException("Instruction " + from + " is not contained in this list.");
787         }
788         if ((to_ih = findInstruction2(to)) == null) {
789             throw new ClassGenException("Instruction " + to + " is not contained in this list.");
790         }
791         delete(from_ih, to_ih);
792     }
793 
794 
795     /**
796      * Search for given Instruction reference, start at beginning of list.
797      *
798      * @param i instruction to search for
799      * @return instruction found on success, null otherwise
800      */
801     private InstructionHandle findInstruction1( Instruction i ) {
802         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
803             if (ih.instruction == i) {
804                 return ih;
805             }
806         }
807         return null;
808     }
809 
810 
811     /**
812      * Search for given Instruction reference, start at end of list
813      *
814      * @param i instruction to search for
815      * @return instruction found on success, null otherwise
816      */
817     private InstructionHandle findInstruction2( Instruction i ) {
818         for (InstructionHandle ih = end; ih != null; ih = ih.prev) {
819             if (ih.instruction == i) {
820                 return ih;
821             }
822         }
823         return null;
824     }
825 
826 
827     public boolean contains( InstructionHandle i ) {
828         if (i == null) {
829             return false;
830         }
831         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
832             if (ih == i) {
833                 return true;
834             }
835         }
836         return false;
837     }
838 
839 
840     public boolean contains( Instruction i ) {
841         return findInstruction1(i) != null;
842     }
843 
844 
845     public void setPositions() {
846         setPositions(false);
847     }
848 
849 
850     /**
851      * Give all instructions their position number (offset in byte stream), i.e.,
852      * make the list ready to be dumped.
853      *
854      * @param check Perform sanity checks, e.g. if all targeted instructions really belong
855      * to this list
856      */
857     public void setPositions( boolean check ) {
858         int max_additional_bytes = 0, additional_bytes = 0;
859         int index = 0, count = 0;
860         int[] pos = new int[length];
861         /* Pass 0: Sanity checks
862          */
863         if (check) {
864             for (InstructionHandle ih = start; ih != null; ih = ih.next) {
865                 Instruction i = ih.instruction;
866                 if (i instanceof BranchInstruction) { // target instruction within list?
867                     Instruction inst = ((BranchInstruction) i).getTarget().instruction;
868                     if (!contains(inst)) {
869                         throw new ClassGenException("Branch target of "
870                                 + Constants.OPCODE_NAMES[i.opcode] + ":" + inst
871                                 + " not in instruction list");
872                     }
873                     if (i instanceof Select) {
874                         InstructionHandle[] targets = ((Select) i).getTargets();
875                         for (int j = 0; j < targets.length; j++) {
876                             inst = targets[j].instruction;
877                             if (!contains(inst)) {
878                                 throw new ClassGenException("Branch target of "
879                                         + Constants.OPCODE_NAMES[i.opcode] + ":" + inst
880                                         + " not in instruction list");
881                             }
882                         }
883                     }
884                     if (!(ih instanceof BranchHandle)) {
885                         throw new ClassGenException("Branch instruction "
886                                 + Constants.OPCODE_NAMES[i.opcode] + ":" + inst
887                                 + " not contained in BranchHandle.");
888                     }
889                 }
890             }
891         }
892         /* Pass 1: Set position numbers and sum up the maximum number of bytes an
893          * instruction may be shifted.
894          */
895         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
896             Instruction i = ih.instruction;
897             ih.setPosition(index);
898             pos[count++] = index;
899             /* Get an estimate about how many additional bytes may be added, because
900              * BranchInstructions may have variable length depending on the target
901              * offset (short vs. int) or alignment issues (TABLESWITCH and
902              * LOOKUPSWITCH).
903              */
904             switch (i.getOpcode()) {
905                 case Constants.JSR:
906                 case Constants.GOTO:
907                     max_additional_bytes += 2;
908                     break;
909                 case Constants.TABLESWITCH:
910                 case Constants.LOOKUPSWITCH:
911                     max_additional_bytes += 3;
912                     break;
913             }
914             index += i.getLength();
915         }
916         /* Pass 2: Expand the variable-length (Branch)Instructions depending on
917          * the target offset (short or int) and ensure that branch targets are
918          * within this list.
919          */
920         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
921             additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes);
922         }
923         /* Pass 3: Update position numbers (which may have changed due to the
924          * preceding expansions), like pass 1.
925          */
926         index = count = 0;
927         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
928             Instruction i = ih.instruction;
929             ih.setPosition(index);
930             pos[count++] = index;
931             index += i.getLength();
932         }
933         byte_positions = new int[count]; // Trim to proper size
934         System.arraycopy(pos, 0, byte_positions, 0, count);
935     }
936 
937 
938     /**
939      * When everything is finished, use this method to convert the instruction
940      * list into an array of bytes.
941      *
942      * @return the byte code ready to be dumped
943      */
944     public byte[] getByteCode() {
945         // Update position indices of instructions
946         setPositions();
947         ByteArrayOutputStream b = new ByteArrayOutputStream();
948         DataOutputStream out = new DataOutputStream(b);
949         try {
950             for (InstructionHandle ih = start; ih != null; ih = ih.next) {
951                 Instruction i = ih.instruction;
952                 i.dump(out); // Traverse list
953             }
954         } catch (IOException e) {
955             System.err.println(e);
956             return new byte[0];
957         }
958         return b.toByteArray();
959     }
960 
961 
962     /**
963      * @return an array of instructions without target information for branch instructions.
964      */
965     public Instruction[] getInstructions() {
966         ByteSequence bytes = new ByteSequence(getByteCode());
967         List<Instruction> instructions = new ArrayList<Instruction>();
968         try {
969             while (bytes.available() > 0) {
970                 instructions.add(Instruction.readInstruction(bytes));
971             }
972         } catch (IOException e) {
973             throw new ClassGenException(e.toString(), e);
974         }
975         return instructions.toArray(new Instruction[instructions.size()]);
976     }
977 
978 
979     @Override
980     public String toString() {
981         return toString(true);
982     }
983 
984 
985     /**
986      * @param verbose toggle output format
987      * @return String containing all instructions in this list.
988      */
989     public String toString( boolean verbose ) {
990         StringBuilder buf = new StringBuilder();
991         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
992             buf.append(ih.toString(verbose)).append("\n");
993         }
994         return buf.toString();
995     }
996 
997 
998     /**
999      * @return iterator that lists all instructions (handles)
1000      */
1001     public Iterator<InstructionHandle> iterator() {
1002         return new Iterator<InstructionHandle>() {
1003 
1004             private InstructionHandle ih = start;
1005 
1006 
1007             public InstructionHandle next() throws NoSuchElementException {
1008             	if (ih == null)
1009             		throw new NoSuchElementException();
1010                 InstructionHandle i = ih;
1011                 ih = ih.next;
1012                 return i;
1013             }
1014 
1015 
1016             public void remove() {
1017                 throw new UnsupportedOperationException();
1018             }
1019 
1020 
1021             public boolean hasNext() {
1022                 return ih != null;
1023             }
1024         };
1025     }
1026 
1027 
1028     /**
1029      * @return array containing all instructions (handles)
1030      */
1031     public InstructionHandle[] getInstructionHandles() {
1032         InstructionHandle[] ihs = new InstructionHandle[length];
1033         InstructionHandle ih = start;
1034         for (int i = 0; i < length; i++) {
1035             ihs[i] = ih;
1036             ih = ih.next;
1037         }
1038         return ihs;
1039     }
1040 
1041 
1042     /**
1043      * Get positions (offsets) of all instructions in the list. This relies on that
1044      * the list has been freshly created from an byte code array, or that setPositions()
1045      * has been called. Otherwise this may be inaccurate.
1046      *
1047      * @return array containing all instruction's offset in byte code
1048      */
1049     public int[] getInstructionPositions() {
1050         return byte_positions;
1051     }
1052 
1053 
1054     /**
1055      * @return complete, i.e., deep copy of this list
1056      */
1057     public InstructionList copy() {
1058         Map<InstructionHandle, InstructionHandle> map = new HashMap<InstructionHandle, InstructionHandle>();
1059         InstructionList il = new InstructionList();
1060         /* Pass 1: Make copies of all instructions, append them to the new list
1061          * and associate old instruction references with the new ones, i.e.,
1062          * a 1:1 mapping.
1063          */
1064         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
1065             Instruction i = ih.instruction;
1066             Instruction c = i.copy(); // Use clone for shallow copy
1067             if (c instanceof BranchInstruction) {
1068                 map.put(ih, il.append((BranchInstruction) c));
1069             } else {
1070                 map.put(ih, il.append(c));
1071             }
1072         }
1073         /* Pass 2: Update branch targets.
1074          */
1075         InstructionHandle ih = start;
1076         InstructionHandle ch = il.start;
1077         while (ih != null) {
1078             Instruction i = ih.instruction;
1079             Instruction c = ch.instruction;
1080             if (i instanceof BranchInstruction) {
1081                 BranchInstruction bi = (BranchInstruction) i;
1082                 BranchInstruction bc = (BranchInstruction) c;
1083                 InstructionHandle itarget = bi.getTarget(); // old target
1084                 // New target is in hash map
1085                 bc.setTarget(map.get(itarget));
1086                 if (bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
1087                     InstructionHandle[] itargets = ((Select) bi).getTargets();
1088                     InstructionHandle[] ctargets = ((Select) bc).getTargets();
1089                     for (int j = 0; j < itargets.length; j++) { // Update all targets
1090                         ctargets[j] = map.get(itargets[j]);
1091                     }
1092                 }
1093             }
1094             ih = ih.next;
1095             ch = ch.next;
1096         }
1097         return il;
1098     }
1099 
1100 
1101     /** Replace all references to the old constant pool with references to the new
1102      *  constant pool
1103      */
1104     public void replaceConstantPool( ConstantPoolGen old_cp, ConstantPoolGen new_cp ) {
1105         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
1106             Instruction i = ih.instruction;
1107             if (i instanceof CPInstruction) {
1108                 CPInstruction ci = (CPInstruction) i;
1109                 Constant c = old_cp.getConstant(ci.getIndex());
1110                 ci.setIndex(new_cp.addConstant(c, old_cp));
1111             }
1112         }
1113     }
1114 
1115 
1116     private void clear() {
1117         start = end = null;
1118         length = 0;
1119     }
1120 
1121 
1122     /**
1123      * Delete contents of list. Provides besser memory utilization,
1124      * because the system then may reuse the instruction handles. This
1125      * method is typically called right after
1126      * <href="MethodGen.html#getMethod()">MethodGen.getMethod()</a>.
1127      */
1128     public void dispose() {
1129         // Traverse in reverse order, because ih.next is overwritten
1130         for (InstructionHandle ih = end; ih != null; ih = ih.prev) {
1131             /* Causes BranchInstructions to release target and targeters, because it
1132              * calls dispose() on the contained instruction.
1133              */
1134             ih.dispose();
1135         }
1136         clear();
1137     }
1138 
1139 
1140     /**
1141      * @return start of list
1142      */
1143     public InstructionHandle getStart() {
1144         return start;
1145     }
1146 
1147 
1148     /**
1149      * @return end of list
1150      */
1151     public InstructionHandle getEnd() {
1152         return end;
1153     }
1154 
1155 
1156     /**
1157      * @return length of list (Number of instructions, not bytes)
1158      */
1159     public int getLength() {
1160         return length;
1161     }
1162 
1163 
1164     /**
1165      * @return length of list (Number of instructions, not bytes)
1166      */
1167     public int size() {
1168         return length;
1169     }
1170 
1171 
1172     /**
1173      * Redirect all references from old_target to new_target, i.e., update targets 
1174      * of branch instructions.
1175      *
1176      * @param old_target the old target instruction handle
1177      * @param new_target the new target instruction handle
1178      */
1179     public void redirectBranches( InstructionHandle old_target, InstructionHandle new_target ) {
1180         for (InstructionHandle ih = start; ih != null; ih = ih.next) {
1181             Instruction i = ih.getInstruction();
1182             if (i instanceof BranchInstruction) {
1183                 BranchInstruction b = (BranchInstruction) i;
1184                 InstructionHandle target = b.getTarget();
1185                 if (target == old_target) {
1186                     b.setTarget(new_target);
1187                 }
1188                 if (b instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
1189                     InstructionHandle[] targets = ((Select) b).getTargets();
1190                     for (int j = 0; j < targets.length; j++) {
1191                         if (targets[j] == old_target) {
1192                             ((Select) b).setTarget(j, new_target);
1193                         }
1194                     }
1195                 }
1196             }
1197         }
1198     }
1199 
1200 
1201     /**
1202      * Redirect all references of local variables from old_target to new_target.
1203      *
1204      * @param lg array of local variables
1205      * @param old_target the old target instruction handle
1206      * @param new_target the new target instruction handle
1207      * @see MethodGen
1208      */
1209     public void redirectLocalVariables( LocalVariableGen[] lg, InstructionHandle old_target,
1210             InstructionHandle new_target ) {
1211         for (int i = 0; i < lg.length; i++) {
1212             InstructionHandle start = lg[i].getStart();
1213             InstructionHandle end = lg[i].getEnd();
1214             if (start == old_target) {
1215                 lg[i].setStart(new_target);
1216             }
1217             if (end == old_target) {
1218                 lg[i].setEnd(new_target);
1219             }
1220         }
1221     }
1222 
1223 
1224     /**
1225      * Redirect all references of exception handlers from old_target to new_target.
1226      *
1227      * @param exceptions array of exception handlers
1228      * @param old_target the old target instruction handle
1229      * @param new_target the new target instruction handle
1230      * @see MethodGen
1231      */
1232     public void redirectExceptionHandlers( CodeExceptionGen[] exceptions,
1233             InstructionHandle old_target, InstructionHandle new_target ) {
1234         for (int i = 0; i < exceptions.length; i++) {
1235             if (exceptions[i].getStartPC() == old_target) {
1236                 exceptions[i].setStartPC(new_target);
1237             }
1238             if (exceptions[i].getEndPC() == old_target) {
1239                 exceptions[i].setEndPC(new_target);
1240             }
1241             if (exceptions[i].getHandlerPC() == old_target) {
1242                 exceptions[i].setHandlerPC(new_target);
1243             }
1244         }
1245     }
1246 
1247     private List<InstructionListObserver> observers;
1248 
1249 
1250     /** Add observer for this object.
1251      */
1252     public void addObserver( InstructionListObserver o ) {
1253         if (observers == null) {
1254             observers = new ArrayList<InstructionListObserver>();
1255         }
1256         observers.add(o);
1257     }
1258 
1259 
1260     /** Remove observer for this object.
1261      */
1262     public void removeObserver( InstructionListObserver o ) {
1263         if (observers != null) {
1264             observers.remove(o);
1265         }
1266     }
1267 
1268 
1269     /** Call notify() method on all observers. This method is not called
1270      * automatically whenever the state has changed, but has to be
1271      * called by the user after he has finished editing the object.
1272      */
1273     public void update() {
1274         if (observers != null) {
1275             for (InstructionListObserver observer : observers) {
1276                 observer.notify(this);
1277             }
1278         }
1279     }
1280 }