disjoint should work like pointer in that taints for DOJ have whereDefined initialize...
[IRC.git] / Robust / src / Analysis / OoOJava / OoOJavaAnalysis.java
1 package Analysis.OoOJava;
2
3 import java.io.*;
4 import java.util.*;
5
6 import Analysis.*;
7 import Analysis.CallGraph.*;
8 import Analysis.Disjoint.*;
9 import Analysis.Pointer.*;
10 import Util.*;
11 import IR.*;
12 import IR.Flat.*;
13
14 public class OoOJavaAnalysis {
15
16   // data from the compiler
17   private State state;
18   private TypeUtil typeUtil;
19   private CallGraph callGraph;
20   private Liveness liveness;
21   private RBlockRelationAnalysis rblockRel;
22   private HeapAnalysis disjointAnalysisTaints;
23   private DisjointAnalysis disjointAnalysisReach;
24   private BuildStateMachines buildStateMachines;
25
26   private Set<MethodDescriptor> descriptorsToAnalyze;
27
28   private Hashtable<FlatNode, Set<TempDescriptor>> livenessGlobalView;
29   private Hashtable<FlatNode, Set<TempDescriptor>> livenessVirtualReads;
30   private Hashtable<FlatNode, VarSrcTokTable> variableResults;
31   private Hashtable<FlatNode, Set<TempDescriptor>> notAvailableResults;
32   private Hashtable<FlatNode, CodePlan> codePlans;
33
34   private Hashtable<FlatSESEEnterNode, Set<TempDescriptor>> notAvailableIntoSESE;
35
36   private Hashtable<FlatEdge, FlatWriteDynamicVarNode> wdvNodesToSpliceIn;
37
38   private Hashtable<FlatNode, ContextTaskNames> fn2contextTaskNames;
39
40   // get the flat method that contains any given flat node
41   private Hashtable<FlatNode, FlatMethod> fn2fm;
42
43   // temporal data structures to track analysis progress.
44   static private int uniqueLockSetId = 0;
45   // mapping of a conflict graph to its compiled lock
46   private Hashtable<ConflictGraph, HashSet<SESELock>> conflictGraph2SESELock;
47   // mapping of a sese block to its conflict graph
48   private Hashtable<FlatNode, ConflictGraph> sese2conflictGraph;
49
50   public static int maxSESEage = -1;
51
52   public int getMaxSESEage() {
53     return maxSESEage;
54   }
55
56   // may be null
57   public CodePlan getCodePlan(FlatNode fn) {
58     CodePlan cp = codePlans.get(fn);
59     return cp;
60   }
61
62   public Set<FlatNode> getNodesWithPlans() {
63     return codePlans.keySet();
64   }
65
66   public ContextTaskNames getContextTaskNames(FlatMethod fm) {
67     ContextTaskNames out = fn2contextTaskNames.get(fm);
68     if (out == null) {
69       out = new ContextTaskNames();
70     }
71     return out;
72   }
73
74   public ContextTaskNames getContextTaskNames(FlatSESEEnterNode fsen) {
75     ContextTaskNames out = fn2contextTaskNames.get(fsen);
76     if (out == null) {
77       out = new ContextTaskNames();
78     }
79     return out;
80   }
81
82   public FlatMethod getContainingFlatMethod(FlatNode fn) {
83     FlatMethod fm = fn2fm.get(fn);
84     assert fm != null;
85     return fm;
86   }
87
88   public HeapAnalysis getDisjointAnalysis() {
89     return disjointAnalysisTaints;
90   }
91
92   public BuildStateMachines getBuildStateMachines() {
93     return buildStateMachines;
94   }
95
96   public OoOJavaAnalysis(State state, TypeUtil typeUtil, CallGraph callGraph, Liveness liveness,
97                          ArrayReferencees arrayReferencees) {
98
99     State.logEvent("Starting OoOJavaAnalysis");
100     this.state = state;
101     this.typeUtil = typeUtil;
102     this.callGraph = callGraph;
103     this.liveness = liveness;
104     this.maxSESEage = state.OOO_MAXSESEAGE;
105
106     livenessGlobalView = new Hashtable<FlatNode, Set<TempDescriptor>>();
107     livenessVirtualReads = new Hashtable<FlatNode, Set<TempDescriptor>>();
108     variableResults = new Hashtable<FlatNode, VarSrcTokTable>();
109     notAvailableResults = new Hashtable<FlatNode, Set<TempDescriptor>>();
110     codePlans = new Hashtable<FlatNode, CodePlan>();
111     wdvNodesToSpliceIn = new Hashtable<FlatEdge, FlatWriteDynamicVarNode>();
112     notAvailableIntoSESE = new Hashtable<FlatSESEEnterNode, Set<TempDescriptor>>();
113     sese2conflictGraph = new Hashtable<FlatNode, ConflictGraph>();
114     conflictGraph2SESELock = new Hashtable<ConflictGraph, HashSet<SESELock>>();
115     fn2contextTaskNames = new Hashtable<FlatNode, ContextTaskNames>();
116     fn2fm = new Hashtable<FlatNode, FlatMethod>();
117
118     // state machines support heap examiners with
119     // state transitions to improve precision
120     if (state.RCR) {
121       buildStateMachines = new BuildStateMachines();
122     }
123
124     // add all methods transitively reachable from the
125     // source's main to set for analysis
126     MethodDescriptor mdSourceEntry = typeUtil.getMain();
127     FlatMethod fmMain = state.getMethodFlat(mdSourceEntry);
128
129     descriptorsToAnalyze = callGraph.getAllMethods(mdSourceEntry);
130
131     descriptorsToAnalyze.add(mdSourceEntry);
132
133     // 0th pass, setup a useful mapping of any flat node to the
134     // flat method it is a part of
135     Iterator<MethodDescriptor> methItr = descriptorsToAnalyze.iterator();
136     while (methItr.hasNext()) {
137       Descriptor d = methItr.next();
138       FlatMethod fm = state.getMethodFlat(d);
139       buildFlatNodeToFlatMethod(fm);
140     }
141     State.logEvent("OoOJavaAnalysis Oth pass completed");
142
143     // 1st pass, find basic rblock relations & potential stall sites
144     rblockRel = new RBlockRelationAnalysis(state, typeUtil, callGraph);
145     VarSrcTokTable.rblockRel = rblockRel;
146
147     State.logEvent("OoOJavaAnalysis 1st pass completed");
148
149     // 2nd pass, liveness, in-set out-set (no virtual reads yet!)
150     Iterator<FlatSESEEnterNode> seseItr = rblockRel.getLocalRootSESEs().iterator();
151     while (seseItr.hasNext()) {
152       FlatSESEEnterNode sese = seseItr.next();
153       livenessAnalysisBackward(sese);
154     }
155
156     State.logEvent("OoOJavaAnalysis 2nd pass completed");
157
158     // 3rd pass, variable analysis
159     methItr = rblockRel.getMethodsWithSESEs().iterator();
160     while (methItr.hasNext()) {
161       Descriptor d = methItr.next();
162       FlatMethod fm = state.getMethodFlat(d);
163       // starting from roots do a forward, fixed-point
164       // variable analysis for refinement and stalls
165       variableAnalysisForward(fm);
166     }
167
168     State.logEvent("OoOJavaAnalysis 3rd pass completed");
169
170     // 4th pass, compute liveness contribution from
171     // virtual reads discovered in variable pass
172     seseItr = rblockRel.getLocalRootSESEs().iterator();
173     while (seseItr.hasNext()) {
174       FlatSESEEnterNode sese = seseItr.next();
175       livenessAnalysisBackward(sese);
176     }
177
178     State.logEvent("OoOJavaAnalysis 4th pass completed");
179
180     // 5th pass, use disjointness with NO FLAGGED REGIONS
181     // to compute taints and effects
182     if (state.POINTER) {
183       disjointAnalysisTaints =
184         new Pointer(state, typeUtil, callGraph, rblockRel, liveness, buildStateMachines);
185       ((Pointer) disjointAnalysisTaints).doAnalysis();
186     } else {
187       disjointAnalysisTaints =
188         new DisjointAnalysis(state, typeUtil, callGraph, liveness, arrayReferencees, null,
189                              rblockRel, buildStateMachines, 
190                              !state.OOODEBUG // only print out in OoOJava debug mode
191                              );
192     }
193     State.logEvent("OoOJavaAnalysis 5th pass completed");
194
195     // 6th pass, not available analysis FOR VARIABLES!
196     methItr = rblockRel.getMethodsWithSESEs().iterator();
197     while (methItr.hasNext()) {
198       Descriptor d = methItr.next();
199       FlatMethod fm = state.getMethodFlat(d);
200       // compute what is not available at every program
201       // point, in a forward fixed-point pass
202       notAvailableForward(fm);
203     }
204     State.logEvent("OoOJavaAnalysis 6th pass completed");
205     // 7th pass, start conflict graphs where a parent's graph has a
206     // node for possibly conflicting children and its own stall sites
207     startConflictGraphs();
208     State.logEvent("OoOJavaAnalysis 7th pass completed");
209     // 8th pass, calculate all possible conflicts without using
210     // reachability info and identify set of FlatNew that next
211     // disjoint reach. analysis should flag
212     Set<FlatNew> sitesToFlag = new HashSet<FlatNew>();
213     calculateConflicts(sitesToFlag, false);
214     State.logEvent("OoOJavaAnalysis 8th pass completed");
215     if (!state.RCR) {
216       // 9th pass, ask disjoint analysis to compute reachability
217       // for objects that may cause heap conflicts so the most
218       // efficient method to deal with conflict can be computed
219       // later
220       disjointAnalysisReach =
221         new DisjointAnalysis(state, typeUtil, callGraph, liveness, arrayReferencees, sitesToFlag,
222                              null, // don't do effects analysis again!
223                              null, // no BuildStateMachines needed
224                              !state.OOODEBUG // only print out in OoOJava debug mode
225                              );
226       State.logEvent("OoOJavaAnalysis 9th pass completed");
227       // 10th pass, calculate conflicts with reachability info
228       calculateConflicts(null, true);
229       State.logEvent("OoOJavaAnalysis 10th pass completed");
230     } else {
231       // in RCR/DFJ we want to do some extra processing on the
232       // state machines before they get handed off to code gen,
233       // and we're doing the same effect-conflict traversal needed
234       // to identify heap examiners that are weakly connected, so
235       // accomplish both at the same time
236       pruneMachinesAndFindWeaklyConnectedExaminers();
237       State.logEvent("OoOJavaAnalysis RCR pruneMachines pass completed");
238     }
239
240     // 11th pass, compiling memory Qs! The name "lock" is a legacy
241     // term for the heap dependence queue, or memQ as the runtime calls it
242     synthesizeLocks();
243     State.logEvent("OoOJavaAnalysis 11th pass completed");
244
245     // 12th pass, compute a plan for code injections
246     methItr = descriptorsToAnalyze.iterator();
247     while (methItr.hasNext()) {
248       Descriptor d = methItr.next();
249       FlatMethod fm = state.getMethodFlat(d);
250       codePlansForward(fm);
251     }
252
253     State.logEvent("OoOJavaAnalysis 12th pass completed");
254     // 13th pass,
255     // splice new IR nodes into graph after all
256     // analysis passes are complete
257     Iterator spliceItr = wdvNodesToSpliceIn.entrySet().iterator();
258     while (spliceItr.hasNext()) {
259       Map.Entry me = (Map.Entry)spliceItr.next();
260       FlatWriteDynamicVarNode fwdvn = (FlatWriteDynamicVarNode) me.getValue();
261       fwdvn.spliceIntoIR();
262     }
263     State.logEvent("OoOJavaAnalysis 13th pass completed");
264
265     if (state.OOODEBUG) {
266       try {
267         writeReports("");
268         disjointAnalysisTaints.getEffectsAnalysis().writeEffects("effects.txt");
269         writeConflictGraph();
270       } catch (IOException e) {
271       }
272     }
273     State.logEvent("OoOJavaAnalysis completed");
274   }
275
276   private void buildFlatNodeToFlatMethod(FlatMethod fm) {
277     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
278     flatNodesToVisit.add(fm);
279
280     Set<FlatNode> flatNodesVisited = new HashSet<FlatNode>();
281
282     while (!flatNodesToVisit.isEmpty()) {
283       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
284       flatNodesToVisit.remove(fn);
285       flatNodesVisited.add(fn);
286
287       fn2fm.put(fn, fm);
288
289       for (int i = 0; i < fn.numNext(); i++) {
290         FlatNode nn = fn.getNext(i);
291         if (!flatNodesVisited.contains(nn)) {
292           flatNodesToVisit.add(nn);
293         }
294       }
295     }
296   }
297
298   // debug routine
299   /*
300    * Iterator iter = sese2conflictGraph.entrySet().iterator(); while
301    * (iter.hasNext()) { Entry e = (Entry) iter.next(); FlatNode fn = (FlatNode)
302    * e.getKey(); ConflictGraph conflictGraph = (ConflictGraph) e.getValue();
303    * System.out.println("---------------------------------------");
304    * System.out.println("CONFLICT GRAPH for " + fn); Set<String> keySet =
305    * conflictGraph.id2cn.keySet(); for (Iterator iterator = keySet.iterator();
306    * iterator.hasNext();) { String key = (String) iterator.next(); ConflictNode
307    * node = conflictGraph.id2cn.get(key); System.out.println("key=" + key +
308    * " \n" + node.toStringAllEffects()); } }
309    */
310
311   private void writeFile(Set<FlatNew> sitesToFlag) {
312
313     try {
314       BufferedWriter bw = new BufferedWriter(new FileWriter("sitesToFlag.txt"));
315
316       for (Iterator iterator = sitesToFlag.iterator(); iterator.hasNext(); ) {
317         FlatNew fn = (FlatNew) iterator.next();
318         bw.write(fn + "\n");
319       }
320       bw.close();
321     } catch (IOException e) {
322
323     }
324
325   }
326
327   private void livenessAnalysisBackward(FlatSESEEnterNode fsen) {
328
329     // flow backward across nodes to compute liveness, and
330     // take special care with sese enter/exit nodes that
331     // alter this from normal liveness analysis
332     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
333     // flatNodesToVisit.add( fm.getFlatExit() );
334     flatNodesToVisit.add(fsen.getFlatExit());
335
336     while (!flatNodesToVisit.isEmpty()) {
337       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
338       flatNodesToVisit.remove(fn);
339
340       Set<TempDescriptor> prev = livenessGlobalView.get(fn);
341
342       // merge sets from control flow joins
343       Set<TempDescriptor> livein = new HashSet<TempDescriptor>();
344       for (int i = 0; i < fn.numNext(); i++) {
345         FlatNode nn = fn.getNext(i);
346         Set<TempDescriptor> s = livenessGlobalView.get(nn);
347         if (s != null) {
348           livein.addAll(s);
349         }
350       }
351
352       Set<TempDescriptor> curr = liveness_nodeActions(fn, livein);
353
354       // if a new result, schedule backward nodes for analysis
355       if (!curr.equals(prev)) {
356
357         if (fn != fsen) {
358           livenessGlobalView.put(fn, curr);
359           for (int i = 0; i < fn.numPrev(); i++) {
360             FlatNode nn = fn.getPrev(i);
361             flatNodesToVisit.add(nn);
362           }
363         }
364       }
365     }
366   }
367
368   private Set<TempDescriptor> liveness_nodeActions(FlatNode fn, Set<TempDescriptor> liveIn) {
369     switch (fn.kind()) {
370
371     case FKind.FlatSESEEnterNode: {
372       // add whatever is live-in at a task enter to that
373       // task's in-var set
374       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
375       if (liveIn != null) {
376         fsen.addInVarSet(liveIn);
377       }
378       // no break, should also execute default actions
379     }
380
381     default: {
382       // handle effects of statement in reverse, writes then reads
383       TempDescriptor[] writeTemps = fn.writesTemps();
384       for (int i = 0; i < writeTemps.length; ++i) {
385         liveIn.remove(writeTemps[i]);
386
387         // if we are analyzing code declared directly in a task,
388         FlatSESEEnterNode fsen = rblockRel.getLocalInnerRBlock(fn);
389         if (fsen != null) {
390           // check to see if we are writing to variables that will
391           // be live-out at the task's exit (and therefore should
392           // go in the task's out-var set)
393           FlatSESEExitNode fsexn = fsen.getFlatExit();
394           // note: liveness analysis can have corresponding decisions
395           Set<TempDescriptor> livetemps = liveness.getLiveInTemps(fsen.getfmEnclosing(), fsexn);
396           if (livetemps != null && livetemps.contains(writeTemps[i])) {
397             fsen.addOutVar(writeTemps[i]);
398           }
399         }
400       }
401
402       TempDescriptor[] readTemps = fn.readsTemps();
403       for (int i = 0; i < readTemps.length; ++i) {
404         liveIn.add(readTemps[i]);
405       }
406
407       Set<TempDescriptor> virtualReadTemps = livenessVirtualReads.get(fn);
408       if (virtualReadTemps != null) {
409         liveIn.addAll(virtualReadTemps);
410       }
411     }
412     break;
413
414     } // end switch
415
416     return liveIn;
417   }
418
419   private void variableAnalysisForward(FlatMethod fm) {
420
421     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
422     flatNodesToVisit.add(fm);
423
424     while (!flatNodesToVisit.isEmpty()) {
425       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
426       flatNodesToVisit.remove(fn);
427
428       VarSrcTokTable prev = variableResults.get(fn);
429
430       // merge sets from control flow joins
431       VarSrcTokTable curr = new VarSrcTokTable();
432       for (int i = 0; i < fn.numPrev(); i++) {
433         FlatNode nn = fn.getPrev(i);
434         VarSrcTokTable incoming = variableResults.get(nn);
435         curr.merge(incoming);
436       }
437
438       FlatSESEEnterNode currentSESE = rblockRel.getLocalInnerRBlock(fn);
439       if (currentSESE == null) {
440         currentSESE = rblockRel.getCallerProxySESE();
441       }
442
443       variable_nodeActions(fn, curr, currentSESE);
444
445       // if a new result, schedule forward nodes for analysis
446       if (!curr.equals(prev)) {
447         variableResults.put(fn, curr);
448
449         for (int i = 0; i < fn.numNext(); i++) {
450           FlatNode nn = fn.getNext(i);
451           flatNodesToVisit.add(nn);
452         }
453       }
454     }
455   }
456
457   private void variable_nodeActions(FlatNode fn, VarSrcTokTable vstTable,
458                                     FlatSESEEnterNode currentSESE) {
459     switch (fn.kind()) {
460
461     case FKind.FlatSESEEnterNode: {
462       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
463       // ignore currently executing SESE, at this point
464       // the analysis considers a new instance is becoming
465       // the current SESE
466       vstTable.age(fsen);
467       vstTable.assertConsistency();
468     }
469     break;
470
471     case FKind.FlatSESEExitNode: {
472       FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
473
474       // fsen is the child of currently executing tasks
475       FlatSESEEnterNode fsen = fsexn.getFlatEnter();
476
477       // remap all of this child's children tokens to be
478       // from this child as the child exits
479       vstTable.remapChildTokens(fsen);
480
481       // liveness virtual reads are things that might be
482       // written by an SESE and should be added to the in-set
483       // anything virtually read by this SESE should be pruned
484       // of parent or sibling sources
485       Set<TempDescriptor> liveVars = liveness.getLiveInTemps(fsen.getfmEnclosing(), fn);
486
487       Set<TempDescriptor> fsenVirtReads =
488         vstTable.calcVirtReadsAndPruneParentAndSiblingTokens(fsen, liveVars);
489
490       Set<TempDescriptor> fsenVirtReadsOld = livenessVirtualReads.get(fn);
491       if (fsenVirtReadsOld != null) {
492         fsenVirtReads.addAll(fsenVirtReadsOld);
493       }
494       livenessVirtualReads.put(fn, fsenVirtReads);
495
496       // virtual reads are forced in-vars!
497       fsen.addInVarSet(fsenVirtReads);
498
499       // then all child out-set tokens are guaranteed
500       // to be filled in, so clobber those entries with
501       // the latest, clean sources
502       Iterator<TempDescriptor> outVarItr = fsen.getOutVarSet().iterator();
503       while (outVarItr.hasNext()) {
504         TempDescriptor outVar = outVarItr.next();
505         HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
506         ts.add(outVar);
507         VariableSourceToken vst = new VariableSourceToken(ts, fsen, new Integer(0), outVar);
508         vstTable.remove(outVar);
509         vstTable.add(vst);
510       }
511       vstTable.assertConsistency();
512     }
513     break;
514
515     case FKind.FlatOpNode: {
516       FlatOpNode fon = (FlatOpNode) fn;
517
518       if (fon.getOp().getOp() == Operation.ASSIGN) {
519         TempDescriptor lhs = fon.getDest();
520         TempDescriptor rhs = fon.getLeft();
521
522         vstTable.remove(lhs);
523
524         Set<VariableSourceToken> forAddition = new HashSet<VariableSourceToken>();
525
526         Iterator<VariableSourceToken> itr = vstTable.get(rhs).iterator();
527         while (itr.hasNext()) {
528           VariableSourceToken vst = itr.next();
529
530           HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
531           ts.add(lhs);
532
533           // when we do x = y for variables, just copy over from a child,
534           // there are two cases:
535           // 1. if the current task is the caller proxy, any local root is a
536           // child
537           boolean case1 =
538             currentSESE.getIsCallerProxySESE()
539             && rblockRel.getLocalRootSESEs().contains(vst.getSESE());
540
541           // 2. if the child task is a locally-defined child of the current task
542           boolean case2 = currentSESE.getLocalChildren().contains(vst.getSESE());
543
544           if (case1 || case2) {
545             // if the source comes from a child, copy it over
546             forAddition.add(new VariableSourceToken(ts, vst.getSESE(), vst.getAge(), vst
547                                                     .getAddrVar()));
548           } else {
549             // otherwise, stamp it as us as the source
550             forAddition.add(new VariableSourceToken(ts, currentSESE, new Integer(0), lhs));
551           }
552         }
553
554         vstTable.addAll(forAddition);
555
556         // only break if this is an ASSIGN op node,
557         // otherwise fall through to default case
558         vstTable.assertConsistency();
559         break;
560       }
561     }
562
563     // note that FlatOpNode's that aren't ASSIGN
564     // fall through to this default case
565     default: {
566       TempDescriptor[] writeTemps = fn.writesTemps();
567       if (writeTemps.length > 0) {
568
569         // for now, when writeTemps > 1, make sure
570         // its a call node, programmer enforce only
571         // doing stuff like calling a print routine
572         if (writeTemps.length > 1) {
573           assert fn.kind() == FKind.FlatCall || fn.kind() == FKind.FlatMethod;
574           break;
575         }
576
577         vstTable.remove(writeTemps[0]);
578
579         HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
580         ts.add(writeTemps[0]);
581
582         vstTable.add(new VariableSourceToken(ts, currentSESE, new Integer(0), writeTemps[0]));
583       }
584
585       vstTable.assertConsistency();
586     }
587     break;
588
589     } // end switch
590   }
591
592   private void notAvailableForward(FlatMethod fm) {
593
594     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
595     flatNodesToVisit.add(fm);
596
597     while (!flatNodesToVisit.isEmpty()) {
598       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
599       flatNodesToVisit.remove(fn);
600
601       Set<TempDescriptor> prev = notAvailableResults.get(fn);
602
603       Set<TempDescriptor> curr = new HashSet<TempDescriptor>();
604       for (int i = 0; i < fn.numPrev(); i++) {
605         FlatNode nn = fn.getPrev(i);
606         Set<TempDescriptor> notAvailIn = notAvailableResults.get(nn);
607         if (notAvailIn != null) {
608           curr.addAll(notAvailIn);
609         }
610       }
611
612       FlatSESEEnterNode currentSESE = rblockRel.getLocalInnerRBlock(fn);
613       if (currentSESE == null) {
614         currentSESE = rblockRel.getCallerProxySESE();
615       }
616
617       notAvailable_nodeActions(fn, curr, currentSESE);
618
619       // if a new result, schedule forward nodes for analysis
620       if (!curr.equals(prev)) {
621         notAvailableResults.put(fn, curr);
622
623         for (int i = 0; i < fn.numNext(); i++) {
624           FlatNode nn = fn.getNext(i);
625           flatNodesToVisit.add(nn);
626         }
627       }
628     }
629   }
630
631   private void notAvailable_nodeActions(FlatNode fn, Set<TempDescriptor> notAvailSet,
632                                         FlatSESEEnterNode currentSESE) {
633
634     // any temps that are removed from the not available set
635     // at this node should be marked in this node's code plan
636     // as temps to be grabbed at runtime!
637
638     switch (fn.kind()) {
639
640     case FKind.FlatSESEEnterNode: {
641       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
642
643       // keep a copy of what's not available into the SESE
644       // and restore it at the matching exit node
645       Set<TempDescriptor> notAvailCopy = new HashSet<TempDescriptor>();
646       Iterator<TempDescriptor> tdItr = notAvailSet.iterator();
647       while (tdItr.hasNext()) {
648         notAvailCopy.add(tdItr.next());
649       }
650       notAvailableIntoSESE.put(fsen, notAvailCopy);
651
652       notAvailSet.clear();
653     }
654     break;
655
656     case FKind.FlatSESEExitNode: {
657       FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
658       FlatSESEEnterNode fsen = fsexn.getFlatEnter();
659
660       notAvailSet.addAll(fsen.getOutVarSet());
661
662       Set<TempDescriptor> notAvailIn = notAvailableIntoSESE.get(fsen);
663       assert notAvailIn != null;
664       notAvailSet.addAll(notAvailIn);
665     }
666     break;
667
668     case FKind.FlatMethod: {
669       notAvailSet.clear();
670     }
671     break;
672
673     case FKind.FlatOpNode: {
674       FlatOpNode fon = (FlatOpNode) fn;
675
676       if (fon.getOp().getOp() == Operation.ASSIGN) {
677         TempDescriptor lhs = fon.getDest();
678         TempDescriptor rhs = fon.getLeft();
679
680         // copy makes lhs same availability as rhs
681         if (notAvailSet.contains(rhs)) {
682           notAvailSet.add(lhs);
683         } else {
684           notAvailSet.remove(lhs);
685         }
686
687         // only break if this is an ASSIGN op node,
688         // otherwise fall through to default case
689         break;
690       }
691     }
692
693     // note that FlatOpNode's that aren't ASSIGN
694     // fall through to this default case
695     default: {
696       TempDescriptor[] writeTemps = fn.writesTemps();
697       for (int i = 0; i < writeTemps.length; i++) {
698         TempDescriptor wTemp = writeTemps[i];
699         notAvailSet.remove(wTemp);
700       }
701       TempDescriptor[] readTemps = fn.readsTemps();
702       for (int i = 0; i < readTemps.length; i++) {
703         TempDescriptor rTemp = readTemps[i];
704         notAvailSet.remove(rTemp);
705
706         // if this variable has exactly one source, potentially
707         // get other things from this source as well
708         VarSrcTokTable vstTable = variableResults.get(fn);
709
710         VSTWrapper vstIfStatic = new VSTWrapper();
711         Integer srcType = vstTable.getRefVarSrcType(rTemp, currentSESE, vstIfStatic);
712
713         if (srcType.equals(VarSrcTokTable.SrcType_STATIC)) {
714
715           VariableSourceToken vst = vstIfStatic.vst;
716
717           Iterator<VariableSourceToken> availItr =
718             vstTable.get(vst.getSESE(), vst.getAge()).iterator();
719
720           // look through things that are also available from same source
721           while (availItr.hasNext()) {
722             VariableSourceToken vstAlsoAvail = availItr.next();
723
724             Iterator<TempDescriptor> refVarItr = vstAlsoAvail.getRefVars().iterator();
725             while (refVarItr.hasNext()) {
726               TempDescriptor refVarAlso = refVarItr.next();
727
728               // if a variable is available from the same source, AND it ALSO
729               // only comes from one statically known source, mark it available
730               VSTWrapper vstIfStaticNotUsed = new VSTWrapper();
731               Integer srcTypeAlso =
732                 vstTable.getRefVarSrcType(refVarAlso, currentSESE, vstIfStaticNotUsed);
733               if (srcTypeAlso.equals(VarSrcTokTable.SrcType_STATIC)) {
734                 notAvailSet.remove(refVarAlso);
735               }
736             }
737           }
738         }
739       }
740     }
741     break;
742
743     } // end switch
744   }
745
746   private void codePlansForward(FlatMethod fm) {
747
748     // start from flat method top, visit every node in
749     // method exactly once
750     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
751     flatNodesToVisit.add(fm);
752
753     Set<FlatNode> visited = new HashSet<FlatNode>();
754
755     while (!flatNodesToVisit.isEmpty()) {
756       Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
757       FlatNode fn = fnItr.next();
758
759       flatNodesToVisit.remove(fn);
760       visited.add(fn);
761
762       // use incoming results as "dot statement" or just
763       // before the current statement
764       VarSrcTokTable dotSTtable = new VarSrcTokTable();
765       for (int i = 0; i < fn.numPrev(); i++) {
766         FlatNode nn = fn.getPrev(i);
767         dotSTtable.merge(variableResults.get(nn));
768       }
769
770       // find dt-st notAvailableSet also
771       Set<TempDescriptor> dotSTnotAvailSet = new HashSet<TempDescriptor>();
772       for (int i = 0; i < fn.numPrev(); i++) {
773         FlatNode nn = fn.getPrev(i);
774         Set<TempDescriptor> notAvailIn = notAvailableResults.get(nn);
775         if (notAvailIn != null) {
776           dotSTnotAvailSet.addAll(notAvailIn);
777         }
778       }
779
780       Set<TempDescriptor> dotSTlive = livenessGlobalView.get(fn);
781
782       FlatSESEEnterNode currentSESE = rblockRel.getLocalInnerRBlock(fn);
783       if (currentSESE == null) {
784         currentSESE = rblockRel.getCallerProxySESE();
785       }
786
787       codePlans_nodeActions(fm, fn, dotSTtable, dotSTnotAvailSet, currentSESE);
788
789       for (int i = 0; i < fn.numNext(); i++) {
790         FlatNode nn = fn.getNext(i);
791
792         if (!visited.contains(nn)) {
793           flatNodesToVisit.add(nn);
794         }
795       }
796     }
797   }
798
799   private void codePlans_nodeActions(FlatMethod fm, FlatNode fn, VarSrcTokTable vstTableIn,
800                                      Set<TempDescriptor> notAvailSetIn, FlatSESEEnterNode currentSESE) {
801
802     CodePlan plan = new CodePlan(currentSESE);
803
804     switch (fn.kind()) {
805
806     case FKind.FlatSESEEnterNode: {
807       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
808
809       // track the source types of the in-var set so generated
810       // code at this SESE issue can compute the number of
811       // dependencies properly
812       Iterator<TempDescriptor> inVarItr = fsen.getInVarSet().iterator();
813       while (inVarItr.hasNext()) {
814         TempDescriptor inVar = inVarItr.next();
815
816         // when we get to an SESE enter node we change the
817         // currentSESE variable of this analysis to the
818         // child that is declared by the enter node, so
819         // in order to classify in-vars correctly, pass
820         // the parent SESE in--at other FlatNode types just
821         // use the currentSESE
822         FlatSESEEnterNode parent = rblockRel.getLocalInnerRBlock(fn);
823         if (parent == null) {
824           parent = rblockRel.getCallerProxySESE();
825         }
826
827         VSTWrapper vstIfStatic = new VSTWrapper();
828         Integer srcType = vstTableIn.getRefVarSrcType(inVar, parent, vstIfStatic);
829
830         // the current SESE needs a local space to track the dynamic
831         // variable and the child needs space in its SESE record
832         if (srcType.equals(VarSrcTokTable.SrcType_DYNAMIC)) {
833           fsen.addDynamicInVar(inVar);
834           addDynamicVar(parent, fm, inVar);
835
836         } else if (srcType.equals(VarSrcTokTable.SrcType_STATIC)) {
837           fsen.addStaticInVar(inVar);
838           VariableSourceToken vst = vstIfStatic.vst;
839           fsen.putStaticInVar2src(inVar, vst);
840           fsen.addStaticInVarSrc(new SESEandAgePair(vst.getSESE(), vst.getAge()));
841
842         } else {
843           assert srcType.equals(VarSrcTokTable.SrcType_READY);
844           fsen.addReadyInVar(inVar);
845         }
846       }
847     }
848     break;
849
850     case FKind.FlatSESEExitNode: {
851       FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
852
853       // Classify the sources of out-set variables so code
854       // gen can acquire them from children if necessary
855       // before this task exits
856       FlatSESEEnterNode exiter = fsexn.getFlatEnter();
857
858       Iterator<TempDescriptor> outVarItr = exiter.getOutVarSet().iterator();
859       while (outVarItr.hasNext()) {
860         TempDescriptor outVar = outVarItr.next();
861
862         VSTWrapper vstIfStatic = new VSTWrapper();
863         Integer srcType = vstTableIn.getRefVarSrcType(outVar, exiter, vstIfStatic);
864
865         if (srcType.equals(VarSrcTokTable.SrcType_DYNAMIC)) {
866           // if the out-var is dynamic, put it in the set of dyn out vars
867           // so exiting code gen knows to look for the value, but also put
868           // it in the set of dynamic vars the exiter must track!
869           exiter.addDynamicOutVar(outVar);
870           addDynamicVar(exiter, fm, outVar);
871
872         } else if (srcType.equals(VarSrcTokTable.SrcType_STATIC)) {
873           exiter.addStaticOutVar(outVar);
874           VariableSourceToken vst = vstIfStatic.vst;
875           exiter.putStaticOutVar2src(outVar, vst);
876           exiter.addStaticOutVarSrc(new SESEandAgePair(vst.getSESE(), vst.getAge()));
877
878         } else {
879           assert srcType.equals(VarSrcTokTable.SrcType_READY);
880           exiter.addReadyOutVar(outVar);
881         }
882       }
883     }
884     break;
885
886     case FKind.FlatOpNode: {
887       FlatOpNode fon = (FlatOpNode) fn;
888
889       if (fon.getOp().getOp() == Operation.ASSIGN) {
890         TempDescriptor lhs = fon.getDest();
891         TempDescriptor rhs = fon.getLeft();
892
893         // if this is an op node, don't stall, copy
894         // source and delay until we need to use value
895
896         // ask whether lhs and rhs sources are dynamic, static, etc.
897         VSTWrapper vstIfStatic = new VSTWrapper();
898         Integer lhsSrcType = vstTableIn.getRefVarSrcType(lhs, currentSESE, vstIfStatic);
899         Integer rhsSrcType = vstTableIn.getRefVarSrcType(rhs, currentSESE, vstIfStatic);
900
901         if (rhsSrcType.equals(VarSrcTokTable.SrcType_DYNAMIC)) {
902           // if rhs is dynamic going in, lhs will definitely be dynamic
903           // going out of this node, so track that here
904           plan.addDynAssign(lhs, rhs);
905           addDynamicVar(currentSESE, fm, lhs);
906           addDynamicVar(currentSESE, fm, rhs);
907
908         } else if (lhsSrcType.equals(VarSrcTokTable.SrcType_DYNAMIC)) {
909           // otherwise, if the lhs is dynamic, but the rhs is not, we
910           // need to update the variable's dynamic source as "current SESE"
911           plan.addDynAssign(lhs);
912         }
913
914         // only break if this is an ASSIGN op node,
915         // otherwise fall through to default case
916         break;
917       }
918     }
919
920     // note that FlatOpNode's that aren't ASSIGN
921     // fall through to this default case
922     default: {
923
924       // a node with no live set has nothing to stall for
925       // note: no reason to check here, remove this....
926       // if (liveSetIn == null) {
927       // break;
928       // }
929
930       TempDescriptor[] readarray = fn.readsTemps();
931       for (int i = 0; i < readarray.length; i++) {
932         TempDescriptor readtmp = readarray[i];
933
934         // ignore temps that are definitely available
935         // when considering to stall on it
936         if (!notAvailSetIn.contains(readtmp)) {
937           continue;
938         }
939
940         // check the source type of this variable
941         VSTWrapper vstIfStatic = new VSTWrapper();
942         Integer srcType = vstTableIn.getRefVarSrcType(readtmp, currentSESE, vstIfStatic);
943
944         if (srcType.equals(VarSrcTokTable.SrcType_DYNAMIC)) {
945           // 1) It is not clear statically where this variable will
946           // come from, so dynamically we must keep track
947           // along various control paths, and therefore when we stall,
948           // just stall for the exact thing we need and move on
949           plan.addDynamicStall(readtmp);
950           addDynamicVar(currentSESE, fm, readtmp);
951
952         } else if (srcType.equals(VarSrcTokTable.SrcType_STATIC)) {
953           // 2) Single token/age pair: Stall for token/age pair, and copy
954           // all live variables with same token/age pair at the same
955           // time. This is the same stuff that the notavaialable analysis
956           // marks as now available.
957           VariableSourceToken vst = vstIfStatic.vst;
958
959           Iterator<VariableSourceToken> availItr =
960             vstTableIn.get(vst.getSESE(), vst.getAge()).iterator();
961
962           while (availItr.hasNext()) {
963             VariableSourceToken vstAlsoAvail = availItr.next();
964
965             // only grab additional stuff that is live
966             Set<TempDescriptor> copySet = new HashSet<TempDescriptor>();
967
968             Iterator<TempDescriptor> refVarItr = vstAlsoAvail.getRefVars().iterator();
969
970             while (refVarItr.hasNext()) {
971               TempDescriptor refVar = refVarItr.next();
972               // note: this should just use normal liveness in...only want to
973               // copy live variables...
974               if (liveness.getLiveInTemps(fm, fn).contains(refVar)) {
975                 copySet.add(refVar);
976               }
977             }
978
979             if (!copySet.isEmpty()) {
980               plan.addStall2CopySet(vstAlsoAvail, copySet);
981             }
982           }
983
984         } else {
985           // the other case for srcs is READY, so do nothing
986         }
987
988         // assert that everything being stalled for is in the
989         // "not available" set coming into this flat node and
990         // that every VST identified is in the possible "stall set"
991         // that represents VST's from children SESE's
992
993       }
994     }
995     break;
996
997     } // end switch
998
999     // identify sese-age pairs that are statically useful
1000     // and should have an associated SESE variable in code
1001     // JUST GET ALL SESE/AGE NAMES FOR NOW, PRUNE LATER,
1002     // AND ALWAYS GIVE NAMES TO LOCAL PARENTS
1003     Set<VariableSourceToken> staticSet = vstTableIn.get();
1004     Iterator<VariableSourceToken> vstItr = staticSet.iterator();
1005     while (vstItr.hasNext()) {
1006       VariableSourceToken vst = vstItr.next();
1007
1008       // the caller proxy generates useful analysis facts, but we
1009       // never need to generate another name for it in code (it is
1010       // ALWAYS the task executing the local method context)
1011       if (vst.getSESE().getIsCallerProxySESE()) {
1012         continue;
1013       }
1014
1015       SESEandAgePair sap = new SESEandAgePair(vst.getSESE(), vst.getAge());
1016       sap.getSESE().mustTrackAtLeastAge(sap.getAge());
1017
1018       FlatSESEEnterNode sese = currentSESE;
1019       while (sese != null) {
1020         addNeededStaticName(sese, fm, sap);
1021         sese = sese.getLocalParent();
1022       }
1023     }
1024
1025     codePlans.put(fn, plan);
1026
1027     // if any variables at this-node-*dot* have a static source (exactly one
1028     // vst)
1029     // but go to a dynamic source at next-node-*dot*, create a new IR graph
1030     // node on that edge to track the sources dynamically
1031     // NOTE: for this calculation use the currentSESE variable, except when the
1032     // FlatNode fn is an Exit--in that case currentSESE is for the exiting task,
1033     // be we want to consider that the parent is tracking a variable coming out
1034     // of the exiting task
1035     FlatSESEEnterNode fsenDoingTracking;
1036     if (fn instanceof FlatSESEExitNode) {
1037       fsenDoingTracking = currentSESE.getLocalParent();
1038
1039       if (fsenDoingTracking == null) {
1040         // if there is no local parent, there are one of two cases
1041         // 1) the current task is main, in which case this FlatNode
1042         // is the main's exit, and doesn't need to do any of the
1043         // following dynamic tracking
1044         // 2) the current task is defined in a method, so use the
1045         // caller proxy in the variable source calcs below
1046         if (currentSESE.equals(rblockRel.getMainSESE())) {
1047           return;
1048         } else {
1049           fsenDoingTracking = rblockRel.getCallerProxySESE();
1050         }
1051       }
1052     } else {
1053       fsenDoingTracking = currentSESE;
1054     }
1055
1056     VarSrcTokTable thisVstTable = variableResults.get(fn);
1057     for (int i = 0; i < fn.numNext(); i++) {
1058       FlatNode nn = fn.getNext(i);
1059       VarSrcTokTable nextVstTable = variableResults.get(nn);
1060       // note: using the result of liveness analysis regardless of task
1061       // structures
1062       Set<TempDescriptor> nextLiveIn = liveness.getLiveInTemps(fm, nn);
1063
1064       // the table can be null if it is one of the few IR nodes
1065       // completely outside of the root SESE scope
1066       if (nextVstTable != null && nextLiveIn != null) {
1067
1068         Hashtable<TempDescriptor, VSTWrapper> readyOrStatic2dynamicSet =
1069           thisVstTable.getReadyOrStatic2DynamicSet(nextVstTable, nextLiveIn, fsenDoingTracking);
1070
1071         if (!readyOrStatic2dynamicSet.isEmpty()) {
1072
1073           // either add these results to partial fixed-point result
1074           // or make a new one if we haven't made any here yet
1075           FlatEdge fe = new FlatEdge(fn, nn);
1076           FlatWriteDynamicVarNode fwdvn = wdvNodesToSpliceIn.get(fe);
1077
1078           if (fwdvn == null) {
1079             fwdvn =
1080               new FlatWriteDynamicVarNode(fn, nn, readyOrStatic2dynamicSet, fsenDoingTracking);
1081             wdvNodesToSpliceIn.put(fe, fwdvn);
1082           } else {
1083             fwdvn.addMoreVar2Src(readyOrStatic2dynamicSet);
1084           }
1085         }
1086       }
1087     }
1088   }
1089
1090   private void addDynamicVar(FlatSESEEnterNode fsen, FlatMethod fm, TempDescriptor var) {
1091     FlatNode fnContext;
1092
1093     // note: dynamic variable declarations are always located in the flat method
1094     // that encloses task block
1095     // there is no need to set fnContext to fsen
1096     if (fsen.getIsCallerProxySESE()) {
1097       // attach the dynamic variable to track to
1098       // the flat method, so it can be declared at entry
1099       fnContext = fm;
1100     } else {
1101       // otherwise the code context is a task body
1102       fnContext = fsen;
1103     }
1104     // fnContext=fm;
1105
1106     ContextTaskNames ctn = fn2contextTaskNames.get(fnContext);
1107     if (ctn == null) {
1108       ctn = new ContextTaskNames();
1109     }
1110
1111     ctn.addDynamicVar(var);
1112     fn2contextTaskNames.put(fnContext, ctn);
1113
1114   }
1115
1116   private void addNeededStaticName(FlatSESEEnterNode fsen, FlatMethod fm, SESEandAgePair sap) {
1117     FlatNode fnContext;
1118
1119     if (fsen.getIsCallerProxySESE()) {
1120       // attach the dynamic variable to track to
1121       // the flat method, so it can be declared at entry
1122       fnContext = fm;
1123     } else {
1124       // otherwise the code context is a task body
1125       fnContext = fsen;
1126     }
1127
1128     ContextTaskNames ctn = fn2contextTaskNames.get(fnContext);
1129     if (ctn == null) {
1130       ctn = new ContextTaskNames();
1131     }
1132
1133     ctn.addNeededStaticName(sap);
1134
1135     fn2contextTaskNames.put(fnContext, ctn);
1136   }
1137
1138   private void startConflictGraphs() {
1139
1140     // first, for each task, consider whether it has any children, and if
1141     // effects analysis says they should be a conflict node in the that
1142     // parent's conflict graph
1143     Set<FlatSESEEnterNode> allSESEs = rblockRel.getAllSESEs();
1144     for (Iterator iterator = allSESEs.iterator(); iterator.hasNext(); ) {
1145
1146       FlatSESEEnterNode parent = (FlatSESEEnterNode) iterator.next();
1147       if (parent.getIsLeafSESE()) {
1148         continue;
1149       }
1150
1151       EffectsAnalysis effectsAnalysis = disjointAnalysisTaints.getEffectsAnalysis();
1152       ConflictGraph conflictGraph = sese2conflictGraph.get(parent);
1153       assert conflictGraph == null;
1154       conflictGraph = new ConflictGraph(state);
1155
1156       Set<FlatSESEEnterNode> children = parent.getChildren();
1157       for (Iterator iterator2 = children.iterator(); iterator2.hasNext(); ) {
1158         FlatSESEEnterNode child = (FlatSESEEnterNode) iterator2.next();
1159         Hashtable<Taint, Set<Effect>> taint2Effects = effectsAnalysis.get(child);
1160         conflictGraph.addLiveIn(taint2Effects);
1161       }
1162
1163       sese2conflictGraph.put(parent, conflictGraph);
1164     }
1165
1166     // then traverse all methods looking for potential stall sites, and
1167     // add those stall sites as nodes in any task's conflict graph that
1168     // might be executing at the point of the stall site
1169     Iterator<MethodDescriptor> descItr = descriptorsToAnalyze.iterator();
1170     while (descItr.hasNext()) {
1171       MethodDescriptor md = descItr.next();
1172       FlatMethod fm = state.getMethodFlat(md);
1173       if (fm != null) {
1174         addStallSitesToConflictGraphs(fm);
1175       }
1176     }
1177   }
1178
1179   private void addStallSitesToConflictGraphs(FlatMethod fm) {
1180
1181     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
1182     flatNodesToVisit.add(fm);
1183
1184     Set<FlatNode> visited = new HashSet<FlatNode>();
1185
1186     while (!flatNodesToVisit.isEmpty()) {
1187       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
1188       flatNodesToVisit.remove(fn);
1189       visited.add(fn);
1190
1191       Set<FlatSESEEnterNode> currentSESEs = rblockRel.getPossibleExecutingRBlocks(fn);
1192
1193       conflictGraph_nodeAction(fn, currentSESEs, fm.getMethod().getClassDesc());
1194
1195       // schedule forward nodes for analysis
1196       for (int i = 0; i < fn.numNext(); i++) {
1197         FlatNode nn = fn.getNext(i);
1198         if (!visited.contains(nn)) {
1199           flatNodesToVisit.add(nn);
1200         }
1201       }
1202     }
1203   }
1204
1205   private void conflictGraph_nodeAction(FlatNode fn, Set<FlatSESEEnterNode> currentSESEs,
1206                                         ClassDescriptor cd) {
1207
1208     EffectsAnalysis effectsAnalysis = disjointAnalysisTaints.getEffectsAnalysis();
1209
1210     Hashtable<Taint, Set<Effect>> taint2Effects = effectsAnalysis.get(fn);
1211
1212     // repeat the process of adding a stall site to a conflict graph
1213     // for each task that might be executing at a possible stall site
1214     Iterator<FlatSESEEnterNode> seseItr = currentSESEs.iterator();
1215     while (seseItr.hasNext()) {
1216       FlatSESEEnterNode currentSESE = seseItr.next();
1217
1218       ConflictGraph conflictGraph = sese2conflictGraph.get(currentSESE);
1219       if (conflictGraph == null) {
1220         assert currentSESE.getIsLeafSESE();
1221         continue;
1222       }
1223
1224       TempDescriptor lhs;
1225       TempDescriptor rhs;
1226
1227       switch (fn.kind()) {
1228
1229       case FKind.FlatFieldNode:
1230       case FKind.FlatElementNode: {
1231
1232         if (fn instanceof FlatFieldNode) {
1233           FlatFieldNode ffn = (FlatFieldNode) fn;
1234           rhs = ffn.getSrc();
1235         } else {
1236           FlatElementNode fen = (FlatElementNode) fn;
1237           rhs = fen.getSrc();
1238         }
1239
1240         conflictGraph.addStallSite(taint2Effects, rhs, cd);
1241       }
1242       break;
1243
1244       case FKind.FlatSetFieldNode:
1245       case FKind.FlatSetElementNode: {
1246
1247         if (fn instanceof FlatSetFieldNode) {
1248           FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
1249           lhs = fsfn.getDst();
1250           rhs = fsfn.getSrc();
1251         } else {
1252           FlatSetElementNode fsen = (FlatSetElementNode) fn;
1253           lhs = fsen.getDst();
1254           rhs = fsen.getSrc();
1255         }
1256
1257         conflictGraph.addStallSite(taint2Effects, rhs, cd);
1258         conflictGraph.addStallSite(taint2Effects, lhs, cd);
1259       }
1260       break;
1261
1262       case FKind.FlatCall: {
1263         FlatCall fc = (FlatCall) fn;
1264         lhs = fc.getThis();
1265
1266         conflictGraph.addStallSite(taint2Effects, lhs, cd);
1267       }
1268       break;
1269
1270       }
1271
1272       if (conflictGraph.id2cn.size() > 0) {
1273         sese2conflictGraph.put(currentSESE, conflictGraph);
1274       }
1275     }
1276   }
1277
1278   private void calculateConflicts(Set<FlatNew> sitesToFlag, boolean useReachInfo) {
1279
1280     // decide fine-grain edge or coarse-grain edge among all vertexes by
1281     // pair-wise comparison
1282     Iterator<FlatNode> seseIter = sese2conflictGraph.keySet().iterator();
1283     while (seseIter.hasNext()) {
1284       FlatSESEEnterNode sese = (FlatSESEEnterNode) seseIter.next();
1285       ConflictGraph conflictGraph = sese2conflictGraph.get(sese);
1286
1287       if (useReachInfo) {
1288         // clear current conflict before recalculating with reachability info
1289         conflictGraph.clearAllConflictEdge();
1290         conflictGraph.setDisJointAnalysis(disjointAnalysisReach);
1291         conflictGraph.setFMEnclosing(sese.getfmEnclosing());
1292       }
1293       conflictGraph.analyzeConflicts(sitesToFlag, useReachInfo);
1294       sese2conflictGraph.put(sese, conflictGraph);
1295     }
1296   }
1297
1298   private void writeConflictGraph() {
1299     Enumeration<FlatNode> keyEnum = sese2conflictGraph.keys();
1300     while (keyEnum.hasMoreElements()) {
1301       FlatNode key = (FlatNode) keyEnum.nextElement();
1302       ConflictGraph cg = sese2conflictGraph.get(key);
1303       try {
1304         if (cg.hasConflictEdge()) {
1305           cg.writeGraph("ConflictGraphFor" + key, false);
1306         }
1307       } catch (IOException e) {
1308         System.out.println("Error writing");
1309         System.exit(0);
1310       }
1311     }
1312   }
1313
1314   // the traversal for pruning state machines and finding
1315   // machines that are weakly connected BOTH consider conflicting
1316   // effects between heap roots, so it is smart to compute all of
1317   // this together
1318   public void pruneMachinesAndFindWeaklyConnectedExaminers() {
1319     ProcessStateMachines psm = new ProcessStateMachines(buildStateMachines, rblockRel);
1320     psm.doProcess();
1321     buildStateMachines.writeStateMachines("pruned");
1322   }
1323
1324   private void synthesizeLocks() {
1325     // for every conflict graph, generate a set of memory queues
1326     // (called SESELock in this code!) to cover the graph
1327     Set<Map.Entry<FlatNode, ConflictGraph>> graphEntrySet = sese2conflictGraph.entrySet();
1328     for (Iterator iterator = graphEntrySet.iterator(); iterator.hasNext(); ) {
1329       Map.Entry<FlatNode, ConflictGraph> graphEntry =
1330         (Map.Entry<FlatNode, ConflictGraph>)iterator.next();
1331       FlatNode sese = graphEntry.getKey();
1332       ConflictGraph conflictGraph = graphEntry.getValue();
1333       calculateCovering(conflictGraph);
1334     }
1335   }
1336
1337   private void calculateCovering(ConflictGraph conflictGraph) {
1338     uniqueLockSetId = 0; // reset lock counter for every new conflict graph
1339     HashSet<ConflictEdge> fineToCover = new HashSet<ConflictEdge>();
1340     HashSet<ConflictEdge> coarseToCover = new HashSet<ConflictEdge>();
1341     HashSet<SESELock> lockSet = new HashSet<SESELock>();
1342
1343     Set<ConflictEdge> tempCover = conflictGraph.getEdgeSet();
1344     for (Iterator iterator = tempCover.iterator(); iterator.hasNext(); ) {
1345       ConflictEdge conflictEdge = (ConflictEdge) iterator.next();
1346       if (conflictEdge.isCoarseEdge()) {
1347         coarseToCover.add(conflictEdge);
1348       } else {
1349         fineToCover.add(conflictEdge);
1350       }
1351     }
1352
1353     HashSet<ConflictEdge> toCover = new HashSet<ConflictEdge>();
1354     toCover.addAll(fineToCover);
1355     toCover.addAll(coarseToCover);
1356
1357     while (!toCover.isEmpty()) {
1358
1359       SESELock seseLock = new SESELock();
1360       seseLock.setID(uniqueLockSetId++);
1361
1362       boolean changed;
1363
1364       do { // fine-grained edge
1365
1366         changed = false;
1367
1368         for (Iterator iterator = fineToCover.iterator(); iterator.hasNext(); ) {
1369
1370           int type;
1371           ConflictEdge edge = (ConflictEdge) iterator.next();
1372           if (seseLock.getConflictNodeSet().size() == 0) {
1373             // initial setup
1374             if (seseLock.isWriteNode(edge.getVertexU())) {
1375               // mark as fine_write
1376               if (edge.getVertexU().isStallSiteNode()) {
1377                 type = ConflictNode.PARENT_WRITE;
1378               } else {
1379                 type = ConflictNode.FINE_WRITE;
1380               }
1381               seseLock.addConflictNode(edge.getVertexU(), type);
1382             } else {
1383               // mark as fine_read
1384               if (edge.getVertexU().isStallSiteNode()) {
1385                 type = ConflictNode.PARENT_READ;
1386               } else {
1387                 type = ConflictNode.FINE_READ;
1388               }
1389               seseLock.addConflictNode(edge.getVertexU(), type);
1390             }
1391             if (edge.getVertexV() != edge.getVertexU()) {
1392               if (seseLock.isWriteNode(edge.getVertexV())) {
1393                 // mark as fine_write
1394                 if (edge.getVertexV().isStallSiteNode()) {
1395                   type = ConflictNode.PARENT_WRITE;
1396                 } else {
1397                   type = ConflictNode.FINE_WRITE;
1398                 }
1399                 seseLock.addConflictNode(edge.getVertexV(), type);
1400               } else {
1401                 // mark as fine_read
1402                 if (edge.getVertexV().isStallSiteNode()) {
1403                   type = ConflictNode.PARENT_READ;
1404                 } else {
1405                   type = ConflictNode.FINE_READ;
1406                 }
1407                 seseLock.addConflictNode(edge.getVertexV(), type);
1408               }
1409             }
1410             changed = true;
1411             seseLock.addConflictEdge(edge);
1412             fineToCover.remove(edge);
1413             break; // exit iterator loop
1414           } // end of initial setup
1415
1416           ConflictNode newNode;
1417           if ((newNode = seseLock.getNewNodeConnectedWithGroup(edge)) != null) {
1418             // new node has a fine-grained edge to all current node
1419             // If there is a coarse grained edge where need a fine edge, it's
1420             // okay to add the node
1421             // but the edge must remain uncovered.
1422
1423             changed = true;
1424
1425             if (seseLock.containsConflictNode(newNode)) {
1426               seseLock.addEdge(edge);
1427               fineToCover.remove(edge);
1428               break;
1429             }
1430
1431             if (seseLock.isWriteNode(newNode)) {
1432               if (newNode.isStallSiteNode()) {
1433                 type = ConflictNode.PARENT_WRITE;
1434               } else {
1435                 type = ConflictNode.FINE_WRITE;
1436               }
1437               seseLock.setNodeType(newNode, type);
1438             } else {
1439               if (newNode.isStallSiteNode()) {
1440                 type = ConflictNode.PARENT_READ;
1441               } else {
1442                 type = ConflictNode.FINE_READ;
1443               }
1444               seseLock.setNodeType(newNode, type);
1445             }
1446
1447             seseLock.addEdge(edge);
1448             Set<ConflictEdge> edgeSet = newNode.getEdgeSet();
1449             for (Iterator iterator2 = edgeSet.iterator(); iterator2.hasNext(); ) {
1450               ConflictEdge conflictEdge = (ConflictEdge) iterator2.next();
1451
1452               // mark all fine edges between new node and nodes in the group as
1453               // covered
1454               if (!conflictEdge.getVertexU().equals(newNode)) {
1455                 if (seseLock.containsConflictNode(conflictEdge.getVertexU())) {
1456                   changed = true;
1457                   seseLock.addConflictEdge(conflictEdge);
1458                   fineToCover.remove(conflictEdge);
1459                 }
1460               } else if (!conflictEdge.getVertexV().equals(newNode)) {
1461                 if (seseLock.containsConflictNode(conflictEdge.getVertexV())) {
1462                   changed = true;
1463                   seseLock.addConflictEdge(conflictEdge);
1464                   fineToCover.remove(conflictEdge);
1465                 }
1466               }
1467
1468             }
1469
1470             break; // exit iterator loop
1471           }
1472         }
1473
1474       } while (changed);
1475       HashSet<ConflictEdge> notCovered = new HashSet<ConflictEdge>();
1476       do { // coarse
1477         changed = false;
1478         int type;
1479         for (Iterator iterator = coarseToCover.iterator(); iterator.hasNext(); ) {
1480
1481           ConflictEdge edge = (ConflictEdge) iterator.next();
1482           if (seseLock.getConflictNodeSet().size() == 0) {
1483             // initial setup
1484             if (seseLock.hasSelfCoarseEdge(edge.getVertexU())) {
1485               // node has a coarse-grained edge with itself
1486               if (!(edge.getVertexU().isStallSiteNode())) {
1487                 // and it is not parent
1488                 type = ConflictNode.SCC;
1489               } else {
1490                 if (state.RCR) {
1491                   type = ConflictNode.PARENT_COARSE;
1492                 } else {
1493                   type = ConflictNode.PARENT_WRITE;
1494                 }
1495               }
1496               seseLock.addConflictNode(edge.getVertexU(), type);
1497             } else {
1498               if (edge.getVertexU().isStallSiteNode()) {
1499                 if (state.RCR) {
1500                   type = ConflictNode.PARENT_COARSE;
1501                 } else {
1502                   if (edge.getVertexU().getWriteEffectSet().isEmpty()) {
1503                     type = ConflictNode.PARENT_READ;
1504                   } else {
1505                     type = ConflictNode.PARENT_WRITE;
1506                   }
1507                 }
1508               } else {
1509                 type = ConflictNode.COARSE;
1510               }
1511               seseLock.addConflictNode(edge.getVertexU(), type);
1512             }
1513             if (seseLock.hasSelfCoarseEdge(edge.getVertexV())) {
1514               // node has a coarse-grained edge with itself
1515               if (!(edge.getVertexV().isStallSiteNode())) {
1516                 // and it is not parent
1517                 type = ConflictNode.SCC;
1518               } else {
1519                 if (state.RCR) {
1520                   type = ConflictNode.PARENT_COARSE;
1521                 } else {
1522                   type = ConflictNode.PARENT_WRITE;
1523                 }
1524               }
1525               seseLock.addConflictNode(edge.getVertexV(), type);
1526             } else {
1527               if (edge.getVertexV().isStallSiteNode()) {
1528                 if (state.RCR) {
1529                   type = ConflictNode.PARENT_COARSE;
1530                 } else {
1531                   if (edge.getVertexV().getWriteEffectSet().isEmpty()) {
1532                     type = ConflictNode.PARENT_READ;
1533                   } else {
1534                     type = ConflictNode.PARENT_WRITE;
1535                   }
1536                 }
1537               } else {
1538                 type = ConflictNode.COARSE;
1539               }
1540               seseLock.addConflictNode(edge.getVertexV(), type);
1541             }
1542             changed = true;
1543             coarseToCover.remove(edge);
1544             seseLock.addConflictEdge(edge);
1545             break; // exit iterator loop
1546           } // end of initial setup
1547
1548           ConflictNode newNode;
1549           if ((newNode = seseLock.getNewNodeConnectedWithGroup(edge)) != null) {
1550             // new node has a coarse-grained edge to all fine-read, fine-write,
1551             // parent
1552             changed = true;
1553
1554             if (newNode.isInVarNode() && (!seseLock.hasSelfCoarseEdge(newNode))
1555                 && seseLock.hasCoarseEdgeWithParentCoarse(newNode)) {
1556               // this case can't be covered by this queue
1557               coarseToCover.remove(edge);
1558               notCovered.add(edge);
1559               break;
1560             }
1561
1562             if (seseLock.containsConflictNode(newNode)) {
1563               seseLock.addEdge(edge);
1564               coarseToCover.remove(edge);
1565               break;
1566             }
1567
1568             if (seseLock.hasSelfCoarseEdge(newNode)) {
1569               // SCC
1570               if (newNode.isStallSiteNode()) {
1571                 type = ConflictNode.PARENT_COARSE;
1572               } else {
1573                 type = ConflictNode.SCC;
1574               }
1575               seseLock.setNodeType(newNode, type);
1576             } else {
1577               if (newNode.isStallSiteNode()) {
1578                 type = ConflictNode.PARENT_COARSE;
1579               } else {
1580                 type = ConflictNode.COARSE;
1581               }
1582               seseLock.setNodeType(newNode, type);
1583             }
1584
1585             seseLock.addEdge(edge);
1586             Set<ConflictEdge> edgeSet = newNode.getEdgeSet();
1587             for (Iterator iterator2 = edgeSet.iterator(); iterator2.hasNext(); ) {
1588               ConflictEdge conflictEdge = (ConflictEdge) iterator2.next();
1589               // mark all coarse edges between new node and nodes in the group
1590               // as covered
1591               if (!conflictEdge.getVertexU().equals(newNode)) {
1592                 if (seseLock.containsConflictNode(conflictEdge.getVertexU())) {
1593                   changed = true;
1594                   seseLock.addConflictEdge(conflictEdge);
1595                   coarseToCover.remove(conflictEdge);
1596                 }
1597               } else if (!conflictEdge.getVertexV().equals(newNode)) {
1598                 if (seseLock.containsConflictNode(conflictEdge.getVertexV())) {
1599                   changed = true;
1600                   seseLock.addConflictEdge(conflictEdge);
1601                   coarseToCover.remove(conflictEdge);
1602                 }
1603               }
1604
1605             }
1606             break; // exit iterator loop
1607           }
1608
1609         }
1610
1611       } while (changed);
1612       lockSet.add(seseLock);
1613
1614       toCover.clear();
1615       coarseToCover.addAll(notCovered);
1616       toCover.addAll(fineToCover);
1617       toCover.addAll(coarseToCover);
1618
1619     }
1620
1621     conflictGraph2SESELock.put(conflictGraph, lockSet);
1622   }
1623
1624   public ConflictGraph getConflictGraph(FlatNode sese) {
1625     return sese2conflictGraph.get(sese);
1626   }
1627
1628   public Set<SESELock> getLockMappings(ConflictGraph graph) {
1629     return conflictGraph2SESELock.get(graph);
1630   }
1631
1632   public Set<FlatSESEEnterNode> getAllSESEs() {
1633     return rblockRel.getAllSESEs();
1634   }
1635
1636   public FlatSESEEnterNode getMainSESE() {
1637     return rblockRel.getMainSESE();
1638   }
1639
1640   public FlatSESEEnterNode getCallerProxySESE() {
1641     return rblockRel.getCallerProxySESE();
1642   }
1643
1644   public Set<FlatSESEEnterNode> getPossibleExecutingRBlocks(FlatNode fn) {
1645     return rblockRel.getPossibleExecutingRBlocks(fn);
1646   }
1647
1648   public void writeReports(String timeReport) throws java.io.IOException {
1649
1650     BufferedWriter bw = new BufferedWriter(new FileWriter("ooojReport_summary.txt"));
1651     bw.write("OoOJava Analysis Results\n\n");
1652     bw.write(timeReport + "\n\n");
1653     printSESEHierarchy(bw);
1654     bw.write("\n");
1655     printSESEInfo(bw);
1656     bw.close();
1657
1658     Iterator<MethodDescriptor> methItr = descriptorsToAnalyze.iterator();
1659     while (methItr.hasNext()) {
1660       MethodDescriptor md = methItr.next();
1661       FlatMethod fm = state.getMethodFlat(md);
1662       if (fm != null) {
1663         bw =
1664           new BufferedWriter(new FileWriter("ooojReport_" + md.getClassMethodName()
1665                                             + md.getSafeMethodDescriptor() + ".txt"));
1666         bw.write("OoOJava Results for " + md + "\n-------------------\n");
1667
1668         bw.write("Dynamic vars to manage:\n  " + getContextTaskNames(fm).getDynamicVarSet());
1669
1670         bw.write("\n\nLive-In, Root View\n------------------\n"
1671                  + fm.printMethod(livenessGlobalView));
1672         bw.write("\n\nVariable Results-Out\n----------------\n" + fm.printMethod(variableResults));
1673         bw.write("\n\nNot Available Results-Out\n---------------------\n"
1674                  + fm.printMethod(notAvailableResults));
1675         bw.write("\n\nCode Plans\n----------\n" + fm.printMethod(codePlans));
1676         bw.close();
1677       }
1678     }
1679   }
1680
1681   private void printSESEHierarchy(BufferedWriter bw) throws java.io.IOException {
1682     bw.write("SESE Local Hierarchy\n--------------\n");
1683     Iterator<FlatSESEEnterNode> rootItr = rblockRel.getLocalRootSESEs().iterator();
1684     while (rootItr.hasNext()) {
1685       FlatSESEEnterNode root = rootItr.next();
1686       printSESEHierarchyTree(bw, root, 0);
1687     }
1688   }
1689
1690   private void printSESEHierarchyTree(BufferedWriter bw, FlatSESEEnterNode fsen, int depth)
1691   throws java.io.IOException {
1692     for (int i = 0; i < depth; ++i) {
1693       bw.write("  ");
1694     }
1695     bw.write("- " + fsen.getPrettyIdentifier() + "\n");
1696
1697     Iterator<FlatSESEEnterNode> childItr = fsen.getLocalChildren().iterator();
1698     while (childItr.hasNext()) {
1699       FlatSESEEnterNode fsenChild = childItr.next();
1700       printSESEHierarchyTree(bw, fsenChild, depth + 1);
1701     }
1702   }
1703
1704   private void printSESEInfo(BufferedWriter bw) throws java.io.IOException {
1705     bw.write("\nSESE info\n-------------\n");
1706     Iterator<FlatSESEEnterNode> fsenItr = rblockRel.getAllSESEs().iterator();
1707     while (fsenItr.hasNext()) {
1708       FlatSESEEnterNode fsen = fsenItr.next();
1709
1710       bw.write("SESE " + fsen.getPrettyIdentifier());
1711       if (fsen.getIsLeafSESE()) {
1712         bw.write(" (leaf)");
1713       }
1714       bw.write(" {\n");
1715
1716       bw.write("  in-set: " + fsen.getInVarSet() + "\n");
1717       Iterator<TempDescriptor> tItr = fsen.getInVarSet().iterator();
1718       while (tItr.hasNext()) {
1719         TempDescriptor inVar = tItr.next();
1720         if (fsen.getReadyInVarSet().contains(inVar)) {
1721           bw.write("    (ready)  " + inVar + "\n");
1722         }
1723         if (fsen.getStaticInVarSet().contains(inVar)) {
1724           bw.write("    (static) " + inVar + " from " + fsen.getStaticInVarSrc(inVar) + "\n");
1725         }
1726         if (fsen.getDynamicInVarSet().contains(inVar)) {
1727           bw.write("    (dynamic)" + inVar + "\n");
1728         }
1729       }
1730
1731       bw.write("   Dynamic vars to manage: " + getContextTaskNames(fsen).getDynamicVarSet() + "\n");
1732
1733       bw.write("  out-set: " + fsen.getOutVarSet() + "\n");
1734       tItr = fsen.getOutVarSet().iterator();
1735       while (tItr.hasNext()) {
1736         TempDescriptor outVar = tItr.next();
1737         if (fsen.getReadyOutVarSet().contains(outVar)) {
1738           bw.write("    (ready)  " + outVar + "\n");
1739         }
1740         if (fsen.getStaticOutVarSet().contains(outVar)) {
1741           bw.write("    (static) " + outVar + " from " + fsen.getStaticOutVarSrc(outVar) + "\n");
1742         }
1743         if (fsen.getDynamicOutVarSet().contains(outVar)) {
1744           bw.write("    (dynamic)" + outVar + "\n");
1745         }
1746       }
1747
1748       bw.write("  local parent:   " + fsen.getLocalParent() + "\n");
1749       bw.write("  local children: " + fsen.getLocalChildren() + "\n");
1750
1751       bw.write("  possible parents:  " + fsen.getParents() + "\n");
1752       bw.write("  possible children: " + fsen.getChildren() + "\n");
1753
1754       bw.write("}\n");
1755     }
1756   }
1757 }