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;
11 import java.util.Vector;
13 import Analysis.Disjoint.*;
14 import Analysis.MLP.CodePlan;
16 import IR.TypeDescriptor;
17 import Analysis.OoOJava.ConflictGraph;
18 import Analysis.OoOJava.ConflictNode;
19 import Analysis.OoOJava.OoOJavaAnalysis;
21 /* An instance of this class manages all OoOJava coarse-grained runtime conflicts
22 * by generating C-code to either rule out the conflict at runtime or resolve one.
25 * 1) Instantiate singleton object (String input is to specify output dir)
26 * 2) Call setGlobalEffects setGlobalEffects(Hashtable<Taint, Set<Effect>> ) ONCE
27 * 3) Input SESE blocks, for each block:
28 * 3a) call addToTraverseToDoList(FlatSESEEnterNode , ReachGraph , Hashtable<Taint, Set<Effect>>) for the seseBlock
29 * 3b) call String getTraverserInvocation(TempDescriptor, String, FlatSESEEnterNode) to get the name of the traverse method in C
30 * 4) Call void close()
31 * Note: All computation is done upon closing the object. Steps 1-3 only input data
33 public class RuntimeConflictResolver {
34 public static final boolean generalDebug = true;
35 //Prints out effects and data structure used to steer RCR traversals
36 public static final boolean printEffectsAndEffectsTable = false;
37 //Prints steps taken to build internal representation of pruned reach graph
38 public static final boolean traceDataStructureBuild = false;
39 public static final boolean cSideDebug = false;
41 private PrintWriter cFile;
42 private PrintWriter headerFile;
43 private static final String hashAndQueueCFileDir = "oooJava/";
44 //This keeps track of taints we've traversed to prevent printing duplicate traverse functions
45 //The Integer keeps track of the weakly connected group it's in (used in enumerateHeapRoots)
46 private Hashtable<Taint, Integer> doneTaints;
47 private Hashtable<Tuple, Integer> idMap=new Hashtable<Tuple,Integer>();
48 private Hashtable<Tuple, Integer> weakMap=new Hashtable<Tuple,Integer>();
49 private Hashtable<Taint, Set<Effect>> globalEffects;
50 private Hashtable<Taint, Set<Effect>> globalConflicts;
51 private ArrayList<TraversalInfo> toTraverse;
53 public int currentID=1;
55 // initializing variables can be found in printHeader()
56 private static final String getAllocSiteInC = "->allocsite";
57 private static final String queryVistedHashtable = "hashRCRInsert";
58 private static final String addToQueueInC = "enqueueRCRQueue(";
59 private static final String dequeueFromQueueInC = "dequeueRCRQueue()";
60 private static final String clearQueue = "resetRCRQueue()";
61 // Make hashtable; hashRCRCreate(unsigned int size, double loadfactor)
62 private static final String mallocVisitedHashtable = "hashRCRCreate(128, 0.75)";
63 private static final String deallocVisitedHashTable = "hashRCRDelete()";
64 private static final String resetVisitedHashTable = "hashRCRreset()";
66 // Hashtable provides fast access to heaproot # lookups
67 private Hashtable<Taint, WeaklyConectedHRGroup> connectedHRHash;
68 private ArrayList<WeaklyConectedHRGroup> num2WeaklyConnectedHRGroup;
69 private int traverserIDCounter;
70 private int weaklyConnectedHRCounter;
71 private ArrayList<TaintAndInternalHeapStructure> pendingPrintout;
72 private EffectsTable effectsLookupTable;
73 private OoOJavaAnalysis oooa;
76 public RuntimeConflictResolver(String buildir, OoOJavaAnalysis oooa, State state) throws FileNotFoundException {
77 String outputFile = buildir + "RuntimeConflictResolver";
81 cFile = new PrintWriter(new File(outputFile + ".c"));
82 headerFile = new PrintWriter(new File(outputFile + ".h"));
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\"");
92 headerFile.println("#ifndef __3_RCR_H_");
93 headerFile.println("#define __3_RCR_H_");
95 doneTaints = new Hashtable<Taint, Integer>();
96 connectedHRHash = new Hashtable<Taint, WeaklyConectedHRGroup>();
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
106 public void setGlobalEffects(Hashtable<Taint, Set<Effect>> effects) {
107 globalEffects = effects;
109 if(printEffectsAndEffectsTable) {
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);
117 System.out.println("====================END LIST====================");
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());
132 // if (fsen.getParent() != null) {
133 FlatSESEEnterNode parentSESE = null;
134 if (fsen.getSESEParent().size() > 0) {
135 parentSESE = (FlatSESEEnterNode) fsen.getSESEParent().iterator().next();
136 System.out.println("fsen getParent=" + parentSESE);
137 conflictGraph = oooa.getConflictGraph(parentSESE);
138 System.out.println("CG=" + conflictGraph);
139 if (conflictGraph != null)
140 System.out.println("Conflicts=" + conflictGraph.getConflictEffectSet(fsen));
141 // conflictGraph = oooa.getConflictGraph(fsen.getParent());
142 // System.out.println("CG=" + conflictGraph);
143 // if (conflictGraph != null)
144 // System.out.println("Conflicts=" +
145 // conflictGraph.getConflictEffectSet(fsen));
148 // if (!fsen.getIsCallerSESEplaceholder() && fsen.getParent() != null
149 // && (conflictGraph = oooa.getConflictGraph(fsen.getParent())) != null
150 // && (conflicts = conflictGraph.getConflictEffectSet(fsen)) != null) {
151 if(!fsen.getIsCallerSESEplaceholder() && fsen.getSESEParent().size() > 0
152 && (conflictGraph = oooa.getConflictGraph(parentSESE)) != null
153 && (conflicts = conflictGraph.getConflictEffectSet(fsen)) != null ){
154 FlatMethod fm = fsen.getfmEnclosing();
155 ReachGraph rg = oooa.getDisjointAnalysis().getReachGraph(fm.getMethod());
157 rg.writeGraph("RCR_RG_SESE_DEBUG");
159 addToTraverseToDoList(fsen, rg, conflicts);
162 // Go through the stall sites
163 for (Iterator<FlatNode> codeit = oooa.getNodesWithPlans().iterator(); codeit.hasNext();) {
164 FlatNode fn = codeit.next();
165 CodePlan cp = oooa.getCodePlan(fn);
166 FlatSESEEnterNode currentSESE = cp.getCurrentSESE();
168 if(currentSESE.getSESEParent().size()==0){
171 FlatSESEEnterNode parent=(FlatSESEEnterNode)currentSESE.getSESEParent().iterator().next();
172 // Analysis.OoOJava.ConflictGraph graph = oooa.getConflictGraph(currentSESE);
173 Analysis.OoOJava.ConflictGraph graph = oooa.getConflictGraph(parent);
176 Set<Analysis.OoOJava.SESELock> seseLockSet = oooa.getLockMappings(graph);
177 Set<Analysis.OoOJava.WaitingElement> waitingElementSet =
178 graph.getStallSiteWaitingElementSet(fn, seseLockSet);
180 if (waitingElementSet.size() > 0) {
181 for (Iterator<Analysis.OoOJava.WaitingElement> iterator = waitingElementSet.iterator(); iterator.hasNext();) {
182 Analysis.OoOJava.WaitingElement waitingElement =
183 (Analysis.OoOJava.WaitingElement) iterator.next();
185 Analysis.OoOJava.ConflictGraph conflictGraph = graph;
186 Hashtable<Taint, Set<Effect>> conflicts;
187 ReachGraph rg = oooa.getDisjointAnalysis().getReachGraph(currentSESE.getmdEnclosing());
189 rg.writeGraph("RCR_RG_STALLSITE_DEBUG");
191 if ((conflictGraph != null) && (conflicts = graph.getConflictEffectSet(fn)) != null
193 addToTraverseToDoList(fn, waitingElement.getTempDesc(), rg, conflicts);
200 buildEffectsLookupStructure();
206 * 1) Get global effects and conflicts
207 * 2) Create a hash structure (EffectsTable) to manage effects (hashed by affected Allocsite, then taint, then field)
208 * 2a) Use Effects to verify we can access something (reads)
209 * 2b) Use conflicts to mark conflicts (read/write/strongupdate)
210 * 2c) At second level of hash, store Heaproots that can cause conflicts at the field
211 * 3) Walk hash structure to identify and enumerate weakly connected groups and generate waiting queue slots.
212 * 4) Build internal representation of the rgs (pruned)
213 * 5) Print c methods by walking internal representation
216 public void addToTraverseToDoList(FlatSESEEnterNode rblock, ReachGraph rg,
217 Hashtable<Taint, Set<Effect>> conflicts) {
219 toTraverse.add(new TraversalInfo(rblock, rg));
221 //Add to Global conflicts
222 for(Taint t: conflicts.keySet()) {
223 if(globalConflicts.containsKey(t)) {
224 globalConflicts.get(t).addAll(conflicts.get(t));
226 globalConflicts.put(t, conflicts.get(t));
232 public void addToTraverseToDoList(FlatNode fn, TempDescriptor tempDesc,
233 ReachGraph rg, Hashtable<Taint, Set<Effect>> conflicts) {
234 toTraverse.add(new TraversalInfo(fn, rg, tempDesc));
236 for(Taint t: conflicts.keySet()) {
237 if(globalConflicts.containsKey(t)) {
238 globalConflicts.get(t).addAll(conflicts.get(t));
240 globalConflicts.put(t, conflicts.get(t));
245 private void traverseSESEBlock(FlatSESEEnterNode rblock, ReachGraph rg) {
246 Collection<TempDescriptor> inVars = rblock.getInVarSet();
248 if (inVars.size() == 0)
250 System.out.println("RBLOCK:"+rblock);
251 System.out.println("["+inVars+"]");
253 // For every non-primitive variable, generate unique method
254 for (TempDescriptor invar : inVars) {
255 TypeDescriptor type = invar.getType();
256 if(isReallyAPrimitive(type)) {
259 System.out.println(invar);
260 //"created" stores nodes with specific alloc sites that have been traversed while building
261 //internal data structure. Created is later traversed sequentially to find inset variables and
263 //NOTE: Integer stores Allocation Site ID in hashtable
264 Hashtable<Integer, ConcreteRuntimeObjNode> created = new Hashtable<Integer, ConcreteRuntimeObjNode>();
265 VariableNode varNode = rg.getVariableNodeNoMutation(invar);
266 Taint taint = getProperTaintForFlatSESEEnterNode(rblock, varNode, globalEffects);
268 printDebug(generalDebug, "Null FOR " +varNode.getTempDescriptor().getSafeSymbol() + rblock.toPrettyString());
272 //This is to prevent duplicate traversals from being generated
273 if(doneTaints.containsKey(taint))
276 doneTaints.put(taint, traverserIDCounter++);
277 createConcreteGraph(effectsLookupTable, created, varNode, taint);
280 //This will add the taint to the printout, there will be NO duplicates (checked above)
281 if(!created.isEmpty()) {
282 for(Iterator<ConcreteRuntimeObjNode> it=created.values().iterator();it.hasNext();) {
283 ConcreteRuntimeObjNode obj=it.next();
284 if (obj.hasPrimitiveConflicts()||obj.decendantsConflict()||obj.hasDirectObjConflict) {
285 rblock.addInVarForDynamicCoarseConflictResolution(invar);
290 pendingPrintout.add(new TaintAndInternalHeapStructure(taint, created));
295 //This extends a tempDescriptor's isPrimitive test by also excluding primitive arrays.
296 private boolean isReallyAPrimitive(TypeDescriptor type) {
297 return (type.isPrimitive() && !type.isArray());
300 private void traverseStallSite(FlatNode enterNode, TempDescriptor invar, ReachGraph rg) {
301 TypeDescriptor type = invar.getType();
302 if(type == null || isReallyAPrimitive(type)) {
306 Hashtable<Integer, ConcreteRuntimeObjNode> created = new Hashtable<Integer, ConcreteRuntimeObjNode>();
307 VariableNode varNode = rg.getVariableNodeNoMutation(invar);
308 Taint taint = getProperTaintForEnterNode(enterNode, varNode, globalEffects);
311 printDebug(generalDebug, "Null FOR " +varNode.getTempDescriptor().getSafeSymbol() + enterNode.toString());
315 if(doneTaints.containsKey(taint))
318 doneTaints.put(taint, traverserIDCounter++);
319 createConcreteGraph(effectsLookupTable, created, varNode, taint);
321 if (!created.isEmpty()) {
322 pendingPrintout.add(new TaintAndInternalHeapStructure(taint, created));
326 public String getTraverserInvocation(TempDescriptor invar, String varString, FlatNode fn) {
328 if(fn instanceof FlatSESEEnterNode) {
329 flatname = ((FlatSESEEnterNode) fn).getPrettyIdentifier();
331 flatname = fn.toString();
334 return "traverse___" + invar.getSafeSymbol() +
335 removeInvalidChars(flatname) + "___("+varString+");";
338 public int getWeakID(TempDescriptor invar, FlatNode fn) {
339 return weakMap.get(new Tuple(invar, fn)).intValue();
342 public int getTraverserID(TempDescriptor invar, FlatNode fn) {
343 Tuple t=new Tuple(invar, fn);
344 if (idMap.containsKey(t))
345 return idMap.get(t).intValue();
346 int value=currentID++;
347 idMap.put(t, new Integer(value));
351 public String removeInvalidChars(String in) {
352 StringBuilder s = new StringBuilder(in);
353 for(int i = 0; i < s.length(); i++) {
354 if(s.charAt(i) == ' ' || s.charAt(i) == '.' || s.charAt(i) == '='||s.charAt(i)=='['||s.charAt(i)==']') {
362 public void close() {
363 //prints out all generated code
364 for(TaintAndInternalHeapStructure ths: pendingPrintout) {
365 printCMethod(ths.nodesInHeap, ths.t);
368 //Prints out the master traverser Invocation that'll call all other traversers
369 //based on traverserID
370 printMasterTraverserInvocation();
371 printResumeTraverserInvocation();
373 //TODO this is only temporary, remove when thread local vars implemented.
374 createMasterHashTableArray();
376 // Adds Extra supporting methods
377 cFile.println("void initializeStructsRCR() {\n " + mallocVisitedHashtable + ";\n " + clearQueue + ";\n}");
378 cFile.println("void destroyRCR() {\n " + deallocVisitedHashTable + ";\n}");
380 headerFile.println("void initializeStructsRCR();\nvoid destroyRCR();");
381 headerFile.println("#endif\n");
387 //Builds Effects Table and runs the analysis on them to get weakly connected HRs
388 //SPECIAL NOTE: Only runs after we've taken all the conflicts and effects
389 private void buildEffectsLookupStructure(){
390 effectsLookupTable = new EffectsTable(globalEffects, globalConflicts);
391 effectsLookupTable.runAnalysis();
392 enumerateHeaproots();
395 private void runAllTraversals() {
396 for(TraversalInfo t: toTraverse) {
397 printDebug(generalDebug, "Running Traversal a traversal on " + t.f);
399 if(t.f instanceof FlatSESEEnterNode) {
400 traverseSESEBlock((FlatSESEEnterNode)t.f, t.rg);
402 if(t.invar == null) {
403 System.out.println("RCR ERROR: Attempted to run a stall site traversal with NO INVAR");
405 traverseStallSite(t.f, t.invar, t.rg);
412 //TODO: This is only temporary, remove when thread local variables are functional.
413 private void createMasterHashTableArray() {
414 headerFile.println("struct Hashtable_rcr ** createAndFillMasterHashStructureArray();");
415 cFile.println("struct Hashtable_rcr ** createAndFillMasterHashStructureArray() {");
416 cFile.println(" struct Hashtable_rcr **table=rcr_createMasterHashTableArray("+weaklyConnectedHRCounter + ");");
418 for(int i = 0; i < weaklyConnectedHRCounter; i++) {
419 cFile.println(" table["+i+"] = (struct Hashtable_rcr *) rcr_createHashtable("+num2WeaklyConnectedHRGroup.get(i).connectedHRs.size()+");");
421 cFile.println(" return table;");
425 private void printMasterTraverserInvocation() {
426 headerFile.println("\nint tasktraverse(SESEcommon * record);");
427 cFile.println("\nint tasktraverse(SESEcommon * record) {");
428 cFile.println(" if(!CAS(&record->rcrstatus,1,2)) {");
429 //release traverser reference...no traversal necessary
430 cFile.println("#ifndef OOO_DISABLE_TASKMEMPOOL");
431 cFile.println(" RELEASE_REFERENCE_TO(record);");
432 cFile.println("#endif");
433 cFile.println(" return;");
435 cFile.println(" switch(record->classID) {");
437 for(Iterator<FlatSESEEnterNode> seseit=oooa.getAllSESEs().iterator();seseit.hasNext();) {
438 FlatSESEEnterNode fsen=seseit.next();
439 cFile.println( " /* "+fsen.getPrettyIdentifier()+" */");
440 cFile.println( " case "+fsen.getIdentifier()+": {");
441 cFile.println( " "+fsen.getSESErecordName()+" * rec=("+fsen.getSESErecordName()+" *) record;");
442 Vector<TempDescriptor> invars=fsen.getInVarsForDynamicCoarseConflictResolution();
443 for(int i=0;i<invars.size();i++) {
444 TempDescriptor tmp=invars.get(i);
446 // FIX IT LATER! Right now, we assume that there is only one parent
447 FlatSESEEnterNode parentSESE = (FlatSESEEnterNode) fsen.getSESEParent().iterator().next();
448 ConflictGraph graph=oooa.getConflictGraph(parentSESE);
449 String id = tmp + "_sese" + fsen.getPrettyIdentifier();
450 ConflictNode node = graph.getId2cn().get(id);
453 cFile.println(" if (record->rcrstatus!=0)");
456 if(state.NOSTALLTR && node.IsValidToPrune()){
457 cFile.println(" /* " + this.getTraverserInvocation(tmp, "rec->"+tmp+", rec", fsen)+"*/");
459 cFile.println(" " + this.getTraverserInvocation(tmp, "rec->"+tmp+", rec", fsen));
463 //release traverser reference...traversal finished...
464 //executing thread will clean bins for us
465 cFile.println(" record->rcrstatus=0;");
466 cFile.println("#ifndef OOO_DISABLE_TASKMEMPOOL");
467 cFile.println(" RELEASE_REFERENCE_TO(record);");
468 cFile.println("#endif");
469 cFile.println( " }");
470 cFile.println( " break;");
473 for(Taint t: doneTaints.keySet()) {
474 if (t.isStallSiteTaint()){
475 cFile.println( " case -" + getTraverserID(t.getVar(), t.getStallSite())+ ": {");
476 cFile.println( " SESEstall * rec=(SESEstall*) record;");
477 cFile.println( " " + this.getTraverserInvocation(t.getVar(), "rec->___obj___, rec", t.getStallSite())+";");
478 cFile.println( " record->rcrstatus=0;");
479 cFile.println( " }");
480 cFile.println(" break;");
484 cFile.println(" default:\n printf(\"Invalid SESE ID was passed in: %d.\\n\",record->classID);\n break;");
490 //This will print the traverser invocation that takes in a traverserID and starting ptr
491 private void printResumeTraverserInvocation() {
492 headerFile.println("\nint traverse(void * startingPtr, SESEcommon * record, int traverserID);");
493 cFile.println("\nint traverse(void * startingPtr, SESEcommon *record, int traverserID) {");
494 cFile.println(" switch(traverserID) {");
496 for(Taint t: doneTaints.keySet()) {
497 cFile.println(" case " + doneTaints.get(t)+ ":");
498 if(t.isRBlockTaint()) {
499 cFile.println(" " + this.getTraverserInvocation(t.getVar(), "startingPtr, ("+t.getSESE().getSESErecordName()+" *)record", t.getSESE()));
500 } else if (t.isStallSiteTaint()){
501 cFile.println("/* " + this.getTraverserInvocation(t.getVar(), "startingPtr, record", t.getStallSite())+"*/");
503 System.out.println("RuntimeConflictResolver encountered a taint that is neither SESE nor stallsite: " + t);
505 cFile.println(" break;");
508 if(RuntimeConflictResolver.cSideDebug) {
509 cFile.println(" default:\n printf(\"Invalid traverser ID %u was passed in.\\n\", traverserID);\n break;");
511 cFile.println(" default:\n break;");
518 private void createConcreteGraph(
520 Hashtable<Integer, ConcreteRuntimeObjNode> created,
521 VariableNode varNode,
524 // if table is null that means there's no conflicts, therefore we need not
525 // create a traversal
529 Iterator<RefEdge> possibleEdges = varNode.iteratorToReferencees();
530 while (possibleEdges.hasNext()) {
531 RefEdge edge = possibleEdges.next();
534 ConcreteRuntimeObjNode singleRoot = new ConcreteRuntimeObjNode(edge.getDst(), true);
535 int rootKey = singleRoot.allocSite.getUniqueAllocSiteID();
537 if (!created.containsKey(rootKey)) {
538 created.put(rootKey, singleRoot);
539 createHelper(singleRoot, edge.getDst().iteratorToReferencees(), created, table, t);
544 // Plan is to add stuff to the tree depth-first sort of way. That way, we can
545 // propagate up conflicts
546 private void createHelper(ConcreteRuntimeObjNode curr,
547 Iterator<RefEdge> edges,
548 Hashtable<Integer, ConcreteRuntimeObjNode> created,
551 assert table != null;
552 AllocSite parentKey = curr.allocSite;
553 EffectsGroup currEffects = table.getEffects(parentKey, taint);
555 if (currEffects == null || currEffects.isEmpty())
558 //Handle Objects (and primitives if child is new)
559 if(currEffects.hasObjectEffects()) {
560 while(edges.hasNext()) {
561 RefEdge edge = edges.next();
562 String field = edge.getField();
563 CombinedObjEffects effectsForGivenField = currEffects.getObjEffect(field);
564 //If there are no effects, then there's no point in traversing this edge
565 if(effectsForGivenField != null) {
566 HeapRegionNode childHRN = edge.getDst();
567 int childKey = childHRN.getAllocSite().getUniqueAllocSiteID();
568 boolean isNewChild = !created.containsKey(childKey);
569 ConcreteRuntimeObjNode child;
572 child = new ConcreteRuntimeObjNode(childHRN, false);
573 created.put(childKey, child);
575 child = created.get(childKey);
578 curr.addObjChild(field, child, effectsForGivenField);
580 if (effectsForGivenField.hasConflict()) {
581 child.hasPotentialToBeIncorrectDueToConflict |= effectsForGivenField.hasReadConflict;
582 propagateObjConflict(curr, child);
585 if(effectsForGivenField.hasReadEffect) {
586 child.addReachableParent(curr);
588 //If isNewChild, flag propagation will be handled at recursive call
590 createHelper(child, childHRN.iteratorToReferencees(), created, table, taint);
592 //This makes sure that all conflicts below the child is propagated up the referencers.
593 if(child.decendantsPrimConflict || child.hasPrimitiveConflicts()) {
594 propagatePrimConflict(child, child.enqueueToWaitingQueueUponConflict);
597 if(child.decendantsObjConflict) {
598 propagateObjConflict(child, child.enqueueToWaitingQueueUponConflict);
607 curr.primitiveConflictingFields = currEffects.primitiveConflictingFields;
608 if(currEffects.hasPrimitiveConflicts()) {
609 //Reminder: primitive conflicts are abstracted to object.
610 propagatePrimConflict(curr, curr);
614 // This will propagate the conflict up the data structure.
615 private void propagateObjConflict(ConcreteRuntimeObjNode curr, HashSet<ConcreteRuntimeObjNode> pointsOfAccess) {
616 for(ConcreteRuntimeObjNode referencer: curr.parentsWithReadToNode) {
617 if(curr.parentsThatWillLeadToConflicts.add(referencer) || //case where referencee has never seen referncer
618 (pointsOfAccess != null && referencer.addPossibleWaitingQueueEnqueue(pointsOfAccess))) // case where referencer has never seen possible unresolved referencee below
620 referencer.decendantsObjConflict = true;
621 propagateObjConflict(referencer, pointsOfAccess);
626 private void propagateObjConflict(ConcreteRuntimeObjNode curr, ConcreteRuntimeObjNode pointOfAccess) {
627 for(ConcreteRuntimeObjNode referencer: curr.parentsWithReadToNode) {
628 if(curr.parentsThatWillLeadToConflicts.add(referencer) || //case where referencee has never seen referncer
629 (pointOfAccess != null && referencer.addPossibleWaitingQueueEnqueue(pointOfAccess))) // case where referencer has never seen possible unresolved referencee below
631 referencer.decendantsObjConflict = true;
632 propagateObjConflict(referencer, pointOfAccess);
637 private void propagatePrimConflict(ConcreteRuntimeObjNode curr, HashSet<ConcreteRuntimeObjNode> pointsOfAccess) {
638 for(ConcreteRuntimeObjNode referencer: curr.parentsWithReadToNode) {
639 if(curr.parentsThatWillLeadToConflicts.add(referencer) || //same cases as above
640 (pointsOfAccess != null && referencer.addPossibleWaitingQueueEnqueue(pointsOfAccess)))
642 referencer.decendantsPrimConflict = true;
643 propagatePrimConflict(referencer, pointsOfAccess);
648 private void propagatePrimConflict(ConcreteRuntimeObjNode curr, ConcreteRuntimeObjNode pointOfAccess) {
649 for(ConcreteRuntimeObjNode referencer: curr.parentsWithReadToNode) {
650 if(curr.parentsThatWillLeadToConflicts.add(referencer) || //same cases as above
651 (pointOfAccess != null && referencer.addPossibleWaitingQueueEnqueue(pointOfAccess)))
653 referencer.decendantsPrimConflict = true;
654 propagatePrimConflict(referencer, pointOfAccess);
660 * This method generates a C method for every inset variable and rblock.
662 * The C method works by generating a large switch statement that will run the appropriate
663 * checking code for each object based on its allocation site. The switch statement is
664 * surrounded by a while statement which dequeues objects to be checked from a queue. An
665 * object is added to a queue only if it contains a conflict (in itself or in its referencees)
666 * and we came across it while checking through it's referencer. Because of this property,
667 * conflicts will be signaled by the referencer; the only exception is the inset variable which can
668 * signal a conflict within itself.
671 private void printCMethod(Hashtable<Integer, ConcreteRuntimeObjNode> created, Taint taint) {
672 String inVar = taint.getVar().getSafeSymbol();
675 if(taint.isStallSiteTaint()) {
676 rBlock = taint.getStallSite().toString();
677 } else if(taint.isRBlockTaint()) {
678 rBlock = taint.getSESE().getPrettyIdentifier();
680 System.out.println("RCR CRITICAL ERROR: TAINT IS NEITHER A STALLSITE NOR SESE! " + taint.toString());
684 //This hash table keeps track of all the case statements generated.
685 Hashtable<AllocSite, StringBuilder> cases = new Hashtable<AllocSite, StringBuilder>();
688 for (ConcreteRuntimeObjNode node : created.values()) {
689 printDebug(generalDebug, "Considering " + node.allocSite + " for traversal");
690 if (!cases.containsKey(node.allocSite) && qualifiesForCaseStatement(node)) {
691 printDebug(generalDebug, "+\t" + node.allocSite + " qualified for case statement");
692 addChecker(taint, node, cases, null, "ptr", 0);
699 if (taint.isStallSiteTaint()) {
700 methodName= "void traverse___" + inVar + removeInvalidChars(rBlock) + "___(void * InVar, SESEstall *record)";
702 methodName= "void traverse___" + inVar + removeInvalidChars(rBlock) + "___(void * InVar, "+taint.getSESE().getSESErecordName() +" *record)";
703 FlatSESEEnterNode fsese=taint.getSESE();
704 TempDescriptor tmp=taint.getVar();
705 index=fsese.getInVarsForDynamicCoarseConflictResolution().indexOf(tmp);
708 cFile.println(methodName + " {");
709 headerFile.println(methodName + ";");
712 cFile.println("printf(\"The traverser ran for " + methodName + "\\n\");");
716 if(cases.size() == 0) {
717 cFile.println(" return;");
719 cFile.println(" int totalcount=RUNBIAS;");
720 if (taint.isStallSiteTaint()) {
721 cFile.println(" record->rcrRecords[0].count=RUNBIAS;");
723 cFile.println(" record->rcrRecords["+index+"].count=RUNBIAS;");
726 //clears queue and hashtable that keeps track of where we've been.
727 cFile.println(clearQueue + ";\n" + resetVisitedHashTable + ";");
728 //generic cast to ___Object___ to access ptr->allocsite field.
729 cFile.println("struct ___Object___ * ptr = (struct ___Object___ *) InVar;\nif (InVar != NULL) {\n " + queryVistedHashtable + "(ptr);\n do {");
730 if (taint.isRBlockTaint()) {
731 cFile.println(" if(unlikely(record->common.doneExecuting)) {");
732 cFile.println(" record->common.rcrstatus=0;");
733 cFile.println(" return;");
736 cFile.println(" switch(ptr->allocsite) {");
738 for(AllocSite singleCase: cases.keySet()) {
739 cFile.append(cases.get(singleCase));
742 cFile.println(" default:\n break; ");
743 cFile.println(" }\n } while((ptr = " + dequeueFromQueueInC + ") != NULL);\n}");
745 if (taint.isStallSiteTaint()) {
747 cFile.println(" if(atomic_sub_and_test(totalcount,&(record->rcrRecords[0].count))) {");
748 cFile.println(" psem_give_tag(record->common.parentsStallSem, record->tag);");
749 cFile.println(" BARRIER();");
752 cFile.println(" if(atomic_sub_and_test(totalcount,&(record->rcrRecords["+index+"].count))) {");
753 cFile.println(" int flag=LOCKXCHG32(&(record->rcrRecords["+index+"].flag),0);");
754 cFile.println(" if(flag) {");
755 //we have resolved a heap root...see if this was the last dependence
756 cFile.println(" if(atomic_sub_and_test(1, &(record->common.unresolvedDependencies))) workScheduleSubmit((void *)record);");
766 * addChecker creates a case statement for every object that is an inset variable, has more
767 * than 1 parent && has conflicts, or where resumes are possible (from waiting queue).
768 * See .qualifiesForCaseStatement
770 private void addChecker(Taint taint,
771 ConcreteRuntimeObjNode node,
772 Hashtable<AllocSite,StringBuilder> cases,
773 StringBuilder possibleContinuingCase,
776 StringBuilder currCase = possibleContinuingCase;
777 if(qualifiesForCaseStatement(node)) {
778 assert prefix.equals("ptr");
779 assert !cases.containsKey(node.allocSite);
780 currCase = new StringBuilder();
781 cases.put(node.allocSite, currCase);
782 currCase.append(" case " + node.getAllocationSite() + ": {\n");
784 //either currCase is continuing off a parent case or is its own.
785 assert currCase !=null;
787 insertEntriesIntoHashStructure(taint, node, prefix, depth, currCase);
789 //Handle conflicts further down.
790 if(node.decendantsConflict()) {
792 currCase.append("{\n");
795 if(node.isArray() && node.decendantsConflict()) {
796 String childPtr = "((struct ___Object___ **)(((char *) &(((struct ArrayObject *)"+ prefix+")->___length___))+sizeof(int)))[i]";
797 String currPtr = "arrayElement" + pdepth;
799 currCase.append("{\n int i;\n");
800 currCase.append(" struct ___Object___ * "+currPtr+";\n");
801 currCase.append(" for(i = 0; i<((struct ArrayObject *) " + prefix + " )->___length___; i++ ) {\n");
803 //There should be only one field, hence we only take the first field in the keyset.
804 assert node.objectRefs.keySet().size() <= 1;
805 ObjRefList refsAtParticularField = node.objectRefs.get(node.objectRefs.keySet().iterator().next());
806 printObjRefSwitchStatement(taint,cases,pdepth,currCase,refsAtParticularField,childPtr,currPtr);
807 currCase.append(" }}\n");
810 String currPtr = "myPtr" + pdepth;
811 currCase.append(" struct ___Object___ * "+currPtr+";\n");
812 for(String field: node.objectRefs.keySet()) {
813 ObjRefList refsAtParticularField = node.objectRefs.get(field);
815 if(refsAtParticularField.hasConflicts()) {
816 String childPtr = "((struct "+node.original.getType().getSafeSymbol()+" *)"+prefix +")->___" + field + "___";
817 printObjRefSwitchStatement(taint,cases, pdepth, currCase, refsAtParticularField, childPtr, currPtr);
822 currCase.append("}\n"); //For particular top level case statement.
824 if(qualifiesForCaseStatement(node)) {
825 currCase.append(" }\n break;\n");
829 private void insertEntriesIntoHashStructure(Taint taint, ConcreteRuntimeObjNode curr,
830 String prefix, int depth, StringBuilder currCase) {
831 boolean primConfRead=false;
832 boolean primConfWrite=false;
833 boolean objConfRead=false;
834 boolean objConfWrite=false;
835 boolean descendantConflict=false;
837 //Direct Primitives Test
838 for(String field: curr.primitiveConflictingFields.keySet()) {
839 CombinedObjEffects effect=curr.primitiveConflictingFields.get(field);
840 primConfRead|=effect.hasReadConflict;
841 primConfWrite|=effect.hasWriteConflict;
844 //Direct Object Reference Test
845 for(String field: curr.objectRefs.keySet()) {
846 for(ObjRef ref: curr.objectRefs.get(field)) {
847 CombinedObjEffects effect=ref.myEffects;
848 objConfRead|=effect.hasReadConflict;
849 objConfWrite|=effect.hasWriteConflict;
854 descendantConflict=curr.decendantsConflict();
858 if (taint.isRBlockTaint()) {
859 FlatSESEEnterNode fsese=taint.getSESE();
860 TempDescriptor tmp=taint.getVar();
861 index=fsese.getInVarsForDynamicCoarseConflictResolution().indexOf(tmp);
864 String strrcr=taint.isRBlockTaint()?"&record->rcrRecords["+index+"], ":"NULL, ";
865 String tasksrc=taint.isRBlockTaint()?"(SESEcommon *) record, ":"(SESEcommon *)(((INTPTR)record)|1LL), ";
867 //Do call if we need it.
868 if(primConfWrite||objConfWrite) {
869 int heaprootNum = connectedHRHash.get(taint).id;
870 assert heaprootNum != -1;
871 int allocSiteID = connectedHRHash.get(taint).getWaitingQueueBucketNum(curr);
872 int traverserID = doneTaints.get(taint);
873 currCase.append(" int tmpkey"+depth+"=rcr_generateKey("+prefix+");\n");
874 if (descendantConflict)
875 currCase.append(" int tmpvar"+depth+"=rcr_WTWRITEBINCASE(allHashStructures["+heaprootNum+"], tmpkey"+depth+", "+tasksrc+strrcr+index+");\n");
877 currCase.append(" int tmpvar"+depth+"=rcr_WRITEBINCASE(allHashStructures["+heaprootNum+"], tmpkey"+depth+", "+ tasksrc+strrcr+index+");\n");
878 } else if (primConfRead||objConfRead) {
879 int heaprootNum = connectedHRHash.get(taint).id;
880 assert heaprootNum != -1;
881 int allocSiteID = connectedHRHash.get(taint).getWaitingQueueBucketNum(curr);
882 int traverserID = doneTaints.get(taint);
883 currCase.append(" int tmpkey"+depth+"=rcr_generateKey("+prefix+");\n");
884 if (descendantConflict)
885 currCase.append(" int tmpvar"+depth+"=rcr_WTREADBINCASE(allHashStructures["+heaprootNum+"], tmpkey"+depth+", "+tasksrc+strrcr+index+");\n");
887 currCase.append(" int tmpvar"+depth+"=rcr_READBINCASE(allHashStructures["+heaprootNum+"], tmpkey"+depth+", "+tasksrc+strrcr+index+");\n");
890 if(primConfWrite||objConfWrite||primConfRead||objConfRead) {
891 currCase.append("if (!(tmpvar"+depth+"&READYMASK)) totalcount--;\n");
895 private void printObjRefSwitchStatement(Taint taint, Hashtable<AllocSite, StringBuilder> cases,
896 int pDepth, StringBuilder currCase, ObjRefList refsAtParticularField, String childPtr,
899 currCase.append(" "+currPtr+"= (struct ___Object___ * ) " + childPtr + ";\n");
900 currCase.append(" if (" + currPtr + " != NULL) { \n");
901 currCase.append(" switch(" + currPtr + getAllocSiteInC + ") {\n");
903 for(ObjRef ref: refsAtParticularField) {
904 if(ref.child.decendantsConflict() || ref.child.hasPrimitiveConflicts()) {
905 currCase.append(" case "+ref.allocSite+":\n {\n");
906 //The hash insert is here because we don't want to enqueue things unless we know it conflicts.
907 currCase.append(" if (" + queryVistedHashtable +"("+ currPtr + ")) {\n");
909 if(qualifiesForCaseStatement(ref.child)){
910 currCase.append(" " + addToQueueInC + childPtr + ");\n ");
912 addChecker(taint, ref.child, cases, currCase, currPtr, pDepth + 1);
915 currCase.append(" }\n"); //close for queryVistedHashtable
917 currCase.append("}\n"); //close for internal case statement
921 currCase.append(" default:\n" +
923 " }}\n"); //internal switch.
926 private boolean qualifiesForCaseStatement(ConcreteRuntimeObjNode node) {
929 (node.isInsetVar && (node.decendantsConflict() || node.hasPrimitiveConflicts()) || node.hasDirectObjConflict) ||
930 //non-inline-able code cases
931 (node.getNumOfReachableParents() != 1 && node.decendantsConflict()) ||
932 //Cases where resumes are possible
933 (node.hasPotentialToBeIncorrectDueToConflict) && node.decendantsObjConflict);
936 private Taint getProperTaintForFlatSESEEnterNode(FlatSESEEnterNode rblock, VariableNode var,
937 Hashtable<Taint, Set<Effect>> effects) {
938 Set<Taint> taints = effects.keySet();
939 for (Taint t : taints) {
940 FlatSESEEnterNode sese = t.getSESE();
941 if(sese != null && sese.equals(rblock) && t.getVar().equals(var.getTempDescriptor())) {
948 // decide whether the given SESE doesn't have traversers at all
949 public boolean hasEmptyTraversers(FlatSESEEnterNode fsen) {
950 boolean hasEmpty = true;
952 Set<FlatSESEEnterNode> children = fsen.getSESEChildren();
953 for (Iterator iterator = children.iterator(); iterator.hasNext();) {
954 FlatSESEEnterNode child = (FlatSESEEnterNode) iterator.next();
955 hasEmpty &= child.getInVarsForDynamicCoarseConflictResolution().size() == 0;
961 private Taint getProperTaintForEnterNode(FlatNode stallSite, VariableNode var,
962 Hashtable<Taint, Set<Effect>> effects) {
963 Set<Taint> taints = effects.keySet();
964 for (Taint t : taints) {
965 FlatNode flatnode = t.getStallSite();
966 if(flatnode != null && flatnode.equals(stallSite) && t.getVar().equals(var.getTempDescriptor())) {
973 private void printDebug(boolean guard, String debugStatements) {
975 System.out.println(debugStatements);
978 private void enumerateHeaproots() {
979 weaklyConnectedHRCounter = 0;
980 num2WeaklyConnectedHRGroup = new ArrayList<WeaklyConectedHRGroup>();
982 for(Taint t: connectedHRHash.keySet()) {
983 if(connectedHRHash.get(t).id == -1) {
984 WeaklyConectedHRGroup hg = connectedHRHash.get(t);
985 hg.id = weaklyConnectedHRCounter;
986 num2WeaklyConnectedHRGroup.add(weaklyConnectedHRCounter, hg);
987 weaklyConnectedHRCounter++;
990 if(t.isRBlockTaint()) {
991 int id=connectedHRHash.get(t).id;
992 Tuple tup=new Tuple(t.getVar(),t.getSESE());
993 if (weakMap.containsKey(tup)) {
994 if (weakMap.get(tup).intValue()!=id)
995 throw new Error("Var/SESE not unique for weak component.");
997 weakMap.put(tup, new Integer(id));
1001 //output weakly connected groups for verification
1003 System.out.println("==============Weakly Connected HeapRoots==============");
1005 for(int i=0; i < num2WeaklyConnectedHRGroup.size(); i++){
1006 System.out.println("Heap Group #" + i);
1007 WeaklyConectedHRGroup hg = num2WeaklyConnectedHRGroup.get(i);
1008 for(Taint t: hg.connectedHRs) {
1009 System.out.println("\t" + t);
1013 System.out.println("=======================END LIST=======================");
1017 private void printoutTable(EffectsTable table) {
1019 System.out.println("==============EFFECTS TABLE PRINTOUT==============");
1020 for(AllocSite as: table.table.keySet()) {
1021 System.out.println("\tFor AllocSite " + as.getUniqueAllocSiteID());
1023 BucketOfEffects boe = table.table.get(as);
1025 if(boe.potentiallyConflictingRoots != null && !boe.potentiallyConflictingRoots.isEmpty()) {
1026 System.out.println("\t\tPotentially conflicting roots: ");
1027 for(String key: boe.potentiallyConflictingRoots.keySet()) {
1028 System.out.println("\t\t-Field: " + key);
1029 System.out.println("\t\t\t" + boe.potentiallyConflictingRoots.get(key));
1032 for(Taint t: boe.taint2EffectsGroup.keySet()) {
1033 System.out.println("\t\t For Taint " + t);
1034 EffectsGroup eg = boe.taint2EffectsGroup.get(t);
1036 if(eg.hasPrimitiveConflicts()) {
1037 System.out.print("\t\t\tPrimitive Conflicts at alloc " + as.getUniqueAllocSiteID() +" : ");
1038 for(String field: eg.primitiveConflictingFields.keySet()) {
1039 System.out.print(field + " ");
1041 System.out.println();
1043 for(String fieldKey: eg.myEffects.keySet()) {
1044 CombinedObjEffects ce = eg.myEffects.get(fieldKey);
1045 System.out.println("\n\t\t\tFor allocSite " + as.getUniqueAllocSiteID() + " && field " + fieldKey);
1046 System.out.println("\t\t\t\tread " + ce.hasReadEffect + "/"+ce.hasReadConflict +
1047 " write " + ce.hasWriteEffect + "/" + ce.hasWriteConflict +
1048 " SU " + ce.hasStrongUpdateEffect + "/" + ce.hasStrongUpdateConflict);
1049 for(Effect ef: ce.originalEffects) {
1050 System.out.println("\t" + ef);
1059 private class EffectsGroup {
1060 Hashtable<String, CombinedObjEffects> myEffects;
1061 Hashtable<String, CombinedObjEffects> primitiveConflictingFields;
1063 public EffectsGroup() {
1064 myEffects = new Hashtable<String, CombinedObjEffects>();
1065 primitiveConflictingFields = new Hashtable<String, CombinedObjEffects>();
1068 public void addPrimitive(Effect e, boolean conflict) {
1069 CombinedObjEffects effects;
1070 if((effects = primitiveConflictingFields.get(e.getField().getSymbol())) == null) {
1071 effects = new CombinedObjEffects();
1072 primitiveConflictingFields.put(e.getField().getSymbol(), effects);
1074 effects.add(e, conflict);
1077 public void addObjEffect(Effect e, boolean conflict) {
1078 CombinedObjEffects effects;
1079 if((effects = myEffects.get(e.getField().getSymbol())) == null) {
1080 effects = new CombinedObjEffects();
1081 myEffects.put(e.getField().getSymbol(), effects);
1083 effects.add(e, conflict);
1086 public boolean isEmpty() {
1087 return myEffects.isEmpty() && primitiveConflictingFields.isEmpty();
1090 public boolean hasPrimitiveConflicts(){
1091 return !primitiveConflictingFields.isEmpty();
1094 public CombinedObjEffects getPrimEffect(String field) {
1095 return primitiveConflictingFields.get(field);
1098 public boolean hasObjectEffects() {
1099 return !myEffects.isEmpty();
1102 public CombinedObjEffects getObjEffect(String field) {
1103 return myEffects.get(field);
1107 //Is the combined effects for all effects with the same affectedAllocSite and field
1108 private class CombinedObjEffects {
1109 ArrayList<Effect> originalEffects;
1111 public boolean hasReadEffect;
1112 public boolean hasWriteEffect;
1113 public boolean hasStrongUpdateEffect;
1115 public boolean hasReadConflict;
1116 public boolean hasWriteConflict;
1117 public boolean hasStrongUpdateConflict;
1120 public CombinedObjEffects() {
1121 originalEffects = new ArrayList<Effect>();
1123 hasReadEffect = false;
1124 hasWriteEffect = false;
1125 hasStrongUpdateEffect = false;
1127 hasReadConflict = false;
1128 hasWriteConflict = false;
1129 hasStrongUpdateConflict = false;
1132 public boolean add(Effect e, boolean conflict) {
1133 if(!originalEffects.add(e))
1136 switch(e.getType()) {
1138 hasReadEffect = true;
1139 hasReadConflict = conflict;
1142 hasWriteEffect = true;
1143 hasWriteConflict = conflict;
1145 case Effect.strongupdate:
1146 hasStrongUpdateEffect = true;
1147 hasStrongUpdateConflict = conflict;
1150 System.out.println("RCR ERROR: An Effect Type never seen before has been encountered");
1157 public boolean hasConflict() {
1158 return hasReadConflict || hasWriteConflict || hasStrongUpdateConflict;
1161 public void mergeWith(CombinedObjEffects other) {
1162 for(Effect e: other.originalEffects) {
1163 if(!originalEffects.contains(e)){
1164 originalEffects.add(e);
1168 hasReadEffect |= other.hasReadEffect;
1169 hasWriteEffect |= other.hasWriteEffect;
1170 hasStrongUpdateEffect |= other.hasStrongUpdateEffect;
1172 hasReadConflict |= other.hasReadConflict;
1173 hasWriteConflict |= other.hasWriteConflict;
1174 hasStrongUpdateConflict |= other.hasStrongUpdateConflict;
1178 //This will keep track of a reference
1179 private class ObjRef {
1182 CombinedObjEffects myEffects;
1184 //This keeps track of the parent that we need to pass by inorder to get
1185 //to the conflicting child (if there is one).
1186 ConcreteRuntimeObjNode child;
1188 public ObjRef(String fieldname,
1189 ConcreteRuntimeObjNode ref,
1190 CombinedObjEffects myEffects) {
1192 allocSite = ref.getAllocationSite();
1195 this.myEffects = myEffects;
1198 public boolean hasConflictsDownThisPath() {
1199 return child.decendantsObjConflict || child.decendantsPrimConflict || child.hasPrimitiveConflicts() || myEffects.hasConflict();
1202 public boolean hasDirectObjConflict() {
1203 return myEffects.hasConflict();
1206 public boolean equals(Object other) {
1207 if(other == null || !(other instanceof ObjRef))
1210 ObjRef o = (ObjRef) other;
1212 if(o.field == this.field && o.allocSite == this.allocSite && this.child.equals(o.child))
1218 public int hashCode() {
1219 return child.allocSite.hashCode() ^ field.hashCode();
1222 public void mergeWith(ObjRef ref) {
1223 myEffects.mergeWith(ref.myEffects);
1227 private class ConcreteRuntimeObjNode {
1228 Hashtable<String, ObjRefList> objectRefs;
1229 Hashtable<String, CombinedObjEffects> primitiveConflictingFields;
1230 HashSet<ConcreteRuntimeObjNode> parentsWithReadToNode;
1231 HashSet<ConcreteRuntimeObjNode> parentsThatWillLeadToConflicts;
1232 //this set keeps track of references down the line that need to be enqueued if traverser is "paused"
1233 HashSet<ConcreteRuntimeObjNode> enqueueToWaitingQueueUponConflict;
1234 boolean decendantsPrimConflict;
1235 boolean decendantsObjConflict;
1236 boolean hasDirectObjConflict;
1237 boolean hasPotentialToBeIncorrectDueToConflict;
1239 AllocSite allocSite;
1240 HeapRegionNode original;
1242 public ConcreteRuntimeObjNode(HeapRegionNode me, boolean isInVar) {
1243 objectRefs = new Hashtable<String, ObjRefList>(5);
1244 primitiveConflictingFields = null;
1245 parentsThatWillLeadToConflicts = new HashSet<ConcreteRuntimeObjNode>();
1246 parentsWithReadToNode = new HashSet<ConcreteRuntimeObjNode>();
1247 enqueueToWaitingQueueUponConflict = new HashSet<ConcreteRuntimeObjNode>();
1248 allocSite = me.getAllocSite();
1250 isInsetVar = isInVar;
1251 decendantsPrimConflict = false;
1252 decendantsObjConflict = false;
1253 hasDirectObjConflict = false;
1254 hasPotentialToBeIncorrectDueToConflict = false;
1257 public void addReachableParent(ConcreteRuntimeObjNode curr) {
1258 parentsWithReadToNode.add(curr);
1262 public boolean equals(Object other) {
1263 if(other == null || !(other instanceof ConcreteRuntimeObjNode))
1266 return original.equals(((ConcreteRuntimeObjNode)other).original);
1269 public int getAllocationSite() {
1270 return allocSite.getUniqueAllocSiteID();
1273 public int getNumOfReachableParents() {
1274 return parentsThatWillLeadToConflicts.size();
1277 public boolean hasPrimitiveConflicts() {
1278 return primitiveConflictingFields != null && !primitiveConflictingFields.isEmpty();
1281 public boolean decendantsConflict() {
1282 return decendantsPrimConflict || decendantsObjConflict;
1285 //returns true if at least one of the objects in points of access has been added
1286 public boolean addPossibleWaitingQueueEnqueue(HashSet<ConcreteRuntimeObjNode> pointsOfAccess) {
1287 boolean addedNew = false;
1288 for(ConcreteRuntimeObjNode dec: pointsOfAccess) {
1289 if(dec != null && dec != this){
1290 addedNew = addedNew || enqueueToWaitingQueueUponConflict.add(dec);
1297 public boolean addPossibleWaitingQueueEnqueue(ConcreteRuntimeObjNode pointOfAccess) {
1298 if(pointOfAccess != null && pointOfAccess != this){
1299 return enqueueToWaitingQueueUponConflict.add(pointOfAccess);
1305 public void addObjChild(String field, ConcreteRuntimeObjNode child, CombinedObjEffects ce) {
1306 printDebug(traceDataStructureBuild,this.allocSite.getUniqueAllocSiteID() + " added child at " + child.getAllocationSite());
1307 hasDirectObjConflict |= ce.hasConflict();
1308 ObjRef ref = new ObjRef(field, child, ce);
1310 if(objectRefs.containsKey(field)){
1311 ObjRefList array = objectRefs.get(field);
1313 if(array.contains(ref)) {
1314 ObjRef other = array.get(array.indexOf(ref));
1315 other.mergeWith(ref);
1316 printDebug(traceDataStructureBuild," Merged with old");
1317 printDebug(traceDataStructureBuild," Old="+ other.child.original + "\n new="+ref.child.original);
1321 printDebug(traceDataStructureBuild," Just added new;\n Field: " + field);
1322 printDebug(traceDataStructureBuild," AllocSite: " + child.getAllocationSite());
1323 printDebug(traceDataStructureBuild," Child: "+child.original);
1327 ObjRefList array = new ObjRefList(3);
1330 objectRefs.put(field, array);
1334 public boolean isArray() {
1335 return original.getType().isArray();
1338 public ArrayList<Integer> getReferencedAllocSites() {
1339 ArrayList<Integer> list = new ArrayList<Integer>();
1341 for(String key: objectRefs.keySet()) {
1342 for(ObjRef r: objectRefs.get(key)) {
1343 if(r.hasDirectObjConflict() || (r.child.parentsWithReadToNode.contains(this) && r.hasConflictsDownThisPath())) {
1344 list.add(r.allocSite);
1352 public String toString() {
1353 return "AllocSite=" + getAllocationSite() + " myConflict=" + !parentsThatWillLeadToConflicts.isEmpty() +
1354 " decCon="+decendantsObjConflict+
1355 " NumOfConParents=" + getNumOfReachableParents() + " ObjectChildren=" + objectRefs.size();
1359 //Simple extension of the ArrayList to allow it to find if any ObjRefs conflict.
1360 private class ObjRefList extends ArrayList<ObjRef> {
1361 private static final long serialVersionUID = 326523675530835596L;
1363 public ObjRefList(int size) {
1367 public boolean add(ObjRef o){
1368 return super.add(o);
1371 public boolean hasConflicts() {
1372 for(ObjRef r: this) {
1373 if(r.hasConflictsDownThisPath() || r.child.hasPrimitiveConflicts())
1381 private class EffectsTable {
1382 private Hashtable<AllocSite, BucketOfEffects> table;
1384 public EffectsTable(Hashtable<Taint, Set<Effect>> effects,
1385 Hashtable<Taint, Set<Effect>> conflicts) {
1386 table = new Hashtable<AllocSite, BucketOfEffects>();
1388 // rehash all effects (as a 5-tuple) by their affected allocation site
1389 for (Taint t : effects.keySet()) {
1390 Set<Effect> localConflicts = conflicts.get(t);
1391 for (Effect e : effects.get(t)) {
1392 BucketOfEffects bucket;
1393 if ((bucket = table.get(e.getAffectedAllocSite())) == null) {
1394 bucket = new BucketOfEffects();
1395 table.put(e.getAffectedAllocSite(), bucket);
1397 printDebug(printEffectsAndEffectsTable, "Added Taint" + t + " Effect " + e + "Conflict Status = " + (localConflicts!=null?localConflicts.contains(e):false)+" localConflicts = "+localConflicts);
1398 bucket.add(t, e, localConflicts!=null?localConflicts.contains(e):false);
1403 public EffectsGroup getEffects(AllocSite parentKey, Taint taint) {
1404 //This would get the proper bucket of effects and then get all the effects
1405 //for a parent for a specific taint
1407 return table.get(parentKey).taint2EffectsGroup.get(taint);
1409 catch (NullPointerException e) {
1414 // Run Analysis will walk the data structure and figure out the weakly
1415 // connected heap roots.
1416 public void runAnalysis() {
1417 if(printEffectsAndEffectsTable) {
1418 printoutTable(this);
1421 for(AllocSite key: table.keySet()) {
1422 BucketOfEffects effects = table.get(key);
1423 //make sure there are actually conflicts in the bucket
1424 if(effects.potentiallyConflictingRoots != null && !effects.potentiallyConflictingRoots.isEmpty()){
1425 for(String field: effects.potentiallyConflictingRoots.keySet()){
1426 ArrayList<Taint> taints = effects.potentiallyConflictingRoots.get(field);
1427 //For simplicity, we just create a new group and add everything to it instead of
1428 //searching through all of them for the largest group and adding everyone in.
1429 WeaklyConectedHRGroup group = new WeaklyConectedHRGroup();
1430 group.add(taints); //This will automatically add the taint to the connectedHRhash
1437 private class WeaklyConectedHRGroup {
1438 HashSet<Taint> connectedHRs;
1439 //This is to keep track of unique waitingQueue positions for each allocsite.
1440 Hashtable<AllocSite, Integer> allocSiteToWaitingQueueMap;
1441 int waitingQueueCounter;
1444 public WeaklyConectedHRGroup() {
1445 connectedHRs = new HashSet<Taint>();
1446 id = -1; //this will be later modified
1447 waitingQueueCounter = 0;
1448 allocSiteToWaitingQueueMap = new Hashtable<AllocSite, Integer>();
1451 public void add(ArrayList<Taint> list) {
1452 for(Taint t: list) {
1457 public int getWaitingQueueBucketNum(ConcreteRuntimeObjNode node) {
1458 if(allocSiteToWaitingQueueMap.containsKey(node.allocSite)) {
1459 return allocSiteToWaitingQueueMap.get(node.allocSite);
1461 allocSiteToWaitingQueueMap.put(node.allocSite, waitingQueueCounter);
1462 return waitingQueueCounter++;
1466 public void add(Taint t) {
1467 connectedHRs.add(t);
1468 WeaklyConectedHRGroup oldGroup = connectedHRHash.get(t);
1469 connectedHRHash.put(t, this); //put new group into hash
1470 //If the taint was already in another group, move all its buddies over.
1471 if(oldGroup != this && oldGroup != null) {
1472 Iterator<Taint> it = oldGroup.connectedHRs.iterator();
1475 while(it.hasNext() && (relatedTaint = it.next()) != null) {
1476 if(!connectedHRs.contains(relatedTaint)){
1477 this.add(relatedTaint);
1484 //This is a class that stores all the effects for an affected allocation site
1485 //across ALL taints. The structure is a hashtable of EffectGroups (see above) hashed
1486 //by a Taint. This way, I can keep EffectsGroups so I can reuse most to all of my old code
1487 //and allows for easier tracking of effects. In addition, a hashtable (keyed by the string
1488 //of the field access) keeps track of an ArrayList of taints of SESEblocks that conflict on that
1490 private class BucketOfEffects {
1491 // This table is used for lookup while creating the traversal.
1492 Hashtable<Taint, EffectsGroup> taint2EffectsGroup;
1494 //This table is used to help identify weakly connected groups: Contains ONLY
1495 //conflicting effects AND is only initialized when needed
1496 //String stores the field
1497 Hashtable<String, ArrayList<Taint>> potentiallyConflictingRoots;
1499 public BucketOfEffects() {
1500 taint2EffectsGroup = new Hashtable<Taint, EffectsGroup>();
1503 public void add(Taint t, Effect e, boolean conflict) {
1504 EffectsGroup effectsForGivenTaint;
1506 if ((effectsForGivenTaint = taint2EffectsGroup.get(t)) == null) {
1507 effectsForGivenTaint = new EffectsGroup();
1508 taint2EffectsGroup.put(t, effectsForGivenTaint);
1511 if (isReallyAPrimitive(e.getField().getType())) {
1513 effectsForGivenTaint.addPrimitive(e, true);
1516 effectsForGivenTaint.addObjEffect(e, conflict);
1520 if(potentiallyConflictingRoots == null) {
1521 potentiallyConflictingRoots = new Hashtable<String, ArrayList<Taint>>();
1524 ArrayList<Taint> taintsForField = potentiallyConflictingRoots.get(e.getField().getSafeSymbol());
1525 if(taintsForField == null) {
1526 taintsForField = new ArrayList<Taint>();
1527 potentiallyConflictingRoots.put(e.getField().getSafeSymbol(), taintsForField);
1530 if(!taintsForField.contains(t)) {
1531 taintsForField.add(t);
1537 private class TaintAndInternalHeapStructure {
1539 public Hashtable<Integer, ConcreteRuntimeObjNode> nodesInHeap;
1541 public TaintAndInternalHeapStructure(Taint taint, Hashtable<Integer, ConcreteRuntimeObjNode> nodesInHeap) {
1543 this.nodesInHeap = nodesInHeap;
1547 private class TraversalInfo {
1549 public ReachGraph rg;
1550 public TempDescriptor invar;
1552 public TraversalInfo(FlatNode fn, ReachGraph g) {
1558 public TraversalInfo(FlatNode fn, ReachGraph rg2, TempDescriptor tempDesc) {