1 17 package org.apache.bcel.verifier.structurals; 18 19 20 import java.util.ArrayList ; 21 import java.util.Hashtable ; 22 import java.util.Map ; 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 42 public class ControlFlowGraph{ 43 44 48 private class InstructionContextImpl implements InstructionContext{ 49 50 57 private int TAG; 58 59 62 private InstructionHandle instruction; 63 64 67 private Map inFrames; 69 72 private Map outFrames; 74 78 private ArrayList executionPredecessors = null; 80 84 public InstructionContextImpl(InstructionHandle inst){ 85 if (inst == null) { 86 throw new AssertionViolatedException("Cannot instantiate InstructionContextImpl from NULL."); 87 } 88 89 instruction = inst; 90 inFrames = new java.util.HashMap (); 91 outFrames = new java.util.HashMap (); 92 } 93 94 95 public int getTag(){ 96 return TAG; 97 } 98 99 100 public void setTag(int tag){ 101 TAG = tag; 102 } 103 104 107 public ExceptionHandler[] getExceptionHandlers(){ 108 return exceptionhandlers.getExceptionHandlers(getInstruction()); 109 } 110 111 114 public Frame getOutFrame(ArrayList execChain){ 115 executionPredecessors = execChain; 116 117 Frame org; 118 119 InstructionContext jsr = lastExecutionJSR(); 120 121 org = (Frame) outFrames.get(jsr); 122 123 if (org == null){ 124 throw new AssertionViolatedException("outFrame not set! This:\n"+this+"\nExecutionChain: "+getExecutionChain()+"\nOutFrames: '"+outFrames+"'."); 125 } 126 return org.getClone(); 127 } 128 129 public Frame getInFrame() { 130 Frame org; 131 132 InstructionContext jsr = lastExecutionJSR(); 133 134 org = (Frame) inFrames.get(jsr); 135 136 if (org == null){ 137 throw new AssertionViolatedException("inFrame not set! This:\n"+this+"\nInFrames: '"+inFrames+"'."); 138 } 139 return org.getClone(); 140 } 141 142 157 public boolean execute(Frame inFrame, ArrayList execPreds, InstConstraintVisitor icv, ExecutionVisitor ev){ 158 159 executionPredecessors = (ArrayList ) execPreds.clone(); 160 161 if ( (lastExecutionJSR() == null) && (subroutines.subroutineOf(getInstruction()) != subroutines.getTopLevel() ) ){ 163 throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?"); 164 } 165 if ( (lastExecutionJSR() != null) && (subroutines.subroutineOf(getInstruction()) == subroutines.getTopLevel() ) ){ 166 throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?"); 167 } 168 169 Frame inF = (Frame) inFrames.get(lastExecutionJSR()); 170 if (inF == null){ inFrames.put(lastExecutionJSR(), inFrame); 172 inF = inFrame; 173 } 174 else{ if (inF.equals(inFrame)){ return false; 177 } 178 if (! mergeInFrames(inFrame)){ 179 return false; 180 } 181 } 182 183 185 Frame workingFrame = inF.getClone(); 187 188 try{ 189 icv.setFrame(workingFrame); 193 getInstruction().accept(icv); 194 } 195 catch(StructuralCodeConstraintException ce){ 196 ce.extendMessage("","\nInstructionHandle: "+getInstruction()+"\n"); 197 ce.extendMessage("","\nExecution Frame:\n"+workingFrame); 198 extendMessageWithFlow(ce); 199 throw ce; 200 } 201 202 ev.setFrame(workingFrame); 206 getInstruction().accept(ev); 207 outFrames.put(lastExecutionJSR(), workingFrame); 209 210 return true; } 213 214 217 public String toString(){ 218 String ret = getInstruction().toString(false)+"\t[InstructionContext]"; 222 return ret; 223 } 224 225 229 private boolean mergeInFrames(Frame inFrame){ 230 Frame inF = (Frame) inFrames.get(lastExecutionJSR()); 232 OperandStack oldstack = inF.getStack().getClone(); 233 LocalVariables oldlocals = inF.getLocals().getClone(); 234 try{ 235 inF.getStack().merge(inFrame.getStack()); 236 inF.getLocals().merge(inFrame.getLocals()); 237 } 238 catch (StructuralCodeConstraintException sce){ 239 extendMessageWithFlow(sce); 240 throw sce; 241 } 242 if ( oldstack.equals(inF.getStack()) && 243 oldlocals.equals(inF.getLocals()) ){ 244 return false; 245 } 246 else{ 247 return true; 248 } 249 } 250 251 256 private String getExecutionChain(){ 257 String s = this.toString(); 258 for (int i=executionPredecessors.size()-1; i>=0; i--){ 259 s = executionPredecessors.get(i)+"\n" + s; 260 } 261 return s; 262 } 263 264 265 270 private void extendMessageWithFlow(StructuralCodeConstraintException e){ 271 String s = "Execution flow:\n"; 272 e.extendMessage("", s+getExecutionChain()); 273 } 274 275 278 public InstructionHandle getInstruction(){ 279 return instruction; 280 } 281 282 289 private InstructionContextImpl lastExecutionJSR(){ 290 291 int size = executionPredecessors.size(); 292 int retcount = 0; 293 294 for (int i=size-1; i>=0; i--){ 295 InstructionContextImpl current = (InstructionContextImpl) (executionPredecessors.get(i)); 296 Instruction currentlast = current.getInstruction().getInstruction(); 297 if (currentlast instanceof RET) { 298 retcount++; 299 } 300 if (currentlast instanceof JsrInstruction){ 301 retcount--; 302 if (retcount == -1) { 303 return current; 304 } 305 } 306 } 307 return null; 308 } 309 310 311 public InstructionContext[] getSuccessors(){ 312 return contextsOf(_getSuccessors()); 313 } 314 315 321 private InstructionHandle[] _getSuccessors(){ 323 final InstructionHandle[] empty = new InstructionHandle[0]; 324 final InstructionHandle[] single = new InstructionHandle[1]; 325 final InstructionHandle[] pair = new InstructionHandle[2]; 326 327 Instruction inst = getInstruction().getInstruction(); 328 329 if (inst instanceof RET){ 330 Subroutine s = subroutines.subroutineOf(getInstruction()); 331 if (s==null){ throw new AssertionViolatedException("Asking for successors of a RET in dead code?!"); 333 } 334 335 339 InstructionHandle[] jsrs = s.getEnteringJsrInstructions(); 340 InstructionHandle[] ret = new InstructionHandle[jsrs.length]; 341 for (int i=0; i<jsrs.length; i++){ 342 ret[i] = jsrs[i].getNext(); 343 } 344 return ret; 345 } 346 347 if (inst instanceof ReturnInstruction){ 349 return empty; 350 } 351 352 if (inst instanceof ATHROW){ 355 return empty; 356 } 357 358 if (inst instanceof JsrInstruction){ 360 single[0] = ((JsrInstruction) inst).getTarget(); 361 return single; 362 } 363 364 if (inst instanceof GotoInstruction){ 365 single[0] = ((GotoInstruction) inst).getTarget(); 366 return single; 367 } 368 369 if (inst instanceof BranchInstruction){ 370 if (inst instanceof Select){ 371 InstructionHandle[] matchTargets = ((Select) inst).getTargets(); 374 InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; 375 ret[0] = ((Select) inst).getTarget(); 376 System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); 377 return ret; 378 } 379 else{ 380 pair[0] = getInstruction().getNext(); 381 pair[1] = ((BranchInstruction) inst).getTarget(); 382 return pair; 383 } 384 } 385 386 single[0] = getInstruction().getNext(); 388 return single; 389 } 390 391 } 393 394 private final MethodGen method_gen; 395 396 397 private final Subroutines subroutines; 398 399 400 private final ExceptionHandlers exceptionhandlers; 401 402 403 private Hashtable instructionContexts = new Hashtable (); 405 408 public ControlFlowGraph(MethodGen method_gen){ 409 subroutines = new Subroutines(method_gen); 410 exceptionhandlers = new ExceptionHandlers(method_gen); 411 412 InstructionHandle[] instructionhandles = method_gen.getInstructionList().getInstructionHandles(); 413 for (int i=0; i<instructionhandles.length; i++){ 414 instructionContexts.put(instructionhandles[i], new InstructionContextImpl(instructionhandles[i])); 415 } 416 417 this.method_gen = method_gen; 418 } 419 420 423 public InstructionContext contextOf(InstructionHandle inst){ 424 InstructionContext ic = (InstructionContext) instructionContexts.get(inst); 425 if (ic == null){ 426 throw new AssertionViolatedException("InstructionContext requested for an InstructionHandle that's not known!"); 427 } 428 return ic; 429 } 430 431 435 public InstructionContext[] contextsOf(InstructionHandle[] insts){ 436 InstructionContext[] ret = new InstructionContext[insts.length]; 437 for (int i=0; i<insts.length; i++){ 438 ret[i] = contextOf(insts[i]); 439 } 440 return ret; 441 } 442 443 448 public InstructionContext[] getInstructionContexts(){ 449 InstructionContext[] ret = new InstructionContext[instructionContexts.values().size()]; 450 return (InstructionContext[]) instructionContexts.values().toArray(ret); 451 } 452 453 457 public boolean isDead(InstructionHandle i){ 458 return subroutines.subroutineOf(i) == null; 459 } 460 } 461 | Popular Tags |