30 /** |
30 /** |
31 * Instances of this class give users a handle to the instructions contained in |
31 * Instances of this class give users a handle to the instructions contained in |
32 * an InstructionList. Instruction objects may be used more than once within a |
32 * an InstructionList. Instruction objects may be used more than once within a |
33 * list, this is useful because it saves memory and may be much faster. |
33 * list, this is useful because it saves memory and may be much faster. |
34 * |
34 * |
35 * Within an InstructionList an InstructionHandle object is wrapped around all |
35 * Within an InstructionList an InstructionHandle object is wrapped |
36 * instructions, i.e., it implements a cell in a doubly-linked list. From the |
36 * around all instructions, i.e., it implements a cell in a |
37 * outside only the next and the previous instruction (handle) are accessible. |
37 * doubly-linked list. From the outside only the next and the |
38 * One can traverse the list via an Enumeration returned by |
38 * previous instruction (handle) are accessible. One |
|
39 * can traverse the list via an Enumeration returned by |
39 * InstructionList.elements(). |
40 * InstructionList.elements(). |
40 * |
41 * |
41 * @version $Id: InstructionHandle.java 1749603 2016-06-21 20:50:19Z ggregory $ |
42 * @version $Id$ |
42 * @see Instruction |
43 * @see Instruction |
43 * @see BranchHandle |
44 * @see BranchHandle |
44 * @see InstructionList |
45 * @see InstructionList |
45 */ |
46 */ |
46 public class InstructionHandle { |
47 public class InstructionHandle { |
52 private int i_position = -1; // byte code offset of instruction |
53 private int i_position = -1; // byte code offset of instruction |
53 |
54 |
54 private Set<InstructionTargeter> targeters; |
55 private Set<InstructionTargeter> targeters; |
55 private Map<Object, Object> attributes; |
56 private Map<Object, Object> attributes; |
56 |
57 |
|
58 |
|
59 /** |
|
60 * Does nothing. |
|
61 * |
|
62 * @deprecated Does nothing as of 6.3.1. |
|
63 */ |
|
64 @Deprecated |
|
65 protected void addHandle() { |
|
66 // noop |
|
67 } |
|
68 |
57 public final InstructionHandle getNext() { |
69 public final InstructionHandle getNext() { |
58 return next; |
70 return next; |
59 } |
71 } |
60 |
72 |
|
73 |
61 public final InstructionHandle getPrev() { |
74 public final InstructionHandle getPrev() { |
62 return prev; |
75 return prev; |
63 } |
76 } |
64 |
77 |
|
78 |
65 public final Instruction getInstruction() { |
79 public final Instruction getInstruction() { |
66 return instruction; |
80 return instruction; |
67 } |
81 } |
68 |
82 |
69 /** |
83 |
70 * Replace current instruction contained in this handle. Old instruction is |
84 /** |
71 * disposed using Instruction.dispose(). |
85 * Replace current instruction contained in this handle. |
72 */ |
86 * Old instruction is disposed using Instruction.dispose(). |
73 public void setInstruction(final Instruction i) { // Overridden in BranchHandle TODO could be package-protected? |
87 */ |
|
88 public void setInstruction( final Instruction i ) { // Overridden in BranchHandle TODO could be package-protected? |
74 if (i == null) { |
89 if (i == null) { |
75 throw new ClassGenException("Assigning null to handle"); |
90 throw new ClassGenException("Assigning null to handle"); |
76 } |
91 } |
77 if ((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction)) { |
92 if ((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction)) { |
78 throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); |
93 throw new ClassGenException("Assigning branch instruction " + i + " to plain handle"); |
81 instruction.dispose(); |
96 instruction.dispose(); |
82 } |
97 } |
83 instruction = i; |
98 instruction = i; |
84 } |
99 } |
85 |
100 |
86 /** |
101 |
87 * Temporarily swap the current instruction, without disturbing anything. |
102 /** |
88 * Meant to be used by a debugger, implementing breakpoints. Current |
103 * Temporarily swap the current instruction, without disturbing |
89 * instruction is returned. |
104 * anything. Meant to be used by a debugger, implementing |
|
105 * breakpoints. Current instruction is returned. |
90 * <p> |
106 * <p> |
91 * Warning: if this is used on a BranchHandle then some methods such as |
107 * Warning: if this is used on a BranchHandle then some methods such as |
92 * getPosition() will still refer to the original cached instruction, |
108 * getPosition() will still refer to the original cached instruction, whereas |
93 * whereas other BH methods may affect the cache and the replacement |
109 * other BH methods may affect the cache and the replacement instruction. |
94 * instruction. |
|
95 */ |
110 */ |
96 // See BCEL-273 |
111 // See BCEL-273 |
97 // TODO remove this method in any redesign of BCEL |
112 // TODO remove this method in any redesign of BCEL |
98 public Instruction swapInstruction(final Instruction i) { |
113 public Instruction swapInstruction( final Instruction i ) { |
99 final Instruction oldInstruction = instruction; |
114 final Instruction oldInstruction = instruction; |
100 instruction = i; |
115 instruction = i; |
101 return oldInstruction; |
116 return oldInstruction; |
102 } |
117 } |
103 |
118 |
104 |
119 |
105 /*private*/ |
120 /*private*/protected InstructionHandle(final Instruction i) { |
106 protected InstructionHandle(final Instruction i) { |
|
107 setInstruction(i); |
121 setInstruction(i); |
108 } |
122 } |
109 |
123 |
110 private static InstructionHandle ih_list = null; // List of reusable handles |
124 /** Factory method. |
111 |
125 */ |
112 /** |
126 static InstructionHandle getInstructionHandle( final Instruction i ) { |
113 * Factory method. |
127 return new InstructionHandle(i); |
114 */ |
128 } |
115 static InstructionHandle getInstructionHandle(final Instruction i) { |
129 |
116 if (ih_list == null) { |
130 |
117 return new InstructionHandle(i); |
131 /** |
118 } |
132 * Called by InstructionList.setPositions when setting the position for every |
119 final InstructionHandle ih = ih_list; |
133 * instruction. In the presence of variable length instructions `setPositions()' |
120 ih_list = ih.next; |
134 * performs multiple passes over the instruction list to calculate the |
121 ih.setInstruction(i); |
135 * correct (byte) positions and offsets by calling this function. |
122 return ih; |
136 * |
123 } |
137 * @param offset additional offset caused by preceding (variable length) instructions |
124 |
138 * @param max_offset the maximum offset that may be caused by these instructions |
125 /** |
139 * @return additional offset caused by possible change of this instruction's length |
126 * Called by InstructionList.setPositions when setting the position for |
140 */ |
127 * every instruction. In the presence of variable length instructions |
141 protected int updatePosition( final int offset, final int max_offset ) { |
128 * `setPositions()' performs multiple passes over the instruction list to |
|
129 * calculate the correct (byte) positions and offsets by calling this |
|
130 * function. |
|
131 * |
|
132 * @param offset additional offset caused by preceding (variable length) |
|
133 * instructions |
|
134 * @param max_offset the maximum offset that may be caused by these |
|
135 * instructions |
|
136 * @return additional offset caused by possible change of this instruction's |
|
137 * length |
|
138 */ |
|
139 protected int updatePosition(final int offset, final int max_offset) { |
|
140 i_position += offset; |
142 i_position += offset; |
141 return 0; |
143 return 0; |
142 } |
144 } |
143 |
145 |
144 /** |
146 |
145 * @return the position, i.e., the byte code offset of the contained |
147 /** @return the position, i.e., the byte code offset of the contained |
146 * instruction. This is accurate only after InstructionList.setPositions() |
148 * instruction. This is accurate only after |
147 * has been called. |
149 * InstructionList.setPositions() has been called. |
148 */ |
150 */ |
149 public int getPosition() { |
151 public int getPosition() { |
150 return i_position; |
152 return i_position; |
151 } |
153 } |
152 |
154 |
153 /** |
155 |
154 * Set the position, i.e., the byte code offset of the contained |
156 /** Set the position, i.e., the byte code offset of the contained |
155 * instruction. |
157 * instruction. |
156 */ |
158 */ |
157 void setPosition(final int pos) { |
159 void setPosition( final int pos ) { |
158 i_position = pos; |
160 i_position = pos; |
159 } |
161 } |
160 |
162 |
161 /** |
163 |
162 * Overridden in BranchHandle |
164 /** |
163 */ |
165 * Delete contents, i.e., remove user access. |
164 protected void addHandle() { |
|
165 next = ih_list; |
|
166 ih_list = this; |
|
167 } |
|
168 |
|
169 /** |
|
170 * Delete contents, i.e., remove user access and make handle reusable. |
|
171 */ |
166 */ |
172 void dispose() { |
167 void dispose() { |
173 next = prev = null; |
168 next = prev = null; |
174 instruction.dispose(); |
169 instruction.dispose(); |
175 instruction = null; |
170 instruction = null; |
176 i_position = -1; |
171 i_position = -1; |
177 attributes = null; |
172 attributes = null; |
178 removeAllTargeters(); |
173 removeAllTargeters(); |
179 addHandle(); |
174 } |
180 } |
175 |
181 |
176 |
182 /** |
177 /** Remove all targeters, if any. |
183 * Remove all targeters, if any. |
|
184 */ |
178 */ |
185 public void removeAllTargeters() { |
179 public void removeAllTargeters() { |
186 if (targeters != null) { |
180 if (targeters != null) { |
187 targeters.clear(); |
181 targeters.clear(); |
188 } |
182 } |
189 } |
183 } |
190 |
184 |
|
185 |
191 /** |
186 /** |
192 * Denote this handle isn't referenced anymore by t. |
187 * Denote this handle isn't referenced anymore by t. |
193 */ |
188 */ |
194 public void removeTargeter(final InstructionTargeter t) { |
189 public void removeTargeter( final InstructionTargeter t ) { |
195 if (targeters != null) { |
190 if (targeters != null) { |
196 targeters.remove(t); |
191 targeters.remove(t); |
197 } |
192 } |
198 } |
193 } |
199 |
194 |
|
195 |
200 /** |
196 /** |
201 * Denote this handle is being referenced by t. |
197 * Denote this handle is being referenced by t. |
202 */ |
198 */ |
203 public void addTargeter(final InstructionTargeter t) { |
199 public void addTargeter( final InstructionTargeter t ) { |
204 if (targeters == null) { |
200 if (targeters == null) { |
205 targeters = new HashSet<>(); |
201 targeters = new HashSet<>(); |
206 } |
202 } |
207 //if(!targeters.contains(t)) |
203 //if(!targeters.contains(t)) |
208 targeters.add(t); |
204 targeters.add(t); |
209 } |
205 } |
210 |
206 |
|
207 |
211 public boolean hasTargeters() { |
208 public boolean hasTargeters() { |
212 return (targeters != null) && (targeters.size() > 0); |
209 return (targeters != null) && (targeters.size() > 0); |
213 } |
210 } |
|
211 |
214 |
212 |
215 /** |
213 /** |
216 * @return null, if there are no targeters |
214 * @return null, if there are no targeters |
217 */ |
215 */ |
218 public InstructionTargeter[] getTargeters() { |
216 public InstructionTargeter[] getTargeters() { |
222 final InstructionTargeter[] t = new InstructionTargeter[targeters.size()]; |
220 final InstructionTargeter[] t = new InstructionTargeter[targeters.size()]; |
223 targeters.toArray(t); |
221 targeters.toArray(t); |
224 return t; |
222 return t; |
225 } |
223 } |
226 |
224 |
227 /** |
225 |
228 * @return a (verbose) string representation of the contained instruction. |
226 /** @return a (verbose) string representation of the contained instruction. |
229 */ |
227 */ |
230 public String toString(final boolean verbose) { |
228 public String toString( final boolean verbose ) { |
231 return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); |
229 return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); |
232 } |
230 } |
233 |
231 |
234 /** |
232 |
235 * @return a string representation of the contained instruction. |
233 /** @return a string representation of the contained instruction. |
236 */ |
234 */ |
237 @Override |
235 @Override |
238 public String toString() { |
236 public String toString() { |
239 return toString(true); |
237 return toString(true); |
240 } |
238 } |
241 |
239 |
242 /** |
240 |
243 * Add an attribute to an instruction handle. |
241 /** Add an attribute to an instruction handle. |
244 * |
242 * |
245 * @param key the key object to store/retrieve the attribute |
243 * @param key the key object to store/retrieve the attribute |
246 * @param attr the attribute to associate with this handle |
244 * @param attr the attribute to associate with this handle |
247 */ |
245 */ |
248 public void addAttribute(final Object key, final Object attr) { |
246 public void addAttribute( final Object key, final Object attr ) { |
249 if (attributes == null) { |
247 if (attributes == null) { |
250 attributes = new HashMap<>(3); |
248 attributes = new HashMap<>(3); |
251 } |
249 } |
252 attributes.put(key, attr); |
250 attributes.put(key, attr); |
253 } |
251 } |
254 |
252 |
255 /** |
253 |
256 * Delete an attribute of an instruction handle. |
254 /** Delete an attribute of an instruction handle. |
257 * |
255 * |
258 * @param key the key object to retrieve the attribute |
256 * @param key the key object to retrieve the attribute |
259 */ |
257 */ |
260 public void removeAttribute(final Object key) { |
258 public void removeAttribute( final Object key ) { |
261 if (attributes != null) { |
259 if (attributes != null) { |
262 attributes.remove(key); |
260 attributes.remove(key); |
263 } |
261 } |
264 } |
262 } |
265 |
263 |
266 /** |
264 |
267 * Get attribute of an instruction handle. |
265 /** Get attribute of an instruction handle. |
268 * |
266 * |
269 * @param key the key object to store/retrieve the attribute |
267 * @param key the key object to store/retrieve the attribute |
270 */ |
268 */ |
271 public Object getAttribute(final Object key) { |
269 public Object getAttribute( final Object key ) { |
272 if (attributes != null) { |
270 if (attributes != null) { |
273 return attributes.get(key); |
271 return attributes.get(key); |
274 } |
272 } |
275 return null; |
273 return null; |
276 } |
274 } |
277 |
275 |
278 /** |
276 |
279 * @return all attributes associated with this handle |
277 /** @return all attributes associated with this handle |
280 */ |
278 */ |
281 public Collection<Object> getAttributes() { |
279 public Collection<Object> getAttributes() { |
282 if (attributes == null) { |
280 if (attributes == null) { |
283 attributes = new HashMap<>(3); |
281 attributes = new HashMap<>(3); |
284 } |
282 } |
285 return attributes.values(); |
283 return attributes.values(); |
286 } |
284 } |
287 |
285 |
288 /** |
286 |
289 * Convenience method, simply calls accept() on the contained instruction. |
287 /** Convenience method, simply calls accept() on the contained instruction. |
290 * |
288 * |
291 * @param v Visitor object |
289 * @param v Visitor object |
292 */ |
290 */ |
293 public void accept(final Visitor v) { |
291 public void accept( final Visitor v ) { |
294 instruction.accept(v); |
292 instruction.accept(v); |
295 } |
293 } |
|
294 |
296 |
295 |
297 /** |
296 /** |
298 * @param next the next to set |
297 * @param next the next to set |
299 * @ since 6.0 |
298 * @ since 6.0 |
300 */ |
299 */ |
301 final InstructionHandle setNext(final InstructionHandle next) { |
300 final InstructionHandle setNext(final InstructionHandle next) { |
302 this.next = next; |
301 this.next = next; |
303 return next; |
302 return next; |
304 } |
303 } |
305 |
304 |
|
305 |
306 /** |
306 /** |
307 * @param prev the prev to set |
307 * @param prev the prev to set |
308 * @ since 6.0 |
308 * @ since 6.0 |
309 */ |
309 */ |
310 final InstructionHandle setPrev(final InstructionHandle prev) { |
310 final InstructionHandle setPrev(final InstructionHandle prev) { |