more core...fix traversers...
[IRC.git] / Robust / src / IR / Flat / RuntimeConflictResolver.java
1 package IR.Flat;
2 import java.io.File;
3 import java.io.FileNotFoundException;
4 import java.io.PrintWriter;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.HashSet;
8 import java.util.Hashtable;
9 import java.util.Iterator;
10 import java.util.Set;
11 import java.util.Vector;
12 import Util.Tuple;
13 import Analysis.Disjoint.*;
14 import Analysis.MLP.CodePlan;
15 import IR.Flat.*;
16 import IR.TypeDescriptor;
17 import Analysis.OoOJava.OoOJavaAnalysis;
18
19 /* An instance of this class manages all OoOJava coarse-grained runtime conflicts
20  * by generating C-code to either rule out the conflict at runtime or resolve one.
21  * 
22  * How to Use:
23  * 1) Instantiate singleton object (String input is to specify output dir)
24  * 2) Call setGlobalEffects setGlobalEffects(Hashtable<Taint, Set<Effect>> ) ONCE
25  * 3) Input SESE blocks, for each block:
26  *    3a) call addToTraverseToDoList(FlatSESEEnterNode , ReachGraph , Hashtable<Taint, Set<Effect>>) for the seseBlock
27  *    3b) call String getTraverserInvocation(TempDescriptor, String, FlatSESEEnterNode) to get the name of the traverse method in C
28  * 4) Call void close() 
29  * Note: All computation is done upon closing the object. Steps 1-3 only input data
30  */
31 public class RuntimeConflictResolver {
32   public static final boolean javaDebug = true;
33   public static final boolean cSideDebug = false;
34   
35   private PrintWriter cFile;
36   private PrintWriter headerFile;
37   private static final String hashAndQueueCFileDir = "oooJava/";
38   //This keeps track of taints we've traversed to prevent printing duplicate traverse functions
39   //The Integer keeps track of the weakly connected group it's in (used in enumerateHeapRoots)
40   private Hashtable<Taint, Integer> doneTaints;
41   private Hashtable<Tuple, Integer> idMap=new Hashtable<Tuple,Integer>();
42   private Hashtable<Taint, Set<Effect>> globalEffects;
43   private Hashtable<Taint, Set<Effect>> globalConflicts;
44   private ArrayList<TraversalInfo> toTraverse;
45
46   public int currentID=1;
47
48   // initializing variables can be found in printHeader()
49   private static final String getAllocSiteInC = "->allocsite";
50   private static final String queryVistedHashtable = "hashRCRInsert";
51   private static final String addToQueueInC = "enqueueRCRQueue(";
52   private static final String dequeueFromQueueInC = "dequeueRCRQueue()";
53   private static final String clearQueue = "resetRCRQueue()";
54   // Make hashtable; hashRCRCreate(unsigned int size, double loadfactor)
55   private static final String mallocVisitedHashtable = "hashRCRCreate(128, 0.75)";
56   private static final String deallocVisitedHashTable = "hashRCRDelete()";
57   private static final String resetVisitedHashTable = "hashRCRreset()";
58   
59   //TODO find correct strings for these
60   private static final String addCheckFromHashStructure = "checkFromHashStructure(";
61   private static final String putWaitingQueueBlock = "putWaitingQueueBlock(";  //lifting of blocks will be done by hashtable.
62   private static final String putIntoAllocQueue = "putIntoWaitingQ(";
63   private static final int noConflict = 0;
64   private static final int conflictButTraverserCanContinue = 1;
65   private static final int conflictButTraverserCannotContinue = 2;
66   private static final int allocQueueIsNotEmpty = 0;
67   
68   // Hashtable provides fast access to heaproot # lookups
69   private Hashtable<Taint, WeaklyConectedHRGroup> connectedHRHash;
70   private ArrayList<WeaklyConectedHRGroup> num2WeaklyConnectedHRGroup;
71   private int traverserIDCounter;
72   private int weaklyConnectedHRCounter;
73   private ArrayList<TaintAndInternalHeapStructure> pendingPrintout;
74   private EffectsTable effectsLookupTable;
75   private OoOJavaAnalysis oooa;
76
77   public RuntimeConflictResolver(String buildir, OoOJavaAnalysis oooa) throws FileNotFoundException {
78     String outputFile = buildir + "RuntimeConflictResolver";
79     this.oooa=oooa;
80
81     cFile = new PrintWriter(new File(outputFile + ".c"));
82     headerFile = new PrintWriter(new File(outputFile + ".h"));
83     
84     cFile.println("#include \"" + hashAndQueueCFileDir + "hashRCR.h\"\n#include \""
85         + hashAndQueueCFileDir + "Queue_RCR.h\"\n#include <stdlib.h>");
86     cFile.println("#include \"classdefs.h\"");
87     cFile.println("#include \"structdefs.h\"");
88     cFile.println("#include \"mlp_runtime.h\"");
89     cFile.println("#include \"RuntimeConflictResolver.h\"");
90     cFile.println("#include \"hashStructure.h\"");
91     
92     headerFile.println("#ifndef __3_RCR_H_");
93     headerFile.println("#define __3_RCR_H_");
94     
95     doneTaints = new Hashtable<Taint, Integer>();
96     connectedHRHash = new Hashtable<Taint, WeaklyConectedHRGroup>();
97     
98     traverserIDCounter = 1;
99     weaklyConnectedHRCounter = 0;
100     pendingPrintout = new ArrayList<TaintAndInternalHeapStructure>();
101     toTraverse = new ArrayList<TraversalInfo>();
102     globalConflicts = new Hashtable<Taint, Set<Effect>>(); 
103     //Note: globalEffects is not instantiated since it'll be passed in whole while conflicts comes in chunks
104   }
105
106   public void setGlobalEffects(Hashtable<Taint, Set<Effect>> effects) {
107     globalEffects = effects;
108     
109     if(javaDebug) {
110       System.out.println("============EFFECTS LIST AS PASSED IN============");
111       for(Taint t: globalEffects.keySet()) {
112         System.out.println("For Taint " + t);
113         for(Effect e: globalEffects.get(t)) {
114           System.out.println("\t" + e);
115         }
116       }
117       System.out.println("====================END  LIST====================");
118     }
119   }
120
121   public void init() {
122     //Go through the SESE's
123     for(Iterator<FlatSESEEnterNode> seseit=oooa.getAllSESEs().iterator();seseit.hasNext();) {
124       FlatSESEEnterNode fsen=seseit.next();
125       Analysis.OoOJava.ConflictGraph conflictGraph;
126       Hashtable<Taint, Set<Effect>> conflicts;
127       System.out.println("-------");
128       System.out.println(fsen);
129       System.out.println(fsen.getIsCallerSESEplaceholder());
130       System.out.println(fsen.getParent());
131       
132       if (fsen.getParent()!=null) {
133         conflictGraph = oooa.getConflictGraph(fsen.getParent());
134         System.out.println("CG="+conflictGraph);
135         if (conflictGraph!=null)
136           System.out.println("Conflicts="+conflictGraph.getConflictEffectSet(fsen));
137       }
138       
139       if(!fsen.getIsCallerSESEplaceholder() && fsen.getParent()!=null && 
140          (conflictGraph = oooa.getConflictGraph(fsen.getParent())) != null && 
141          (conflicts = conflictGraph.getConflictEffectSet(fsen)) != null) {
142         FlatMethod fm=fsen.getfmEnclosing();
143         ReachGraph rg=oooa.getDisjointAnalysis().getReachGraph(fm.getMethod());
144         if(cSideDebug)
145           rg.writeGraph("RCR_RG_SESE_DEBUG");
146         
147         addToTraverseToDoList(fsen, rg, conflicts);
148       }
149     }
150     //Go through the stall sites
151     for(Iterator<FlatNode> codeit=oooa.getNodesWithPlans().iterator();codeit.hasNext();) {
152       FlatNode fn=codeit.next();
153       CodePlan cp=oooa.getCodePlan(fn);
154       FlatSESEEnterNode currentSESE=cp.getCurrentSESE();
155       Analysis.OoOJava.ConflictGraph graph = oooa.getConflictGraph(currentSESE);
156
157       if(graph!=null){
158         Set<Analysis.OoOJava.SESELock> seseLockSet = oooa.getLockMappings(graph);
159         Set<Analysis.OoOJava.WaitingElement> waitingElementSet =
160           graph.getStallSiteWaitingElementSet(fn, seseLockSet);
161         
162         if(waitingElementSet.size()>0){
163           for (Iterator iterator = waitingElementSet.iterator(); iterator.hasNext();) {
164             Analysis.OoOJava.WaitingElement waitingElement = (Analysis.OoOJava.WaitingElement) iterator.next();
165             
166             Analysis.OoOJava.ConflictGraph conflictGraph = graph;
167             Hashtable<Taint, Set<Effect>> conflicts;
168             ReachGraph rg = oooa.getDisjointAnalysis().getReachGraph(currentSESE.getmdEnclosing());
169             if(cSideDebug) {
170               rg.writeGraph("RCR_RG_STALLSITE_DEBUG");
171             }
172             if((conflictGraph != null) && 
173                (conflicts = graph.getConflictEffectSet(fn)) != null &&
174                (rg != null)){
175               addToTraverseToDoList(fn, waitingElement.getTempDesc(), rg, conflicts);
176             }
177           }
178         }
179       }
180     }
181
182     buildEffectsLookupStructure();
183     runAllTraversals();
184   }
185   
186   /*
187    * Basic Strategy:
188    * 1) Get global effects and conflicts 
189    * 2) Create a hash structure (EffectsTable) to manage effects (hashed by affected Allocsite, then taint, then field)
190    *     2a) Use Effects to verify we can access something (reads)
191    *     2b) Use conflicts to mark conflicts (read/write/strongupdate)
192    *     2c) At second level of hash, store Heaproots that can cause conflicts at the field
193    * 3) Walk hash structure to identify and enumerate weakly connected groups and generate waiting queue slots. 
194    * 4) Build internal representation of the rgs (pruned)
195    * 5) Print c methods by walking internal representation
196    */
197   
198   public void addToTraverseToDoList(FlatSESEEnterNode rblock, ReachGraph rg, Hashtable<Taint, Set<Effect>> conflicts) {
199     //Add to todo list
200     toTraverse.add(new TraversalInfo(rblock, rg));
201
202     //Add to Global conflicts
203     for(Taint t: conflicts.keySet()) {
204       if(globalConflicts.containsKey(t)) {
205         globalConflicts.get(t).addAll(conflicts.get(t));
206       } else {
207         globalConflicts.put(t, conflicts.get(t));
208       }
209     }
210   }
211   
212
213   public void addToTraverseToDoList(FlatNode fn, TempDescriptor tempDesc, 
214       ReachGraph rg, Hashtable<Taint, Set<Effect>> conflicts) {
215     toTraverse.add(new TraversalInfo(fn, rg, tempDesc));
216     
217     for(Taint t: conflicts.keySet()) {
218       if(globalConflicts.containsKey(t)) {
219         globalConflicts.get(t).addAll(conflicts.get(t));
220       } else {
221         globalConflicts.put(t, conflicts.get(t));
222       }
223     }
224   }
225
226   private void traverseSESEBlock(FlatSESEEnterNode rblock, ReachGraph rg) {
227     Collection<TempDescriptor> inVars = rblock.getInVarSet();
228     
229     if (inVars.size() == 0)
230       return;
231     
232     // For every non-primitive variable, generate unique method
233     // Special Note: The Criteria for executing printCMethod in this loop should match
234     // exactly the criteria in buildcode.java to invoke the generated C method(s). 
235     for (TempDescriptor invar : inVars) {
236       TypeDescriptor type = invar.getType();
237       if(type == null || type.isPrimitive()) {
238         continue;
239       }
240
241       //created stores nodes with specific alloc sites that have been traversed while building
242       //internal data structure. It is later traversed sequentially to find inset variables and
243       //build output code.
244       Hashtable<AllocSite, ConcreteRuntimeObjNode> created = new Hashtable<AllocSite, ConcreteRuntimeObjNode>();
245       VariableNode varNode = rg.getVariableNodeNoMutation(invar);
246       Taint taint = getProperTaintForFlatSESEEnterNode(rblock, varNode, globalEffects);
247       if (taint == null) {
248         printDebug(javaDebug, "Null FOR " +varNode.getTempDescriptor().getSafeSymbol() + rblock.toPrettyString());
249         return;
250       }
251       
252       //This is to prevent duplicate traversals from being generated 
253       if(doneTaints.containsKey(taint))
254         return;
255       
256       doneTaints.put(taint, traverserIDCounter++);
257       createConcreteGraph(effectsLookupTable, created, varNode, taint);
258       
259       
260       //This will add the taint to the printout, there will be NO duplicates (checked above)
261       if(!created.isEmpty()) {
262         rblock.addInVarForDynamicCoarseConflictResolution(invar);
263         pendingPrintout.add(new TaintAndInternalHeapStructure(taint, created));
264       }
265     }
266   }
267   
268   private void traverseStallSite(FlatNode enterNode, TempDescriptor invar, ReachGraph rg) {
269     TypeDescriptor type = invar.getType();
270     if(type == null || type.isPrimitive()) {
271       return;
272     }
273     Hashtable<AllocSite, ConcreteRuntimeObjNode> created = new Hashtable<AllocSite, ConcreteRuntimeObjNode>();
274     VariableNode varNode = rg.getVariableNodeNoMutation(invar);
275     Taint taint = getProperTaintForEnterNode(enterNode, varNode, globalEffects);
276     
277     if (taint == null) {
278       printDebug(javaDebug, "Null FOR " +varNode.getTempDescriptor().getSafeSymbol() + enterNode.toString());
279       return;
280     }        
281     
282     if(doneTaints.containsKey(taint))
283       return;
284     
285     doneTaints.put(taint, traverserIDCounter++);
286     createConcreteGraph(effectsLookupTable, created, varNode, taint);
287     
288     if (!created.isEmpty()) {
289       pendingPrintout.add(new TaintAndInternalHeapStructure(taint, created));
290     }
291   }
292   
293   public String getTraverserInvocation(TempDescriptor invar, String varString, FlatNode fn) {
294     String flatname;
295     if(fn instanceof FlatSESEEnterNode) {
296       flatname = ((FlatSESEEnterNode) fn).getPrettyIdentifier();
297     } else {
298       flatname = fn.toString();
299     }
300     
301     return "traverse___" + invar.getSafeSymbol() + 
302     removeInvalidChars(flatname) + "___("+varString+");";
303   }
304
305   public int getTraverserID(TempDescriptor invar, FlatNode fn) {
306     Tuple t=new Tuple(invar, fn);
307     if (idMap.containsKey(t))
308       return idMap.get(t).intValue();
309     int value=currentID++;
310     idMap.put(t, new Integer(value));
311     return value;
312   }
313   
314   public String removeInvalidChars(String in) {
315     StringBuilder s = new StringBuilder(in);
316     for(int i = 0; i < s.length(); i++) {
317       if(s.charAt(i) == ' ' || s.charAt(i) == '.' || s.charAt(i) == '='||s.charAt(i)=='['||s.charAt(i)==']') {
318         s.deleteCharAt(i);
319         i--;
320       }
321     }
322     return s.toString();
323   }
324
325   public void close() {
326     //prints out all generated code
327     for(TaintAndInternalHeapStructure ths: pendingPrintout) {
328       printCMethod(ths.nodesInHeap, ths.t);
329     }
330     
331     //Prints out the master traverser Invocation that'll call all other traverser
332     //based on traverserID
333     printMasterTraverserInvocation();
334     printResumeTraverserInvocation();
335     
336     //TODO this is only temporary, remove when thread local vars implemented. 
337     createMasterHashTableArray();
338     
339     // Adds Extra supporting methods
340     cFile.println("void initializeStructsRCR() {\n  " + mallocVisitedHashtable + ";\n  " + clearQueue + ";\n}");
341     cFile.println("void destroyRCR() {\n  " + deallocVisitedHashTable + ";\n}");
342     
343     headerFile.println("void initializeStructsRCR();\nvoid destroyRCR();");
344     headerFile.println("#endif\n");
345
346     cFile.close();
347     headerFile.close();
348   }
349
350   //Builds Effects Table and runs the analysis on them to get weakly connected HRs
351   //SPECIAL NOTE: Only runs after we've taken all the conflicts 
352   private void buildEffectsLookupStructure(){
353     effectsLookupTable = new EffectsTable(globalEffects, globalConflicts);
354     effectsLookupTable.runAnaylsis();
355     enumerateHeaproots();
356   }
357
358   private void runAllTraversals() {
359     for(TraversalInfo t: toTraverse) {
360       printDebug(javaDebug, "Running Traversal a traversal on " + t.f);
361       
362       if(t.f instanceof FlatSESEEnterNode) {
363         traverseSESEBlock((FlatSESEEnterNode)t.f, t.rg);
364       } else {
365         if(t.invar == null) {
366           System.out.println("RCR ERROR: Attempted to run a stall site traversal with NO INVAR");
367         } else {
368           traverseStallSite(t.f, t.invar, t.rg);
369         }
370       }
371         
372     }
373   }
374
375   //TODO: This is only temporary, remove when thread local variables are functional. 
376   private void createMasterHashTableArray() {
377     headerFile.println("void createAndFillMasterHashStructureArray();");
378     cFile.println("void createAndFillMasterHashStructureArray() {\n" +
379                 "  rcr_createMasterHashTableArray("+weaklyConnectedHRCounter + ");");
380     
381     for(int i = 0; i < weaklyConnectedHRCounter; i++) {
382       cFile.println("  allHashStructures["+i+"] = (HashStructure *) rcr_createHashtable("+num2WeaklyConnectedHRGroup.get(i).connectedHRs.size()+");");
383     }
384     cFile.println("}");
385   }
386
387   private void printMasterTraverserInvocation() {
388     headerFile.println("\nint tasktraverse(SESEcommon * record);");
389     cFile.println("\nint tasktraverse(SESEcommon * record) {");
390     cFile.println("  switch(record->classID) {");
391     
392     for(Iterator<FlatSESEEnterNode> seseit=oooa.getAllSESEs().iterator();seseit.hasNext();) {
393       FlatSESEEnterNode fsen=seseit.next();
394       cFile.println(    "    /* "+fsen.getPrettyIdentifier()+" */");
395       cFile.println(    "    case "+fsen.getIdentifier()+": {");
396       cFile.println(    "      "+fsen.getSESErecordName()+" * rec=("+fsen.getSESErecordName()+" *) record;");
397       Vector<TempDescriptor> invars=fsen.getInVarsForDynamicCoarseConflictResolution();
398       for(int i=0;i<invars.size();i++) {
399         TempDescriptor tmp=invars.get(i);
400         cFile.println("      " + this.getTraverserInvocation(tmp, "rec->"+tmp+", rec", fsen));
401       }
402       cFile.println(    "    }");
403       cFile.println(    "    break;");
404     }
405     
406     for(Taint t: doneTaints.keySet()) {
407       if (t.isStallSiteTaint()){
408         cFile.println(    "    case -" + getTraverserID(t.getVar(), t.getStallSite())+ ": {");
409         cFile.println(    "      SESEstall * rec=(SESEstall*) record;");
410         cFile.println(    "      " + this.getTraverserInvocation(t.getVar(), "rec->___obj___, rec", t.getStallSite())+";");
411         cFile.println(    "    }");
412         cFile.println("    break;");
413       }
414     }
415
416     cFile.println("    default:\n    printf(\"Invalid SESE ID was passed in.\\n\");\n    break;");
417     
418     cFile.println("  }");
419     cFile.println("}");
420   }
421
422
423   //This will print the traverser invocation that takes in a traverserID and 
424   //starting ptr
425   private void printResumeTraverserInvocation() {
426     headerFile.println("\nint traverse(void * startingPtr, SESEcommon * record, int traverserID);");
427     cFile.println("\nint traverse(void * startingPtr, SESEcommon *record, int traverserID) {");
428     cFile.println("  switch(traverserID) {");
429     
430     for(Taint t: doneTaints.keySet()) {
431       cFile.println("  case " + doneTaints.get(t)+ ":");
432       if(t.isRBlockTaint()) {
433         cFile.println("    " + this.getTraverserInvocation(t.getVar(), "startingPtr, ("+t.getSESE().getSESErecordName()+" *)record", t.getSESE()));
434       } else if (t.isStallSiteTaint()){
435         cFile.println("/*    " + this.getTraverserInvocation(t.getVar(), "startingPtr, record", t.getStallSite())+"*/");
436       } else {
437         System.out.println("RuntimeConflictResolver encountered a taint that is neither SESE nor stallsite: " + t);
438       }
439       cFile.println("    break;");
440     }
441     
442     if(RuntimeConflictResolver.cSideDebug) {
443       cFile.println("  default:\n    printf(\"Invalid traverser ID %u was passed in.\\n\", traverserID);\n    break;");
444     } else {
445       cFile.println("  default:\n    break;");
446     }
447     
448     cFile.println(" }");
449     cFile.println("}");
450   }
451
452   private void createConcreteGraph(
453       EffectsTable table,
454       Hashtable<AllocSite, ConcreteRuntimeObjNode> created, 
455       VariableNode varNode, 
456       Taint t) {
457     
458     // if table is null that means there's no conflicts, therefore we need not
459     // create a traversal
460     if (table == null)
461       return;
462
463     Iterator<RefEdge> possibleEdges = varNode.iteratorToReferencees();
464     while (possibleEdges.hasNext()) {
465       RefEdge edge = possibleEdges.next();
466       assert edge != null;
467
468       ConcreteRuntimeObjNode singleRoot = new ConcreteRuntimeObjNode(edge.getDst(), true, false);
469       AllocSite rootKey = singleRoot.allocSite;
470
471       if (!created.containsKey(rootKey)) {
472         created.put(rootKey, singleRoot);
473         createHelper(singleRoot, edge.getDst().iteratorToReferencees(), created, table, t);
474       }
475     }
476   }
477   
478   //This code is the old way of generating an effects lookup table. 
479   //The new way is to instantiate an EffectsGroup
480   @Deprecated
481   private Hashtable<AllocSite, EffectsGroup> generateEffectsLookupTable(
482       Taint taint, Hashtable<Taint, 
483       Set<Effect>> effects,
484       Hashtable<Taint, Set<Effect>> conflicts) {
485     if(taint == null)
486       return null;
487     
488     Set<Effect> localEffects = effects.get(taint);
489     Set<Effect> localConflicts = conflicts.get(taint);
490     
491     //Debug Code for manually checking effects
492     if(javaDebug) {
493       printEffectsAndConflictsSets(taint, localEffects, localConflicts);
494     }
495     
496     if (localEffects == null || localEffects.isEmpty() || localConflicts == null || localConflicts.isEmpty())
497       return null;
498     
499     Hashtable<AllocSite, EffectsGroup> lookupTable = new Hashtable<AllocSite, EffectsGroup>();
500     
501     for (Effect e : localEffects) {
502       boolean conflict = localConflicts.contains(e);
503       AllocSite key = e.getAffectedAllocSite();
504       EffectsGroup myEffects = lookupTable.get(key);
505       
506       if(myEffects == null) {
507         myEffects = new EffectsGroup();
508         lookupTable.put(key, myEffects);
509       }
510       
511       if(e.getField().getType().isPrimitive()) {
512         if(conflict) {
513           myEffects.addPrimitive(e, true);
514         }
515       }
516       else {
517         myEffects.addObjEffect(e, conflict);
518       }      
519     }
520     
521     return lookupTable;
522   }
523
524   // Plan is to add stuff to the tree depth-first sort of way. That way, we can
525   // propagate up conflicts
526   private void createHelper(ConcreteRuntimeObjNode curr, 
527                             Iterator<RefEdge> edges, 
528                             Hashtable<AllocSite, ConcreteRuntimeObjNode> created,
529                             EffectsTable table, 
530                             Taint taint) {
531     assert table != null;
532     AllocSite parentKey = curr.allocSite;
533     EffectsGroup currEffects = table.getEffects(parentKey, taint); 
534     
535     if (currEffects == null || currEffects.isEmpty()) 
536       return;
537     
538     //Handle Objects (and primitives if child is new)
539     if(currEffects.hasObjectEffects()) {
540       while(edges.hasNext()) {
541         RefEdge edge = edges.next();
542         String field = edge.getField();
543         CombinedObjEffects effectsForGivenField = currEffects.getObjEffect(field);
544         //If there are no effects, then there's no point in traversing this edge
545         if(effectsForGivenField != null) {
546           HeapRegionNode childHRN = edge.getDst();
547           AllocSite childKey = childHRN.getAllocSite();
548           boolean isNewChild = !created.containsKey(childKey);
549           ConcreteRuntimeObjNode child; 
550           
551           if(isNewChild) {
552             child = new ConcreteRuntimeObjNode(childHRN, false, curr.isObjectArray());
553             created.put(childKey, child);
554           } else {
555             child = created.get(childKey);
556           }
557     
558           curr.addObjChild(field, child, effectsForGivenField);
559           
560           if (effectsForGivenField.hasConflict()) {
561             child.hasPotentialToBeIncorrectDueToConflict = true;
562             propogateObjConflict(curr, child);
563           }
564           
565           if(effectsForGivenField.hasReadEffect) {
566             child.addReachableParent(curr);
567             
568             //If isNewChild, flag propagation will be handled at recursive call
569             if(isNewChild) {
570               createHelper(child, childHRN.iteratorToReferencees(), created, table, taint);
571             } else {
572             //This makes sure that all conflicts below the child is propagated up the referencers.
573               if(child.decendantsPrimConflict || child.hasPrimitiveConflicts()) {
574                 propogatePrimConflict(child, child.enqueueToWaitingQueueUponConflict);
575               }
576               
577               if(child.decendantsObjConflict) {
578                 propogateObjConflict(child, child.enqueueToWaitingQueueUponConflict);
579               }
580             }
581           }
582         }
583       }
584     }
585     
586     //Handles primitives
587     curr.primitiveConflictingFields = currEffects.primitiveConflictingFields; 
588     if(currEffects.hasPrimitiveConflicts()) {
589       //Reminder: primitive conflicts are abstracted to object. 
590       propogatePrimConflict(curr, curr);
591     }
592   }
593
594   // This will propagate the conflict up the data structure.
595   private void propogateObjConflict(ConcreteRuntimeObjNode curr, HashSet<ConcreteRuntimeObjNode> pointsOfAccess) {
596     for(ConcreteRuntimeObjNode referencer: curr.parentsWithReadToNode) {
597       if(curr.parentsThatWillLeadToConflicts.add(referencer) || //case where referencee has never seen referncer
598           (pointsOfAccess != null && referencer.addPossibleWaitingQueueEnqueue(pointsOfAccess))) // case where referencer has never seen possible unresolved referencee below 
599       {
600         referencer.decendantsObjConflict = true;
601         propogateObjConflict(referencer, pointsOfAccess);
602       }
603     }
604   }
605   
606   private void propogateObjConflict(ConcreteRuntimeObjNode curr, ConcreteRuntimeObjNode pointOfAccess) {
607     for(ConcreteRuntimeObjNode referencer: curr.parentsWithReadToNode) {
608       if(curr.parentsThatWillLeadToConflicts.add(referencer) || //case where referencee has never seen referncer
609           (pointOfAccess != null && referencer.addPossibleWaitingQueueEnqueue(pointOfAccess))) // case where referencer has never seen possible unresolved referencee below 
610       {
611         referencer.decendantsObjConflict = true;
612         propogateObjConflict(referencer, pointOfAccess);
613       }
614     }
615   }
616   
617   private void propogatePrimConflict(ConcreteRuntimeObjNode curr, HashSet<ConcreteRuntimeObjNode> pointsOfAccess) {
618     for(ConcreteRuntimeObjNode referencer: curr.parentsWithReadToNode) {
619       if(curr.parentsThatWillLeadToConflicts.add(referencer) || //same cases as above
620           (pointsOfAccess != null && referencer.addPossibleWaitingQueueEnqueue(pointsOfAccess))) 
621       {
622         referencer.decendantsPrimConflict = true;
623         propogatePrimConflict(referencer, pointsOfAccess);
624       }
625     }
626   }
627   
628   private void propogatePrimConflict(ConcreteRuntimeObjNode curr, ConcreteRuntimeObjNode pointOfAccess) {
629     for(ConcreteRuntimeObjNode referencer: curr.parentsWithReadToNode) {
630       if(curr.parentsThatWillLeadToConflicts.add(referencer) || //same cases as above
631           (pointOfAccess != null && referencer.addPossibleWaitingQueueEnqueue(pointOfAccess))) 
632       {
633         referencer.decendantsPrimConflict = true;
634         propogatePrimConflict(referencer, pointOfAccess);
635       }
636     }
637   }
638   
639   
640
641   /*
642    * This method generates a C method for every inset variable and rblock. 
643    * 
644    * The C method works by generating a large switch statement that will run the appropriate 
645    * checking code for each object based on its allocation site. The switch statement is 
646    * surrounded by a while statement which dequeues objects to be checked from a queue. An
647    * object is added to a queue only if it contains a conflict (in itself or in its referencees)
648    *  and we came across it while checking through it's referencer. Because of this property, 
649    *  conflicts will be signaled by the referencer; the only exception is the inset variable which can 
650    *  signal a conflict within itself. 
651    */
652   
653   private void printCMethod(Hashtable<AllocSite, ConcreteRuntimeObjNode> created, Taint taint) {
654     //This hash table keeps track of all the case statements generated. Although it may seem a bit much 
655    //for its purpose, I think it may come in handy later down the road to do it this way. 
656     //(i.e. what if we want to eliminate some cases? Or build filter for 1 case)
657     String inVar = taint.getVar().getSafeSymbol();
658     String rBlock;
659     
660     if(taint.isStallSiteTaint()) {
661       rBlock = taint.getStallSite().toString();
662     } else if(taint.isRBlockTaint()) {
663       rBlock = taint.getSESE().getPrettyIdentifier();
664     } else {
665       System.out.println("RCR CRITICAL ERROR: TAINT IS NEITHER A STALLSITE NOR SESE! " + taint.toString());
666       return;
667     }
668     
669     Hashtable<AllocSite, StringBuilder> cases = new Hashtable<AllocSite, StringBuilder>();
670     
671     //Generate C cases 
672     for (ConcreteRuntimeObjNode node : created.values()) {
673       printDebug(javaDebug, "Considering " + node.allocSite + " for traversal");
674       if (!cases.containsKey(node.allocSite) && qualifiesForCaseStatement(node)) {
675         printDebug(javaDebug, "+\t" + node.allocSite + " qualified for case statement");
676         addChecker(taint, node, cases, null, "ptr", 0);
677       }
678     }
679     //IMPORTANT: remember to change getTraverserInvocation if you change the line below
680     String methodName;
681     int index=-1;
682
683     if (taint.isStallSiteTaint()) {
684       methodName= "void traverse___" + inVar + removeInvalidChars(rBlock) + "___(void * InVar, SESEstall *record)";
685     } else {
686       methodName= "void traverse___" + inVar + removeInvalidChars(rBlock) + "___(void * InVar, "+taint.getSESE().getSESErecordName() +" *record)";
687       FlatSESEEnterNode fsese=taint.getSESE();
688       TempDescriptor tmp=taint.getVar();
689       index=fsese.getInVarsForDynamicCoarseConflictResolution().indexOf(tmp);
690     }
691
692     cFile.println(methodName + " {");
693     headerFile.println(methodName + ";");
694     cFile.println("    int totalcount=RUNBIAS;\n");
695     if (taint.isStallSiteTaint()) {
696       cFile.println("    record->rcrRecords[0].count=RUNBIAS;\n");
697       cFile.println("    record->rcrRecords[0].index=0;\n");
698     } else {
699       cFile.println("    record->rcrRecords["+index+"].count=RUNBIAS;\n");
700       cFile.println("    record->rcrRecords["+index+"].index=0;\n");
701     }
702     
703     if(cSideDebug) {
704       cFile.println("printf(\"The traverser ran for " + methodName + "\\n\");");
705     }
706     
707     if(cases.size() == 0) {
708       cFile.println(" return;");
709     } else {
710       //clears queue and hashtable that keeps track of where we've been. 
711       cFile.println(clearQueue + ";\n" + resetVisitedHashTable + ";"); 
712       
713       //Casts the ptr to a generic object struct so we can get to the ptr->allocsite field. 
714       cFile.println("struct ___Object___ * ptr = (struct ___Object___ *) InVar;\nif (InVar != NULL) {\n " + queryVistedHashtable + "(ptr);\n do {");
715       
716       cFile.println("  switch(ptr->allocsite) {");
717       
718       for(AllocSite singleCase: cases.keySet())
719         cFile.append(cases.get(singleCase));
720       
721       cFile.println("  default:\n    break; ");
722       cFile.println("  }\n } while((ptr = " + dequeueFromQueueInC + ") != NULL);\n}");
723     }
724     if (taint.isStallSiteTaint()) {
725       //need to add this
726       cFile.println("     if(atomic_sub_and_test(RUNBIAS-totalcount,&(record->rcrRecords[0].count))) {");
727       cFile.println("         psem_give_tag(record->common.parentsStallSem, record->tag);");
728       cFile.println("}");
729     } else {
730       cFile.println("     if(atomic_sub_and_test(RUNBIAS-totalcount,&(record->rcrRecords["+index+"].count))) {");
731       cFile.println("        int flag=LOCKXCHG32(&(record->rcrRecords["+index+"].flag),0);");
732       cFile.println("        if(flag) {");
733       //we have resolved a heap root...see if this was the last dependence
734       cFile.println("            if(atomic_sub_and_test(1, &(record->common.unresolvedDependencies))) workScheduleSubmit((void *)record);");
735       cFile.println("        }");
736       cFile.println("}");
737     }
738     cFile.println("}");
739     cFile.flush();
740   }
741   
742   /*
743    * addChecker creates a case statement for every object that is either an inset variable
744    * or has multiple referencers (incoming edges). Else it just prints the checker for that object
745    * so that its processing can be pushed up to the referencer node. 
746    */
747   private void addChecker(Taint taint, 
748                           ConcreteRuntimeObjNode node, 
749                           Hashtable<AllocSite,StringBuilder> cases, 
750                           StringBuilder possibleContinuingCase, 
751                           String prefix, 
752                           int depth) {
753     StringBuilder currCase = possibleContinuingCase;
754     // We don't need a case statement for things with either 1 incoming or 0 out
755     // going edges, because they can be processed when checking the parent. 
756     if(qualifiesForCaseStatement(node)) {
757       assert prefix.equals("ptr") && !cases.containsKey(node.allocSite);
758       currCase = new StringBuilder();
759       cases.put(node.allocSite, currCase);
760       currCase.append("  case " + node.getAllocationSite() + ": {\n");
761     }
762     //either currCase is continuing off a parent case or is its own. 
763     assert currCase !=null;
764     boolean primConfRead=false;
765     boolean primConfWrite=false;
766     boolean objConfRead=false;
767     boolean objConfWrite=false;
768
769     //Primitives Test
770     for(String field: node.primitiveConflictingFields.keySet()) {
771       CombinedObjEffects effect=node.primitiveConflictingFields.get(field);
772       primConfRead|=effect.hasReadConflict;
773       primConfWrite|=effect.hasWriteConflict;
774     }
775
776     //Object Reference Test
777     for(ObjRef ref: node.objectRefs) {
778       CombinedObjEffects effect=ref.myEffects;
779       objConfRead|=effect.hasReadConflict;
780       objConfWrite|=effect.hasWriteConflict;
781     }
782
783     int index=-1;
784     if (taint.isRBlockTaint()) {
785       FlatSESEEnterNode fsese=taint.getSESE();
786       TempDescriptor tmp=taint.getVar();
787       index=fsese.getInVarsForDynamicCoarseConflictResolution().indexOf(tmp);
788     }
789
790     //Do call if we need it.
791     if(primConfWrite||objConfWrite) {
792       int heaprootNum = connectedHRHash.get(taint).id;
793       assert heaprootNum != -1;
794       int allocSiteID = connectedHRHash.get(taint).getWaitingQueueBucketNum(node);
795       int traverserID = doneTaints.get(taint);
796       if (objConfRead)
797         currCase.append("    int tmpvar"+depth+"=rcr_WTWRITEBINCASE(allHashStructures["+heaprootNum+"],"+prefix+", (SESEcommon *) record, "+index+");\n");
798       else
799         currCase.append("    int tmpvar"+depth+"=rcr_WRITEBINCASE(allHashStructures["+heaprootNum+"],"+prefix+", (SESEcommon *) record, "+index+");\n");
800     } else if (primConfRead||objConfRead) {
801       int heaprootNum = connectedHRHash.get(taint).id;
802       assert heaprootNum != -1;
803       int allocSiteID = connectedHRHash.get(taint).getWaitingQueueBucketNum(node);
804       int traverserID = doneTaints.get(taint);
805       if (objConfRead) 
806         currCase.append("    int tmpvar"+depth+"=rcr_WTREADBINCASE(allHashStructures["+heaprootNum+"],"+prefix+", (SESEcommon *) record, "+index+");\n");
807       else
808         currCase.append("    int tmpvar"+depth+"=rcr_READBINCASE(allHashStructures["+heaprootNum+"],"+prefix+", (SESEcommon *) record, "+index+");\n");
809     }
810
811     if(primConfWrite||objConfWrite||primConfRead||objConfRead) {
812       currCase.append("if (!(tmpvar"+depth+"&READYMASK)) totalcount--;\n");
813       currCase.append("if (!(tmpvar"+depth+"&SPEC)) {\n");
814       currCase.append("  struct rcrRecord * rcrrec=&record->rcrRecords["+index+"];");
815       currCase.append("  rcrrec->array[rcrrec->index++];");
816       currCase.append("}\n");
817     }
818     
819     //Array Case
820     if(node.isObjectArray() && node.decendantsConflict()) {
821       //since each array element will get its own case statement, we just need to enqueue each item into the queue
822       //note that the ref would be the actual object and node would be of struct ArrayObject
823       
824       ArrayList<Integer> allocSitesWithProblems = node.getReferencedAllocSites();
825       if(!allocSitesWithProblems.isEmpty()) {
826         //This is done with the assumption that an array of object stores pointers. 
827         currCase.append("{\n  int i;\n");
828         currCase.append("  for(i = 0; i<((struct ArrayObject *) " + prefix + " )->___length___; i++ ) {\n");
829         currCase.append("    struct ___Object___ * arrayElement =((struct ___Object___ **)(((char *) &(((struct ArrayObject *)"+ prefix+")->___length___))+sizeof(int)))[i];\n");
830         currCase.append("    if( arrayElement != NULL && (");
831         
832         for(Integer i: allocSitesWithProblems) {
833           currCase.append("( arrayElement->allocsite == " + i.toString() +") ||");
834         }
835         //gets rid of the last ||
836         currCase.delete(currCase.length()-3, currCase.length());
837         
838         currCase.append(") && "+queryVistedHashtable +"(arrayElement)) {\n");
839         currCase.append("      " + addToQueueInC + "arrayElement); }}}\n");
840       }
841     } else {
842     //All other cases
843       for(ObjRef ref: node.objectRefs) {     
844         // Will only process edge if there is some sort of conflict with the Child
845         if (ref.hasConflictsDownThisPath()) {  
846           String childPtr = "((struct "+node.original.getType().getSafeSymbol()+" *)"+prefix +")->___" + ref.field + "___";
847           int pdepth=depth+1;
848           String currPtr = "myPtr" + pdepth;
849           String structType = ref.child.original.getType().getSafeSymbol();
850           currCase.append("    struct " + structType + " * "+currPtr+"= (struct "+ structType + " * ) " + childPtr + ";\n");
851   
852           // Checks if the child exists and has allocsite matching the conflict
853           currCase.append("    if (" + currPtr + " != NULL && " + currPtr + getAllocSiteInC + "==" + ref.allocSite + ") {\n");
854   
855           if (ref.child.decendantsConflict() || ref.child.hasPrimitiveConflicts()) {
856             // Checks if we have visited the child before
857
858             currCase.append("    if (" + queryVistedHashtable +"("+ currPtr + ")) {\n");
859             if (ref.child.getNumOfReachableParents() == 1 && !ref.child.isInsetVar) {
860               addChecker(taint, ref.child, cases, currCase, currPtr, depth + 1);
861             }
862             else {
863               currCase.append("      " + addToQueueInC + childPtr + ");\n ");
864             }
865             currCase.append("    }\n");
866           }
867           //one more brace for the opening if
868           if(ref.hasDirectObjConflict()) {
869             currCase.append("   }\n");
870           }
871           currCase.append("  }\n ");
872         }
873       }
874     }
875
876     if(qualifiesForCaseStatement(node)) {
877       currCase.append("  }\n  break;\n");
878     }
879   }
880   
881   private boolean qualifiesForCaseStatement(ConcreteRuntimeObjNode node) {
882     return (          
883         //insetVariable case
884         (node.isInsetVar && (node.decendantsConflict() || node.hasPrimitiveConflicts())) ||
885         //non-inline-able code cases
886         (node.getNumOfReachableParents() != 1 && node.decendantsConflict()) ||
887         //Cases where resumes are possible
888         (node.hasPotentialToBeIncorrectDueToConflict) && node.decendantsObjConflict) ||
889         //Array elements since we have to enqueue them all, we can't in line their checks
890         (node.canBeArrayElement() && (node.decendantsConflict() || node.hasPrimitiveConflicts()));
891   }
892
893   //This method will touch the waiting queues if necessary.
894   //IMPORTANT NOTE: This needs a closing } from the caller and the if is cannot continue
895   private void addCheckHashtableAndWaitingQ(StringBuilder currCase, Taint t, ConcreteRuntimeObjNode node, String ptr, int depth) {
896     Iterator<ConcreteRuntimeObjNode> it = node.enqueueToWaitingQueueUponConflict.iterator();
897     
898     currCase.append("    int retval"+depth+" = "+ addCheckFromHashStructure + ptr + ");\n");
899     currCase.append("    if (retval"+depth+" == " + conflictButTraverserCannotContinue + " || ");
900     checkWaitingQueue(currCase, t,  node);
901     currCase.append(") {\n");
902     //If cannot continue, then add all the undetermined references that lead from this child, including self.
903     //TODO need waitingQueue Side to automatically check the thing infront of it to prevent double adds. 
904     putIntoWaitingQueue(currCase, t, node, ptr);  
905     
906     ConcreteRuntimeObjNode related;
907     while(it.hasNext()) {
908       related = it.next();
909       //TODO maybe ptr won't even be needed since upon resume, the hashtable will remove obj. 
910       putIntoWaitingQueue(currCase, t, related, ptr);
911     }
912   }
913
914   /*
915   private void handleObjConflict(StringBuilder currCase, String childPtr, AllocSite allocSite, ObjRef ref) {
916     currCase.append("printf(\"Conflict detected with %p from parent with allocation site %u\\n\"," + childPtr + "," + allocSite.getUniqueAllocSiteID() + ");");
917   }
918   
919   private void handlePrimitiveConflict(StringBuilder currCase, String ptr, ArrayList<String> conflicts, AllocSite allocSite) {
920     currCase.append("printf(\"Primitive Conflict detected with %p with alloc site %u\\n\", "+ptr+", "+allocSite.getUniqueAllocSiteID()+"); ");
921   }
922   */
923   
924   private Taint getProperTaintForFlatSESEEnterNode(FlatSESEEnterNode rblock, VariableNode var,
925       Hashtable<Taint, Set<Effect>> effects) {
926     Set<Taint> taints = effects.keySet();
927     for (Taint t : taints) {
928       FlatSESEEnterNode sese = t.getSESE();
929       if(sese != null && sese.equals(rblock) && t.getVar().equals(var.getTempDescriptor())) {
930         return t;
931       }
932     }
933     return null;
934   }
935   
936   
937   private Taint getProperTaintForEnterNode(FlatNode stallSite, VariableNode var,
938       Hashtable<Taint, Set<Effect>> effects) {
939     Set<Taint> taints = effects.keySet();
940     for (Taint t : taints) {
941       FlatNode flatnode = t.getStallSite();
942       if(flatnode != null && flatnode.equals(stallSite) && t.getVar().equals(var.getTempDescriptor())) {
943         return t;
944       }
945     }
946     return null;
947   }
948   
949   private void printEffectsAndConflictsSets(Taint taint, Set<Effect> localEffects,
950       Set<Effect> localConflicts) {
951     System.out.println("#### List of Effects/Conflicts ####");
952     System.out.println("For Taint " + taint);
953     System.out.println("Effects");
954     if(localEffects != null) {
955       for(Effect e: localEffects) {
956        System.out.println(e); 
957       }
958     }
959     System.out.println("Conflicts");
960     if(localConflicts != null) {
961       for(Effect e: localConflicts) {
962         System.out.println(e); 
963       }
964     }
965   }
966
967   private void printDebug(boolean guard, String debugStatements) {
968     if(guard)
969       System.out.println(debugStatements);
970   }
971   
972   //TODO finish this once waitingQueue side is figured out
973   private void putIntoWaitingQueue(StringBuilder sb, Taint taint, ConcreteRuntimeObjNode node, String resumePtr ) {
974     //Method looks like this: void put(int allocSiteID,  x
975     //struct WaitingQueue * queue, //get this from hashtable
976     //int effectType, //not so sure we would actually need this one. 
977     //void * resumePtr, 
978     //int traverserID);  }
979     int heaprootNum = connectedHRHash.get(taint).id;
980     assert heaprootNum != -1;
981     int allocSiteID = connectedHRHash.get(taint).getWaitingQueueBucketNum(node);
982     int traverserID = doneTaints.get(taint);
983     
984     //NOTE if the C-side is changed, this will have to be changed accordingly
985     //TODO make sure this matches c-side
986     sb.append("      putIntoWaitingQueue("+allocSiteID+", " +
987                 "allHashStructures["+ heaprootNum +"]->waitingQueue, " +
988                 resumePtr + ", " +
989                 traverserID+");\n");
990   }
991   
992   //TODO finish waitingQueue side
993   /**
994    * Inserts check to see if waitingQueue is occupied.
995    * 
996    * On C-side, =0 means empty queue, else occupied. 
997    */
998   private void checkWaitingQueue(StringBuilder sb, Taint taint, ConcreteRuntimeObjNode node) {
999     //Method looks like int check(struct WaitingQueue * queue, int allocSiteID)
1000     assert sb != null && taint !=null;    
1001     int heaprootNum = connectedHRHash.get(taint).id;
1002     assert heaprootNum != -1;
1003     int allocSiteID = connectedHRHash.get(taint).getWaitingQueueBucketNum(node);
1004     
1005     sb.append(" (isEmptyForWaitingQ(allHashStructures["+ heaprootNum +"]->waitingQueue, " + allocSiteID + ") == "+ allocQueueIsNotEmpty+")");
1006   }
1007   
1008   private void enumerateHeaproots() {
1009     //reset numbers jsut in case
1010     weaklyConnectedHRCounter = 0;
1011     num2WeaklyConnectedHRGroup = new ArrayList<WeaklyConectedHRGroup>();
1012     
1013     for(Taint t: connectedHRHash.keySet()) {
1014       if(connectedHRHash.get(t).id == -1) {
1015         WeaklyConectedHRGroup hg = connectedHRHash.get(t);
1016         hg.id = weaklyConnectedHRCounter;
1017         num2WeaklyConnectedHRGroup.add(weaklyConnectedHRCounter, hg);
1018         weaklyConnectedHRCounter++;
1019       }
1020     }
1021   }
1022   
1023   private void printoutTable(EffectsTable table) {
1024     
1025     System.out.println("==============EFFECTS TABLE PRINTOUT==============");
1026     for(AllocSite as: table.table.keySet()) {
1027       System.out.println("\tFor AllocSite " + as.getUniqueAllocSiteID());
1028       
1029       BucketOfEffects boe = table.table.get(as);
1030       
1031       if(boe.potentiallyConflictingRoots != null && !boe.potentiallyConflictingRoots.isEmpty()) {
1032         System.out.println("\t\tPotentially conflicting roots: ");
1033         for(String key: boe.potentiallyConflictingRoots.keySet()) {
1034           System.out.println("\t\t-Field: " + key);
1035           System.out.println("\t\t\t" + boe.potentiallyConflictingRoots.get(key));
1036         }
1037       }
1038       for(Taint t: boe.taint2EffectsGroup.keySet()) {
1039         System.out.println("\t\t For Taint " + t);
1040         EffectsGroup eg = boe.taint2EffectsGroup.get(t);
1041           
1042         if(eg.hasPrimitiveConflicts()) {
1043           System.out.print("\t\t\tPrimitive Conflicts at alloc " + as.getUniqueAllocSiteID() +" : ");
1044           for(String field: eg.primitiveConflictingFields.keySet()) {
1045             System.out.print(field + " ");
1046           }
1047           System.out.println();
1048         }
1049         for(String fieldKey: eg.myEffects.keySet()) {
1050           CombinedObjEffects ce = eg.myEffects.get(fieldKey);
1051           System.out.println("\n\t\t\tFor allocSite " + as.getUniqueAllocSiteID() + " && field " + fieldKey);
1052           System.out.println("\t\t\t\tread " + ce.hasReadEffect + "/"+ce.hasReadConflict + 
1053               " write " + ce.hasWriteEffect + "/" + ce.hasWriteConflict + 
1054               " SU " + ce.hasStrongUpdateEffect + "/" + ce.hasStrongUpdateConflict);
1055           for(Effect ef: ce.originalEffects) {
1056             System.out.println("\t" + ef);
1057           }
1058         }
1059       }
1060         
1061     }
1062     
1063   }
1064   
1065   private class EffectsGroup {
1066     Hashtable<String, CombinedObjEffects> myEffects;
1067     Hashtable<String, CombinedObjEffects> primitiveConflictingFields;
1068     
1069     public EffectsGroup() {
1070       myEffects = new Hashtable<String, CombinedObjEffects>();
1071       primitiveConflictingFields = new Hashtable<String, CombinedObjEffects>();
1072     }
1073
1074     public void addPrimitive(Effect e, boolean conflict) {
1075       CombinedObjEffects effects;
1076       if((effects = primitiveConflictingFields.get(e.getField().getSymbol())) == null) {
1077         effects = new CombinedObjEffects();
1078         primitiveConflictingFields.put(e.getField().getSymbol(), effects);
1079       }
1080       effects.add(e, conflict);
1081     }
1082     
1083     public void addObjEffect(Effect e, boolean conflict) {
1084       CombinedObjEffects effects;
1085       if((effects = myEffects.get(e.getField().getSymbol())) == null) {
1086         effects = new CombinedObjEffects();
1087         myEffects.put(e.getField().getSymbol(), effects);
1088       }
1089       effects.add(e, conflict);
1090     }
1091     
1092     public boolean isEmpty() {
1093       return myEffects.isEmpty() && primitiveConflictingFields.isEmpty();
1094     }
1095     
1096     public boolean hasPrimitiveConflicts(){
1097       return !primitiveConflictingFields.isEmpty();
1098     }
1099     
1100     public CombinedObjEffects getPrimEffect(String field) {
1101       return primitiveConflictingFields.get(field);
1102     }
1103
1104     public boolean hasObjectEffects() {
1105       return !myEffects.isEmpty();
1106     }
1107     
1108     public CombinedObjEffects getObjEffect(String field) {
1109       return myEffects.get(field);
1110     }
1111   }
1112   
1113   //Is the combined effects for all effects with the same affectedAllocSite and field
1114   private class CombinedObjEffects {
1115     ArrayList<Effect> originalEffects;
1116     
1117     public boolean hasReadEffect;
1118     public boolean hasWriteEffect;
1119     public boolean hasStrongUpdateEffect;
1120     
1121     public boolean hasReadConflict;
1122     public boolean hasWriteConflict;
1123     public boolean hasStrongUpdateConflict;
1124     
1125     
1126     public CombinedObjEffects() {
1127       originalEffects = new ArrayList<Effect>();
1128       
1129       hasReadEffect = false;
1130       hasWriteEffect = false;
1131       hasStrongUpdateEffect = false;
1132       
1133       hasReadConflict = false;
1134       hasWriteConflict = false;
1135       hasStrongUpdateConflict = false;
1136     }
1137     
1138     public boolean add(Effect e, boolean conflict) {
1139       if(!originalEffects.add(e))
1140         return false;
1141       
1142       switch(e.getType()) {
1143       case Effect.read:
1144         hasReadEffect = true;
1145         hasReadConflict = conflict;
1146         break;
1147       case Effect.write:
1148         hasWriteEffect = true;
1149         hasWriteConflict = conflict;
1150         break;
1151       case Effect.strongupdate:
1152         hasStrongUpdateEffect = true;
1153         hasStrongUpdateConflict = conflict;
1154         break;
1155       default:
1156         System.out.println("RCR ERROR: An Effect Type never seen before has been encountered");
1157         assert false;
1158         break;
1159       }
1160       return true;
1161     }
1162     
1163     public boolean hasConflict() {
1164       return hasReadConflict || hasWriteConflict || hasStrongUpdateConflict;
1165     }
1166   }
1167
1168   //This will keep track of a reference
1169   private class ObjRef {
1170     String field;
1171     int allocSite;
1172     CombinedObjEffects myEffects;
1173     
1174     //This keeps track of the parent that we need to pass by inorder to get
1175     //to the conflicting child (if there is one). 
1176     ConcreteRuntimeObjNode child;
1177
1178     public ObjRef(String fieldname, 
1179                   ConcreteRuntimeObjNode ref, 
1180                   CombinedObjEffects myEffects) {
1181       field = fieldname;
1182       allocSite = ref.getAllocationSite();
1183       child = ref;
1184       
1185       this.myEffects = myEffects;
1186     }
1187     
1188     public boolean hasConflictsDownThisPath() {
1189       return child.decendantsObjConflict || child.decendantsPrimConflict || child.hasPrimitiveConflicts() || myEffects.hasConflict(); 
1190     }
1191     
1192     public boolean hasDirectObjConflict() {
1193       return myEffects.hasConflict();
1194     }
1195   }
1196
1197   private class ConcreteRuntimeObjNode {
1198     ArrayList<ObjRef> objectRefs;
1199     Hashtable<String, CombinedObjEffects> primitiveConflictingFields;
1200     HashSet<ConcreteRuntimeObjNode> parentsWithReadToNode;
1201     HashSet<ConcreteRuntimeObjNode> parentsThatWillLeadToConflicts;
1202     //this set keeps track of references down the line that need to be enqueued if traverser is "paused"
1203     HashSet<ConcreteRuntimeObjNode> enqueueToWaitingQueueUponConflict;
1204     boolean decendantsPrimConflict;
1205     boolean decendantsObjConflict;
1206     boolean hasPotentialToBeIncorrectDueToConflict;
1207     boolean isInsetVar;
1208     boolean isArrayElement;
1209     AllocSite allocSite;
1210     HeapRegionNode original;
1211
1212     public ConcreteRuntimeObjNode(HeapRegionNode me, boolean isInVar, boolean isArrayElement) {
1213       objectRefs = new ArrayList<ObjRef>();
1214       primitiveConflictingFields = null;
1215       parentsThatWillLeadToConflicts = new HashSet<ConcreteRuntimeObjNode>();
1216       parentsWithReadToNode = new HashSet<ConcreteRuntimeObjNode>();
1217       enqueueToWaitingQueueUponConflict = new HashSet<ConcreteRuntimeObjNode>();
1218       allocSite = me.getAllocSite();
1219       original = me;
1220       isInsetVar = isInVar;
1221       decendantsPrimConflict = false;
1222       decendantsObjConflict = false;
1223       hasPotentialToBeIncorrectDueToConflict = false;
1224       this.isArrayElement = isArrayElement;
1225     }
1226
1227     public void addReachableParent(ConcreteRuntimeObjNode curr) {
1228       parentsWithReadToNode.add(curr);
1229     }
1230
1231     @Override
1232     public boolean equals(Object obj) {
1233       return original.equals(obj);
1234     }
1235
1236     public int getAllocationSite() {
1237       return allocSite.getUniqueAllocSiteID();
1238     }
1239
1240     public int getNumOfReachableParents() {
1241       return parentsThatWillLeadToConflicts.size();
1242     }
1243     
1244     public boolean hasPrimitiveConflicts() {
1245       return primitiveConflictingFields != null && !primitiveConflictingFields.isEmpty();
1246     }
1247     
1248     public boolean decendantsConflict() {
1249       return decendantsPrimConflict || decendantsObjConflict;
1250     }
1251     
1252     
1253     //returns true if at least one of the objects in points of access has been added
1254     public boolean addPossibleWaitingQueueEnqueue(HashSet<ConcreteRuntimeObjNode> pointsOfAccess) {
1255       boolean addedNew = false;
1256       for(ConcreteRuntimeObjNode dec: pointsOfAccess) {
1257         if(dec != null && dec != this){
1258           addedNew = addedNew || enqueueToWaitingQueueUponConflict.add(dec);
1259         }
1260       }
1261       
1262       return addedNew;
1263     }
1264     
1265     public boolean addPossibleWaitingQueueEnqueue(ConcreteRuntimeObjNode pointOfAccess) {
1266       if(pointOfAccess != null && pointOfAccess != this){
1267         return enqueueToWaitingQueueUponConflict.add(pointOfAccess);
1268       }
1269       
1270       return false;
1271     }
1272
1273     public void addObjChild(String field, ConcreteRuntimeObjNode child, CombinedObjEffects ce) {
1274       ObjRef ref = new ObjRef(field, child, ce);
1275       objectRefs.add(ref);
1276     }
1277     
1278     public boolean isObjectArray() {
1279       return original.getType().isArray() && !original.getType().isPrimitive() && !original.getType().isImmutable();
1280     }
1281     
1282     public boolean canBeArrayElement() {
1283       return isArrayElement;
1284     }
1285     
1286     public ArrayList<Integer> getReferencedAllocSites() {
1287       ArrayList<Integer> list = new ArrayList<Integer>();
1288       
1289       for(ObjRef r: objectRefs) {
1290         if(r.hasDirectObjConflict() || (r.child.parentsWithReadToNode.contains(this) && r.hasConflictsDownThisPath())) {
1291           list.add(r.allocSite);
1292         }
1293       }
1294       
1295       return list;
1296     }
1297     
1298     public String toString() {
1299       return "AllocSite=" + getAllocationSite() + " myConflict=" + !parentsThatWillLeadToConflicts.isEmpty() + 
1300               " decCon="+decendantsObjConflict+ 
1301               " NumOfConParents=" + getNumOfReachableParents() + " ObjectChildren=" + objectRefs.size();
1302     }
1303   }
1304   
1305   private class EffectsTable {
1306     private Hashtable<AllocSite, BucketOfEffects> table;
1307
1308     public EffectsTable(Hashtable<Taint, Set<Effect>> effects,
1309         Hashtable<Taint, Set<Effect>> conflicts) {
1310       table = new Hashtable<AllocSite, BucketOfEffects>();
1311
1312       // rehash all effects (as a 5-tuple) by their affected allocation site
1313       for (Taint t : effects.keySet()) {
1314         Set<Effect> localConflicts = conflicts.get(t);
1315         for (Effect e : effects.get(t)) {
1316           BucketOfEffects bucket;
1317           if ((bucket = table.get(e.getAffectedAllocSite())) == null) {
1318             bucket = new BucketOfEffects();
1319             table.put(e.getAffectedAllocSite(), bucket);
1320           }
1321           printDebug(javaDebug, "Added Taint" + t + " Effect " + e + "Conflict Status = " + (localConflicts!=null?localConflicts.contains(e):false)+" localConflicts = "+localConflicts);
1322           bucket.add(t, e, localConflicts!=null?localConflicts.contains(e):false);
1323         }
1324       }
1325     }
1326
1327     public EffectsGroup getEffects(AllocSite parentKey, Taint taint) {
1328       //This would get the proper bucket of effects and then get all the effects
1329       //for a parent for a specific taint
1330       try {
1331         return table.get(parentKey).taint2EffectsGroup.get(taint);
1332       }
1333       catch (NullPointerException e) {
1334         return null;
1335       }
1336     }
1337
1338     // Run Analysis will walk the data structure and figure out the weakly
1339     // connected heap roots. 
1340     public void runAnaylsis() {
1341       if(javaDebug) {
1342         printoutTable(this); 
1343       }
1344       
1345       //TODO is there a higher performance way to do this? 
1346       for(AllocSite key: table.keySet()) {
1347         BucketOfEffects effects = table.get(key);
1348         //make sure there are actually conflicts in the bucket
1349         if(effects.potentiallyConflictingRoots != null && !effects.potentiallyConflictingRoots.isEmpty()){
1350           for(String field: effects.potentiallyConflictingRoots.keySet()){
1351             ArrayList<Taint> taints = effects.potentiallyConflictingRoots.get(field);
1352             //For simplicity, we just create a new group and add everything to it instead of
1353             //searching through all of them for the largest group and adding everyone in. 
1354             WeaklyConectedHRGroup group = new WeaklyConectedHRGroup();
1355             group.add(taints); //This will automatically add the taint to the connectedHRhash
1356           }
1357         }
1358       }
1359     }
1360   }
1361   
1362   private class WeaklyConectedHRGroup {
1363     HashSet<Taint> connectedHRs;
1364     //This is to keep track of unique waitingQueue positions for each allocsite. 
1365     Hashtable<AllocSite, Integer> allocSiteToWaitingQueueMap;
1366     int waitingQueueCounter;
1367     int id;
1368     
1369     public WeaklyConectedHRGroup() {
1370       connectedHRs = new HashSet<Taint>();
1371       id = -1; //this will be later modified
1372       waitingQueueCounter = 0;
1373       allocSiteToWaitingQueueMap = new Hashtable<AllocSite, Integer>();
1374     }
1375     
1376     public void add(ArrayList<Taint> list) {
1377       for(Taint t: list) {
1378         this.add(t);
1379       }
1380     }
1381     
1382     public int getWaitingQueueBucketNum(ConcreteRuntimeObjNode node) {
1383       if(allocSiteToWaitingQueueMap.containsKey(node.allocSite)) {
1384         return allocSiteToWaitingQueueMap.get(node.allocSite);
1385       }
1386       else {
1387         allocSiteToWaitingQueueMap.put(node.allocSite, waitingQueueCounter);
1388         return waitingQueueCounter++;
1389       }
1390     }
1391     
1392     public void add(Taint t) {
1393       connectedHRs.add(t);
1394       WeaklyConectedHRGroup oldGroup = connectedHRHash.get(t);
1395       connectedHRHash.put(t, this); //put new group into hash
1396       //If the taint was already in another group, move all its buddies over. 
1397       if(oldGroup != this && oldGroup != null) {
1398         Iterator<Taint> it = oldGroup.connectedHRs.iterator();
1399         Taint relatedTaint;
1400         
1401         while((relatedTaint = it.next()) != null && !connectedHRs.contains(relatedTaint)) {
1402           this.add(relatedTaint);
1403         }
1404       }
1405     }
1406   }
1407   
1408   //This is a class that stores all the effects for an affected allocation site
1409   //across ALL taints. The structure is a hashtable of EffectGroups (see above) hashed
1410   //by a Taint. This way, I can keep EffectsGroups so I can reuse most to all of my old code
1411   //and allows for easier tracking of effects. In addition, a hashtable (keyed by the string
1412   //of the field access) keeps track of an ArrayList of taints of SESEblocks that conflict on that
1413   //field.
1414   private class BucketOfEffects {
1415     // This table is used for lookup while creating the traversal.
1416     Hashtable<Taint, EffectsGroup> taint2EffectsGroup;
1417     
1418     //This table is used to help identify weakly connected groups: Contains ONLY 
1419     //conflicting effects AND is only initialized when needed
1420     //String stores the field
1421     Hashtable<String, ArrayList<Taint>> potentiallyConflictingRoots;
1422
1423     public BucketOfEffects() {
1424       taint2EffectsGroup = new Hashtable<Taint, EffectsGroup>();
1425     }
1426
1427     public void add(Taint t, Effect e, boolean conflict) {
1428       EffectsGroup effectsForGivenTaint;
1429
1430       if ((effectsForGivenTaint = taint2EffectsGroup.get(t)) == null) {
1431         effectsForGivenTaint = new EffectsGroup();
1432         taint2EffectsGroup.put(t, effectsForGivenTaint);
1433       }
1434
1435       if (e.getField().getType().isPrimitive()) {
1436         if (conflict) {
1437           effectsForGivenTaint.addPrimitive(e, true);
1438         }
1439       } else {
1440         effectsForGivenTaint.addObjEffect(e, conflict);
1441       }
1442       
1443       if(conflict) {
1444         if(potentiallyConflictingRoots == null) {
1445           potentiallyConflictingRoots = new Hashtable<String, ArrayList<Taint>>();
1446         }
1447         
1448         ArrayList<Taint> taintsForField = potentiallyConflictingRoots.get(e.getField().getSafeSymbol());
1449         if(taintsForField == null) {
1450           taintsForField = new ArrayList<Taint>();
1451           potentiallyConflictingRoots.put(e.getField().getSafeSymbol(), taintsForField);
1452         }
1453         
1454         if(!taintsForField.contains(t)) {
1455           taintsForField.add(t);
1456         }
1457       }
1458     }
1459   }
1460   
1461   private class TaintAndInternalHeapStructure {
1462     public Taint t;
1463     public Hashtable<AllocSite, ConcreteRuntimeObjNode> nodesInHeap;
1464     
1465     public TaintAndInternalHeapStructure(Taint taint, Hashtable<AllocSite, ConcreteRuntimeObjNode> nodesInHeap) {
1466       t = taint;
1467       this.nodesInHeap = nodesInHeap;
1468     }
1469   }
1470   
1471   private class TraversalInfo {
1472     public FlatNode f;
1473     public ReachGraph rg;
1474     public TempDescriptor invar;
1475     
1476     public TraversalInfo(FlatNode fn, ReachGraph g) {
1477       f = fn;
1478       rg =g;
1479       invar = null;
1480     }
1481
1482     public TraversalInfo(FlatNode fn, ReachGraph rg2, TempDescriptor tempDesc) {
1483       f = fn;
1484       rg =rg2;
1485       invar = tempDesc;
1486     }
1487   }
1488 }