KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quilt > cl > TryStacks


1 /* TryStacks.java */
2
3 package org.quilt.cl;
4
5 import java.util.*;
6 import org.apache.bcel.generic.*;
7
8 import org.quilt.graph.*;
9
10 /**
11  * Manages try/catch blocks. Adds subgraphs to the method
12  * graph for each exception handler, building the graph that
13  * GraphTransformer hangs bytecode off.
14  *
15  * This module must cope with the fact that the compiler allocates exception
16  * handlers in no particular order.
17  *
18  * Hacked from earlier 0.5-compatible code.
19  *
20  * @author < a HREF="jdd@dixons.org">Jim Dixon</a>
21  */

22 public class TryStacks {
23
24     private ControlFlowGraph graph = null;
25     private SortedBlocks blox = null;
26
27     private int handlerCount = 0;
28    
29     private int index; // index into the arrays that follow
30
private int tryStart[]; // bytecount position ...
31
private int tryEnd[]; // inclusive
32
private int handlerPC[]; // start of catch blocks
33
private ObjectType exception[];
34     private boolean done []; // debugging only?
35

36     /** Hash of bytecode offsets of end of try blocks. */
37     private Map tryEndNdx = new HashMap();
38
39     /**
40      * Comparator for exception handlers. These need to be sorted
41      * by tryStart (offset of beginning of try block) in ascending
42      * order, then by tryEnd (offset of end of try block) in
43      * descending order, then by handlerPC in ascending order.
44      */

45     private class CmpHandlers implements Comparator {
46         /** Implementation of compare.
47          * @param o1 first handler in comparison
48          * @param o2 second
49          * @return -1 if o1 < o2, 0 if 01 == o2, 1 if o1 > o2
50          */

51         public int compare (Object JavaDoc o1, Object JavaDoc o2) {
52             CodeExceptionGen a = (CodeExceptionGen) o1;
53             CodeExceptionGen b = (CodeExceptionGen) o2;
54
55             // -1 if a < b, 0 if a = b, 1 if a > b, in some sense
56
int aStart = a.getStartPC().getPosition();
57             int bStart = b.getStartPC().getPosition();
58             // ascending order of start offset
59
if (aStart < bStart) {
60                 return -1;
61             } else if (aStart > bStart) {
62                 return 1;
63             }
64             // descending order of end offset
65
int aEnd = a.getEndPC().getPosition();
66             int bEnd = b.getEndPC().getPosition();
67             if (aEnd < bEnd) {
68                 return 1;
69             } else if (aEnd > bEnd) {
70                 return -1;
71             }
72             // ascending order of handler offset
73
int aHandler = a.getHandlerPC().getPosition();
74             int bHandler = b.getHandlerPC().getPosition();
75             if (aHandler < bHandler) {
76                 return -1;
77             } else if (aHandler > bHandler) {
78                 return 1;
79             } else {
80                 return 0;
81             }
82         }
83     }
84     
85     // CONSTRUCTOR //////////////////////////////////////////////////
86
/**
87      * Constructor setting up try/catch arrays. Sorts the exception
88      * handlers and then builds a nested control flow graph, including
89      * the first code vertex in each try block who first vertex is a
90      * code vertex.
91      *
92      * @param handlers Array of exception handlers for a method.
93      * @param blocks Vertices indexed by position in bytecode (?).
94      * @param g Graph for the method.
95      */

96     public TryStacks (
97             final CodeExceptionGen[] handlers,
98             SortedBlocks blocks,
99             ControlFlowGraph g) {
100         if (handlers == null || blocks == null || g == null) {
101             throw new IllegalArgumentException JavaDoc("null constructor argument");
102         }
103         blox = blocks;
104         graph = g;
105
106         handlerCount = handlers.length;
107         if (handlerCount > 0) {
108             tryStart = new int[handlerCount];
109             tryEnd = new int[handlerCount];
110             handlerPC = new int[handlerCount];
111             exception = new ObjectType[handlerCount];
112             done = new boolean [handlerCount];
113             
114             // sort the handlers first by position of beginning of
115
// try block, then by position of end of try block, then
116
// by handler address
117
SortedMap sm = new TreeMap(new CmpHandlers());
118             for (int i=0; i<handlerCount; i++) {
119                 sm.put ( handlers[i], new Integer JavaDoc(i) );
120             }
121             Iterator it = sm.keySet().iterator();
122             for (int j = 0; it.hasNext(); j++ ) {
123                 Integer JavaDoc iInt = (Integer JavaDoc) sm.get (
124                                             (CodeExceptionGen) it.next() );
125                 int i = iInt.intValue();
126                 tryStart[j] = handlers[i].getStartPC().getPosition();
127                 tryEnd[j] = handlers[i].getEndPC().getPosition();
128                 handlerPC[j] = handlers[i].getHandlerPC().getPosition();
129                 exception[j] = handlers[i].getCatchType();
130
131                 done[j] = false;
132             }
133             Edge edge = graph.getEntry().getEdge();
134             for (int i = 0; i < handlerCount && !done[i]; /* */ ) {
135                 ControlFlowGraph sub = handleTry(graph, edge) ;
136                 edge = sub.getExit().getEdge();
137             }
138         } // if handlerCount > 0
139
}
140
141     /**
142      * Initialize the graph and set up catch blocks for the i-th
143      * try block.
144      *
145      * @param index Index into table of exception handlers, updated by this
146      * method.
147      * @param g Graph which will be parent of the graph created.
148      * @param e On entry, edge along which graph is created
149      * @return Subgraph created
150      */

151     private ControlFlowGraph handleTry (
152                     final ControlFlowGraph g, final Edge parentEdge ) {
153         int start = tryStart[index];
154         int end = tryEnd[index];
155         if ( parentEdge == null) {
156             throw new IllegalArgumentException JavaDoc("null edge");
157         }
158         // deal with tries with multiple exception handlers
159
ControlFlowGraph subgraph = handleTryGroup (g, parentEdge);
160         Vertex subEntry = subgraph.getEntry();
161         Edge currEdge = subEntry.getEdge();
162         
163         // deal with trys starting at the same bytecode offset
164
ControlFlowGraph subsub;
165         if ((index < handlerCount) && (tryStart[index] == start)) {
166             subsub = handleTry (subgraph, currEdge);
167             currEdge = subsub.getExit().getEdge();
168         } else {
169             // this was the most deeply nested try block starting at
170
// this offset, so bytecode gets assigned to vertex
171
// hanging off the Entry's preferred edge. Create that
172
// vertex along currEdge.
173
currEdge = blox.add (tryStart[index - 1], currEdge ).getEdge();
174         }
175         // other tries nested within this try block
176
int nested = 0;
177         while ((index < handlerCount) && (tryStart[index] < end)) {
178             subsub = handleTry (subgraph, currEdge);
179             currEdge = subsub.getExit().getEdge();
180         }
181         // set up tryEnd index by graph
182
tryEndNdx.put(subgraph, new Integer JavaDoc(start));
183         return subgraph;
184     }
185
186     /**
187      * Deal with a try block with one or more catch blocks.
188      *
189      * @param i Index into handler table, updated by this method.
190      * @param parent Parent graph.
191      * @param parentEdge Edge along which subgraph is created.
192      * @returns Subgraph created.
193      */

194     private ControlFlowGraph handleTryGroup (final ControlFlowGraph parent,
195                                             final Edge parentEdge) {
196        
197         int k = 1; // number of catch blocks
198
int pos = tryStart[index];
199         int end = tryEnd[index];
200         for (int j = index + 1; j < handlerCount
201                          && tryStart[j] == pos && tryEnd[j] == end;
202                                                                 j++) {
203             // try blocks are identical
204
k++;
205         }
206         // create a subgraph with a k-sized connector
207
ControlFlowGraph subgraph
208                     = (ControlFlowGraph) parent.subgraph (parentEdge, k);
209         Edge currentEdge = subgraph.getExit().getEdge();
210
211         // connect to catch blocks
212
ComplexConnector conn
213                     = (ComplexConnector)subgraph.getEntry().getConnector();
214         for (int j = 0; j < k; j++) {
215             done[index + j] = true;
216             Edge edge = conn.getEdge(j);
217             CodeVertex v = subgraph.insertCodeVertex (edge);
218             v.setPos (handlerPC[index + j] );
219             // v.getConnector().setData ( new ConnData() );
220
blox.add (v);
221         }
222         index += k;
223         return subgraph;
224     }
225     /**
226      * Return an array of CatchData, with vertices for the beginning
227      * and end of the try block, a vertex for the handler, and the
228      * exception handled.
229      *
230      * @return Catch handler descriptions for the graph.
231      */

232     public CatchData [] getCatchData() {
233         CatchData [] cd = new CatchData[tryStart.length];
234         for (int i = 0; i < tryStart.length; i++) {
235             cd [i] = new CatchData (blox.get(tryStart[i]), blox.get(tryEnd[i]),
236                                     blox.get(handlerPC[i]), exception[i] );
237         }
238         return cd;
239     }
240     /**
241      * Return the class TryStack uses to sort exception handlers.
242      *
243      * @return The comparator used to sort handlers.
244      */

245     public Comparator getComparator() {
246         return new CmpHandlers();
247     }
248     /**
249      * Get the bytecode offset of end of the try block for this graph.
250      *
251      * @param graph A subgraph created by this package.
252      * @return The bytecode offset of the end of the try block for this
253      * or -1 if there is no such graph.
254      */

255     int getEndTry (final ControlFlowGraph graph) {
256         if (tryEndNdx.containsKey(graph)) {
257             Integer JavaDoc i = (Integer JavaDoc)tryEndNdx.get(graph);
258             return i.intValue();
259         }
260         return -1;
261     }
262     /**
263      * @return Newline-terminated string description of try blocks and
264      * handlers.
265      */

266     public String JavaDoc toString() {
267         String JavaDoc s = "";
268         if (handlerCount > 0) {
269             // columns will not align properly for non-trivial cases
270
s = " index start end handler pc\n";
271             for (int i = 0; i < handlerCount; i++) {
272                 s += " " + i + " [" + tryStart[i]
273                    + ".." + tryEnd[i]
274                    + "] --> " + handlerPC[i] + "\n";
275             }
276         }
277         return s;
278     }
279 }
280
Popular Tags