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.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;
47 Instruction instruction;
48 protected int i_position = -1;
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 ) {
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
99 setInstruction(i);
100 }
101
102 private static InstructionHandle ih_list = null;
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
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 }