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