📄 controlflowgraph.java
字号:
/**
* Does the actual merging (vmspec2, page 146).
* Returns true IFF this.inFrame was changed in course of merging with inFrame.
*/
private boolean mergeInFrames(Frame inFrame){
// TODO: Can be performance-improved.
Frame inF = (Frame) inFrames.get(lastExecutionJSR());
OperandStack oldstack = inF.getStack().getClone();
LocalVariables oldlocals = inF.getLocals().getClone();
try{
inF.getStack().merge(inFrame.getStack());
inF.getLocals().merge(inFrame.getLocals());
}
catch (StructuralCodeConstraintException sce){
extendMessageWithFlow(sce);
throw sce;
}
if ( oldstack.equals(inF.getStack()) &&
oldlocals.equals(inF.getLocals()) ){
return false;
}
else{
return true;
}
}
/**
* Returns the control flow execution chain. This is built
* while execute(Frame, ArrayList)-ing the code represented
* by the surrounding ControlFlowGraph.
*/
private String getExecutionChain(){
String s = this.toString();
for (int i=executionPredecessors.size()-1; i>=0; i--){
s = executionPredecessors.get(i)+"\n" + s;
}
return s;
}
/**
* Extends the StructuralCodeConstraintException ("e") object with an at-the-end-extended message.
* This extended message will then reflect the execution flow needed to get to the constraint
* violation that triggered the throwing of the "e" object.
*/
private void extendMessageWithFlow(StructuralCodeConstraintException e){
String s = "Execution flow:\n";
e.extendMessage("", s+getExecutionChain());
}
/*
* Fulfils the contract of InstructionContext.getInstruction().
*/
public InstructionHandle getInstruction(){
return instruction;
}
/**
* Returns the InstructionContextImpl with an JSR/JSR_W
* that was last in the ExecutionChain, without
* a corresponding RET, i.e.
* we were called by this one.
* Returns null if we were called from the top level.
*/
private InstructionContextImpl lastExecutionJSR(){
int size = executionPredecessors.size();
int retcount = 0;
for (int i=size-1; i>=0; i--){
InstructionContextImpl current = (InstructionContextImpl) (executionPredecessors.get(i));
Instruction currentlast = current.getInstruction().getInstruction();
if (currentlast instanceof RET) retcount++;
if (currentlast instanceof JsrInstruction){
retcount--;
if (retcount == -1) return current;
}
}
return null;
}
/* Satisfies InstructionContext.getSuccessors(). */
public InstructionContext[] getSuccessors(){
return contextsOf(_getSuccessors());
}
/**
* A utility method that calculates the successors of a given InstructionHandle
* That means, a RET does have successors as defined here.
* A JsrInstruction has its target as its successor
* (opposed to its physical successor) as defined here.
*/
// TODO: implement caching!
private InstructionHandle[] _getSuccessors(){
final InstructionHandle[] empty = new InstructionHandle[0];
final InstructionHandle[] single = new InstructionHandle[1];
final InstructionHandle[] pair = new InstructionHandle[2];
Instruction inst = getInstruction().getInstruction();
if (inst instanceof RET){
Subroutine s = subroutines.subroutineOf(getInstruction());
if (s==null){ //return empty; // RET in dead code. "empty" would be the correct answer, but we know something about the surrounding project...
throw new AssertionViolatedException("Asking for successors of a RET in dead code?!");
}
//TODO: remove
throw new AssertionViolatedException("DID YOU REALLY WANT TO ASK FOR RET'S SUCCS?");
/*
InstructionHandle[] jsrs = s.getEnteringJsrInstructions();
InstructionHandle[] ret = new InstructionHandle[jsrs.length];
for (int i=0; i<jsrs.length; i++){
ret[i] = jsrs[i].getNext();
}
return ret;
*/
}
// Terminates method normally.
if (inst instanceof ReturnInstruction){
return empty;
}
// Terminates method abnormally, because JustIce mandates
// subroutines not to be protected by exception handlers.
if (inst instanceof ATHROW){
return empty;
}
// See method comment.
if (inst instanceof JsrInstruction){
single[0] = ((JsrInstruction) inst).getTarget();
return single;
}
if (inst instanceof GotoInstruction){
single[0] = ((GotoInstruction) inst).getTarget();
return single;
}
if (inst instanceof BranchInstruction){
if (inst instanceof Select){
// BCEL's getTargets() returns only the non-default targets,
// thanks to Eli Tilevich for reporting.
InstructionHandle[] matchTargets = ((Select) inst).getTargets();
InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1];
ret[0] = ((Select) inst).getTarget();
System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
return ret;
}
else{
pair[0] = getInstruction().getNext();
pair[1] = ((BranchInstruction) inst).getTarget();
return pair;
}
}
// default case: Fall through.
single[0] = getInstruction().getNext();
return single;
}
} // End Inner InstructionContextImpl Class.
/** The MethofGen object we're working on. */
//private final MethodGen method_gen;
/** The Subroutines object for the method whose control flow is represented by this ControlFlowGraph. */
private final Subroutines subroutines;
/** The ExceptionHandlers object for the method whose control flow is represented by this ControlFlowGraph. */
private final ExceptionHandlers exceptionhandlers;
/** All InstructionContext instances of this ControlFlowGraph. */
private Hashtable<InstructionHandle, InstructionContextImpl> instructionContexts = new Hashtable<InstructionHandle, InstructionContextImpl>(); //keys: InstructionHandle, values: InstructionContextImpl
/**
* A Control Flow Graph.
*/
public ControlFlowGraph(MethodGen method_gen){
subroutines = new Subroutines(method_gen);
exceptionhandlers = new ExceptionHandlers(method_gen);
InstructionHandle[] instructionhandles = method_gen.getInstructionList().getInstructionHandles();
for (int i=0; i<instructionhandles.length; i++){
instructionContexts.put(instructionhandles[i], new InstructionContextImpl(instructionhandles[i]));
}
//this.method_gen = method_gen;
}
/**
* Returns the InstructionContext of a given instruction.
*/
public InstructionContext contextOf(InstructionHandle inst){
InstructionContext ic = (InstructionContext) instructionContexts.get(inst);
if (ic == null){
throw new AssertionViolatedException("InstructionContext requested for an InstructionHandle that's not known!");
}
return ic;
}
/**
* Returns the InstructionContext[] of a given InstructionHandle[],
* in a naturally ordered manner.
*/
public InstructionContext[] contextsOf(InstructionHandle[] insts){
InstructionContext[] ret = new InstructionContext[insts.length];
for (int i=0; i<insts.length; i++){
ret[i] = contextOf(insts[i]);
}
return ret;
}
/**
* Returns an InstructionContext[] with all the InstructionContext instances
* for the method whose control flow is represented by this ControlFlowGraph
* <B>(NOT ORDERED!)</B>.
*/
public InstructionContext[] getInstructionContexts(){
InstructionContext[] ret = new InstructionContext[instructionContexts.values().size()];
return (InstructionContext[]) instructionContexts.values().toArray(ret);
}
/**
* Returns true, if and only if the said instruction is not reachable; that means,
* if it not part of this ControlFlowGraph.
*/
public boolean isDead(InstructionHandle i){
return instructionContexts.containsKey(i);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -