package gov.nasa.jpf.listener;
import java.util.logging.Logger;
import gov.nasa.jpf.Config;
import gov.nasa.jpf.JPF;
import gov.nasa.jpf.ListenerAdapter;
import gov.nasa.jpf.search.Search;
import gov.nasa.jpf.util.ObjVector;
import gov.nasa.jpf.vm.Instruction;
import gov.nasa.jpf.vm.ThreadInfo;
import gov.nasa.jpf.vm.VM;
/**
* This is the simple version of IdleFilter. This one simply breaks all back-edges
* encountered to make sure JPF's partial-order reduction doesn't add meaningless
* transitions forever. This is our dual of the cycle-proviso in classic po-reduction theory.
*
* One can set how many back-edges to consider before breaking, but by default it is 1
*
*/
public class SimpleIdleFilter extends ListenerAdapter {
static Logger log = JPF.getLogger("gov.nasa.jpf.listener.SimpleIdleFilter");
static class ThreadStat {
String tname;
int backJumps;
int loopStartPc;
int loopEndPc;
int loopStackDepth;
ThreadStat(String tname) {
this.tname = tname;
}
}
ObjVector<ThreadStat> threadStats = new ObjVector<ThreadStat>();
ThreadStat ts;
int maxBackJumps;
// ----------------------------------------------------- SearchListener
// interface
public SimpleIdleFilter(Config config) {
maxBackJumps = config.getInt("idle.max_backjumps", 1);
}
@Override
public void stateAdvanced(Search search) {
ts.backJumps = 0;
ts.loopStackDepth = 0;
ts.loopStartPc = ts.loopEndPc = 0;
}
@Override
public void stateBacktracked(Search search) {
ts.backJumps = 0;
ts.loopStackDepth = 0;
ts.loopStartPc = ts.loopEndPc = 0;
}
// ----------------------------------------------------- VMListener interface
@Override
public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) {
if (!executedInsn.isBackJump()) { // Put this test first for a performance optimization.
return;
}
int tid = ti.getId();
ts = threadStats.get(tid);
if (ts == null) {
ts = new ThreadStat(ti.getName());
threadStats.set(tid, ts);
}
ts.backJumps++;
int loopStackDepth = ti.getStackDepth();
int loopPc = nextInsn.getPosition();
if ((loopStackDepth != ts.loopStackDepth) || (loopPc != ts.loopStartPc)) {
// new loop, reset
ts.loopStackDepth = loopStackDepth;
ts.loopStartPc = loopPc;
ts.loopEndPc = executedInsn.getPosition();
ts.backJumps = 0;
} else {
if (ts.backJumps > maxBackJumps) {
ti.reschedule("idleFilter"); // this breaks the executePorStep loop
}
}
}
}