1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.javaflow.bytecode.transformation.bcel.analyser;
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.Hashtable;
22
23 import org.apache.bcel.generic.ATHROW;
24 import org.apache.bcel.generic.BranchInstruction;
25 import org.apache.bcel.generic.GotoInstruction;
26 import org.apache.bcel.generic.Instruction;
27 import org.apache.bcel.generic.InstructionHandle;
28 import org.apache.bcel.generic.JsrInstruction;
29 import org.apache.bcel.generic.MethodGen;
30 import org.apache.bcel.generic.RET;
31 import org.apache.bcel.generic.ReturnInstruction;
32 import org.apache.bcel.generic.Select;
33 import org.apache.bcel.verifier.exc.AssertionViolatedException;
34 import org.apache.bcel.verifier.exc.StructuralCodeConstraintException;
35
36
37
38
39
40
41
42
43
44
45 public class ControlFlowGraph{
46
47
48
49
50
51 private class InstructionContextImpl implements InstructionContext{
52
53
54
55
56 private InstructionHandle instruction;
57
58
59
60
61 private HashMap inFrames;
62
63
64
65
66 private HashMap outFrames;
67
68
69
70
71
72 private ExecutionPath executionPredecessors = null;
73
74
75
76
77
78 public InstructionContextImpl(InstructionHandle inst){
79 if (inst == null) throw new AssertionViolatedException("Cannot instantiate InstructionContextImpl from NULL.");
80
81 instruction = inst;
82 inFrames = new java.util.HashMap();
83 outFrames = new java.util.HashMap();
84 }
85
86
87
88
89 public ExceptionHandler[] getExceptionHandlers(){
90 return exceptionhandlers.getExceptionHandlers(getInstruction());
91 }
92
93
94
95
96 public Frame getOutFrame(ExecutionPath execChain){
97 executionPredecessors = execChain;
98
99 Frame org;
100
101 InstructionContext jsr = lastExecutionJSR();
102
103 org = (Frame) outFrames.get(jsr);
104
105 if (org == null){
106 throw new AssertionViolatedException("outFrame not set! This:\n"+this+"\nExecutionChain: "+getExecutionChain()+"\nOutFrames: '"+outFrames+"'.");
107 }
108 return org.getClone();
109 }
110
111 public Frame getInFrame() {
112 Frame org;
113
114 InstructionContext jsr = lastExecutionJSR();
115
116 org = (Frame) inFrames.get(jsr);
117
118 if (org == null){
119 throw new AssertionViolatedException("inFrame not set! This:\n"+this+"\nInFrames: '"+inFrames+"'.");
120 }
121 return org.getClone();
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 public boolean execute(Frame inFrame, ExecutionPath execPreds, ExecutionVisitor ev){
140
141
142 ExecutionPath oldExecPreds = executionPredecessors;
143
144 executionPredecessors = execPreds;
145
146
147 if ( (lastExecutionJSR() == null) && (subroutines.subroutineOf(getInstruction()) != subroutines.getTopLevel() ) ){
148
149 return false;
150 }
151 if ( (lastExecutionJSR() != null) && (subroutines.subroutineOf(getInstruction()) == subroutines.getTopLevel() ) ){
152
153 return false;
154 }
155
156 Frame inF = (Frame) inFrames.get(lastExecutionJSR());
157 if (inF == null){
158 inFrames.put(lastExecutionJSR(), inFrame);
159 inF = inFrame;
160 }
161 else{
162 if (inF.equals(inFrame)){
163 return false;
164 }
165 if (! mergeInFrames(inFrame)){
166 return false;
167 }
168 }
169
170
171
172
173 Frame workingFrame = inF.getClone();
174
175
176
177
178 ev.setFrame(workingFrame);
179 getInstruction().accept(ev);
180
181 outFrames.put(lastExecutionJSR(), workingFrame);
182
183 return true;
184
185 }
186
187
188
189
190 public String toString(){
191
192
193
194 String ret = getInstruction().toString(false)+"\t[InstructionContext]";
195 return ret;
196 }
197
198
199
200
201
202 private boolean mergeInFrames(Frame inFrame){
203
204 Frame inF = (Frame) inFrames.get(lastExecutionJSR());
205 OperandStack oldstack = inF.getStack().getClone();
206 LocalVariables oldlocals = inF.getLocals().getClone();
207 try{
208 inF.getStack().merge(inFrame.getStack());
209 inF.getLocals().merge(inFrame.getLocals());
210 }
211 catch (StructuralCodeConstraintException sce){
212 extendMessageWithFlow(sce);
213 throw sce;
214 }
215 if ( oldstack.equals(inF.getStack()) &&
216 oldlocals.equals(inF.getLocals()) ){
217 return false;
218 }
219 else{
220 return true;
221 }
222 }
223
224
225
226
227
228
229 private String getExecutionChain(){
230 return executionPredecessors.toString()+"\n"+this.toString();
231 }
232
233
234
235
236
237
238
239 private void extendMessageWithFlow(StructuralCodeConstraintException e){
240 String s = "Execution flow:\n";
241 e.extendMessage("", s+getExecutionChain());
242 }
243
244
245
246
247 public InstructionHandle getInstruction(){
248 return instruction;
249 }
250
251 private InstructionContext lastExecutionJSR(){
252 return executionPredecessors.lastExecutionJSR();
253 }
254
255
256 public InstructionContext[] getSuccessors(){
257 return contextsOf(_getSuccessors());
258 }
259
260
261
262
263
264
265
266
267 private InstructionHandle[] _getSuccessors(){
268 final InstructionHandle[] empty = new InstructionHandle[0];
269 final InstructionHandle[] single = new InstructionHandle[1];
270 final InstructionHandle[] pair = new InstructionHandle[2];
271
272 Instruction inst = getInstruction().getInstruction();
273
274 if (inst instanceof RET){
275 Subroutine s = subroutines.subroutineOf(getInstruction());
276 if (s==null){
277 throw new AssertionViolatedException("Asking for successors of a RET in dead code?!");
278 }
279
280 throw new AssertionViolatedException("DID YOU REALLY WANT TO ASK FOR RET'S SUCCS?");
281
282
283
284
285
286
287
288
289 }
290
291
292 if (inst instanceof ReturnInstruction){
293 return empty;
294 }
295
296
297
298 if (inst instanceof ATHROW){
299 return empty;
300 }
301
302
303 if (inst instanceof JsrInstruction){
304 single[0] = ((JsrInstruction) inst).getTarget();
305 return single;
306 }
307
308 if (inst instanceof GotoInstruction){
309 single[0] = ((GotoInstruction) inst).getTarget();
310 return single;
311 }
312
313 if (inst instanceof BranchInstruction){
314 if (inst instanceof Select){
315
316
317 InstructionHandle[] matchTargets = ((Select) inst).getTargets();
318 InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1];
319 ret[0] = ((Select) inst).getTarget();
320 System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
321 return ret;
322 }
323 else{
324 pair[0] = getInstruction().getNext();
325 pair[1] = ((BranchInstruction) inst).getTarget();
326 return pair;
327 }
328 }
329
330
331 single[0] = getInstruction().getNext();
332 return single;
333 }
334
335 }
336
337
338 private final Subroutines subroutines;
339
340
341 private final ExceptionHandlers exceptionhandlers;
342
343
344 private Hashtable instructionContexts = new Hashtable();
345
346
347
348
349 public ControlFlowGraph(MethodGen method_gen){
350 subroutines = new Subroutines(method_gen);
351 exceptionhandlers = new ExceptionHandlers(method_gen);
352
353 InstructionHandle[] instructionhandles = method_gen.getInstructionList().getInstructionHandles();
354 for (int i=0; i<instructionhandles.length; i++){
355 instructionContexts.put(instructionhandles[i], new InstructionContextImpl(instructionhandles[i]));
356 }
357 }
358
359
360
361
362 public InstructionContext contextOf(InstructionHandle inst){
363 InstructionContext ic = (InstructionContext) instructionContexts.get(inst);
364 if (ic == null){
365 throw new AssertionViolatedException("InstructionContext requested for an InstructionHandle that's not known!");
366 }
367 return ic;
368 }
369
370
371
372
373
374 public InstructionContext[] contextsOf(InstructionHandle[] insts){
375 InstructionContext[] ret = new InstructionContext[insts.length];
376 for (int i=0; i<insts.length; i++){
377 ret[i] = contextOf(insts[i]);
378 }
379 return ret;
380 }
381
382
383
384
385
386
387 public InstructionContext[] getInstructionContexts(){
388 InstructionContext[] ret = new InstructionContext[instructionContexts.values().size()];
389 return (InstructionContext[]) instructionContexts.values().toArray(ret);
390 }
391
392
393
394
395
396 public boolean isDead(InstructionHandle i){
397 return subroutines.subroutineOf(i) == null;
398 }
399 }