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