Making field exclusion checks more efficient.
[jpf-core.git] / src / main / gov / nasa / jpf / listener / ConflictTracker.java
index 9d2cd19f6e791d298d29dbc1276a2f6dd1bc2c11..620d1be410597f8ef34963696a895ca7c3e1592b 100644 (file)
@@ -27,6 +27,7 @@ import gov.nasa.jpf.vm.bytecode.LocalVariableInstruction;
 import gov.nasa.jpf.vm.bytecode.ReadInstruction;
 import gov.nasa.jpf.vm.bytecode.StoreInstruction;
 import gov.nasa.jpf.vm.bytecode.WriteInstruction;
+import gov.nasa.jpf.vm.choice.IntChoiceFromSet;
 
 import java.io.PrintWriter;
 
@@ -37,11 +38,12 @@ import java.util.*;
  **/
 
 public class ConflictTracker extends ListenerAdapter {
+
   private final PrintWriter out;
+  private final HashMap<Integer, Node> nodes = new HashMap<Integer, Node>(); // Nodes of a graph
   private final HashSet<String> conflictSet = new HashSet<String>(); // Variables we want to track
   private final HashSet<String> appSet = new HashSet<String>(); // Apps we want to find their conflicts
   private final HashSet<String> manualSet = new HashSet<String>(); // Writer classes with manual inputs to detect direct-direct(No Conflict) interactions
-  private final HashMap<Integer, Node> nodes = new HashMap<Integer, Node>(); // Nodes of a graph
   private HashSet<Transition> transitions = new HashSet<Transition>();
   private ArrayList<Update> currUpdates = new ArrayList<Update>();
   private long timeout;
@@ -50,16 +52,21 @@ public class ConflictTracker extends ListenerAdapter {
   private String operation;
   private String detail;
   private String errorMessage;
+  private String varName;
   private int depth;
   private int id;
   private boolean manual = false;
   private boolean conflictFound = false;
+  private int currentEvent = -1;
+  private boolean debugMode = false;
+  private int popRef = 0;
 
   private final String SET_LOCATION_METHOD = "setLocationMode";
   private final String LOCATION_VAR = "locationMode";
 
   public ConflictTracker(Config config, JPF jpf) {
     out = new PrintWriter(System.out, true);
+    debugMode = config.getBoolean("debug_mode", false);
 
     String[] conflictVars = config.getStringArray("variables");
     // We are not tracking anything if it is null
@@ -124,7 +131,8 @@ public class ConflictTracker extends ListenerAdapter {
       }
 
       //Check for conflict with the appropriate update set if we are not a manual transition
-      if (confupdates != null && !u.isManual()) {
+      //If this is debug mode, then we do not report any conflicts
+      if (!debugMode && confupdates != null && !u.isManual()) {
         for(Update u2: confupdates) {
           if (conflicts(u, u2)) {
             //throw new RuntimeException(createErrorMessage(u, u2));
@@ -174,13 +182,13 @@ public class ConflictTracker extends ListenerAdapter {
     return message;
   }
 
-  Edge createEdge(Node parent, Node current, Transition transition) {
+  Edge createEdge(Node parent, Node current, Transition transition, int evtNum) {
     //Check if this transition is explored.  If so, just skip everything
     if (transitions.contains(transition))
       return null;
 
     //Create edge
-    Edge e = new Edge(parent, current, transition, currUpdates);
+    Edge e = new Edge(parent, current, transition, evtNum, currUpdates);
     parent.addOutEdge(e);
 
     //Mark transition as explored
@@ -218,12 +226,14 @@ public class ConflictTracker extends ListenerAdapter {
   static class Edge {
     Node source, destination;
     Transition transition;
+    int eventNumber;
     ArrayList<Update> updates = new ArrayList<Update>();
     
-    Edge(Node src, Node dst, Transition t, ArrayList<Update> _updates) {
+    Edge(Node src, Node dst, Transition t, int evtNum, ArrayList<Update> _updates) {
       this.source = src;
       this.destination = dst;
       this.transition = t;
+      this.eventNumber = evtNum;
       this.updates.addAll(_updates);
     }
 
@@ -239,6 +249,8 @@ public class ConflictTracker extends ListenerAdapter {
       return transition;
     }
 
+    int getEventNumber() { return eventNumber; }
+
     ArrayList<Update> getUpdates() {
       return updates;
     }
@@ -371,6 +383,15 @@ public class ConflictTracker extends ListenerAdapter {
 
     System.out.println("}");
   }
+
+  @Override
+  public void choiceGeneratorAdvanced(VM vm, ChoiceGenerator<?> currentCG) {
+
+    if (currentCG instanceof IntChoiceFromSet) {
+      IntChoiceFromSet icsCG = (IntChoiceFromSet) currentCG;
+      currentEvent = icsCG.getNextChoice();
+    }
+  }
   
   @Override
   public void stateAdvanced(Search search) {
@@ -384,7 +405,7 @@ public class ConflictTracker extends ListenerAdapter {
     Node currentNode = getNode(id);
 
     // Create an edge based on the current transition
-    Edge newEdge = createEdge(parentNode, currentNode, transition);
+    Edge newEdge = createEdge(parentNode, currentNode, transition, currentEvent);
 
     // Reset the temporary variables and flags
     currUpdates.clear();
@@ -591,55 +612,60 @@ public class ConflictTracker extends ListenerAdapter {
         ti.setNextPC(nextIns);
       }
     }
-    
+
     if (conflictFound) {
       StringBuilder sb = new StringBuilder();
       sb.append(errorMessage);
       Instruction nextIns = ti.createAndThrowException("java.lang.RuntimeException", sb.toString());
       ti.setNextPC(nextIns);
-    } else if (conflictSet.contains(LOCATION_VAR)) {
-      MethodInfo mi = executedInsn.getMethodInfo();
-      // Find the last load before return and get the value here
-      if (mi.getName().equals(SET_LOCATION_METHOD) &&
-          executedInsn instanceof ALOAD && nextInsn instanceof ARETURN) {
-        byte type  = getType(ti, executedInsn);
-        String value = getValue(ti, executedInsn, type);
-        
-        // Extract the writer app name
-        ClassInfo ci = mi.getClassInfo();
-        String writer = ci.getName();
-        
-        // Update the temporary Set set.
-        writeWriterAndValue(writer, LOCATION_VAR, value);
-      }
     } else {
+      // Check if we are ready to pop the values
+      if (popRef == 2) {
+       byte type = getType(ti, executedInsn);
+        varName = getValue(ti, executedInsn, type);
+       String writer = getWriter(ti.getStack(), appSet);
+
+       popRef = popRef-1;
+      } else if (popRef == 1) {
+       byte type = getType(ti, executedInsn);
+       String value = getValue(ti, executedInsn, type);
+       String writer = getWriter(ti.getStack(), appSet);       
+
+       for (String var: conflictSet) {
+               if (varName.contains(var)) {
+                       if (writer != null)
+                               writeWriterAndValue(writer, varName, value);
+               }
+       }
+
+       popRef = popRef-1;
+      }
+
+
+      if (executedInsn.getMnemonic().equals("getfield")) {
+       if (executedInsn.toString().contains("deviceValueSmartThing") || 
+           executedInsn.toString().contains("deviceIntValueSmartThing")) {
+               if (executedInsn.getNext() != null) {
+                       if (executedInsn.getNext().getMnemonic().contains("load")) {
+
+                               if (executedInsn.getNext().getNext() != null)
+                                       if (executedInsn.getNext().getNext().getMnemonic().contains("load"))
+                                               popRef = 2;
+                       }
+               }
+       }
+      }
+
       if (executedInsn instanceof WriteInstruction) {
         String varId = ((WriteInstruction) executedInsn).getFieldInfo().getFullName();
-         
-       // Check if we have an update to isManualTransaction to update manual field
-       if (varId.contains("isManualTransaction")) {
-               byte type = getType(ti, executedInsn);
-               String value = getValue(ti, executedInsn, type);
-            
-               manual = (value.equals("true"))?true:false;
-       }
-        for (String var : conflictSet) {
-          if (varId.contains(var)) {
-            // Get variable info
-            byte type = getType(ti, executedInsn);
-            String value = getValue(ti, executedInsn, type);
-            String writer = getWriter(ti.getStack(), appSet);
-
-            // Just return if the writer is not one of the listed apps in the .jpf file
-            if (writer == null)
-              return;
-            
-            // Update the current updates
-            writeWriterAndValue(writer, var, value);
-          }
+        // Check if we have an update to isManualTransaction to update manual field
+        if (varId.contains("isManualTransaction")) {
+          byte type = getType(ti, executedInsn);
+          String value = getValue(ti, executedInsn, type);
+
+          manual = (value.equals("true"))?true:false;
         }
       }
-    }
+    }    
   }
 }