View Javadoc
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 o1, Object 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("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(i) ); 120 } 121 Iterator it = sm.keySet().iterator(); 122 for (int j = 0; it.hasNext(); j++ ) { 123 Integer iInt = (Integer) 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("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(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 i = (Integer)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 toString() { 267 String 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 }

This page was automatically generated by Maven