private HashMap<Integer, HashSet<Integer>> conflictPairMap; // Record conflicting events
private HashSet<String> doneBacktrackSet; // Record state ID and trace already constructed
private HashMap<Integer, ReadWriteSet> readWriteFieldsMap; // Record fields that are accessed
- private HashMap<Integer, RestorableState> restorableStateMap; // Maps state IDs to the restorable state object
+ private HashMap<Integer, RestorableVMState> restorableStateMap; // Maps state IDs to the restorable state object
+ private HashMap<Integer, Integer> stateToChoiceCounterMap; // Maps state IDs to the choice counter
// Boolean states
private boolean isBooleanCGFlipped;
}
}
- // This class compactly stores: 1) restorable VM state, and 2) global choice counter
- private class RestorableState {
- private RestorableVMState restorableState;
- private int choiceCounter;
-
- public RestorableState (RestorableVMState restState, int choCtr) {
- restorableState = restState;
- choiceCounter = choCtr;
- }
-
- public RestorableVMState getRestorableState() {
- return restorableState;
- }
-
- public int getChoiceCounter() {
- return choiceCounter;
- }
- }
-
// -- CONSTANTS
private final static String DO_CALL_METHOD = "doCall";
// We exclude fields that come from libraries (Java and Groovy), and also the infrastructure
backtrackPointList.add(new BacktrackPoint(icsCG, stateId, refChoices[choiceIndex]));
// Store restorable state object for this state (always store the latest)
RestorableVMState restorableState = vm.getRestorableState();
- restorableStateMap.put(stateId, new RestorableState(restorableState, choiceCounter));
+ restorableStateMap.put(stateId, restorableState);
+ // Map multiple state IDs to a choice counter
+ for (Integer stId : justVisitedStates) {
+ stateToChoiceCounterMap.put(stId, choiceCounter);
+ }
}
private Integer[] copyChoices(Integer[] choicesToCopy) {
conflictPairMap = new HashMap<>();
doneBacktrackSet = new HashSet<>();
readWriteFieldsMap = new HashMap<>();
+ stateToChoiceCounterMap = new HashMap<>();
// Booleans
isEndOfExecution = false;
}
// Update the state variables
// Line 19 in the paper page 11 (see the heading note above)
int stateId = search.getStateId();
- currVisitedStates.add(stateId);
// Insert state ID into the map if it is new
if (!stateToEventMap.containsKey(stateId)) {
HashSet<Integer> eventSet = new HashSet<>();
stateToEventMap.put(stateId, eventSet);
}
- justVisitedStates.add(stateId);
analyzeReachabilityAndCreateBacktrackPoints(search.getVM(), stateId);
+ justVisitedStates.add(stateId);
+ currVisitedStates.add(stateId);
}
// --- Functions related to Read/Write access analysis on shared fields
int hiStateId = backtrackStateQ.peek();
// Restore the state first if necessary
if (vm.getStateId() != hiStateId) {
- RestorableVMState restorableState = restorableStateMap.get(hiStateId).getRestorableState();
+ RestorableVMState restorableState = restorableStateMap.get(hiStateId);
vm.restoreState(restorableState);
}
// Set the backtrack CG
// 2) We need to analyze and find conflicts for the reachable choices/events in the cycle
// 3) Then we create a new backtrack point for every new conflict
private void analyzeReachabilityAndCreateBacktrackPoints(VM vm, int stateId) {
- // Perform this analysis only when there is a state match
- if (!vm.isNewState()) {
- if (restorableStateMap.containsKey(stateId)) {
- // Find the choice/event that marks the start of this cycle: first choice we explore for conflicts
- int conflictChoice = restorableStateMap.get(stateId).getChoiceCounter();
- int currentChoice = choiceCounter - 1;
- // Find conflicts between choices/events in this cycle (we scan forward in the cycle, not backward)
- while (conflictChoice < currentChoice) {
- for (int eventCounter = conflictChoice + 1; eventCounter <= currentChoice; eventCounter++) {
- if (isConflictFound(eventCounter, conflictChoice) && isNewConflict(conflictChoice, eventCounter)) {
- createBacktrackingPoint(conflictChoice, eventCounter);
- }
+ // Perform this analysis only when:
+ // 1) there is a state match,
+ // 2) this is not during a switch to a new execution,
+ // 3) at least 2 choices/events have been explored (choiceCounter > 1),
+ // 4) the matched state has been encountered in the current execution, and
+ // 5) state > 0 (state 0 is for boolean CG)
+ if (!vm.isNewState() && !isEndOfExecution && choiceCounter > 1 &&
+ currVisitedStates.contains(stateId) && (stateId > 0)) {
+ // Find the choice/event that marks the start of this cycle: first choice we explore for conflicts
+ int conflictChoice = stateToChoiceCounterMap.get(stateId);
+ int currentChoice = choiceCounter - 1;
+ // Find conflicts between choices/events in this cycle (we scan forward in the cycle, not backward)
+ while (conflictChoice < currentChoice) {
+ for (int eventCounter = conflictChoice + 1; eventCounter <= currentChoice; eventCounter++) {
+ if (isConflictFound(eventCounter, conflictChoice) && isNewConflict(conflictChoice, eventCounter)) {
+ createBacktrackingPoint(conflictChoice, eventCounter);
}
- conflictChoice++;
}
+ conflictChoice++;
}
}
}