4 import java.io.FileNotFoundException;
5 import java.util.ArrayList;
6 import java.util.HashSet;
7 import java.util.Hashtable;
8 import java.util.Iterator;
10 import java.util.Vector;
12 import Analysis.Disjoint.*;
13 import Analysis.Pointer.*;
14 import Analysis.Pointer.AllocFactory.AllocNode;
16 import IR.TypeDescriptor;
17 import Analysis.OoOJava.ConflictEdge;
18 import Analysis.OoOJava.ConflictGraph;
19 import Analysis.OoOJava.ConflictNode;
20 import Analysis.OoOJava.OoOJavaAnalysis;
21 import Util.CodePrinter;
23 /* An instance of this class manages all OoOJava coarse-grained runtime conflicts
24 * by generating C-code to either rule out the conflict at runtime or resolve one.
27 * 1) Instantiate singleton object (String input is to specify output dir)
28 * 2) Call void close()
30 public class RuntimeConflictResolver {
31 private CodePrinter headerFile, cFile;
32 private static final String hashAndQueueCFileDir = "oooJava/";
34 //This keeps track of taints we've traversed to prevent printing duplicate traverse functions
35 //The Integer keeps track of the weakly connected group it's in (used in enumerateHeapRoots)
36 //private Hashtable<Taint, Integer> doneTaints;
37 private Hashtable<Pair, Integer> idMap=new Hashtable<Pair,Integer>();
39 //Keeps track of stallsites that we've generated code for.
40 protected Hashtable <FlatNode, TempDescriptor> processedStallSites = new Hashtable <FlatNode, TempDescriptor>();
42 public int currentID=1;
43 private int totalWeakGroups;
44 private OoOJavaAnalysis oooa;
45 private State globalState;
47 // initializing variables can be found in printHeader()
48 private static final String allocSite = "allocsite";
49 private static final String queryAndAddToVisitedHashtable = "hashRCRInsert";
50 private static final String enqueueInC = "enqueueRCRQueue";
51 private static final String dequeueFromQueueInC = "dequeueRCRQueue()";
52 private static final String clearQueue = "resetRCRQueue()";
53 // Make hashtable; hashRCRCreate(unsigned int size, double loadfactor)
54 private static final String mallocVisitedHashtable = "hashRCRCreate(128, 0.75)";
55 private static final String deallocVisitedHashTable = "hashRCRDelete()";
56 private static final String resetVisitedHashTable = "hashRCRreset()";
58 public RuntimeConflictResolver( String buildir,
61 throws FileNotFoundException {
63 this.globalState = state;
65 processedStallSites = new Hashtable <FlatNode, TempDescriptor>();
66 BuildStateMachines bsm = oooa.getBuildStateMachines();
67 totalWeakGroups = bsm.getTotalNumOfWeakGroups();
69 setupOutputFiles(buildir);
71 for( Pair<FlatNode, TempDescriptor> p: bsm.getAllMachineNames() ) {
72 FlatNode taskOrStallSite = p.getFirst();
73 TempDescriptor var = p.getSecond();
74 StateMachineForEffects stateMachine = bsm.getStateMachine( taskOrStallSite, var );
76 //prints the traversal code
77 printCMethod( taskOrStallSite, var, stateMachine);
80 //IMPORTANT must call .close() elsewhere to finish printing the C files.
84 * This method generates a C method for every inset variable and rblock.
86 * The C method works by generating a large switch statement that will run the appropriate
87 * checking code for each object based on the current state. The switch statement is
88 * surrounded by a while statement which dequeues objects to be checked from a queue. An
89 * object is added to a queue only if it contains a conflict (in itself or in its referencees)
90 * and we came across it while checking through it's referencer. Because of this property,
91 * conflicts will be signaled by the referencer; the only exception is the inset variable which can
92 * signal a conflict within itself.
95 private void printCMethod( FlatNode taskOrStallSite,
97 StateMachineForEffects smfe) {
99 // collect info for code gen
100 FlatSESEEnterNode task = null;
101 String inVar = var.getSafeSymbol();
102 SMFEState initialState = smfe.getInitialState();
103 boolean isStallSite = !(taskOrStallSite instanceof FlatSESEEnterNode);
104 int weakID = smfe.getWeaklyConnectedGroupID(taskOrStallSite);
107 //No need generate code for empty traverser
112 blockName = taskOrStallSite.toString();
113 processedStallSites.put(taskOrStallSite, var);
115 task = (FlatSESEEnterNode) taskOrStallSite;
117 //if the task is the main task, there's no traverser
121 blockName = task.getPrettyIdentifier();
126 String methodName = "void traverse___" + inVar + removeInvalidChars(blockName) + "___(void * InVar, ";
130 methodName += "SESEstall *record)";
132 methodName += task.getSESErecordName() +" *record)";
133 //TODO check that this HACK is correct (i.e. adding and then polling immediately afterwards)
134 task.addInVarForDynamicCoarseConflictResolution(var);
135 index = task.getInVarsForDynamicCoarseConflictResolution().indexOf( var );
138 cFile.println( methodName + " {");
139 headerFile.println( methodName + ";" );
141 cFile.println( " int totalcount = RUNBIAS;");
143 cFile.println(" record->rcrRecords[0].count = RUNBIAS;");
145 cFile.println(" record->rcrRecords["+index+"].count = RUNBIAS;");
148 //clears queue and hashtable that keeps track of where we've been.
149 cFile.println(clearQueue + ";");
150 cFile.println(resetVisitedHashTable + ";");
151 cFile.println(" RCRQueueEntry * queueEntry; //needed for dequeuing");
153 cFile.println(" int traverserState = "+initialState.getID()+";");
155 //generic cast to ___Object___ to access ptr->allocsite field.
156 cFile.println(" struct ___Object___ * ptr = (struct ___Object___ *) InVar;");
157 cFile.println(" if (InVar != NULL) {");
158 cFile.println(" " + queryAndAddToVisitedHashtable + "(ptr, "+initialState.getID()+");");
159 cFile.println(" do {");
162 cFile.println(" if(unlikely(record->common.doneExecuting)) {");
163 cFile.println(" record->common.rcrstatus=0;");
164 cFile.println(" return;");
169 // Traverse the StateMachineForEffects (a graph)
170 // that serves as a plan for building the heap examiner code.
171 // SWITCH on the states in the state machine, THEN
172 // SWITCH on the concrete object's allocation site THEN
173 // consider conflicts, enqueue more work, inline more SWITCHES, etc.
175 boolean needswitch=smfe.getStates().size()>1;
178 cFile.println(" switch( traverserState ) {");
180 for(SMFEState state: smfe.getStates()) {
182 if(state.getRefCount() != 1 || initialState == state) {
184 cFile.println(" case "+state.getID()+":");
186 cFile.println(" if(traverserState=="+state.getID()+") {");
189 printAllocChecksInsideState(state, taskOrStallSite, var, "ptr", 0, weakID);
191 cFile.println(" break;");
196 cFile.println(" default: break;");
198 cFile.println(" } // end switch on traverser state");
199 cFile.println(" queueEntry = " + dequeueFromQueueInC + ";");
200 cFile.println(" if(queueEntry == NULL) {");
201 cFile.println(" break;");
203 cFile.println(" ptr = queueEntry->object;");
204 cFile.println(" traverserState = queueEntry->traverserState;");
205 cFile.println(" } while(ptr != NULL);");
206 cFile.println(" } // end if inVar not null");
210 cFile.println(" if(atomic_sub_and_test(totalcount,&(record->rcrRecords[0].count))) {");
211 cFile.println(" psem_give_tag(record->common.parentsStallSem, record->tag);");
212 cFile.println(" BARRIER();");
215 cFile.println(" if(atomic_sub_and_test(totalcount,&(record->rcrRecords["+index+"].count))) {");
216 cFile.println(" int flag=LOCKXCHG32(&(record->rcrRecords["+index+"].flag),0);");
217 cFile.println(" if(flag) {");
218 //we have resolved a heap root...see if this was the last dependence
219 cFile.println(" if(atomic_sub_and_test(1, &(record->common.unresolvedDependencies))) workScheduleSubmit((void *)record);");
228 public void printAllocChecksInsideState(SMFEState state, FlatNode fn, TempDescriptor tmp, String prefix, int depth, int weakID) {
229 EffectsTable et = new EffectsTable(state);
230 boolean needswitch=et.getAllAllocs().size()>1;
232 cFile.println(" switch(" + prefix+"->"+allocSite + ") {");
235 //we assume that all allocs given in the effects are starting locs.
236 for(Alloc a: et.getAllAllocs()) {
238 cFile.println(" case "+a.getUniqueAllocSiteID()+": {");
240 cFile.println(" if("+prefix+"->"+allocSite+"=="+a.getUniqueAllocSiteID()+") {");
242 addChecker(a, fn, tmp, state, et, prefix, depth, weakID);
245 cFile.println(" break;");
249 cFile.println(" default:");
250 cFile.println(" break;");
255 public void addChecker(Alloc a, FlatNode fn, TempDescriptor tmp, SMFEState state, EffectsTable et, String prefix, int depth, int weakID) {
257 System.out.println(fn+" "+state+" "+state.toStringDOT());
260 insertEntriesIntoHashStructureNew(fn, tmp, et, a, prefix, depth, weakID);
262 int pdepth = depth+1;
264 if(a.getType().isArray()) {
265 String childPtr = "((struct ___Object___ **)(((char *) &(((struct ArrayObject *)"+ prefix+")->___length___))+sizeof(int)))[i]";
266 String currPtr = "arrayElement" + pdepth;
270 for(Effect e: et.getEffects(a)) {
271 if (!state.transitionsTo(e).isEmpty()) {
273 cFile.println(" int i;");
274 cFile.println(" struct ___Object___ * "+currPtr+";");
275 cFile.println(" for(i = 0; i<((struct ArrayObject *) " + prefix + " )->___length___; i++ ) {");
278 printRefSwitch(fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID);
285 String currPtr = "myPtr" + pdepth;
286 cFile.println(" struct ___Object___ * "+currPtr+";");
288 for(Effect e: et.getEffects(a)) {
289 if (!state.transitionsTo(e).isEmpty()) {
290 String childPtr = "((struct "+a.getType().getSafeSymbol()+" *)"+prefix +")->" + e.getField().getSafeSymbol();
291 printRefSwitch(fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID);
297 private void printRefSwitch(FlatNode fn, TempDescriptor tmp, int pdepth, String childPtr, String currPtr, Set<SMFEState> transitions, int weakID) {
299 for(SMFEState tr: transitions) {
300 if(tr.getRefCount() == 1) { //in-lineable case
301 //Don't need to update state counter since we don't care really if it's inlined...
302 cFile.println(" "+currPtr+"= (struct ___Object___ * ) " + childPtr + ";");
303 cFile.println(" if (" + currPtr + " != NULL) { ");
305 printAllocChecksInsideState(tr, fn, tmp, currPtr, pdepth+1, weakID);
307 cFile.println(" }"); //break for internal switch and if
308 } else { //non-inlineable cases
309 cFile.println(" "+currPtr+"= (struct ___Object___ * ) " + childPtr + ";");
310 cFile.println(" if("+queryAndAddToVisitedHashtable+"("+currPtr+","+tr.getID()+"))");
311 cFile.println(" " + enqueueInC +"("+ currPtr + ", "+tr.getID()+");");
317 //FlatNode and TempDescriptor are what are used to make the taint
318 private void insertEntriesIntoHashStructureNew(FlatNode fn, TempDescriptor tmp, EffectsTable et, Alloc a, String prefix, int depth, int weakID) {
320 boolean isRblock = (fn instanceof FlatSESEEnterNode);
322 FlatSESEEnterNode fsese = (FlatSESEEnterNode) fn;
323 index = fsese.getInVarsForDynamicCoarseConflictResolution().indexOf(tmp);
326 String strrcr = isRblock ? "&record->rcrRecords[" + index + "], " : "NULL, ";
327 String tasksrc =isRblock ? "(SESEcommon *) record, ":"(SESEcommon *)(((INTPTR)record)|1LL), ";
329 if(et.hasWriteConflict(a)) {
330 cFile.append(" int tmpkey" + depth + " = rcr_generateKey(" + prefix + ");\n");
331 if (et.conflictDereference(a))
332 cFile.append(" int tmpvar" + depth + " = rcr_WTWRITEBINCASE(allHashStructures[" + weakID + "], tmpkey" + depth + ", " + tasksrc + strrcr + index + ");\n");
334 cFile.append(" int tmpvar" + depth + " = rcr_WRITEBINCASE(allHashStructures["+ weakID + "], tmpkey" + depth + ", " + tasksrc + strrcr + index + ");\n");
335 } else if(et.hasReadConflict(a)) {
336 cFile.append(" int tmpkey" + depth + " = rcr_generateKey(" + prefix + ");\n");
337 if (et.conflictDereference(a))
338 cFile.append(" int tmpvar" + depth + " = rcr_WTREADBINCASE(allHashStructures[" + weakID + "], tmpkey" + depth + ", " + tasksrc + strrcr + index + ");\n");
340 cFile.append(" int tmpvar" + depth + " = rcr_READBINCASE(allHashStructures["+ weakID + "], tmpkey" + depth + ", " + tasksrc + strrcr + index + ");\n");
343 if (et.hasReadConflict(a) || et.hasWriteConflict(a)) {
344 cFile.append("if (!(tmpvar" + depth + "&READYMASK)) totalcount--;\n");
348 private void setupOutputFiles(String buildir) throws FileNotFoundException {
349 cFile = new CodePrinter(new File(buildir + "RuntimeConflictResolver" + ".c"));
350 headerFile = new CodePrinter(new File(buildir + "RuntimeConflictResolver" + ".h"));
352 cFile.println("#include \"" + hashAndQueueCFileDir + "hashRCR.h\"\n#include \""
353 + hashAndQueueCFileDir + "Queue_RCR.h\"\n#include <stdlib.h>");
354 cFile.println("#include \"classdefs.h\"");
355 cFile.println("#include \"structdefs.h\"");
356 cFile.println("#include \"mlp_runtime.h\"");
357 cFile.println("#include \"RuntimeConflictResolver.h\"");
358 cFile.println("#include \"hashStructure.h\"");
360 headerFile.println("#ifndef __3_RCR_H_");
361 headerFile.println("#define __3_RCR_H_");
364 //The official way to generate the name for a traverser call
365 public String getTraverserInvocation(TempDescriptor invar, String varString, FlatNode fn) {
367 if(fn instanceof FlatSESEEnterNode) { //is SESE block
368 flatname = ((FlatSESEEnterNode) fn).getPrettyIdentifier();
369 } else { //is stallsite
370 flatname = fn.toString();
373 return "traverse___" + invar.getSafeSymbol() + removeInvalidChars(flatname) + "___("+varString+");";
376 public String removeInvalidChars(String in) {
377 StringBuilder s = new StringBuilder(in);
378 for(int i = 0; i < s.length(); i++) {
379 if(s.charAt(i) == ' ' ||
380 s.charAt(i) == '.' ||
381 s.charAt(i) == '=' ||
382 s.charAt(i) == '[' ||
383 s.charAt(i) == ']' ) {
392 public int getTraverserID(TempDescriptor invar, FlatNode fn) {
393 Pair<TempDescriptor, FlatNode> t = new Pair<TempDescriptor, FlatNode>(invar, fn);
394 if (idMap.containsKey(t)) {
395 return idMap.get(t).intValue();
397 int value=currentID++;
398 idMap.put(t, new Integer(value));
402 public void close() {
403 //Prints out the master traverser Invocation that'll call all other traversers
404 //based on traverserID
405 printMasterTraverserInvocation();
406 createMasterHashTableArray();
408 // Adds Extra supporting methods
409 cFile.println("void initializeStructsRCR() {\n " + mallocVisitedHashtable + ";\n " + clearQueue + ";\n}");
410 cFile.println("void destroyRCR() {\n " + deallocVisitedHashTable + ";\n}");
412 headerFile.println("void initializeStructsRCR();\nvoid destroyRCR();");
413 headerFile.println("#endif\n");
419 private void printMasterTraverserInvocation() {
420 headerFile.println("int tasktraverse(SESEcommon * record);");
421 cFile.println("int tasktraverse(SESEcommon * record) {");
422 cFile.println(" if(!CAS(&record->rcrstatus,1,2)) {");
424 //release traverser reference...no traversal necessary
425 cFile.println("#ifndef OOO_DISABLE_TASKMEMPOOL");
426 cFile.println(" RELEASE_REFERENCE_TO(record);");
427 cFile.println("#endif");
429 cFile.println(" return;");
431 cFile.println(" switch(record->classID) {");
433 for(Iterator<FlatSESEEnterNode> seseit=oooa.getAllSESEs().iterator();seseit.hasNext();) {
434 FlatSESEEnterNode fsen=seseit.next();
435 cFile.println( " /* "+fsen.getPrettyIdentifier()+" */");
436 cFile.println( " case "+fsen.getIdentifier()+": {");
437 cFile.println( " "+fsen.getSESErecordName()+" * rec=("+fsen.getSESErecordName()+" *) record;");
438 Vector<TempDescriptor> invars=fsen.getInVarsForDynamicCoarseConflictResolution();
439 for(int i=0;i<invars.size();i++) {
440 TempDescriptor tmp=invars.get(i);
442 /* In some cases we don't want to a dynamic traversal if it is
443 * unlikely to increase parallelism...these are cases where we
444 * are just enabling a stall site to possible clear faster*/
446 boolean isValidToPrune=true;
447 for( FlatSESEEnterNode parentSESE: fsen.getParents() ) {
448 ConflictGraph graph = oooa.getConflictGraph(parentSESE);
450 String id = tmp + "_sese" + fsen.getPrettyIdentifier();
451 ConflictNode node = graph.getId2cn().get(id);
452 isValidToPrune &= node.IsValidToPrune();
457 // if node is valid to prune examiner,
458 // also needs to turn off stall site examiners connected to this node
459 for( FlatSESEEnterNode parentSESE: fsen.getParents() ) {
460 ConflictGraph graph = oooa.getConflictGraph(parentSESE);
461 String id = tmp + "_sese" + fsen.getPrettyIdentifier();
462 ConflictNode node = graph.getId2cn().get(id);
464 for (Iterator iterator = node.getEdgeSet().iterator(); iterator.hasNext();) {
465 ConflictEdge edge = (ConflictEdge) iterator.next();
466 if (edge.getVertexU() == node) {
467 if (edge.getVertexV().isStallSiteNode()) {
468 edge.getVertexV().setToBePruned(true);
471 if (edge.getVertexU().isStallSiteNode()) {
472 edge.getVertexU().setToBePruned(true);
480 cFile.println(" if (record->rcrstatus!=0)");
483 if(globalState.NOSTALLTR && isValidToPrune) {
484 cFile.println(" /* " + getTraverserInvocation(tmp, "rec->"+tmp+", rec", fsen)+"*/");
486 cFile.println(" " + getTraverserInvocation(tmp, "rec->"+tmp+", rec", fsen));
489 //release traverser reference...traversal finished...
490 //executing thread will clean bins for us
491 cFile.println(" record->rcrstatus=0;");
492 cFile.println("#ifndef OOO_DISABLE_TASKMEMPOOL");
493 cFile.println(" RELEASE_REFERENCE_TO(record);");
494 cFile.println("#endif");
495 cFile.println( " }");
496 cFile.println( " break;");
499 for(FlatNode stallsite: processedStallSites.keySet()) {
501 TempDescriptor var = processedStallSites.get(stallsite);
502 Set<FlatSESEEnterNode> seseSet=oooa.getPossibleExecutingRBlocks(stallsite);
503 boolean isValidToPrune=true;
504 for (Iterator iterator = seseSet.iterator(); iterator.hasNext();) {
505 FlatSESEEnterNode sese = (FlatSESEEnterNode) iterator.next();
506 ConflictGraph graph = oooa.getConflictGraph(sese);
508 String id = var + "_fn" + stallsite.hashCode();
509 ConflictNode node = graph.getId2cn().get(id);
510 isValidToPrune &= node.isTobePruned();
514 cFile.println( " case -" + getTraverserID(var, stallsite)+ ": {");
515 cFile.println( " SESEstall * rec=(SESEstall*) record;");
516 if(globalState.NOSTALLTR && isValidToPrune){
517 cFile.println( " /*" + getTraverserInvocation(var, "rec->___obj___, rec", stallsite)+";*/");
519 cFile.println( " " + getTraverserInvocation(var, "rec->___obj___, rec", stallsite)+";");
521 cFile.println( " record->rcrstatus=0;");
522 cFile.println( " }");
523 cFile.println(" break;");
526 cFile.println(" default:");
527 cFile.println(" printf(\"Invalid SESE ID was passed in: %d.\\n\",record->classID);");
528 cFile.println(" break;");
533 private void createMasterHashTableArray() {
534 headerFile.println("struct Hashtable_rcr ** createAndFillMasterHashStructureArray();");
535 cFile.println("struct Hashtable_rcr ** createAndFillMasterHashStructureArray() {");
537 cFile.println(" struct Hashtable_rcr **table=rcr_createMasterHashTableArray("+totalWeakGroups + ");");
539 for(int i = 0; i < totalWeakGroups; i++) {
540 cFile.println(" table["+i+"] = (struct Hashtable_rcr *) rcr_createHashtable();");
542 cFile.println(" return table;");
546 public int getWeakID(TempDescriptor invar, FlatNode fn) {
547 //return weakMap.get(new Pair(invar, fn)).intValue();
552 public boolean hasEmptyTraversers(FlatSESEEnterNode fsen) {
553 boolean hasEmpty = true;
555 Set<FlatSESEEnterNode> children = fsen.getChildren();
556 for (Iterator<FlatSESEEnterNode> iterator = children.iterator(); iterator.hasNext();) {
557 FlatSESEEnterNode child = (FlatSESEEnterNode) iterator.next();
558 hasEmpty &= child.getInVarsForDynamicCoarseConflictResolution().size() == 0;
564 //Simply rehashes and combines all effects for a AffectedAllocSite + Field.
565 private class EffectsTable {
566 private Hashtable<Alloc,Set<Effect>> table;
569 public EffectsTable(SMFEState state) {
570 table = new Hashtable<Alloc, Set<Effect>>();
572 for(Effect e: state.getEffectsAllowed()) {
574 if((eg = table.get(e.getAffectedAllocSite())) == null) {
575 eg = new HashSet<Effect>();
576 table.put(e.getAffectedAllocSite(), eg);
582 public boolean conflictDereference(Alloc a) {
583 for(Effect e:getEffects(a)) {
584 if (!state.transitionsTo(e).isEmpty()&&state.getConflicts().contains(e))
590 public boolean hasWriteConflict(Alloc a) {
591 for(Effect e:getEffects(a)) {
592 if (e.isWrite() && state.getConflicts().contains(e))
598 public boolean hasReadConflict(Alloc a) {
599 for(Effect e:getEffects(a)) {
600 if (e.isRead() && state.getConflicts().contains(e))
606 public Set<Effect> getEffects(Alloc a) {
610 public Set<Alloc> getAllAllocs() {
611 return table.keySet();