package janala.solvers;
import janala.Main;
import janala.instrument.Coverage;
import java.util.List;
import java.util.LinkedList;
public class AbstractRefineStrategy implements Strategy {
@Override
public int solve(List<Element> history, int historySize, History solver) {
int oldBeginIndex = findUnsatBeginScopeIndex(history, historySize);
int beginIndex = oldBeginIndex;
if (Main.skipPath) {
beginIndex = -1;
}
int endIndex = findMatchingEndScopeIndex(history, historySize, beginIndex);
if (oldBeginIndex == -1 && !Main.skipPath) {
Coverage.instance.commitBranches(false);
Main.setRealInput(true);
} else {
Main.setRealInput(false);
}
int ret = searchWithIfPossibleAssert(history, beginIndex, endIndex, historySize, solver);
while (ret == -1) {
if (beginIndex == -1) {
return ret;
}
beginIndex = findPreviousBeginScopeIndex(history, beginIndex);
endIndex = findMatchingEndScopeIndex(history, historySize, beginIndex);
ret = searchWithIfPossibleAssert(history, beginIndex, endIndex, historySize, solver);
}
return ret;
}
private int findPreviousBeginScopeIndex(List<Element> history, int beginScopeIndex) {
int ret = -1; // Assume
for (int i = 0; i <= beginScopeIndex; i++) {
Element tmp = history.get(i);
if (tmp instanceof MethodElement) {
if (i == beginScopeIndex) {
return ret;
}
if (((MethodElement) tmp).isBegin) {
ret = i;
}
}
}
throw new RuntimeException(
"Should not reach here beginScopeIndex =" + beginScopeIndex + " history " + history);
}
private int findNextBeginScopeIndex(List<Element> history, int start, int end) {
for (int i = start + 1; i < end; i++) {
Element tmp = history.get(i);
if (tmp instanceof MethodElement) {
if (((MethodElement) tmp).isBegin) {
return i;
} else {
return -1;
}
}
}
return -1;
}
private int findMatchingEndScopeIndex(List<Element> history, int historySize, int beginScopeIndex) {
int scopeIdx = 0;
for (int i = beginScopeIndex + 1; i < historySize; i++) {
Element tmp = history.get(i);
if (tmp instanceof MethodElement) {
if (((MethodElement) tmp).isBegin) {
scopeIdx++;
} else {
if (scopeIdx == 0) {
return i;
} else {
scopeIdx--;
}
}
}
}
return historySize;
}
class RemovalPair {
final int b;
final int e;
RemovalPair(int b, int e) {
this.b = b;
this.e = e;
}
}
private List<RemovalPair> findRanges(List<Element> history, int from, int to) {
List<RemovalPair> toBeRemovedRanges = new LinkedList<RemovalPair>();
int bi = findNextBeginScopeIndex(history, from, to);
while (bi != -1) {
int ei = findMatchingEndScopeIndex(history, to, bi);
toBeRemovedRanges.add(new RemovalPair(bi, ei));
bi = findNextBeginScopeIndex(history, ei, to);
}
return toBeRemovedRanges;
}
private void removeElements(
List<Element> history, int low, int high, int idx, int historySize) {
List<RemovalPair> toRemove = findRanges(history, low, idx);
toRemove.add(new RemovalPair(idx, high));
toRemove.addAll(findRanges(history, high, historySize));
for (int i = toRemove.size() - 1; i >= 0; i--) {
RemovalPair pair = toRemove.get(i);
for (int j = pair.e - 1; j > pair.b; j--) {
history.remove(j);
}
}
}
private int findUnsatBeginScopeIndex(List<Element> history, int historySize) {
for (int i = 0; i < historySize; i++) {
Element tmp = history.get(i);
if (tmp.isInvalidScopeBegin()) {
return i;
}
}
return -1;
}
public int searchWithIfPossibleAssert(
List<Element> history, int low, int high, int historySize, History solver) {
int to, from = low, ret;
for (to = low + 1; to < high; to++) {
Element tmp = history.get(to);
BranchElement current;
if (tmp instanceof BranchElement) {
current = (BranchElement) tmp;
if (current.isForceTruth) {
if (!current.getBranch()) {
ret = dfs(history, from, to + 1, high, historySize, solver);
if (ret != -1) {
// Found a solution to satisfy the ForceTruth
return ret;
}
}
// Do not solve for any path that is no deeper than the
// ForceTruth
from = to;
}
}
}
return dfs(history, from, to, high, historySize, solver);
}
private int dfs(List<Element> history, int low, int start, int high, int historySize, History solver) {
LinkedList<Integer> indices = new LinkedList<Integer>();
int skip = 0;
for (int i = start - 1; i > low; i--) {
Element tmp = history.get(i);
if (tmp instanceof MethodElement) {
if (((MethodElement) tmp).isBegin) {
skip++;
} else {
skip--;
}
}
if (tmp instanceof BranchElement && skip == 0) {
indices.addLast(i);
}
}
for (int i : indices) {
Element tmp = history.get(i);
if (tmp instanceof BranchElement) {
BranchElement current = (BranchElement) tmp;
if (!current.getDone() && current.pathConstraintIndex != -1) {
if (solver.solveAt(low, i)) {
current.setDone(true);
current.setBranch(!current.getBranch());
removeElements(history, low, high, i, historySize);
return Integer.MAX_VALUE;
}
}
}
}
return -1;
}
}