KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > BasicBlock


1 /*
2  * Bytecode Analysis Framework
3  * Copyright (C) 2003,2004 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.ba;
21
22 import java.util.BitSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.NoSuchElementException JavaDoc;
25
26 import org.apache.bcel.Constants;
27 import org.apache.bcel.generic.CodeExceptionGen;
28 import org.apache.bcel.generic.InstructionHandle;
29
30 import edu.umd.cs.findbugs.graph.AbstractVertex;
31
32 /**
33  * Simple basic block abstraction for BCEL.
34  *
35  * @author David Hovemeyer
36  * @see CFG
37  */

38 public class BasicBlock extends AbstractVertex<Edge, BasicBlock> implements Debug {
39
40     /* ----------------------------------------------------------------------
41      * Static data
42      * ---------------------------------------------------------------------- */

43
44     /**
45      * Set of instruction opcodes that have an implicit null check.
46      */

47     private static final BitSet JavaDoc nullCheckInstructionSet = new BitSet JavaDoc();
48
49     static {
50         nullCheckInstructionSet.set(Constants.GETFIELD);
51         nullCheckInstructionSet.set(Constants.PUTFIELD);
52         nullCheckInstructionSet.set(Constants.INVOKESPECIAL);
53         nullCheckInstructionSet.set(Constants.INVOKEVIRTUAL);
54         nullCheckInstructionSet.set(Constants.INVOKEINTERFACE);
55         nullCheckInstructionSet.set(Constants.AALOAD);
56         nullCheckInstructionSet.set(Constants.AASTORE);
57         nullCheckInstructionSet.set(Constants.BALOAD);
58         nullCheckInstructionSet.set(Constants.BASTORE);
59         nullCheckInstructionSet.set(Constants.CALOAD);
60         nullCheckInstructionSet.set(Constants.CASTORE);
61         nullCheckInstructionSet.set(Constants.DALOAD);
62         nullCheckInstructionSet.set(Constants.DASTORE);
63         nullCheckInstructionSet.set(Constants.FALOAD);
64         nullCheckInstructionSet.set(Constants.FASTORE);
65         nullCheckInstructionSet.set(Constants.IALOAD);
66         nullCheckInstructionSet.set(Constants.IASTORE);
67         nullCheckInstructionSet.set(Constants.LALOAD);
68         nullCheckInstructionSet.set(Constants.LASTORE);
69         nullCheckInstructionSet.set(Constants.SALOAD);
70         nullCheckInstructionSet.set(Constants.SASTORE);
71         nullCheckInstructionSet.set(Constants.MONITORENTER);
72         nullCheckInstructionSet.set(Constants.ARRAYLENGTH);
73         // nullCheckInstructionSet.set(Constants.MONITOREXIT);
74
//nullCheckInstructionSet.set(Constants.ATHROW);
75
// Any others?
76
}
77
78     /* ----------------------------------------------------------------------
79      * Fields
80      * ---------------------------------------------------------------------- */

81
82     private InstructionHandle firstInstruction;
83     private InstructionHandle lastInstruction;
84     private InstructionHandle exceptionThrower; // instruction for which this block is the ETB
85
private CodeExceptionGen exceptionGen; // set if this block is the entry point of an exception handler
86
private boolean inJSRSubroutine;
87     
88     /* ----------------------------------------------------------------------
89      * Public methods
90      * ---------------------------------------------------------------------- */

91
92     /**
93      * Constructor.
94      */

95     public BasicBlock() {
96         this.firstInstruction = null;
97         this.lastInstruction = null;
98         this.exceptionThrower = null;
99         this.exceptionGen = null;
100         this.inJSRSubroutine = false;
101     }
102     
103     public boolean isInJSRSubroutine() {
104         return inJSRSubroutine;
105     }
106     
107     void setInJSRSubroutine(boolean inJSRSubroutine) {
108         this.inJSRSubroutine = inJSRSubroutine;
109     }
110
111     public int getId() {
112         return getLabel();
113     }
114     
115     @Override JavaDoc
116          public String JavaDoc toString() {
117         return "block " + String.valueOf(getLabel());
118     }
119
120     /**
121      * Set the instruction for which this block is the ETB.
122      *
123      * @param exceptionThrower the instruction
124      */

125     public void setExceptionThrower(InstructionHandle exceptionThrower) {
126         this.exceptionThrower = exceptionThrower;
127     }
128
129     /**
130      * Return whether or not this block is an exception thrower.
131      */

132     public boolean isExceptionThrower() {
133         return exceptionThrower != null;
134     }
135
136     /**
137      * Get the instruction for which this block is an exception thrower.
138      *
139      * @return the instruction, or null if this block is not an exception thrower
140      */

141     public InstructionHandle getExceptionThrower() {
142         return exceptionThrower;
143     }
144
145     /**
146      * Return whether or not this block is a null check.
147      */

148     public boolean isNullCheck() {
149         // Null check blocks must be exception throwers,
150
// and are always empty. (The only kind of non-empty
151
// exception throwing block is one terminated by an ATHROW).
152
if (!isExceptionThrower() || getFirstInstruction() != null)
153             return false;
154         short opcode = exceptionThrower.getInstruction().getOpcode();
155         return nullCheckInstructionSet.get(opcode);
156     }
157
158     /**
159      * Get the first instruction in the basic block.
160      */

161     public InstructionHandle getFirstInstruction() {
162         return firstInstruction;
163     }
164
165     /**
166      * Get the last instruction in the basic block.
167      */

168     public InstructionHandle getLastInstruction() {
169         return lastInstruction;
170     }
171
172     /**
173      * Get the successor of given instruction within the basic block.
174      * @param handle the instruction
175      * @return the instruction's successor, or null if the instruction
176      * is the last in the basic block
177      */

178     public InstructionHandle getSuccessorOf(InstructionHandle handle) {
179         if (VERIFY_INTEGRITY) {
180             if (!containsInstruction(handle))
181                 throw new IllegalStateException JavaDoc();
182         }
183         return handle == lastInstruction
184             ? null
185             : handle.getNext();
186     }
187
188     /**
189      * Get the predecessor of given instruction within the basic block.
190      * @param handle the instruction
191      * @return the instruction's predecessor, or null if the instruction
192      * is the first in the basic block
193      */

194     public InstructionHandle getPredecessorOf(InstructionHandle handle) {
195         if (VERIFY_INTEGRITY) {
196             if (!containsInstruction(handle))
197                 throw new IllegalStateException JavaDoc();
198         }
199         return handle == firstInstruction
200             ? null
201             : handle.getPrev();
202     }
203
204     /**
205      * Add an InstructionHandle to the basic block.
206      *
207      * @param handle the InstructionHandle
208      */

209     public void addInstruction(InstructionHandle handle) {
210         if (firstInstruction == null) {
211             firstInstruction = lastInstruction = handle;
212         } else {
213             if (VERIFY_INTEGRITY && handle != lastInstruction.getNext())
214                 throw new IllegalStateException JavaDoc("Adding non-consecutive instruction");
215             lastInstruction = handle;
216         }
217     }
218
219     /**
220      * A forward Iterator over the instructions of a basic block.
221      * The duplicate() method can be used to make an exact copy of
222      * this iterator. Calling next() on the duplicate will not affect
223      * the original, and vice versa.
224      */

225     public class InstructionIterator implements Iterator JavaDoc<InstructionHandle> {
226         private InstructionHandle next, last;
227
228         public InstructionIterator(InstructionHandle first, InstructionHandle last) {
229             this.next = first;
230             this.last = last;
231         }
232
233         public boolean hasNext() {
234             return next != null;
235         }
236
237         public InstructionHandle next() {
238             if (!hasNext())
239                 throw new NoSuchElementException JavaDoc();
240             InstructionHandle result = next;
241             next = (result == last) ? null : next.getNext();
242             return result;
243         }
244
245         public void remove() {
246             throw new UnsupportedOperationException JavaDoc();
247         }
248
249         public InstructionIterator duplicate() {
250             return new InstructionIterator(next, last);
251         }
252
253         @Override JavaDoc
254                  public boolean equals(Object JavaDoc o) {
255             if (!(o instanceof InstructionIterator))
256                 return false;
257             InstructionIterator other = (InstructionIterator) o;
258             return this.next == other.next && this.last == other.last;
259         }
260
261         @Override JavaDoc
262                  public int hashCode() {
263             int code = getBasicBlock().hashCode() * 227;
264             if (next != null)
265                 code += next.getPosition() + 1;
266             return code;
267         }
268
269         private BasicBlock getBasicBlock() {
270             return BasicBlock.this;
271         }
272
273         @Override JavaDoc
274                  public String JavaDoc toString() {
275             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
276             buf.append("[basicBlock=");
277             buf.append(getBasicBlock().getId());
278             buf.append(", index=");
279             buf.append(next == null ? "end" : String.valueOf(next.getPosition()));
280             buf.append(']');
281             return buf.toString();
282         }
283     }
284
285     /**
286      * Get an Iterator over the instructions in the basic block.
287      */

288     public InstructionIterator instructionIterator() {
289         return new InstructionIterator(firstInstruction, lastInstruction);
290     }
291
292     /**
293      * A reverse Iterator over the instructions in a basic block.
294      */

295     private static class InstructionReverseIterator implements Iterator JavaDoc<InstructionHandle> {
296         private InstructionHandle next, first;
297
298         public InstructionReverseIterator(InstructionHandle last, InstructionHandle first) {
299             this.next = last;
300             this.first = first;
301         }
302
303         public boolean hasNext() {
304             return next != null;
305         }
306
307         public InstructionHandle next() throws NoSuchElementException JavaDoc {
308             if (!hasNext())
309                 throw new NoSuchElementException JavaDoc();
310             InstructionHandle result = next;
311             next = (result == first) ? null : next.getPrev();
312             return result;
313         }
314
315         public void remove() {
316             throw new UnsupportedOperationException JavaDoc();
317         }
318     }
319
320     /**
321      * Get an Iterator over the instructions in the basic block in reverse order.
322      * This is useful for backwards dataflow analyses.
323      */

324     public Iterator JavaDoc<InstructionHandle> instructionReverseIterator() {
325         return new InstructionReverseIterator(lastInstruction, firstInstruction);
326     }
327
328     /**
329      * Return true if there are no Instructions in this basic block.
330      */

331     public boolean isEmpty() {
332         return firstInstruction == null;
333     }
334
335     /**
336      * Is this block an exception handler?
337      */

338     public boolean isExceptionHandler() {
339         return exceptionGen != null;
340     }
341
342     /**
343      * Get CodeExceptionGen object; returns null if this basic block is
344      * not the entry point of an exception handler.
345      *
346      * @return the CodeExceptionGen object, or null
347      */

348     public CodeExceptionGen getExceptionGen() {
349         return exceptionGen;
350     }
351
352     /**
353      * Set the CodeExceptionGen object. Marks this basic block as
354      * the entry point of an exception handler.
355      *
356      * @param exceptionGen the CodeExceptionGen object for the block
357      */

358     public void setExceptionGen(CodeExceptionGen exceptionGen) {
359         this.exceptionGen = exceptionGen;
360     }
361
362     /**
363      * Return whether or not the basic block contains the given instruction.
364      *
365      * @param handle the instruction
366      * @return true if the block contains the instruction, false otherwise
367      */

368     public boolean containsInstruction(InstructionHandle handle) {
369         Iterator JavaDoc<InstructionHandle> i = instructionIterator();
370         while (i.hasNext()) {
371             if (i.next() == handle)
372                 return true;
373         }
374         return false;
375     }
376
377     /**
378      * Return whether or not the basic block contains the instruction
379      * with the given bytecode offset.
380      *
381      * @param offset the bytecode offset
382      * @return true if the block contains an instruction with the given offset,
383      * false if it does not
384      */

385     public boolean containsInstructionWithOffset(int offset) {
386         Iterator JavaDoc<InstructionHandle> i = instructionIterator();
387         while (i.hasNext()) {
388             if (i.next().getPosition() == offset)
389                 return true;
390         }
391         return false;
392     }
393 }
394
395 // vim:ts=4
396
Popular Tags