View Javadoc
1 /*** 2 * ControlFlowGraph 3 * 4 * This is a class which represents a ControlFlowGraph. 5 * 6 * It subclasses the Graph from org/apache/commons/graph 7 * and stores things such as the MethodGen object. 8 */ 9 10 package junit.quilt.cover.generic; 11 12 import junit.quilt.exception.QuiltException; 13 14 import org.apache.bcel.*; 15 import org.apache.bcel.generic.*; 16 import org.apache.bcel.classfile.*; 17 18 import org.apache.commons.graph.*; 19 import org.apache.commons.graph.algorithm.search.*; 20 import org.apache.commons.graph.domain.basic.*; 21 22 import java.util.*; 23 24 public class ControlFlowGraph 25 extends DirectedGraphImpl 26 implements DirectedGraph 27 { 28 private ClassGen clazz = null; 29 private MethodGen method = null; 30 private Method oldMethod = null; 31 private ConstantPoolGen pool = null; 32 private BlockVertex start = null; 33 private BlockVertex end = null; 34 35 /*** 36 * This constructs an empty ControlFlowGraph 37 * for the current class. 38 * 39 * You need to call "initialize()" before the 40 * graph is valid. 41 */ 42 public ControlFlowGraph(InstContext context, 43 MethodGen method) 44 { 45 super( ); 46 this.clazz = context.getClassGen(); 47 this.method = method; 48 this.oldMethod = method.getMethod(); 49 this.pool = context.getConstantPoolGen(); 50 } 51 52 public void initialize( EdgeFactory factory ) { 53 SortedMap blocks = null; // Position X Block Vertex 54 55 // Simple Setup 56 LocalVariableTable lvt = // Local Variable definitions. 57 method.getLocalVariableTable( pool ); 58 59 setStartVertex( factory.makeStartVertex() ); 60 setEndVertex( factory.makeEndVertex() ); 61 62 63 // Create the mapping between Vertices. 64 // Also, make sure they are in the graph. 65 blocks = initVertices( factory, method, pool ); 66 67 68 // This is to make sure our vertex is attached to 69 // the right entry point. 70 addEdge( factory.makeNormalEdge( getStartVertex(), 71 lookup(blocks, 0)), 72 getStartVertex(), 73 lookup(blocks, 0)); 74 75 76 // Now, we iterate over all of the blocks, and set up their 77 // edges. . . 78 79 Iterator allBlocks = blocks.values().iterator(); 80 while (allBlocks.hasNext()) { 81 BlockVertex vertex = (BlockVertex) allBlocks.next(); 82 InstructionHandle last = vertex.getLastInst(); 83 InstructionHandle next = last.getNext(); 84 85 if (last.getInstruction() instanceof ReturnInstruction) { 86 FlowControlEdge rEdge = factory.makeReturnEdge( vertex ); 87 addEdge( rEdge, vertex, getEndVertex() ); 88 89 } else if (last.getInstruction() instanceof RET) { 90 // RET - This is tough. Skip this for now. 91 } else if (last.getInstruction() instanceof Select) { 92 handleSelect( factory, next, last, vertex, blocks, lvt ); 93 } else if (last.getInstruction() instanceof IfInstruction) { 94 handleIf( factory, next, last, vertex, blocks, lvt ); 95 } else if (last.getInstruction() instanceof GotoInstruction) { 96 handleGoto( factory, next, last, vertex, blocks, lvt ); 97 } else if (last.getInstruction() instanceof JsrInstruction) { 98 handleJSR( factory, next, last, vertex, blocks, lvt ); 99 } else if (last.getInstruction() instanceof ExceptionThrower) { 100 handleExceptionThrower( factory, next, last, 101 vertex, blocks, lvt ); 102 } else { 103 handleNormal( factory, next, last, vertex, blocks, lvt ); 104 } 105 } 106 } 107 108 /*** 109 * Returns a map between the Position 110 * of an Instruction, and the BlockVertex 111 * which contains it. 112 * 113 * It uses the method and pool to initialize 114 * everything. 115 * 116 * @param method The method the graph is representing. 117 * @param pool The constant pool. 118 */ 119 120 private SortedMap initVertices( EdgeFactory factory, 121 MethodGen method, 122 ConstantPoolGen pool ) 123 { 124 InstructionList iList = method.getInstructionList(); 125 LineNumberTable lines = method.getLineNumberTable( pool ); 126 127 InstructionHandle inst[] = iList.getInstructionHandles(); 128 SortedMap RC = new TreeMap(); 129 130 for (int i = 0; i < inst.length; i++) { 131 // Create a new vertex. . . 132 BlockVertex vert = 133 factory.makeBlockVertex( lines ); 134 135 // . . . Add the instruction and position . . . 136 vert.addInstruction( inst[i] ); 137 RC.put( new Integer( inst[i].getPosition() ), 138 vert ); 139 140 // . . . finally, add it into the Graph 141 addVertex( vert ); 142 } 143 144 return RC; 145 } 146 147 /*** 148 * getStackContents 149 * 150 * Given an InstructionHandle, it builds up a String 151 * representing what comprises the top element 152 * of the stack. 153 * 154 * It works, by looking at the stack backwards 155 * 156 * @param handle is the handle we want to find the 157 * stack value for. 158 * 159 * @param locals is a LocalVariableTable which is 160 * used for looking up the name of a variable. 161 */ 162 private String getStackContents( InstructionHandle handle, 163 LocalVariableTable locals ) 164 { 165 Instruction inst = handle.getInstruction(); 166 167 if (handle.hasTargeters()) { 168 return "???"; 169 } 170 171 if (inst instanceof LoadInstruction) { 172 int index = ((LoadInstruction) inst).getIndex(); 173 return locals.getLocalVariable(index).getName(); 174 } 175 176 return "???"; 177 } 178 179 private BlockVertex lookup( Map vertices, int position ) 180 { 181 return (BlockVertex) vertices.get( new Integer( position ) ); 182 } 183 184 private BlockVertex lookup( Map vertices, InstructionHandle ih ) 185 { 186 return (BlockVertex) vertices.get( new Integer( ih.getPosition() )); 187 } 188 189 private boolean isCatchCompatible( Class exception, ObjectType catchType ) 190 { 191 return true; 192 193 // TODO: Fix this in BCEL!!!!! 194 195 // NULL means ALL. 196 // if (catchType == null) return true; 197 198 // ObjectType excepType = 199 // new ObjectType( exception.getName() ); 200 201 // if (excepType.getSignature().equals( catchType.getSignature() )) 202 // return true; 203 // return catchType.subclassOf( excepType ); 204 } 205 206 public BlockVertex getStartVertex() { 207 return this.start; 208 } 209 210 public BlockVertex getEndVertex() { 211 return this.end; 212 } 213 214 public void setStartVertex(BlockVertex start) { 215 this.start = start; 216 addVertex( start ); 217 } 218 219 public void setEndVertex(BlockVertex end) { 220 this.end = end; 221 addVertex( end ); 222 } 223 224 public int makeNewLocal(String name, Type type) { 225 LocalVariableGen lvg = 226 method.addLocalVariable( name, type, 227 method.getInstructionList().getStart(), 228 method.getInstructionList().getEnd()); 229 230 return lvg.getIndex(); 231 } 232 233 public Method getMethod() { 234 BytecodeLayout layout = new BytecodeLayout( method ); 235 DFS dfs = new DFS(); 236 dfs.visit( this, getStartVertex(), layout ); 237 238 // layout.visit( this, getStartVertex() ); 239 240 try { 241 return layout.getMethod(); 242 } catch (QuiltException e) { 243 System.err.println("Warning: Instrumentation Failed."); 244 e.printStackTrace(); 245 return oldMethod; 246 } 247 } 248 249 public boolean doesHandle( InstructionHandle ih, 250 CodeExceptionGen handler ) 251 { 252 InstructionHandle curr = handler.getStartPC(); 253 254 if (handler.getEndPC() == ih) return true; 255 256 while ( curr != handler.getEndPC() ) { 257 if (ih == curr) return true; 258 curr = curr.getNext(); 259 } 260 261 return false; 262 } 263 264 public String getMethodName() { 265 return method.getName(); 266 } 267 268 public void updateEdge( FlowControlEdge edge ) { 269 if ( getEdges().contains( edge )) { 270 removeEdge( edge ); 271 } 272 addEdge( edge ); 273 } 274 275 public void addEdge( FlowControlEdge edge ) { 276 BlockVertex source = edge.getSource(); 277 BlockVertex target = edge.getTarget(); 278 279 if (source == null) { 280 source = getStartVertex(); 281 } 282 283 if (target == null) { 284 target = getEndVertex(); 285 } 286 287 addEdge( edge, source, target ); 288 } 289 290 private void handleNormal( EdgeFactory factory, 291 InstructionHandle next, 292 InstructionHandle last, 293 BlockVertex vertex, 294 Map blocks, 295 LocalVariableTable lvt) { 296 BlockVertex target = lookup( blocks, next ); 297 FlowControlEdge nEdge = 298 factory.makeNormalEdge( vertex, target ); 299 300 addEdge(nEdge, vertex, target ); 301 } 302 303 private void handleSelect( EdgeFactory factory, 304 InstructionHandle next, 305 InstructionHandle last, 306 BlockVertex vertex, 307 Map blocks, 308 LocalVariableTable lvt) { 309 310 Select instruction = (Select) last.getInstruction(); 311 String expr = getStackContents( last, lvt ); 312 InstructionHandle targets[] = 313 instruction.getTargets(); 314 int match[] = 315 instruction.getMatchs(); 316 317 BlockVertex target; 318 FlowControlEdge sEdge; 319 320 // CASE . . . 321 for (int i = 0; i < targets.length; i++) { 322 target = lookup( blocks, targets[i] ); 323 sEdge = factory.makeSelectEdge( vertex, target, 324 expr, match[i] ); 325 326 addEdge( sEdge, vertex, target ); 327 } 328 329 // DEFAULT 330 target = lookup( blocks, instruction.getTarget() ); 331 sEdge = factory.makeSelectEdge( vertex, target, expr ); 332 333 addEdge( sEdge, vertex, target ); 334 } 335 336 private void handleIf( EdgeFactory factory, 337 InstructionHandle next, 338 InstructionHandle last, 339 BlockVertex vertex, 340 Map blocks, 341 LocalVariableTable lvt) { 342 343 BlockVertex target; 344 FlowControlEdge bEdge; 345 String expr = getStackContents( last, lvt ); 346 IfInstruction ifInst = 347 (IfInstruction) last.getInstruction(); 348 349 // THEN 350 target = lookup( blocks, ifInst.getTarget() ); 351 bEdge = factory.makeBranchEdge( vertex, target, expr, true ); 352 353 addEdge( bEdge, vertex, target ); 354 355 // ELSE 356 target = lookup( blocks, next ); 357 bEdge = factory.makeBranchEdge( vertex, target, expr, false ); 358 359 addEdge( bEdge, vertex, target ); 360 } 361 362 private void handleGoto( EdgeFactory factory, 363 InstructionHandle next, 364 InstructionHandle last, 365 BlockVertex vertex, 366 Map blocks, 367 LocalVariableTable lvt) { 368 369 // Unconditional Jump 370 GotoInstruction goI = (GotoInstruction) last.getInstruction(); 371 BlockVertex target = lookup( blocks, goI.getTarget() ); 372 FlowControlEdge nEdge = 373 factory.makeNormalEdge( vertex, target ); 374 375 addEdge( nEdge, vertex, target ); 376 } 377 378 private void handleJSR( EdgeFactory factory, 379 InstructionHandle next, 380 InstructionHandle last, 381 BlockVertex vertex, 382 Map blocks, 383 LocalVariableTable lvt) { 384 // SUBROUTINE. . . Don't forget about the RET. 385 JsrInstruction jsrI = (JsrInstruction) last.getInstruction(); 386 387 BlockVertex jsrTarget = lookup( blocks, jsrI.getTarget() ); 388 BlockVertex nTarget = lookup( blocks, last.getNext() ); 389 390 FlowControlEdge jEdge = 391 factory.makeJSREdge( vertex, jsrTarget ); 392 FlowControlEdge nEdge = 393 factory.makeNormalEdge( vertex, nTarget ); 394 395 addEdge( jEdge, vertex, jsrTarget ); 396 addEdge( nEdge, vertex, nTarget ); 397 } 398 399 private void handleExceptionThrower( EdgeFactory factory, 400 InstructionHandle next, 401 InstructionHandle last, 402 BlockVertex vertex, 403 Map blocks, 404 LocalVariableTable lvt) { 405 406 if (last.getInstruction() instanceof InvokeInstruction) { 407 BlockVertex target = lookup( blocks, next ); 408 FlowControlEdge nEdge = factory.makeNormalEdge( vertex, 409 target ); 410 addEdge( nEdge, vertex, target ); 411 412 CodeExceptionGen handlers[] = 413 method.getExceptionHandlers(); 414 415 for (int j = 0; j < handlers.length; j++) { 416 if (doesHandle( last, handlers[j] )) { 417 FlowControlEdge xEdge = 418 factory.makeExceptionEdge( vertex, 419 lookup( blocks, 420 handlers[j].getHandlerPC() ), 421 handlers[j].getCatchType()); 422 addEdge( xEdge, vertex, 423 lookup( blocks, 424 handlers[j].getHandlerPC() ) ); 425 } 426 } 427 } 428 // ATHROW always throws an Exception. So, don't 429 // create a Normal Edge for it. 430 if (!(last.getInstruction() instanceof ATHROW)) { 431 BlockVertex target = lookup( blocks, next ); 432 FlowControlEdge nEdge = factory.makeNormalEdge( vertex, 433 target ); 434 435 addEdge(nEdge, vertex, target); 436 } 437 438 ExceptionThrower inst = 439 (ExceptionThrower) last.getInstruction(); 440 441 Class exceptions[] = inst.getExceptions(); 442 CodeExceptionGen handlers[] = 443 method.getExceptionHandlers(); 444 445 for (int i = 0; i < exceptions.length; i++) { 446 int numHandlers = 0; 447 for (int j = 0; j < handlers.length; j++) { 448 if (handlers[j].containsTarget( last )) { 449 if (isCatchCompatible( exceptions[i], 450 handlers[j].getCatchType())) { 451 numHandlers ++; 452 FlowControlEdge xEdge = 453 factory.makeExceptionEdge( vertex, 454 lookup( blocks, 455 handlers[j].getHandlerPC() ), 456 exceptions[i] ); 457 addEdge( xEdge, vertex, 458 lookup( blocks, 459 handlers[j].getHandlerPC() )); 460 } 461 } 462 } 463 464 // if (numHandlers == 0) { 465 // FlowControlEdge xEdge = 466 // factory.makeExceptionEdge( vertex, 467 // exceptions[i]); 468 // addEdge( xEdge, vertex, getEndVertex() ); 469 // } 470 } 471 } 472 } 473 474

This page was automatically generated by Maven