1
2
3
4 package joeq.Compiler.Quad;
5 import java.util.Collection;
6 import java.util.NoSuchElementException;
7 import joeq.Class.jq_Class;
8 import joeq.Util.Templates.List;
9 import joeq.Util.Templates.ListIterator;
10 import joeq.Util.Templates.UnmodifiableList;
11 import jwutil.graphs.Navigator;
12
13 /***
14 *
15 * @author John Whaley <jwhaley@alum.mit.edu>
16 * @version $Id: QuadIterator.java 1931 2004-09-22 22:17:47Z joewhaley $
17 */
18 public class QuadIterator implements ListIterator.Quad {
19
20 /*** A reference to the control flow graph that we are iterating over. */
21 protected final ControlFlowGraph cfg;
22 /*** The reverse post order iteration of basic blocks in the control flow graph.
23 * When going forward, nextBasicBlock should always be the last basic block
24 * returned by this iterator. */
25 protected final ListIterator.BasicBlock rpoBasicBlocks;
26 /*** References to the previous non-empty basic block, the current basic block,
27 * and the next non-empty basic block. */
28 protected BasicBlock previousBasicBlock, currentBasicBlock, nextBasicBlock;
29 /*** An iteration of the quads in the current basic block. */
30 protected ListIterator.Quad quadsInCurrentBasicBlock;
31
32 /*** The index of the last quad that was returned. */
33 protected int lastIndex;
34 /*** The last quad that was returned. */
35 protected Quad lastQuad;
36
37 /***
38 * Initialize the iterator to iterate over the quads in the
39 * given control flow graph in reverse post order.
40 * @param cfg the control flow graph
41 */
42 public QuadIterator(ControlFlowGraph cfg) { this(cfg, true); }
43 /***
44 * Initialize the iterator to iterate over the quads in the
45 * given control flow graph.
46 * If direction is true, the order is reverse post order and the
47 * iteration starts at the first quad.
48 * If direction is false, the order is post order on the
49 * reverse graph and the iteration starts at the last quad.
50 * @param direction the direction to iterate, forward==true
51 * @param cfg the control flow graph
52 */
53 public QuadIterator(ControlFlowGraph cfg, boolean direction) {
54
55 this.cfg = cfg;
56
57 this.rpoBasicBlocks = direction ? cfg.reversePostOrderIterator() : cfg.postOrderOnReverseGraphIterator();
58
59 this.rpoBasicBlocks.nextBasicBlock();
60 this.previousBasicBlock = null;
61 this.currentBasicBlock = this.rpoBasicBlocks.nextBasicBlock();
62 updateNextBB();
63
64 this.quadsInCurrentBasicBlock = this.currentBasicBlock.iterator();
65
66 if (!direction) {
67 while (hasNext()) nextQuad();
68 }
69
70 this.lastIndex = -1; this.lastQuad = null;
71 }
72
73 /*** Update the nextBasicBlock field to point to the next non-empty basic
74 * block from the reverse post order, or null if there are no more
75 * non-empty basic blocks. */
76 protected void updateNextBB() {
77 for (;;) {
78 if (!this.rpoBasicBlocks.hasNext()) {
79 this.nextBasicBlock = null;
80 break;
81 }
82 this.nextBasicBlock = this.rpoBasicBlocks.nextBasicBlock();
83 if (this.nextBasicBlock.size() > 0) break;
84 }
85 }
86 /*** Update the previousBasicBlock field to point to the previous non-empty basic
87 * block from the reverse post order, or null if there are no more previous
88 * non-empty basic blocks. */
89 protected void updatePreviousBB() {
90
91
92 for (;;) {
93 BasicBlock p = this.rpoBasicBlocks.previousBasicBlock();
94 if (p == this.previousBasicBlock) break;
95 }
96 for (;;) {
97 if (!this.rpoBasicBlocks.hasPrevious()) {
98 this.previousBasicBlock = null;
99 break;
100 }
101 this.previousBasicBlock = this.rpoBasicBlocks.previousBasicBlock();
102 if (this.previousBasicBlock.size() > 0) break;
103 }
104
105 for (;;) {
106 BasicBlock p = this.rpoBasicBlocks.nextBasicBlock();
107 if (p == this.nextBasicBlock) break;
108 }
109 }
110
111 public BasicBlock getCurrentBasicBlock() { return this.currentBasicBlock; }
112
113 public Quad getCurrentQuad() { return lastQuad; }
114
115 /*** Return the next quad in the iteration. */
116 public Quad nextQuad() {
117 if (!this.quadsInCurrentBasicBlock.hasNext()) {
118
119 if (this.nextBasicBlock == null)
120 throw new NoSuchElementException();
121 this.previousBasicBlock = this.currentBasicBlock;
122 this.currentBasicBlock = this.nextBasicBlock;
123 this.quadsInCurrentBasicBlock = this.currentBasicBlock.iterator();
124
125 updateNextBB();
126 }
127 ++this.lastIndex;
128 return this.lastQuad = this.quadsInCurrentBasicBlock.nextQuad();
129 }
130 /*** Return the next quad in the iteration. Use nextQuad to avoid the type cast. */
131 public Object next() { return nextQuad(); }
132 /*** Returns whether there is a next quad in this iteration. */
133 public boolean hasNext() {
134 if (this.quadsInCurrentBasicBlock.hasNext()) return true;
135 return this.nextBasicBlock != null;
136 }
137
138 /*** Returns the first quad reachable from the start of the given basic block. */
139 protected Quad getFirstQuad(BasicBlock bb) {
140 for (;;) {
141 if (bb.isExit()) return null;
142 if (bb.size() > 0) return bb.getQuad(0);
143 bb = bb.getFallthroughSuccessor();
144 }
145 }
146
147 /*** Returns the last quad reachable from the end of the given basic block. */
148 protected Quad getLastQuad(BasicBlock bb) {
149 for (;;) {
150 if (bb.isEntry()) return null;
151 if (bb.size() > 0) return bb.getLastQuad();
152 if (bb.getPredecessors().isEmpty()) return null;
153 bb = bb.getFallthroughPredecessor();
154 }
155 }
156
157 /*** Sets the current quad. */
158 public void set(Object obj) { this.quadsInCurrentBasicBlock.set(obj); }
159 /*** Returns the index of the next quad to be returned. */
160 public int nextIndex() { return this.lastIndex+1; }
161
162 /*** Returns the previous quad in the iteration. */
163 public Quad previousQuad() {
164 if (!this.quadsInCurrentBasicBlock.hasPrevious()) {
165
166 if (this.previousBasicBlock == null)
167 throw new NoSuchElementException();
168 this.nextBasicBlock = this.currentBasicBlock;
169 this.currentBasicBlock = this.previousBasicBlock;
170 this.quadsInCurrentBasicBlock = this.currentBasicBlock.iterator();
171
172 while (this.quadsInCurrentBasicBlock.hasNext())
173 this.quadsInCurrentBasicBlock.nextQuad();
174
175 updatePreviousBB();
176 }
177 this.lastQuad = this.quadsInCurrentBasicBlock.previousQuad();
178 --this.lastIndex;
179 return this.lastQuad;
180 }
181 /*** Returns the previous quad in the iteration. Use previousQuad to avoid the type cast. */
182 public Object previous() { return previousQuad(); }
183
184 /*** Removes the last-returned-quad from the underlying list. */
185 public void remove() { this.quadsInCurrentBasicBlock.remove(); lastQuad = null; --lastIndex; }
186
187 /*** Returns the index of the previous quad. */
188 public int previousIndex() { return this.lastIndex; }
189
190 /*** Returns whether this iteration has a previous quad. */
191 public boolean hasPrevious() {
192 if (this.quadsInCurrentBasicBlock.hasPrevious()) return true;
193 return this.previousBasicBlock != null;
194 }
195
196 /*** Adds a quad to the underlying quad list. */
197 public void add(Object obj) { this.quadsInCurrentBasicBlock.add(obj); lastQuad = null; ++lastIndex; }
198
199 /***
200 * Return an iterator of the possible successor quads of the most recently returned quad.
201 * If a possible successor is the method exit, it includes the "null" value in the iteration.
202 * @throws IllegalStateException if the nextQuad method has not yet been called.
203 */
204 public java.util.Iterator
205 return successors1().iterator();
206 }
207 public Collection
208
209 if (lastQuad == null) throw new IllegalStateException();
210
211 java.util.Set
212
213
214
215
216 ListIterator.jq_Class exceptions = lastQuad.getThrownExceptions().classIterator();
217 while (exceptions.hasNext()) {
218 jq_Class exception = exceptions.nextClass();
219
220
221 ListIterator.ExceptionHandler mayCatch = currentBasicBlock.getExceptionHandlers().mayCatch(exception).exceptionHandlerIterator();
222 while (mayCatch.hasNext()) {
223 ExceptionHandler exceptionHandler = mayCatch.nextExceptionHandler();
224
225 result.add(getFirstQuad(exceptionHandler.getEntry()));
226 }
227
228 if (currentBasicBlock.getExceptionHandlers().mustCatch(exception) == null) {
229 result.add(null);
230 }
231 }
232
233
234
235
236
237
238
239
240 if (this.quadsInCurrentBasicBlock.hasNext()) {
241 Quad next = this.quadsInCurrentBasicBlock.nextQuad();
242 if (next != lastQuad) {
243
244
245
246 result.add(next);
247 this.quadsInCurrentBasicBlock.previousQuad();
248 return result;
249 } else {
250
251 if (this.quadsInCurrentBasicBlock.hasNext()) {
252
253
254 next = this.quadsInCurrentBasicBlock.nextQuad();
255 result.add(next);
256
257 this.quadsInCurrentBasicBlock.previousQuad();
258 this.quadsInCurrentBasicBlock.previousQuad();
259 return result;
260 } else {
261
262
263 this.quadsInCurrentBasicBlock.previousQuad();
264 }
265 }
266 }
267
268
269 ListIterator.BasicBlock succs = this.currentBasicBlock.getSuccessors().basicBlockIterator();
270 while (succs.hasNext())
271 result.add(getFirstQuad(succs.nextBasicBlock()));
272
273 return result;
274 }
275
276 public java.util.Iterator
277 return predecessors1().iterator();
278 }
279 public Collection
280
281 if (lastQuad == null) throw new IllegalStateException();
282
283
284 Quad previous;
285 if (this.quadsInCurrentBasicBlock.hasPrevious()) {
286 previous = this.quadsInCurrentBasicBlock.previousQuad();
287 if (previous != lastQuad) {
288
289
290
291 this.quadsInCurrentBasicBlock.nextQuad();
292 return new UnmodifiableList.Quad(previous);
293 } else {
294
295 if (this.quadsInCurrentBasicBlock.hasPrevious()) {
296
297
298 previous = this.quadsInCurrentBasicBlock.previousQuad();
299
300 this.quadsInCurrentBasicBlock.nextQuad();
301 this.quadsInCurrentBasicBlock.nextQuad();
302 return new UnmodifiableList.Quad(previous);
303 } else {
304
305
306 this.quadsInCurrentBasicBlock.nextQuad();
307 }
308 }
309 }
310
311
312 java.util.Set
313
314
315
316 ListIterator.BasicBlock preds = this.currentBasicBlock.getPredecessors().basicBlockIterator();
317 while (preds.hasNext())
318 result.add(getLastQuad(preds.nextBasicBlock()));
319
320
321 if (currentBasicBlock.isExceptionHandlerEntry()) {
322 java.util.Iterator ex_handlers = cfg.getExceptionHandlersMatchingEntry(currentBasicBlock);
323 while (ex_handlers.hasNext()) {
324 ExceptionHandler eh = (ExceptionHandler)ex_handlers.next();
325 ListIterator.BasicBlock handled = eh.getHandledBasicBlocks().basicBlockIterator();
326 while (handled.hasNext()) {
327 BasicBlock bb = handled.nextBasicBlock();
328 addQuadsThatReachHandler(bb, result, eh);
329 }
330 }
331 }
332 return result;
333 }
334
335 private static void addQuadsThatReachHandler(BasicBlock bb, java.util.Set result, ExceptionHandler eh) {
336 ListIterator.Quad quads = bb.iterator();
337 while (quads.hasNext()) {
338 Quad q = quads.nextQuad();
339 ListIterator.jq_Class exceptions = q.getThrownExceptions().classIterator();
340 while (exceptions.hasNext()) {
341 jq_Class exception = (jq_Class)exceptions.next();
342 List.ExceptionHandler mayCatch = bb.getExceptionHandlers().mayCatch(exception);
343 if (mayCatch.contains(eh))
344 result.add(q);
345 }
346 }
347 }
348
349 public Navigator getNavigator() {
350 return new Navigator() {
351 public Collection next(Object node) {
352 if (node == lastQuad) return successors1();
353 return search(node, true);
354 }
355 public Collection prev(Object node) {
356 if (node == lastQuad) return predecessors1();
357 return search(node, false);
358 }
359 private Collection search(Object node, boolean dir) {
360 Object oldLocation = lastQuad;
361 Collection result = null;
362 if (searchBackward(node)) {
363 result = dir?successors1():predecessors1();
364 }
365 searchForward(oldLocation);
366 if (result == null) {
367 if (searchForward(node)) {
368 result = dir?successors1():predecessors1();
369 }
370 if (result == null) {
371 throw new UnsupportedOperationException();
372 }
373 searchBackward(oldLocation);
374 }
375 return result;
376 }
377 };
378 }
379 public boolean searchForward(Object node) {
380 while (hasNext()) {
381 if (node == nextQuad()) return true;
382 }
383 return false;
384 }
385 public boolean searchBackward(Object node) {
386 while (hasPrevious()) {
387 if (node == previousQuad()) return true;
388 }
389 return false;
390 }
391 }