isInitialized = true;
}
// Record the subsequent Integer CGs only until we hit the upper bound
- if (choiceCounter < choiceUpperBound && !cgMap.containsValue(choiceCounter)) {
+ if (choiceCounter <= choiceUpperBound && !cgMap.containsValue(choiceCounter)) {
// Update the choices of the first CG and add '-1'
Integer[] newChoices = new Integer[choices.length + 1];
System.arraycopy(choices, 0, newChoices, 0, choices.length);
if (isResetAfterAnalysis && icsCG.getNextChoice() == -1) {
int event = cgMap.get(icsCG);
LinkedList<Integer[]> choiceLists = backtrackMap.get(event);
- if (choiceLists.peekFirst() != null) {
+ if (choiceLists != null && choiceLists.peekFirst() != null) {
Integer[] choiceList = choiceLists.removeFirst();
// Deploy the new choice list for this CG
icsCG.setNewValues(choiceList);
}
// This class compactly stores Read and Write field sets
+ // We store the field name and its object ID
+ // Sharing the same field means the same field name and object ID
private class ReadWriteSet {
- private HashSet<String> readSet;
- private HashSet<String> writeSet;
+ private HashMap<String,Integer> readSet;
+ private HashMap<String,Integer> writeSet;
public ReadWriteSet() {
- readSet = new HashSet<>();
- writeSet = new HashSet<>();
+ readSet = new HashMap<>();
+ writeSet = new HashMap<>();
}
- public void addReadField(String field) {
- readSet.add(field);
+ public void addReadField(String field, int objectId) {
+ readSet.put(field, objectId);
}
- public void addWriteField(String field) {
- writeSet.add(field);
+ public void addWriteField(String field, int objectId) {
+ writeSet.put(field, objectId);
}
public boolean readFieldExists(String field) {
- return readSet.contains(field);
+ return readSet.containsKey(field);
}
public boolean writeFieldExists(String field) {
- return writeSet.contains(field);
+ return writeSet.containsKey(field);
+ }
+
+ public int readFieldObjectId(String field) {
+ return readSet.get(field);
+ }
+
+ public int writeFieldObjectId(String field) {
+ return writeSet.get(field);
}
}
- private void analyzeReadWriteAccesses(Instruction executedInsn, String fieldClass) {
+ private void analyzeReadWriteAccesses(Instruction executedInsn, String fieldClass, int currentChoice) {
// Do the analysis to get Read and Write accesses to fields
ReadWriteSet rwSet;
// We already have an entry
- if (readWriteFieldsMap.containsKey(choiceCounter)) {
- rwSet = readWriteFieldsMap.get(choiceCounter);
+ if (readWriteFieldsMap.containsKey(currentChoice)) {
+ rwSet = readWriteFieldsMap.get(currentChoice);
} else { // We need to create a new entry
rwSet = new ReadWriteSet();
- readWriteFieldsMap.put(choiceCounter, rwSet);
+ readWriteFieldsMap.put(currentChoice, rwSet);
}
+ int objectId = ((JVMFieldInstruction) executedInsn).getFieldInfo().getClassInfo().getClassObjectRef();
// Record the field in the map
if (executedInsn instanceof WriteInstruction) {
- rwSet.addWriteField(fieldClass);
- }
- if (executedInsn instanceof ReadInstruction) {
- rwSet.addReadField(fieldClass);
+ // Exclude certain field writes because of infrastructure needs, e.g., Event class field writes
+ for(String str : EXCLUDED_FIELDS_WRITE_INSTRUCTIONS_STARTS_WITH_LIST) {
+ if (fieldClass.startsWith(str)) {
+ return;
+ }
+ }
+ rwSet.addWriteField(fieldClass, objectId);
+ } else if (executedInsn instanceof ReadInstruction) {
+ rwSet.addReadField(fieldClass, objectId);
}
}
backtrackChoiceLists.addLast(choiceList);
}
+ // We exclude fields that come from libraries (Java and Groovy), and also the infrastructure
+ private final static String[] EXCLUDED_FIELDS_STARTS_WITH_LIST =
+ // Java and Groovy libraries
+ { "java", "org", "sun", "com", "gov", "groovy"};
+ private final static String[] EXCLUDED_FIELDS_ENDS_WITH_LIST =
+ // Groovy library created fields
+ {"stMC", "callSiteArray", "metaClass", "staticClassInfo", "__constructor__",
+ // Infrastructure
+ "sendEvent", "Object", "reference", "location", "app", "state", "log", "functionList", "objectList",
+ "eventList", "valueList", "settings", "printToConsole", "app1", "app2"};
+ private final static String[] EXCLUDED_FIELDS_CONTAINS_LIST = {"_closure"};
+ private final static String[] EXCLUDED_FIELDS_WRITE_INSTRUCTIONS_STARTS_WITH_LIST = {"Event"};
+
+ private boolean isFieldExcluded(String field) {
+ // Check against "starts-with" list
+ for(String str : EXCLUDED_FIELDS_STARTS_WITH_LIST) {
+ if (field.startsWith(str)) {
+ return true;
+ }
+ }
+ // Check against "ends-with" list
+ for(String str : EXCLUDED_FIELDS_ENDS_WITH_LIST) {
+ if (field.endsWith(str)) {
+ return true;
+ }
+ }
+ // Check against "contains" list
+ for(String str : EXCLUDED_FIELDS_CONTAINS_LIST) {
+ if (field.contains(str)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
@Override
public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) {
if (stateReductionMode) {
- // Record accesses from executed instructions
- if (executedInsn instanceof JVMFieldInstruction) {
- String fieldClass = ((JVMFieldInstruction) executedInsn).getFieldInfo().getFullName();
- // We don't care about libraries
- if (!fieldClass.startsWith("java") &&
- !fieldClass.startsWith("org") &&
- !fieldClass.startsWith("sun") &&
- !fieldClass.startsWith("com") &&
- !fieldClass.startsWith("gov") &&
- !fieldClass.startsWith("groovy")) {
- analyzeReadWriteAccesses(executedInsn, fieldClass);
+ if (isInitialized) {
+ int currentChoice = choiceCounter - 1;
+ // Record accesses from executed instructions
+ if (executedInsn instanceof JVMFieldInstruction) {
+ // Analyze only after being initialized
+ String fieldClass = ((JVMFieldInstruction) executedInsn).getFieldInfo().getFullName();
+ // We don't care about libraries
+ if (!isFieldExcluded(fieldClass)) {
+ analyzeReadWriteAccesses(executedInsn, fieldClass, currentChoice);
+ }
}
- }
- // Analyze conflicts from next instructions
- if (nextInsn instanceof JVMFieldInstruction) {
- String fieldClass = ((JVMFieldInstruction) nextInsn).getFieldInfo().getFullName();
- // We don't care about libraries
- if (!fieldClass.startsWith("java") &&
- !fieldClass.startsWith("org") &&
- !fieldClass.startsWith("sun") &&
- !fieldClass.startsWith("com") &&
- !fieldClass.startsWith("gov") &&
- !fieldClass.startsWith("groovy")) {
- // Check for conflict (go backward from currentChoice and get the first conflict)
- // If the current event has conflicts with multiple events, then these will be detected
- // one by one as this recursively checks backward when backtrack set is revisited and executed.
- for(int eventNumber=choiceCounter-1; eventNumber>=0; eventNumber--) {
- // Skip if this event number does not have any Read/Write set
- if (!readWriteFieldsMap.containsKey(eventNumber)) {
- continue;
- }
- ReadWriteSet rwSet = readWriteFieldsMap.get(eventNumber);
- // 1) Check for conflicts with Write fields for both Read and Write instructions
- // 2) Check for conflicts with Read fields for Write instructions
- if (((nextInsn instanceof WriteInstruction || nextInsn instanceof ReadInstruction) &&
- rwSet.writeFieldExists(fieldClass)) ||
- (nextInsn instanceof WriteInstruction && rwSet.readFieldExists(fieldClass))) {
- // We do not record and service the same backtrack pair/point twice!
- // If it has been serviced before, we just skip this
- if (recordConflictPair(choiceCounter, eventNumber)) {
- createBacktrackChoiceList(choiceCounter, eventNumber);
- // Break if a conflict is found!
- break;
+ // Analyze conflicts from next instructions
+ if (nextInsn instanceof JVMFieldInstruction) {
+ // The constructor is only called once when the object is initialized
+ // It does not have shared access with other objects
+ MethodInfo mi = nextInsn.getMethodInfo();
+ if (!mi.getName().equals("<init>")) {
+ String fieldClass = ((JVMFieldInstruction) nextInsn).getFieldInfo().getFullName();
+ // We don't care about libraries
+ if (!isFieldExcluded(fieldClass)) {
+ // Check for conflict (go backward from currentChoice and get the first conflict)
+ // If the current event has conflicts with multiple events, then these will be detected
+ // one by one as this recursively checks backward when backtrack set is revisited and executed.
+ for (int eventNumber = currentChoice - 1; eventNumber >= 0; eventNumber--) {
+ // Skip if this event number does not have any Read/Write set
+ if (!readWriteFieldsMap.containsKey(eventNumber)) {
+ continue;
+ }
+ ReadWriteSet rwSet = readWriteFieldsMap.get(eventNumber);
+ int currObjId = ((JVMFieldInstruction) nextInsn).getFieldInfo().getClassInfo().getClassObjectRef();
+ // 1) Check for conflicts with Write fields for both Read and Write instructions
+ if (((nextInsn instanceof WriteInstruction || nextInsn instanceof ReadInstruction) &&
+ rwSet.writeFieldExists(fieldClass) && rwSet.writeFieldObjectId(fieldClass) == currObjId) ||
+ (nextInsn instanceof WriteInstruction && rwSet.readFieldExists(fieldClass) &&
+ rwSet.readFieldObjectId(fieldClass) == currObjId)) {
+ // We do not record and service the same backtrack pair/point twice!
+ // If it has been serviced before, we just skip this
+ if (recordConflictPair(currentChoice, eventNumber)) {
+ createBacktrackChoiceList(currentChoice, eventNumber);
+ // Break if a conflict is found!
+ break;
+ }
+ }
}
}
}