View Javadoc

1   /*
2    * Copyright  2000-2004 The Apache Software Foundation
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License"); 
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License. 
15   *
16   */
17  package org.apache.bcel.generic;
18  
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.Map;
23  import java.util.Set;
24  import org.apache.bcel.classfile.Utility;
25  
26  /***
27   * Instances of this class give users a handle to the instructions contained in
28   * an InstructionList. Instruction objects may be used more than once within a
29   * list, this is useful because it saves memory and may be much faster.
30   *
31   * Within an InstructionList an InstructionHandle object is wrapped
32   * around all instructions, i.e., it implements a cell in a
33   * doubly-linked list. From the outside only the next and the
34   * previous instruction (handle) are accessible. One
35   * can traverse the list via an Enumeration returned by
36   * InstructionList.elements().
37   *
38   * @version $Id: InstructionHandle.java 386056 2006-03-15 11:31:56Z tcurdt $
39   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
40   * @see Instruction
41   * @see BranchHandle
42   * @see InstructionList 
43   */
44  public class InstructionHandle implements java.io.Serializable {
45  
46      InstructionHandle next, prev; // Will be set from the outside
47      Instruction instruction;
48      protected int i_position = -1; // byte code offset of instruction
49      private Set targeters;
50      private Map attributes;
51  
52  
53      public final InstructionHandle getNext() {
54          return next;
55      }
56  
57  
58      public final InstructionHandle getPrev() {
59          return prev;
60      }
61  
62  
63      public final Instruction getInstruction() {
64          return instruction;
65      }
66  
67  
68      /***
69       * Replace current instruction contained in this handle.
70       * Old instruction is disposed using Instruction.dispose().
71       */
72      public void setInstruction( Instruction i ) { // Overridden in BranchHandle
73          if (i == null) {
74              throw new ClassGenException("Assigning null to handle");
75          }
76          if ((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction)) {
77              throw new ClassGenException("Assigning branch instruction " + i + " to plain handle");
78          }
79          if (instruction != null) {
80              instruction.dispose();
81          }
82          instruction = i;
83      }
84  
85  
86      /***
87       * Temporarily swap the current instruction, without disturbing
88       * anything. Meant to be used by a debugger, implementing
89       * breakpoints. Current instruction is returned.
90       */
91      public Instruction swapInstruction( Instruction i ) {
92          Instruction oldInstruction = instruction;
93          instruction = i;
94          return oldInstruction;
95      }
96  
97  
98      /*private*/protected InstructionHandle(Instruction i) {
99          setInstruction(i);
100     }
101 
102     private static InstructionHandle ih_list = null; // List of reusable handles
103 
104 
105     /*** Factory method.
106      */
107     static final InstructionHandle getInstructionHandle( Instruction i ) {
108         if (ih_list == null) {
109             return new InstructionHandle(i);
110         } else {
111             InstructionHandle ih = ih_list;
112             ih_list = ih.next;
113             ih.setInstruction(i);
114             return ih;
115         }
116     }
117 
118 
119     /***
120      * Called by InstructionList.setPositions when setting the position for every
121      * instruction. In the presence of variable length instructions `setPositions()'
122      * performs multiple passes over the instruction list to calculate the
123      * correct (byte) positions and offsets by calling this function.
124      *
125      * @param offset additional offset caused by preceding (variable length) instructions
126      * @param max_offset the maximum offset that may be caused by these instructions
127      * @return additional offset caused by possible change of this instruction's length
128      */
129     protected int updatePosition( int offset, int max_offset ) {
130         i_position += offset;
131         return 0;
132     }
133 
134 
135     /*** @return the position, i.e., the byte code offset of the contained
136      * instruction. This is accurate only after
137      * InstructionList.setPositions() has been called.
138      */
139     public int getPosition() {
140         return i_position;
141     }
142 
143 
144     /*** Set the position, i.e., the byte code offset of the contained
145      * instruction.
146      */
147     void setPosition( int pos ) {
148         i_position = pos;
149     }
150 
151 
152     /*** Overridden in BranchHandle
153      */
154     protected void addHandle() {
155         next = ih_list;
156         ih_list = this;
157     }
158 
159 
160     /***
161      * Delete contents, i.e., remove user access and make handle reusable.
162      */
163     void dispose() {
164         next = prev = null;
165         instruction.dispose();
166         instruction = null;
167         i_position = -1;
168         attributes = null;
169         removeAllTargeters();
170         addHandle();
171     }
172 
173 
174     /*** Remove all targeters, if any.
175      */
176     public void removeAllTargeters() {
177         if (targeters != null) {
178             targeters.clear();
179         }
180     }
181 
182 
183     /***
184      * Denote this handle isn't referenced anymore by t.
185      */
186     public void removeTargeter( InstructionTargeter t ) {
187         if (targeters != null) {
188             targeters.remove(t);
189         }
190     }
191 
192 
193     /***
194      * Denote this handle is being referenced by t.
195      */
196     public void addTargeter( InstructionTargeter t ) {
197         if (targeters == null) {
198             targeters = new HashSet();
199         }
200         //if(!targeters.contains(t))
201         targeters.add(t);
202     }
203 
204 
205     public boolean hasTargeters() {
206         return (targeters != null) && (targeters.size() > 0);
207     }
208 
209 
210     /***
211      * @return null, if there are no targeters
212      */
213     public InstructionTargeter[] getTargeters() {
214         if (!hasTargeters()) {
215             return null;
216         }
217         InstructionTargeter[] t = new InstructionTargeter[targeters.size()];
218         targeters.toArray(t);
219         return t;
220     }
221 
222 
223     /*** @return a (verbose) string representation of the contained instruction. 
224      */
225     public String toString( boolean verbose ) {
226         return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose);
227     }
228 
229 
230     /*** @return a string representation of the contained instruction. 
231      */
232     public String toString() {
233         return toString(true);
234     }
235 
236 
237     /*** Add an attribute to an instruction handle.
238      *
239      * @param key the key object to store/retrieve the attribute
240      * @param attr the attribute to associate with this handle
241      */
242     public void addAttribute( Object key, Object attr ) {
243         if (attributes == null) {
244             attributes = new HashMap(3);
245         }
246         attributes.put(key, attr);
247     }
248 
249 
250     /*** Delete an attribute of an instruction handle.
251      *
252      * @param key the key object to retrieve the attribute
253      */
254     public void removeAttribute( Object key ) {
255         if (attributes != null) {
256             attributes.remove(key);
257         }
258     }
259 
260 
261     /*** Get attribute of an instruction handle.
262      *
263      * @param key the key object to store/retrieve the attribute
264      */
265     public Object getAttribute( Object key ) {
266         if (attributes != null) {
267             return attributes.get(key);
268         }
269         return null;
270     }
271 
272 
273     /*** @return all attributes associated with this handle
274      */
275     public Collection getAttributes() {
276         if (attributes == null) {
277             attributes = new HashMap(3);
278         }
279         return attributes.values();
280     }
281 
282 
283     /*** Convenience method, simply calls accept() on the contained instruction.
284      *
285      * @param v Visitor object
286      */
287     public void accept( Visitor v ) {
288         instruction.accept(v);
289     }
290 }