package soot.spl.ifds;
import heros.FlowFunction;
import heros.FlowFunctions;
import heros.IFDSTabulationProblem;
import heros.flowfunc.Identity;
import heros.flowfunc.KillAll;
import heros.solver.IFDSSolver;
import java.util.BitSet;
import java.util.Set;
import soot.SootMethod;
import soot.Unit;
import soot.tagkit.Host;
import br.ufal.cideei.soot.instrument.FeatureTag;
public class SPLSingleConfigIFDSSolver<D> extends IFDSSolver<Unit,D,SootMethod,ExtendedInterproceduralCFG> {
/**
* Creates a solver for the given problem. The solver must then be started by calling
* {@link #solve()}.
* @param alloyFilePath
* @param numFeaturesPresent
*/
public SPLSingleConfigIFDSSolver(final IFDSTabulationProblem<Unit,D,SootMethod,ExtendedInterproceduralCFG> ifdsProblem, final BitSet enabledFeatures) {
super(new IFDSTabulationProblem<Unit,D,SootMethod,ExtendedInterproceduralCFG>() {
public FlowFunctions<Unit,D,SootMethod> flowFunctions() {
return new FlowFunctions<Unit,D,SootMethod>() {
@Override
public FlowFunction<D> getNormalFlowFunction(Unit curr, Unit succ) {
FlowFunction<D> original = ifdsProblem.flowFunctions().getNormalFlowFunction(curr, succ);
return flowFunction(curr, succ, original, false);
}
@Override
public FlowFunction<D> getCallFlowFunction(Unit callStmt, SootMethod destinationMethod) {
FlowFunction<D> original = ifdsProblem.flowFunctions().getCallFlowFunction(callStmt, destinationMethod);
return flowFunction(callStmt, destinationMethod, original, true);
}
@Override
public FlowFunction<D> getReturnFlowFunction(Unit callSite, SootMethod calleeMethod, Unit exitStmt, Unit returnSite) {
FlowFunction<D> original = ifdsProblem.flowFunctions().getReturnFlowFunction(callSite, calleeMethod, exitStmt, returnSite);
return flowFunction(exitStmt, returnSite, original, false);
}
@Override
public FlowFunction<D> getCallToReturnFlowFunction(Unit callSite, Unit returnSite) {
FlowFunction<D> original = ifdsProblem.flowFunctions().getCallToReturnFlowFunction(callSite, returnSite);
return flowFunction(callSite, returnSite, original, false);
}
protected FlowFunction<D> flowFunction(Unit src, Host successor, FlowFunction<D> original, boolean isCall) {
boolean srcAnnotated = hasFeatureAnnotation(src);
boolean succAnnotated = hasFeatureAnnotation(successor);
if(!srcAnnotated && !(isCall && succAnnotated)) return original;
BitSet features = new BitSet();
if(hasFeatureAnnotation(src))
features.or(features(src));
if(isCall && hasFeatureAnnotation(successor))
features.or(features(successor));
//check if features is a subset of enabledFeatures: features < enabledFeatures <=> features && !enabledFeatures == \empty
features.andNot(enabledFeatures);
boolean stmtEnabled = features.isEmpty();
boolean isFallThroughEdge = false;
if(successor instanceof Unit) {
Unit succUnit = (Unit) successor;
isFallThroughEdge = interproceduralCFG().isFallThroughSuccessor(src,succUnit);
}
boolean canFallThrough = !isCall && src.fallsThrough();
if(stmtEnabled) {
if(isFallThroughEdge && !canFallThrough)
return KillAll.v();
else
return original;
} else {
if(isFallThroughEdge)
return Identity.v();
else
return KillAll.v();
}
}
};
}
public ExtendedInterproceduralCFG interproceduralCFG() {
return new ExtendedInterproceduralCFG(ifdsProblem.interproceduralCFG());
}
public Set<Unit> initialSeeds() {
return ifdsProblem.initialSeeds();
}
public D zeroValue() {
return ifdsProblem.zeroValue();
}
public boolean followReturnsPastSeeds() {
return ifdsProblem.followReturnsPastSeeds();
}
@Override
public boolean autoAddZero() {
return ifdsProblem.autoAddZero();
}
@Override
public int numThreads() {
return ifdsProblem.numThreads();
}
@Override
public boolean computeValues() {
return ifdsProblem.computeValues();
}
});
}
private static boolean hasFeatureAnnotation(Host host) {
return host.hasTag(FeatureTag.FEAT_TAG_NAME);
}
private static BitSet features(Host h) {
FeatureTag tag = (FeatureTag) h.getTag(FeatureTag.FEAT_TAG_NAME);
BitSet features = tag.getFeatureRep();
return features;
}
}