changes.
[IRC.git] / Robust / src / Analysis / SSJava / DefinitelyWrittenCheck.java
1 package Analysis.SSJava;
2
3 import java.util.Enumeration;
4 import java.util.HashSet;
5 import java.util.Hashtable;
6 import java.util.Iterator;
7 import java.util.LinkedList;
8 import java.util.Set;
9 import java.util.Stack;
10
11 import Analysis.CallGraph.CallGraph;
12 import Analysis.Loops.LoopFinder;
13 import IR.Descriptor;
14 import IR.FieldDescriptor;
15 import IR.MethodDescriptor;
16 import IR.Operation;
17 import IR.State;
18 import IR.TypeDescriptor;
19 import IR.TypeExtension;
20 import IR.Flat.FKind;
21 import IR.Flat.FlatCall;
22 import IR.Flat.FlatElementNode;
23 import IR.Flat.FlatFieldNode;
24 import IR.Flat.FlatLiteralNode;
25 import IR.Flat.FlatMethod;
26 import IR.Flat.FlatNew;
27 import IR.Flat.FlatNode;
28 import IR.Flat.FlatOpNode;
29 import IR.Flat.FlatSetElementNode;
30 import IR.Flat.FlatSetFieldNode;
31 import IR.Flat.TempDescriptor;
32 import IR.Tree.Modifiers;
33
34 public class DefinitelyWrittenCheck {
35
36   SSJavaAnalysis ssjava;
37   State state;
38   CallGraph callGraph;
39
40   int debugcount = 0;
41
42   // maps a descriptor to its known dependents: namely
43   // methods or tasks that call the descriptor's method
44   // AND are part of this analysis (reachable from main)
45   private Hashtable<Descriptor, Set<MethodDescriptor>> mapDescriptorToSetDependents;
46
47   // maps a flat node to its WrittenSet: this keeps all heap path overwritten
48   // previously.
49   private Hashtable<FlatNode, Set<NTuple<Descriptor>>> mapFlatNodeToMustWriteSet;
50
51   // maps a temp descriptor to its heap path
52   // each temp descriptor has a unique heap path since we do not allow any
53   // alias.
54   private Hashtable<Descriptor, NTuple<Descriptor>> mapHeapPath;
55
56   // maps a temp descriptor to its composite location
57   private Hashtable<TempDescriptor, NTuple<Location>> mapDescriptorToLocationPath;
58
59   // maps a flat method to the READ that is the set of heap path that is
60   // expected to be written before method invocation
61   private Hashtable<FlatMethod, Set<NTuple<Descriptor>>> mapFlatMethodToReadSet;
62
63   // maps a flat method to the must-write set that is the set of heap path that
64   // is overwritten on every possible path during method invocation
65   private Hashtable<FlatMethod, Set<NTuple<Descriptor>>> mapFlatMethodToMustWriteSet;
66
67   // maps a flat method to the DELETE SET that is a set of heap path to shared
68   // locations that are
69   // written to but not overwritten by the higher value
70   private Hashtable<FlatMethod, SharedLocMap> mapFlatMethodToDeleteSet;
71
72   // maps a flat method to the S SET that is a set of heap path to shared
73   // locations that are overwritten by the higher value
74   private Hashtable<FlatMethod, SharedLocMap> mapFlatMethodToSharedLocMap;
75
76   // maps a flat method to the may-wirte set that is the set of heap path that
77   // might be written to
78   private Hashtable<FlatMethod, Set<NTuple<Descriptor>>> mapFlatMethodToMayWriteSet;
79
80   // maps a call site to the read set contributed by all callees
81   private Hashtable<FlatNode, Set<NTuple<Descriptor>>> mapFlatNodeToBoundReadSet;
82
83   // maps a call site to the must write set contributed by all callees
84   private Hashtable<FlatNode, Set<NTuple<Descriptor>>> mapFlatNodeToBoundMustWriteSet;
85
86   // maps a call site to the may read set contributed by all callees
87   private Hashtable<FlatNode, Set<NTuple<Descriptor>>> mapFlatNodeToBoundMayWriteSet;
88
89   // points to method containing SSJAVA Loop
90   private MethodDescriptor methodContainingSSJavaLoop;
91
92   // maps a flatnode to definitely written analysis mapping M
93   private Hashtable<FlatNode, Hashtable<NTuple<Descriptor>, Set<WriteAge>>> mapFlatNodetoEventLoopMap;
94
95   // maps shared location to the set of descriptors which belong to the shared
96   // location
97
98   // keep current descriptors to visit in fixed-point interprocedural analysis,
99   private Stack<MethodDescriptor> methodDescriptorsToVisitStack;
100
101   // when analyzing flatcall, need to re-schedule set of callee
102   private Set<MethodDescriptor> calleesToEnqueue;
103
104   private Set<ReadSummary> possibleCalleeReadSummarySetToCaller;
105
106   public static final String arrayElementFieldName = "___element_";
107   static protected Hashtable<TypeDescriptor, FieldDescriptor> mapTypeToArrayField;
108
109   // maps a method descriptor to the merged incoming caller's current
110   // reading status
111   // it is for setting clearance flag when all read set is overwritten
112   private Hashtable<MethodDescriptor, ReadSummary> mapMethodDescriptorToReadSummary;
113
114   private Hashtable<MethodDescriptor, MultiSourceMap<NTuple<Location>, NTuple<Descriptor>>> mapMethodToSharedLocCoverSet;
115
116   private Hashtable<FlatNode, SharedLocMap> mapFlatNodeToSharedLocMapping;
117   private Hashtable<FlatNode, SharedLocMap> mapFlatNodeToDeleteSet;
118
119   private Hashtable<Location, Set<Descriptor>> mapSharedLocationToCoverSet;
120
121   private LinkedList<MethodDescriptor> sortedDescriptors;
122
123   private LoopFinder ssjavaLoop;
124   private Set<FlatNode> loopIncElements;
125
126   private Set<NTuple<Descriptor>> calleeUnionBoundReadSet;
127   private Set<NTuple<Descriptor>> calleeIntersectBoundMustWriteSet;
128   private Set<NTuple<Descriptor>> calleeUnionBoundMayWriteSet;
129   private SharedLocMap calleeUnionBoundDeleteSet;
130   private SharedLocMap calleeIntersectBoundSharedSet;
131
132   private Hashtable<Descriptor, Location> mapDescToLocation;
133
134   private TempDescriptor LOCAL;
135
136   public static int MAXAGE = 1;
137
138   public DefinitelyWrittenCheck(SSJavaAnalysis ssjava, State state) {
139     this.state = state;
140     this.ssjava = ssjava;
141     this.callGraph = ssjava.getCallGraph();
142     this.mapFlatNodeToMustWriteSet = new Hashtable<FlatNode, Set<NTuple<Descriptor>>>();
143     this.mapDescriptorToSetDependents = new Hashtable<Descriptor, Set<MethodDescriptor>>();
144     this.mapHeapPath = new Hashtable<Descriptor, NTuple<Descriptor>>();
145     this.mapDescriptorToLocationPath = new Hashtable<TempDescriptor, NTuple<Location>>();
146     this.mapFlatMethodToReadSet = new Hashtable<FlatMethod, Set<NTuple<Descriptor>>>();
147     this.mapFlatMethodToMustWriteSet = new Hashtable<FlatMethod, Set<NTuple<Descriptor>>>();
148     this.mapFlatMethodToMayWriteSet = new Hashtable<FlatMethod, Set<NTuple<Descriptor>>>();
149     this.mapFlatNodetoEventLoopMap =
150         new Hashtable<FlatNode, Hashtable<NTuple<Descriptor>, Set<WriteAge>>>();
151     this.calleeUnionBoundReadSet = new HashSet<NTuple<Descriptor>>();
152     this.calleeIntersectBoundMustWriteSet = new HashSet<NTuple<Descriptor>>();
153     this.calleeUnionBoundMayWriteSet = new HashSet<NTuple<Descriptor>>();
154
155     this.methodDescriptorsToVisitStack = new Stack<MethodDescriptor>();
156     this.calleesToEnqueue = new HashSet<MethodDescriptor>();
157     this.mapTypeToArrayField = new Hashtable<TypeDescriptor, FieldDescriptor>();
158     this.LOCAL = new TempDescriptor("LOCAL");
159     this.mapDescToLocation = new Hashtable<Descriptor, Location>();
160     this.possibleCalleeReadSummarySetToCaller = new HashSet<ReadSummary>();
161     this.mapMethodDescriptorToReadSummary = new Hashtable<MethodDescriptor, ReadSummary>();
162     this.mapFlatNodeToBoundReadSet = new Hashtable<FlatNode, Set<NTuple<Descriptor>>>();
163     this.mapFlatNodeToBoundMustWriteSet = new Hashtable<FlatNode, Set<NTuple<Descriptor>>>();
164     this.mapFlatNodeToBoundMayWriteSet = new Hashtable<FlatNode, Set<NTuple<Descriptor>>>();
165     this.mapSharedLocationToCoverSet = new Hashtable<Location, Set<Descriptor>>();
166     this.mapFlatNodeToSharedLocMapping = new Hashtable<FlatNode, SharedLocMap>();
167     this.mapFlatMethodToDeleteSet = new Hashtable<FlatMethod, SharedLocMap>();
168     this.calleeUnionBoundDeleteSet = new SharedLocMap();
169     this.calleeIntersectBoundSharedSet = new SharedLocMap();
170     this.mapFlatMethodToSharedLocMap = new Hashtable<FlatMethod, SharedLocMap>();
171     this.mapMethodToSharedLocCoverSet =
172         new Hashtable<MethodDescriptor, MultiSourceMap<NTuple<Location>, NTuple<Descriptor>>>();
173     this.mapFlatNodeToDeleteSet = new Hashtable<FlatNode, SharedLocMap>();
174   }
175
176   public void definitelyWrittenCheck() {
177     if (!ssjava.getAnnotationRequireSet().isEmpty()) {
178       initialize();
179
180       methodReadWriteSetAnalysis();
181       computeSharedCoverSet();
182
183       sharedLocAnalysis();
184
185       eventLoopAnalysis();
186
187     }
188   }
189
190   private void sharedLocAnalysis() {
191
192     // perform method READ/OVERWRITE analysis
193     LinkedList<MethodDescriptor> descriptorListToAnalyze =
194         (LinkedList<MethodDescriptor>) sortedDescriptors.clone();
195
196     // current descriptors to visit in fixed-point interprocedural analysis,
197     // prioritized by
198     // dependency in the call graph
199     methodDescriptorsToVisitStack.clear();
200
201     descriptorListToAnalyze.removeFirst();
202
203     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
204     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
205
206     while (!descriptorListToAnalyze.isEmpty()) {
207       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
208       methodDescriptorsToVisitStack.add(md);
209     }
210
211     // analyze scheduled methods until there are no more to visit
212     while (!methodDescriptorsToVisitStack.isEmpty()) {
213       // start to analyze leaf node
214       MethodDescriptor md = methodDescriptorsToVisitStack.pop();
215       FlatMethod fm = state.getMethodFlat(md);
216
217       SharedLocMap sharedLocMap = new SharedLocMap();
218       SharedLocMap deleteSet = new SharedLocMap();
219
220       sharedLoc_analyzeMethod(fm, sharedLocMap, deleteSet);
221       SharedLocMap prevSharedLocMap = mapFlatMethodToSharedLocMap.get(fm);
222       SharedLocMap prevDeleteSet = mapFlatMethodToDeleteSet.get(fm);
223
224       if (!(deleteSet.equals(prevDeleteSet) && sharedLocMap.equals(prevSharedLocMap))) {
225         mapFlatMethodToSharedLocMap.put(fm, sharedLocMap);
226         mapFlatMethodToDeleteSet.put(fm, deleteSet);
227
228         // results for callee changed, so enqueue dependents caller for
229         // further
230         // analysis
231         Iterator<MethodDescriptor> depsItr = getDependents(md).iterator();
232         while (depsItr.hasNext()) {
233           MethodDescriptor methodNext = depsItr.next();
234           if (!methodDescriptorsToVisitStack.contains(methodNext)
235               && methodDescriptorToVistSet.contains(methodNext)) {
236             methodDescriptorsToVisitStack.add(methodNext);
237           }
238
239         }
240
241       }
242
243     }
244
245     sharedLoc_analyzeEventLoop();
246
247   }
248
249   private void sharedLoc_analyzeEventLoop() {
250     if (state.SSJAVADEBUG) {
251       System.out.println("SSJAVA: Definite clearance for shared locations Analyzing: eventloop");
252     }
253     SharedLocMap sharedLocMap = new SharedLocMap();
254     SharedLocMap deleteSet = new SharedLocMap();
255     sharedLoc_analyzeBody(state.getMethodFlat(methodContainingSSJavaLoop),
256         ssjava.getSSJavaLoopEntrance(), sharedLocMap, deleteSet, true);
257
258   }
259
260   private void sharedLoc_analyzeMethod(FlatMethod fm, SharedLocMap sharedLocMap,
261       SharedLocMap deleteSet) {
262     if (state.SSJAVADEBUG) {
263       System.out.println("SSJAVA: Definite clearance for shared locations Analyzing: " + fm);
264     }
265
266     sharedLoc_analyzeBody(fm, fm, sharedLocMap, deleteSet, false);
267
268   }
269
270   private void sharedLoc_analyzeBody(FlatMethod fm, FlatNode startNode, SharedLocMap sharedLocMap,
271       SharedLocMap deleteSet, boolean isEventLoopBody) {
272
273     // intraprocedural analysis
274     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
275     flatNodesToVisit.add(startNode);
276
277     while (!flatNodesToVisit.isEmpty()) {
278       FlatNode fn = flatNodesToVisit.iterator().next();
279       flatNodesToVisit.remove(fn);
280
281       SharedLocMap currSharedSet = new SharedLocMap();
282       SharedLocMap currDeleteSet = new SharedLocMap();
283
284       for (int i = 0; i < fn.numPrev(); i++) {
285         FlatNode prevFn = fn.getPrev(i);
286         SharedLocMap inSharedLoc = mapFlatNodeToSharedLocMapping.get(prevFn);
287         if (inSharedLoc != null) {
288           mergeSharedLocMap(currSharedSet, inSharedLoc);
289         }
290
291         SharedLocMap inDeleteLoc = mapFlatNodeToDeleteSet.get(prevFn);
292         if (inDeleteLoc != null) {
293           mergeDeleteSet(currDeleteSet, inDeleteLoc);
294         }
295       }
296
297       sharedLoc_nodeActions(fm, fn, currSharedSet, currDeleteSet, sharedLocMap, deleteSet,
298           isEventLoopBody);
299
300       SharedLocMap prevSharedSet = mapFlatNodeToSharedLocMapping.get(fn);
301       SharedLocMap prevDeleteSet = mapFlatNodeToDeleteSet.get(fn);
302
303       if (!(currSharedSet.equals(prevSharedSet) && currDeleteSet.equals(prevDeleteSet))) {
304         mapFlatNodeToSharedLocMapping.put(fn, currSharedSet);
305         mapFlatNodeToDeleteSet.put(fn, currDeleteSet);
306         for (int i = 0; i < fn.numNext(); i++) {
307           FlatNode nn = fn.getNext(i);
308           if ((!isEventLoopBody) || loopIncElements.contains(nn)) {
309             flatNodesToVisit.add(nn);
310           }
311
312         }
313       }
314
315     }
316
317   }
318
319   private void sharedLoc_nodeActions(FlatMethod fm, FlatNode fn, SharedLocMap curr,
320       SharedLocMap currDeleteSet, SharedLocMap sharedLocMap, SharedLocMap deleteSet,
321       boolean isEventLoopBody) {
322
323     MethodDescriptor md = fm.getMethod();
324
325     SharedLocMap killSet = new SharedLocMap();
326     SharedLocMap genSet = new SharedLocMap();
327
328     TempDescriptor lhs;
329     TempDescriptor rhs;
330     FieldDescriptor fld;
331
332     switch (fn.kind()) {
333
334     case FKind.FlatOpNode: {
335
336       if (isEventLoopBody) {
337         FlatOpNode fon = (FlatOpNode) fn;
338
339         if (fon.getOp().getOp() == Operation.ASSIGN) {
340           lhs = fon.getDest();
341           rhs = fon.getLeft();
342
343           if (!lhs.getSymbol().startsWith("neverused") && !lhs.getSymbol().startsWith("leftop")
344               && !lhs.getSymbol().startsWith("rightop") && rhs.getType().isImmutable()) {
345
346             Location dstLoc = getLocation(lhs);
347             if (dstLoc != null && ssjava.isSharedLocation(dstLoc)) {
348               NTuple<Descriptor> lhsHeapPath = computePath(lhs);
349               NTuple<Location> lhsLocTuple = mapDescriptorToLocationPath.get(lhs);
350
351               Location srcLoc = getLocation(lhs);
352
353               // computing gen/kill set
354               computeKILLSetForWrite(curr, killSet, lhsLocTuple, lhsHeapPath);
355               if (!dstLoc.equals(srcLoc)) {
356                 computeGENSetForHigherWrite(curr, killSet, lhsLocTuple, lhsHeapPath);
357                 updateDeleteSetForHigherWrite(currDeleteSet, lhsLocTuple, lhsHeapPath);
358               } else {
359                 computeGENSetForSameHeightWrite(curr, killSet, lhsLocTuple, lhsHeapPath);
360                 updateDeleteSetForSameHeightWrite(currDeleteSet, lhsLocTuple, lhsHeapPath);
361               }
362
363               // System.out.println("VAR WRITE:" + fn);
364               // System.out.println("lhsLocTuple=" + lhsLocTuple +
365               // " lhsHeapPath=" + lhsHeapPath);
366               // System.out.println("dstLoc=" + dstLoc + " srcLoc=" + srcLoc);
367               // System.out.println("KILLSET=" + killSet);
368               // System.out.println("GENSet=" + genSet);
369               // System.out.println("DELETESET=" + currDeleteSet);
370
371             }
372
373           }
374
375         }
376
377       }
378
379     }
380       break;
381
382     case FKind.FlatSetFieldNode:
383     case FKind.FlatSetElementNode: {
384
385       Location fieldLoc;
386       if (fn.kind() == FKind.FlatSetFieldNode) {
387         FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
388         lhs = fsfn.getDst();
389         fld = fsfn.getField();
390         rhs = fsfn.getSrc();
391         fieldLoc = (Location) fld.getType().getExtension();
392       } else {
393         FlatSetElementNode fsen = (FlatSetElementNode) fn;
394         lhs = fsen.getDst();
395         rhs = fsen.getSrc();
396         TypeDescriptor td = lhs.getType().dereference();
397         fld = getArrayField(td);
398
399         NTuple<Location> locTuple = deriveLocationTuple(md, lhs);
400         fieldLoc = locTuple.get(locTuple.size() - 1);
401         break;
402       }
403
404       if (!isEventLoopBody && fieldLoc.getDescriptor().equals(md)) {
405         // if the field belongs to the local lattice, no reason to calculate
406         // shared location
407         break;
408       }
409
410       NTuple<Location> fieldLocTuple = new NTuple<Location>();
411       if (fld.isStatic()) {
412         if (fld.isFinal()) {
413           // in this case, fld has TOP location
414           Location topLocation = Location.createTopLocation(md);
415           fieldLocTuple.add(topLocation);
416         } else {
417           fieldLocTuple.addAll(deriveGlobalLocationTuple(md));
418           if (fn.kind() == FKind.FlatSetFieldNode) {
419             fieldLocTuple.add((Location) fld.getType().getExtension());
420           }
421         }
422
423       } else {
424         fieldLocTuple.addAll(deriveLocationTuple(md, lhs));
425         if (fn.kind() == FKind.FlatSetFieldNode) {
426           fieldLocTuple.add((Location) fld.getType().getExtension());
427         }
428       }
429
430       // shared loc extension
431       Location srcLoc = getLocation(rhs);
432       if (ssjava.isSharedLocation(fieldLoc)) {
433         // only care the case that loc(f) is shared location
434         // write(field)
435
436         // NTuple<Location> fieldLocTuple = new NTuple<Location>();
437         // fieldLocTuple.addAll(mapDescriptorToLocationPath.get(lhs));
438         // fieldLocTuple.add(fieldLoc);
439
440         NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>();
441         fldHeapPath.addAll(computePath(lhs));
442         if (fn.kind() == FKind.FlatSetFieldNode) {
443           fldHeapPath.add(fld);
444         }
445
446         // computing gen/kill set
447         computeKILLSetForWrite(curr, killSet, fieldLocTuple, fldHeapPath);
448         if (!fieldLoc.equals(srcLoc)) {
449           computeGENSetForHigherWrite(curr, genSet, fieldLocTuple, fldHeapPath);
450           updateDeleteSetForHigherWrite(currDeleteSet, fieldLocTuple, fldHeapPath);
451         } else {
452           computeGENSetForSameHeightWrite(curr, genSet, fieldLocTuple, fldHeapPath);
453           updateDeleteSetForSameHeightWrite(currDeleteSet, fieldLocTuple, fldHeapPath);
454         }
455
456         // System.out.println("################");
457         // System.out.println("FIELD WRITE:" + fn);
458         // System.out.println("FldHeapPath=" + fldHeapPath);
459         // System.out.println("fieldLocTuple=" + fieldLocTuple + " srcLoc=" +
460         // srcLoc);
461         // System.out.println("KILLSET=" + killSet);
462         // System.out.println("GENSet=" + genSet);
463         // System.out.println("DELETESET=" + currDeleteSet);
464       }
465
466     }
467       break;
468
469     case FKind.FlatCall: {
470       FlatCall fc = (FlatCall) fn;
471
472       // if (ssjava.needTobeAnnotated(fc.getMethod())) {
473       // System.out.println("#FLATCALL=" + fc);
474
475       bindHeapPathCallerArgWithCaleeParamForSharedLoc(fm.getMethod(), fc);
476
477       // computing gen/kill set
478       generateKILLSetForFlatCall(curr, killSet);
479       generateGENSetForFlatCall(curr, genSet);
480
481       // }
482       // System.out.println("#FLATCALL=" + fc);
483       // System.out.println("KILLSET=" + killSet);
484       // System.out.println("GENSet=" + genSet);
485       // System.out.println("bound DELETE Set=" + calleeUnionBoundDeleteSet);
486
487     }
488       break;
489
490     case FKind.FlatExit: {
491       // merge the current delete/shared loc mapping
492       mergeSharedLocMap(sharedLocMap, curr);
493       mergeDeleteSet(deleteSet, currDeleteSet);
494
495       // System.out.println("#FLATEXIT sharedLocMap=" + sharedLocMap);
496     }
497       break;
498
499     }
500
501     computeNewMapping(curr, killSet, genSet);
502     if (!curr.map.isEmpty()) {
503       // System.out.println(fn + "#######" + curr);
504     }
505
506   }
507
508   private void generateGENSetForFlatCall(SharedLocMap curr, SharedLocMap genSet) {
509
510     Set<NTuple<Location>> locTupleSet = calleeIntersectBoundSharedSet.keySet();
511     for (Iterator iterator = locTupleSet.iterator(); iterator.hasNext();) {
512       NTuple<Location> locTupleKey = (NTuple<Location>) iterator.next();
513       genSet.addWrite(locTupleKey, curr.get(locTupleKey));
514       genSet.addWrite(locTupleKey, calleeIntersectBoundSharedSet.get(locTupleKey));
515
516       genSet.removeWriteAll(locTupleKey, calleeUnionBoundDeleteSet.get(locTupleKey));
517     }
518
519   }
520
521   private void generateKILLSetForFlatCall(SharedLocMap curr, SharedLocMap killSet) {
522
523     Set<NTuple<Location>> locTupleSet = calleeIntersectBoundSharedSet.keySet();
524     for (Iterator iterator = locTupleSet.iterator(); iterator.hasNext();) {
525       NTuple<Location> locTupleKey = (NTuple<Location>) iterator.next();
526       killSet.addWrite(locTupleKey, curr.get(locTupleKey));
527     }
528
529   }
530
531   private void mergeDeleteSet(SharedLocMap currDeleteSet, SharedLocMap inDeleteLoc) {
532
533     Set<NTuple<Location>> locTupleKeySet = inDeleteLoc.keySet();
534
535     for (Iterator iterator = locTupleKeySet.iterator(); iterator.hasNext();) {
536       NTuple<Location> locTupleKey = (NTuple<Location>) iterator.next();
537
538       Set<NTuple<Descriptor>> inSet = inDeleteLoc.get(locTupleKey);
539       currDeleteSet.addWrite(locTupleKey, inSet);
540
541     }
542   }
543
544   private void computeNewMapping(SharedLocMap curr, SharedLocMap killSet, SharedLocMap genSet) {
545     curr.kill(killSet);
546     curr.gen(genSet);
547   }
548
549   private void updateDeleteSetForHigherWrite(SharedLocMap currDeleteSet, NTuple<Location> locTuple,
550       NTuple<Descriptor> hp) {
551     currDeleteSet.removeWrite(locTuple, hp);
552   }
553
554   private void updateDeleteSetForSameHeightWrite(SharedLocMap currDeleteSet,
555       NTuple<Location> locTuple, NTuple<Descriptor> hp) {
556     currDeleteSet.addWrite(locTuple, hp);
557   }
558
559   private void computeGENSetForHigherWrite(SharedLocMap curr, SharedLocMap genSet,
560       NTuple<Location> locTuple, NTuple<Descriptor> hp) {
561     Set<NTuple<Descriptor>> currWriteSet = curr.get(locTuple);
562
563     if (currWriteSet != null) {
564       genSet.addWrite(locTuple, currWriteSet);
565     }
566
567     genSet.addWrite(locTuple, hp);
568   }
569
570   private void computeGENSetForSameHeightWrite(SharedLocMap curr, SharedLocMap genSet,
571       NTuple<Location> locTuple, NTuple<Descriptor> hp) {
572     Set<NTuple<Descriptor>> currWriteSet = curr.get(locTuple);
573
574     if (currWriteSet != null) {
575       genSet.addWrite(locTuple, currWriteSet);
576     }
577     genSet.removeWrite(locTuple, hp);
578   }
579
580   private void computeKILLSetForWrite(SharedLocMap curr, SharedLocMap killSet,
581       NTuple<Location> locTuple, NTuple<Descriptor> hp) {
582
583     Set<NTuple<Descriptor>> writeSet = curr.get(locTuple);
584     if (writeSet != null) {
585       killSet.addWrite(locTuple, writeSet);
586     }
587
588   }
589
590   private void mergeSharedLocMap(SharedLocMap currSharedSet, SharedLocMap in) {
591
592     Set<NTuple<Location>> locTupleKeySet = in.keySet();
593     for (Iterator iterator = locTupleKeySet.iterator(); iterator.hasNext();) {
594       NTuple<Location> locTupleKey = (NTuple<Location>) iterator.next();
595
596       Set<NTuple<Descriptor>> inSet = in.get(locTupleKey);
597       Set<NTuple<Descriptor>> currSet = currSharedSet.get(locTupleKey);
598       if (currSet == null) {
599         currSet = new HashSet<NTuple<Descriptor>>();
600         currSet.addAll(inSet);
601         currSharedSet.addWrite(locTupleKey, currSet);
602       }
603       currSet.retainAll(inSet);
604     }
605
606   }
607
608   private void computeSharedCoverSet() {
609     LinkedList<MethodDescriptor> descriptorListToAnalyze =
610         (LinkedList<MethodDescriptor>) sortedDescriptors.clone();
611
612     // current descriptors to visit in fixed-point interprocedural analysis,
613     // prioritized by
614     // dependency in the call graph
615     methodDescriptorsToVisitStack.clear();
616
617     descriptorListToAnalyze.removeFirst();
618
619     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
620     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
621
622     while (!descriptorListToAnalyze.isEmpty()) {
623       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
624       methodDescriptorsToVisitStack.add(md);
625     }
626
627     // analyze scheduled methods until there are no more to visit
628     while (!methodDescriptorsToVisitStack.isEmpty()) {
629       MethodDescriptor md = methodDescriptorsToVisitStack.pop();
630       FlatMethod fm = state.getMethodFlat(md);
631       computeSharedCoverSet_analyzeMethod(fm, md.equals(methodContainingSSJavaLoop));
632     }
633
634     computeSharedCoverSetForEventLoop();
635
636   }
637
638   private void computeSharedCoverSetForEventLoop() {
639     computeSharedCoverSet_analyzeMethod(state.getMethodFlat(methodContainingSSJavaLoop), true);
640   }
641
642   private void computeSharedCoverSet_analyzeMethod(FlatMethod fm, boolean onlyVisitSSJavaLoop) {
643
644     System.out.println("computeSharedCoverSet_analyzeMethod=" + fm);
645     MethodDescriptor md = fm.getMethod();
646
647     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
648
649     Set<FlatNode> visited = new HashSet<FlatNode>();
650
651     if (onlyVisitSSJavaLoop) {
652       flatNodesToVisit.add(ssjava.getSSJavaLoopEntrance());
653     } else {
654       flatNodesToVisit.add(fm);
655     }
656
657     while (!flatNodesToVisit.isEmpty()) {
658       FlatNode fn = flatNodesToVisit.iterator().next();
659       flatNodesToVisit.remove(fn);
660       visited.add(fn);
661
662       computeSharedCoverSet_nodeActions(md, fn, onlyVisitSSJavaLoop);
663
664       for (int i = 0; i < fn.numNext(); i++) {
665         FlatNode nn = fn.getNext(i);
666
667         if (!visited.contains(nn)) {
668           if (!onlyVisitSSJavaLoop || (onlyVisitSSJavaLoop && loopIncElements.contains(nn))) {
669             flatNodesToVisit.add(nn);
670           }
671         }
672
673       }
674
675     }
676
677   }
678
679   private void computeSharedCoverSet_nodeActions(MethodDescriptor md, FlatNode fn,
680       boolean isEventLoopBody) {
681     TempDescriptor lhs;
682     TempDescriptor rhs;
683     FieldDescriptor fld;
684
685     switch (fn.kind()) {
686
687     case FKind.FlatLiteralNode: {
688       FlatLiteralNode fln = (FlatLiteralNode) fn;
689       lhs = fln.getDst();
690
691       NTuple<Location> lhsLocTuple = new NTuple<Location>();
692       lhsLocTuple.add(Location.createTopLocation(md));
693       mapDescriptorToLocationPath.put(lhs, lhsLocTuple);
694
695       if (lhs.getType().isPrimitive() && !lhs.getSymbol().startsWith("neverused")
696           && !lhs.getSymbol().startsWith("srctmp")) {
697         // only need to care about composite location case here
698         if (lhs.getType().getExtension() instanceof SSJavaType) {
699           CompositeLocation compLoc = ((SSJavaType) lhs.getType().getExtension()).getCompLoc();
700           Location lastLocElement = compLoc.get(compLoc.getSize() - 1);
701           // check if the last one is shared loc
702           if (ssjava.isSharedLocation(lastLocElement)) {
703             addSharedLocDescriptor(lastLocElement, lhs);
704           }
705         }
706       }
707
708     }
709       break;
710
711     case FKind.FlatOpNode: {
712       FlatOpNode fon = (FlatOpNode) fn;
713       // for a normal assign node, need to propagate lhs's location path to
714       // rhs
715       if (fon.getOp().getOp() == Operation.ASSIGN) {
716         rhs = fon.getLeft();
717         lhs = fon.getDest();
718
719         if (!lhs.getSymbol().startsWith("neverused") && !lhs.getSymbol().startsWith("leftop")
720             && !lhs.getSymbol().startsWith("rightop")) {
721
722           NTuple<Location> rhsLocTuple = new NTuple<Location>();
723           NTuple<Location> lhsLocTuple = new NTuple<Location>();
724           if (mapDescriptorToLocationPath.containsKey(rhs)) {
725             mapDescriptorToLocationPath.put(lhs, deriveLocationTuple(md, rhs));
726           } else {
727             // rhs side
728             if (rhs.getType().getExtension() != null
729                 && rhs.getType().getExtension() instanceof SSJavaType) {
730
731               if (((SSJavaType) rhs.getType().getExtension()).getCompLoc() != null) {
732                 rhsLocTuple.addAll(((SSJavaType) rhs.getType().getExtension()).getCompLoc()
733                     .getTuple());
734               }
735
736             } else {
737               NTuple<Location> locTuple = deriveLocationTuple(md, rhs);
738               if (locTuple != null) {
739                 rhsLocTuple.addAll(locTuple);
740               }
741             }
742             if (rhsLocTuple.size() > 0) {
743               mapDescriptorToLocationPath.put(rhs, rhsLocTuple);
744             }
745
746             // lhs side
747             if (lhs.getType().getExtension() != null
748                 && lhs.getType().getExtension() instanceof SSJavaType) {
749               lhsLocTuple.addAll(((SSJavaType) lhs.getType().getExtension()).getCompLoc()
750                   .getTuple());
751               mapDescriptorToLocationPath.put(lhs, lhsLocTuple);
752             } else if (mapDescriptorToLocationPath.get(rhs) != null) {
753               // propagate rhs's location to lhs
754               lhsLocTuple.addAll(mapDescriptorToLocationPath.get(rhs));
755               mapDescriptorToLocationPath.put(lhs, lhsLocTuple);
756             }
757
758           }
759
760           if (lhs.getType().isPrimitive() && !lhs.getSymbol().startsWith("srctmp")) {
761
762             NTuple<Descriptor> lhsHeapPath = computePath(lhs);
763
764             if (lhsLocTuple != null) {
765               addMayWrittenSet(md, lhsLocTuple, lhsHeapPath);
766             }
767
768           }
769         }
770
771       }
772     }
773       break;
774
775     case FKind.FlatSetFieldNode:
776     case FKind.FlatSetElementNode: {
777
778       // x.f=y;
779
780       if (fn.kind() == FKind.FlatSetFieldNode) {
781         FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
782         lhs = fsfn.getDst();
783         fld = fsfn.getField();
784         rhs = fsfn.getSrc();
785       } else {
786         FlatSetElementNode fsen = (FlatSetElementNode) fn;
787         lhs = fsen.getDst();
788         rhs = fsen.getSrc();
789         TypeDescriptor td = lhs.getType().dereference();
790         fld = getArrayField(td);
791       }
792
793       Location fieldLocation;
794       if (fn.kind() == FKind.FlatSetFieldNode) {
795         fieldLocation = (Location) fld.getType().getExtension();
796       } else {
797         NTuple<Location> locTuple = mapDescriptorToLocationPath.get(lhs);
798         fieldLocation = locTuple.get(locTuple.size() - 1);
799       }
800
801       if (!isEventLoopBody && fieldLocation.getDescriptor().equals(md)) {
802         // if the field belongs to the local lattice, no reason to calculate
803         // shared location
804         break;
805       }
806
807       NTuple<Location> fieldLocTuple = new NTuple<Location>();
808       if (fld.isStatic()) {
809         if (fld.isFinal()) {
810           // in this case, fld has TOP location
811           Location topLocation = Location.createTopLocation(md);
812           fieldLocTuple.add(topLocation);
813         } else {
814           fieldLocTuple.addAll(deriveGlobalLocationTuple(md));
815           if (fn.kind() == FKind.FlatSetFieldNode) {
816             fieldLocTuple.add((Location) fld.getType().getExtension());
817           }
818         }
819
820       } else {
821         fieldLocTuple.addAll(deriveLocationTuple(md, lhs));
822         if (fn.kind() == FKind.FlatSetFieldNode) {
823           fieldLocTuple.add((Location) fld.getType().getExtension());
824         }
825       }
826
827       NTuple<Location> lTuple = deriveLocationTuple(md, lhs);
828       if (lTuple != null) {
829         NTuple<Location> lhsLocTuple = new NTuple<Location>();
830         lhsLocTuple.addAll(lTuple);
831         mapDescriptorToLocationPath.put(lhs, lhsLocTuple);
832       }
833
834       if (ssjava.isSharedLocation(fieldLocation)) {
835         addSharedLocDescriptor(fieldLocation, fld);
836
837         NTuple<Descriptor> fieldHeapPath = new NTuple<Descriptor>();
838         fieldHeapPath.addAll(computePath(lhs));
839         if (fn.kind() == FKind.FlatSetFieldNode) {
840           fieldHeapPath.add(fld);
841         }
842
843         // mapLocationPathToMayWrittenSet.put(locTuple, null, fld);
844         addMayWrittenSet(md, fieldLocTuple, fieldHeapPath);
845
846       }
847
848     }
849       break;
850
851     case FKind.FlatElementNode:
852     case FKind.FlatFieldNode: {
853
854       // x=y.f;
855
856       if (fn.kind() == FKind.FlatFieldNode) {
857         FlatFieldNode ffn = (FlatFieldNode) fn;
858         lhs = ffn.getDst();
859         rhs = ffn.getSrc();
860         fld = ffn.getField();
861       } else {
862         FlatElementNode fen = (FlatElementNode) fn;
863         lhs = fen.getDst();
864         rhs = fen.getSrc();
865         TypeDescriptor td = rhs.getType().dereference();
866         fld = getArrayField(td);
867       }
868
869       NTuple<Location> locTuple = new NTuple<Location>();
870
871       if (fld.isStatic()) {
872
873         if (fld.isFinal()) {
874           // in this case, fld has TOP location
875           Location topLocation = Location.createTopLocation(md);
876           locTuple.add(topLocation);
877         } else {
878           locTuple.addAll(deriveGlobalLocationTuple(md));
879           if (fn.kind() == FKind.FlatFieldNode) {
880             locTuple.add((Location) fld.getType().getExtension());
881           }
882         }
883
884       } else {
885         locTuple.addAll(deriveLocationTuple(md, rhs));
886         if (fn.kind() == FKind.FlatFieldNode) {
887           locTuple.add((Location) fld.getType().getExtension());
888         }
889       }
890
891       mapDescriptorToLocationPath.put(lhs, locTuple);
892
893     }
894       break;
895
896     case FKind.FlatCall: {
897
898       FlatCall fc = (FlatCall) fn;
899
900       // if (ssjava.needTobeAnnotated(fc.getMethod())) {
901       bindLocationPathCallerArgWithCalleeParam(md, fc);
902       // }
903
904     }
905       break;
906
907     case FKind.FlatNew: {
908
909       FlatNew fnew = (FlatNew) fn;
910       TempDescriptor dst = fnew.getDst();
911       NTuple<Location> locTuple = deriveLocationTuple(md, dst);
912
913       if (locTuple != null) {
914         NTuple<Location> dstLocTuple = new NTuple<Location>();
915         dstLocTuple.addAll(locTuple);
916         mapDescriptorToLocationPath.put(dst, dstLocTuple);
917       }
918
919     }
920       break;
921     }
922   }
923
924   private void addMayWrittenSet(MethodDescriptor md, NTuple<Location> locTuple,
925       NTuple<Descriptor> heapPath) {
926
927     MultiSourceMap<NTuple<Location>, NTuple<Descriptor>> map = mapMethodToSharedLocCoverSet.get(md);
928     if (map == null) {
929       map = new MultiSourceMap<NTuple<Location>, NTuple<Descriptor>>();
930       mapMethodToSharedLocCoverSet.put(md, map);
931     }
932
933     Set<NTuple<Descriptor>> writeSet = map.get(locTuple);
934     if (writeSet == null) {
935       writeSet = new HashSet<NTuple<Descriptor>>();
936       map.put(locTuple, writeSet);
937     }
938     writeSet.add(heapPath);
939
940   }
941
942   private void bindLocationPathCallerArgWithCalleeParam(MethodDescriptor mdCaller, FlatCall fc) {
943
944     if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) {
945       // ssjava util case!
946       // have write effects on the first argument
947       TempDescriptor arg = fc.getArg(0);
948       NTuple<Location> argLocationPath = deriveLocationTuple(mdCaller, arg);
949       NTuple<Descriptor> argHeapPath = computePath(arg);
950       addMayWrittenSet(mdCaller, argLocationPath, argHeapPath);
951     } else {
952
953       // if arg is not primitive type, we need to propagate maywritten set to
954       // the caller's location path
955
956       MethodDescriptor mdCallee = fc.getMethod();
957       Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
958       setPossibleCallees.addAll(callGraph.getMethods(mdCallee));
959
960       // create mapping from arg idx to its heap paths
961       Hashtable<Integer, NTuple<Descriptor>> mapArgIdx2CallerArgHeapPath =
962           new Hashtable<Integer, NTuple<Descriptor>>();
963
964       // create mapping from arg idx to its location paths
965       Hashtable<Integer, NTuple<Location>> mapArgIdx2CallerArgLocationPath =
966           new Hashtable<Integer, NTuple<Location>>();
967
968       // arg idx is starting from 'this' arg
969       if (fc.getThis() != null) {
970         // loc path for 'this'
971         NTuple<Location> thisLocationPath = deriveLocationTuple(mdCaller, fc.getThis());
972         if (thisLocationPath != null) {
973           mapArgIdx2CallerArgLocationPath.put(Integer.valueOf(0), thisLocationPath);
974
975           // heap path for 'this'
976           NTuple<Descriptor> thisHeapPath = new NTuple<Descriptor>();
977           if (mapHeapPath.containsKey(fc.getThis())) {
978             thisHeapPath.addAll(mapHeapPath.get(fc.getThis()));
979           } else {
980             // method is called without creating new flat node representing
981             // 'this'
982             thisHeapPath.add(fc.getThis());
983           }
984           mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath);
985         }
986
987       }
988
989       for (int i = 0; i < fc.numArgs(); i++) {
990         TempDescriptor arg = fc.getArg(i);
991         // create mapping arg to loc path
992         NTuple<Location> argLocationPath = deriveLocationTuple(mdCaller, arg);
993         if (argLocationPath != null) {
994           mapArgIdx2CallerArgLocationPath.put(Integer.valueOf(i + 1), argLocationPath);
995           // create mapping arg to heap path
996           NTuple<Descriptor> argHeapPath = computePath(arg);
997           mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath);
998         }
999
1000       }
1001
1002       Hashtable<Integer, Set<NTuple<Descriptor>>> mapParamIdx2WriteSet =
1003           new Hashtable<Integer, Set<NTuple<Descriptor>>>();
1004
1005       for (int i = 0; i < fc.numArgs() + 1; i++) {
1006         mapParamIdx2WriteSet.put(Integer.valueOf(i), new HashSet<NTuple<Descriptor>>());
1007       }
1008
1009       for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) {
1010         MethodDescriptor callee = (MethodDescriptor) iterator.next();
1011         FlatMethod calleeFlatMethod = state.getMethodFlat(callee);
1012
1013         // binding caller's args and callee's params
1014
1015         Hashtable<Integer, TempDescriptor> mapParamIdx2ParamTempDesc =
1016             new Hashtable<Integer, TempDescriptor>();
1017         int offset = 0;
1018         if (calleeFlatMethod.getMethod().isStatic()) {
1019           // static method does not have implicit 'this' arg
1020           offset = 1;
1021         }
1022         for (int i = 0; i < calleeFlatMethod.numParameters(); i++) {
1023           TempDescriptor param = calleeFlatMethod.getParameter(i);
1024           mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param);
1025         }
1026
1027         Set<Integer> keySet = mapArgIdx2CallerArgLocationPath.keySet();
1028         for (Iterator iterator2 = keySet.iterator(); iterator2.hasNext();) {
1029           Integer idx = (Integer) iterator2.next();
1030           NTuple<Location> callerArgLocationPath = mapArgIdx2CallerArgLocationPath.get(idx);
1031
1032           TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx);
1033
1034           NTuple<Descriptor> callerArgHeapPath = mapArgIdx2CallerArgHeapPath.get(idx);
1035           NTuple<Location> calleeLocationPath = deriveLocationTuple(mdCallee, calleeParam);
1036           NTuple<Descriptor> calleeHeapPath = computePath(calleeParam);
1037
1038           createNewMappingOfMayWrittenSet(mdCaller, callee, callerArgHeapPath,
1039               callerArgLocationPath, calleeHeapPath, calleeLocationPath,
1040               mapParamIdx2WriteSet.get(idx));
1041
1042         }
1043
1044       }
1045
1046     }
1047
1048   }
1049
1050   private Hashtable<NTuple<Location>, Set<NTuple<Descriptor>>> getMappingByStartedWith(
1051       MultiSourceMap<NTuple<Location>, NTuple<Descriptor>> map, NTuple<Location> in) {
1052
1053     Hashtable<NTuple<Location>, Set<NTuple<Descriptor>>> matchedMapping =
1054         new Hashtable<NTuple<Location>, Set<NTuple<Descriptor>>>();
1055
1056     Set<NTuple<Location>> keySet = map.keySet();
1057
1058     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
1059       NTuple<Location> key = (NTuple<Location>) iterator.next();
1060       if (key.startsWith(in)) {
1061         matchedMapping.put(key, map.get(key));
1062       }
1063     }
1064
1065     return matchedMapping;
1066
1067   }
1068
1069   private void createNewMappingOfMayWrittenSet(MethodDescriptor caller, MethodDescriptor callee,
1070       NTuple<Descriptor> callerArgHeapPath, NTuple<Location> callerArgLocPath,
1071       NTuple<Descriptor> calleeParamHeapPath, NTuple<Location> calleeParamLocPath,
1072       Set<NTuple<Descriptor>> writeSet) {
1073
1074     // propagate may-written-set associated with the key that is started with
1075     // calleepath to the caller
1076     // 1) makes a new key by combining caller path and callee path(except local
1077     // loc element of param)
1078     // 2) create new mapping of may-written-set of callee path to caller path
1079
1080     // extract all may written effect accessed through callee param path
1081     MultiSourceMap<NTuple<Location>, NTuple<Descriptor>> calleeMapping =
1082         mapMethodToSharedLocCoverSet.get(callee);
1083
1084     MultiSourceMap<NTuple<Location>, NTuple<Descriptor>> callerMapping =
1085         mapMethodToSharedLocCoverSet.get(caller);
1086
1087     if (callerMapping == null) {
1088       callerMapping = new MultiSourceMap<NTuple<Location>, NTuple<Descriptor>>();
1089       mapMethodToSharedLocCoverSet.put(caller, callerMapping);
1090     }
1091
1092     if (calleeMapping == null) {
1093       return;
1094     }
1095
1096     Hashtable<NTuple<Location>, Set<NTuple<Descriptor>>> paramMapping =
1097         getMappingByStartedWith(calleeMapping, calleeParamLocPath);
1098
1099     Set<NTuple<Location>> calleeKeySet = calleeMapping.keySet();
1100     for (Iterator iterator = calleeKeySet.iterator(); iterator.hasNext();) {
1101       NTuple<Location> calleeKey = (NTuple<Location>) iterator.next();
1102       Set<NTuple<Descriptor>> calleeMayWriteSet = paramMapping.get(calleeKey);
1103
1104       if (calleeMayWriteSet != null) {
1105
1106         Set<NTuple<Descriptor>> boundWriteSet =
1107             convertCallerMayWriteSet(callerArgHeapPath, calleeParamHeapPath, calleeMayWriteSet);
1108
1109         writeSet.addAll(boundWriteSet);
1110
1111         NTuple<Location> newKey = new NTuple<Location>();
1112         newKey.addAll(callerArgLocPath);
1113         // need to replace the local location with the caller's path so skip the
1114         // local location of the parameter
1115         for (int i = 1; i < calleeKey.size(); i++) {
1116           newKey.add(calleeKey.get(i));
1117         }
1118
1119         callerMapping.union(newKey, writeSet);
1120         // mapLocationPathToMayWrittenSet.put(calleeKey, newKey, writeSet);
1121       }
1122
1123     }
1124
1125   }
1126
1127   private Set<NTuple<Descriptor>> convertCallerMayWriteSet(NTuple<Descriptor> callerArgHeapPath,
1128       NTuple<Descriptor> calleeParamHeapPath, Set<NTuple<Descriptor>> calleeMayWriteSet) {
1129
1130     Set<NTuple<Descriptor>> boundSet = new HashSet<NTuple<Descriptor>>();
1131
1132     // replace callee's param path with caller's arg path
1133     for (Iterator iterator = calleeMayWriteSet.iterator(); iterator.hasNext();) {
1134       NTuple<Descriptor> calleeWriteHeapPath = (NTuple<Descriptor>) iterator.next();
1135
1136       NTuple<Descriptor> boundHeapPath = new NTuple<Descriptor>();
1137       boundHeapPath.addAll(callerArgHeapPath);
1138
1139       int startIdx = calleeParamHeapPath.size();
1140
1141       for (int i = startIdx; i < calleeWriteHeapPath.size(); i++) {
1142         boundHeapPath.add(calleeWriteHeapPath.get(i));
1143       }
1144
1145       boundSet.add(boundHeapPath);
1146
1147     }
1148
1149     return boundSet;
1150   }
1151
1152   private void addSharedLocDescriptor(Location sharedLoc, Descriptor desc) {
1153
1154     Set<Descriptor> descSet = mapSharedLocationToCoverSet.get(sharedLoc);
1155     if (descSet == null) {
1156       descSet = new HashSet<Descriptor>();
1157       mapSharedLocationToCoverSet.put(sharedLoc, descSet);
1158     }
1159
1160     descSet.add(desc);
1161
1162   }
1163
1164   private Location getLocation(Descriptor d) {
1165
1166     if (d instanceof FieldDescriptor) {
1167       TypeExtension te = ((FieldDescriptor) d).getType().getExtension();
1168       if (te != null) {
1169         return (Location) te;
1170       }
1171     } else {
1172       assert d instanceof TempDescriptor;
1173       TempDescriptor td = (TempDescriptor) d;
1174
1175       TypeExtension te = td.getType().getExtension();
1176       if (te != null) {
1177         if (te instanceof SSJavaType) {
1178           SSJavaType ssType = (SSJavaType) te;
1179           if (ssType.getCompLoc() != null) {
1180             CompositeLocation comp = ssType.getCompLoc();
1181             return comp.get(comp.getSize() - 1);
1182           } else {
1183             return null;
1184           }
1185         } else {
1186           return (Location) te;
1187         }
1188       }
1189     }
1190
1191     return mapDescToLocation.get(d);
1192   }
1193
1194   private void eventLoopAnalysis() {
1195     // perform second stage analysis: intraprocedural analysis ensure that
1196     // all
1197     // variables are definitely written in-between the same read
1198
1199     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
1200     flatNodesToVisit.add(ssjava.getSSJavaLoopEntrance());
1201
1202     while (!flatNodesToVisit.isEmpty()) {
1203       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
1204       flatNodesToVisit.remove(fn);
1205
1206       Hashtable<NTuple<Descriptor>, Set<WriteAge>> prev = mapFlatNodetoEventLoopMap.get(fn);
1207
1208       Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr =
1209           new Hashtable<NTuple<Descriptor>, Set<WriteAge>>();
1210       for (int i = 0; i < fn.numPrev(); i++) {
1211         FlatNode nn = fn.getPrev(i);
1212         Hashtable<NTuple<Descriptor>, Set<WriteAge>> in = mapFlatNodetoEventLoopMap.get(nn);
1213         if (in != null) {
1214           union(curr, in);
1215         }
1216       }
1217
1218       eventLoopAnalysis_nodeAction(fn, curr, ssjava.getSSJavaLoopEntrance());
1219
1220       // if a new result, schedule forward nodes for analysis
1221       if (!curr.equals(prev)) {
1222         mapFlatNodetoEventLoopMap.put(fn, curr);
1223
1224         for (int i = 0; i < fn.numNext(); i++) {
1225           FlatNode nn = fn.getNext(i);
1226           if (loopIncElements.contains(nn)) {
1227             flatNodesToVisit.add(nn);
1228           }
1229
1230         }
1231       }
1232     }
1233   }
1234
1235   private void union(Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr,
1236       Hashtable<NTuple<Descriptor>, Set<WriteAge>> in) {
1237
1238     Set<NTuple<Descriptor>> inKeySet = in.keySet();
1239     for (Iterator iterator = inKeySet.iterator(); iterator.hasNext();) {
1240       NTuple<Descriptor> inKey = (NTuple<Descriptor>) iterator.next();
1241       Set<WriteAge> inSet = in.get(inKey);
1242
1243       Set<WriteAge> currSet = curr.get(inKey);
1244
1245       if (currSet == null) {
1246         currSet = new HashSet<WriteAge>();
1247         curr.put(inKey, currSet);
1248       }
1249       currSet.addAll(inSet);
1250     }
1251
1252   }
1253
1254   private void eventLoopAnalysis_nodeAction(FlatNode fn,
1255       Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr, FlatNode loopEntrance) {
1256
1257     Hashtable<NTuple<Descriptor>, Set<WriteAge>> readWriteKillSet =
1258         new Hashtable<NTuple<Descriptor>, Set<WriteAge>>();
1259     Hashtable<NTuple<Descriptor>, Set<WriteAge>> readWriteGenSet =
1260         new Hashtable<NTuple<Descriptor>, Set<WriteAge>>();
1261
1262     if (fn.equals(loopEntrance)) {
1263       // it reaches loop entrance: changes all flag to true
1264       Set<NTuple<Descriptor>> keySet = curr.keySet();
1265       for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
1266         NTuple<Descriptor> key = (NTuple<Descriptor>) iterator.next();
1267         Set<WriteAge> writeAgeSet = curr.get(key);
1268
1269         Set<WriteAge> incSet = new HashSet<WriteAge>();
1270         incSet.addAll(writeAgeSet);
1271         writeAgeSet.clear();
1272
1273         for (Iterator iterator2 = incSet.iterator(); iterator2.hasNext();) {
1274           WriteAge writeAge = (WriteAge) iterator2.next();
1275           WriteAge newWriteAge = writeAge.copy();
1276           newWriteAge.inc();
1277           writeAgeSet.add(newWriteAge);
1278         }
1279
1280       }
1281
1282     } else {
1283       TempDescriptor lhs;
1284       TempDescriptor rhs;
1285       FieldDescriptor fld;
1286
1287       switch (fn.kind()) {
1288
1289       case FKind.FlatOpNode: {
1290         FlatOpNode fon = (FlatOpNode) fn;
1291         lhs = fon.getDest();
1292         rhs = fon.getLeft();
1293
1294         if (fon.getOp().getOp() == Operation.ASSIGN) {
1295
1296           if (!lhs.getSymbol().startsWith("neverused") && !lhs.getSymbol().startsWith("leftop")
1297               && !lhs.getSymbol().startsWith("rightop")) {
1298
1299             boolean hasWriteEffect = false;
1300             NTuple<Descriptor> rhsHeapPath = computePath(rhs);
1301
1302             if (rhs.getType().getExtension() instanceof SSJavaType
1303                 && lhs.getType().getExtension() instanceof SSJavaType) {
1304
1305               CompositeLocation rhsCompLoc =
1306                   ((SSJavaType) rhs.getType().getExtension()).getCompLoc();
1307
1308               CompositeLocation lhsCompLoc =
1309                   ((SSJavaType) lhs.getType().getExtension()).getCompLoc();
1310
1311               if (lhsCompLoc != rhsCompLoc) {
1312                 // have a write effect!
1313                 hasWriteEffect = true;
1314               }
1315
1316             } else if (lhs.getType().isImmutable()) {
1317               hasWriteEffect = true;
1318             }
1319
1320             if (hasWriteEffect) {
1321               // write(lhs)
1322               NTuple<Descriptor> lhsPath = new NTuple<Descriptor>();
1323               lhsPath.add(lhs);
1324               Location lhsLoc = getLocation(lhs);
1325               if (ssjava.isSharedLocation(lhsLoc)) {
1326
1327                 NTuple<Descriptor> varHeapPath = computePath(lhs);
1328                 NTuple<Location> varLocTuple = mapDescriptorToLocationPath.get(lhs);
1329
1330                 Set<NTuple<Descriptor>> writtenSet =
1331                     mapFlatNodeToSharedLocMapping.get(fn).get(varLocTuple);
1332
1333                 if (isCovered(varLocTuple, writtenSet)) {
1334                   computeKILLSetForSharedWrite(curr, writtenSet, readWriteKillSet);
1335                   computeGENSetForSharedAllCoverWrite(curr, writtenSet, readWriteGenSet);
1336                 } else {
1337                   computeGENSetForSharedNonCoverWrite(curr, varHeapPath, readWriteGenSet);
1338                 }
1339
1340               } else {
1341
1342                 computeKILLSetForWrite(curr, lhsPath, readWriteKillSet);
1343                 computeGENSetForWrite(lhsPath, readWriteGenSet);
1344               }
1345
1346               // System.out.println("#KILLSET=" + readWriteKillSet);
1347               // System.out.println("#GENSet=" + readWriteGenSet + "\n");
1348
1349               Set<WriteAge> writeAgeSet = curr.get(lhsPath);
1350               checkWriteAgeSet(writeAgeSet, lhsPath, fn);
1351             }
1352
1353           }
1354
1355         }
1356
1357       }
1358         break;
1359
1360       case FKind.FlatFieldNode:
1361       case FKind.FlatElementNode: {
1362
1363         if (fn.kind() == FKind.FlatFieldNode) {
1364           FlatFieldNode ffn = (FlatFieldNode) fn;
1365           lhs = ffn.getDst();
1366           rhs = ffn.getSrc();
1367           fld = ffn.getField();
1368         } else {
1369           FlatElementNode fen = (FlatElementNode) fn;
1370           lhs = fen.getDst();
1371           rhs = fen.getSrc();
1372           TypeDescriptor td = rhs.getType().dereference();
1373           fld = getArrayField(td);
1374         }
1375
1376         // read field
1377         NTuple<Descriptor> srcHeapPath = mapHeapPath.get(rhs);
1378         NTuple<Descriptor> fldHeapPath;
1379         if (srcHeapPath != null) {
1380           fldHeapPath = new NTuple<Descriptor>(srcHeapPath.getList());
1381         } else {
1382           // if srcHeapPath is null, it is static reference
1383           fldHeapPath = new NTuple<Descriptor>();
1384           fldHeapPath.add(rhs);
1385         }
1386         fldHeapPath.add(fld);
1387
1388         Set<WriteAge> writeAgeSet = curr.get(fldHeapPath);
1389
1390         checkWriteAgeSet(writeAgeSet, fldHeapPath, fn);
1391
1392       }
1393         break;
1394
1395       case FKind.FlatSetFieldNode:
1396       case FKind.FlatSetElementNode: {
1397
1398         if (fn.kind() == FKind.FlatSetFieldNode) {
1399           FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
1400           lhs = fsfn.getDst();
1401           fld = fsfn.getField();
1402         } else {
1403           FlatSetElementNode fsen = (FlatSetElementNode) fn;
1404           lhs = fsen.getDst();
1405           rhs = fsen.getSrc();
1406           TypeDescriptor td = lhs.getType().dereference();
1407           fld = getArrayField(td);
1408         }
1409
1410         // System.out.println("FIELD WRITE:" + fn);
1411
1412         // write(field)
1413         NTuple<Descriptor> lhsHeapPath = computePath(lhs);
1414         NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>(lhsHeapPath.getList());
1415         if (fn.kind() == FKind.FlatSetFieldNode) {
1416           fldHeapPath.add(fld);
1417         }
1418
1419         // shared loc extension
1420         Location fieldLoc = (Location) fld.getType().getExtension();
1421         if (ssjava.isSharedLocation(fieldLoc)) {
1422
1423           NTuple<Location> fieldLocTuple = new NTuple<Location>();
1424           fieldLocTuple.addAll(mapDescriptorToLocationPath.get(lhs));
1425           if (fn.kind() == FKind.FlatSetFieldNode) {
1426             fieldLocTuple.add(fieldLoc);
1427           }
1428
1429           Set<NTuple<Descriptor>> writtenSet =
1430               mapFlatNodeToSharedLocMapping.get(fn).get(fieldLocTuple);
1431
1432           if (isCovered(fieldLocTuple, writtenSet)) {
1433             computeKILLSetForSharedWrite(curr, writtenSet, readWriteKillSet);
1434             computeGENSetForSharedAllCoverWrite(curr, writtenSet, readWriteGenSet);
1435           } else {
1436             computeGENSetForSharedNonCoverWrite(curr, fldHeapPath, readWriteGenSet);
1437           }
1438
1439         } else {
1440           computeKILLSetForWrite(curr, fldHeapPath, readWriteKillSet);
1441           computeGENSetForWrite(fldHeapPath, readWriteGenSet);
1442         }
1443
1444         // System.out.println("KILLSET=" + readWriteKillSet);
1445         // System.out.println("GENSet=" + readWriteGenSet);
1446
1447       }
1448         break;
1449
1450       case FKind.FlatCall: {
1451         FlatCall fc = (FlatCall) fn;
1452
1453         SharedLocMap sharedLocMap = mapFlatNodeToSharedLocMapping.get(fc);
1454         // System.out.println("FLATCALL:" + fn);
1455         generateKILLSetForFlatCall(fc, curr, sharedLocMap, readWriteKillSet);
1456         generateGENSetForFlatCall(fc, sharedLocMap, readWriteGenSet);
1457
1458         // System.out.println("KILLSET=" + readWriteKillSet);
1459         // System.out.println("GENSet=" + readWriteGenSet);
1460
1461         checkManyRead(fc, curr);
1462       }
1463         break;
1464
1465       }
1466
1467       computeNewMapping(curr, readWriteKillSet, readWriteGenSet);
1468       // System.out.println("#######" + curr);
1469
1470     }
1471
1472   }
1473
1474   private void computeGENSetForSharedNonCoverWrite(
1475       Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr, NTuple<Descriptor> heapPath,
1476       Hashtable<NTuple<Descriptor>, Set<WriteAge>> genSet) {
1477
1478     Set<WriteAge> writeAgeSet = genSet.get(heapPath);
1479     if (writeAgeSet == null) {
1480       writeAgeSet = new HashSet<WriteAge>();
1481       genSet.put(heapPath, writeAgeSet);
1482     }
1483
1484     writeAgeSet.add(new WriteAge(1));
1485
1486   }
1487
1488   private void computeGENSetForSharedAllCoverWrite(
1489       Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr, Set<NTuple<Descriptor>> writtenSet,
1490       Hashtable<NTuple<Descriptor>, Set<WriteAge>> genSet) {
1491
1492     for (Iterator iterator = writtenSet.iterator(); iterator.hasNext();) {
1493       NTuple<Descriptor> writeHeapPath = (NTuple<Descriptor>) iterator.next();
1494
1495       Set<WriteAge> writeAgeSet = new HashSet<WriteAge>();
1496       writeAgeSet.add(new WriteAge(0));
1497
1498       genSet.put(writeHeapPath, writeAgeSet);
1499     }
1500
1501   }
1502
1503   private void computeKILLSetForSharedWrite(Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr,
1504       Set<NTuple<Descriptor>> writtenSet, Hashtable<NTuple<Descriptor>, Set<WriteAge>> killSet) {
1505
1506     for (Iterator iterator = writtenSet.iterator(); iterator.hasNext();) {
1507       NTuple<Descriptor> writeHeapPath = (NTuple<Descriptor>) iterator.next();
1508       Set<WriteAge> writeSet = curr.get(writeHeapPath);
1509       if (writeSet != null) {
1510         killSet.put(writeHeapPath, writeSet);
1511       }
1512     }
1513
1514   }
1515
1516   private boolean isCovered(NTuple<Location> locTuple, Set<NTuple<Descriptor>> inSet) {
1517
1518     if (inSet == null) {
1519       return false;
1520     }
1521
1522     Set<NTuple<Descriptor>> coverSet =
1523         mapMethodToSharedLocCoverSet.get(methodContainingSSJavaLoop).get(locTuple);
1524
1525     return inSet.containsAll(coverSet);
1526   }
1527
1528   private void checkManyRead(FlatCall fc, Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr) {
1529
1530     Set<NTuple<Descriptor>> boundReadSet = mapFlatNodeToBoundReadSet.get(fc);
1531
1532     for (Iterator iterator = boundReadSet.iterator(); iterator.hasNext();) {
1533       NTuple<Descriptor> readHeapPath = (NTuple<Descriptor>) iterator.next();
1534       Set<WriteAge> writeAgeSet = curr.get(readHeapPath);
1535       checkWriteAgeSet(writeAgeSet, readHeapPath, fc);
1536     }
1537
1538   }
1539
1540   private void checkWriteAgeSet(Set<WriteAge> writeAgeSet, NTuple<Descriptor> path, FlatNode fn) {
1541
1542     // System.out.println("# CHECK WRITE AGE of " + path + " from set=" +
1543     // writeAgeSet);
1544
1545     if (writeAgeSet != null) {
1546       for (Iterator iterator = writeAgeSet.iterator(); iterator.hasNext();) {
1547         WriteAge writeAge = (WriteAge) iterator.next();
1548         if (writeAge.getAge() > MAXAGE) {
1549           generateErrorMessage(path, fn);
1550         }
1551       }
1552     }
1553   }
1554
1555   private void generateErrorMessage(NTuple<Descriptor> path, FlatNode fn) {
1556
1557     Descriptor lastDesc = path.get(getArrayBaseDescriptorIdx(path));
1558     if (ssjava.isSharedLocation(getLocation(lastDesc))) {
1559
1560       NTuple<Location> locPathTuple = getLocationTuple(path);
1561       Set<NTuple<Descriptor>> coverSet =
1562           mapMethodToSharedLocCoverSet.get(methodContainingSSJavaLoop).get(locPathTuple);
1563       throw new Error("Shared memory locations, which is reachable through references " + path
1564           + ", are not completely overwritten by the higher values at "
1565           + methodContainingSSJavaLoop.getClassDesc().getSourceFileName() + "::" + fn.getNumLine()
1566           + ".\nThe following memory locations belong to the same shared locations:" + coverSet);
1567
1568     } else {
1569       throw new Error(
1570           "Memory location, which is reachable through references "
1571               + path
1572               + ", who comes back to the same read statement without being overwritten at the out-most iteration at "
1573               + methodContainingSSJavaLoop.getClassDesc().getSourceFileName() + "::"
1574               + fn.getNumLine());
1575     }
1576
1577   }
1578
1579   private void generateGENSetForFlatCall(FlatCall fc, SharedLocMap sharedLocMap,
1580       Hashtable<NTuple<Descriptor>, Set<WriteAge>> GENSet) {
1581
1582     Set<NTuple<Descriptor>> boundMayWriteSet = mapFlatNodeToBoundMayWriteSet.get(fc);
1583     // System.out.println("boundMayWriteSet=" + boundMayWriteSet);
1584
1585     for (Iterator iterator = boundMayWriteSet.iterator(); iterator.hasNext();) {
1586       NTuple<Descriptor> heapPath = (NTuple<Descriptor>) iterator.next();
1587
1588       if (!isSharedLocation(heapPath)) {
1589         addWriteAgeToSet(heapPath, GENSet, new WriteAge(0));
1590       } else {
1591         // if the current heap path is shared location
1592
1593         NTuple<Location> locTuple = getLocationTuple(heapPath);
1594
1595         Set<NTuple<Descriptor>> sharedWriteHeapPathSet = sharedLocMap.get(locTuple);
1596
1597         if (isCovered(locTuple, sharedLocMap.get(locTuple))) {
1598           // if it is covered, add all of heap paths belong to the same shared
1599           // loc with write age 0
1600
1601           for (Iterator iterator2 = sharedWriteHeapPathSet.iterator(); iterator2.hasNext();) {
1602             NTuple<Descriptor> sharedHeapPath = (NTuple<Descriptor>) iterator2.next();
1603             addWriteAgeToSet(sharedHeapPath, GENSet, new WriteAge(0));
1604           }
1605
1606         } else {
1607           // if not covered, add write age 1 to the heap path that is
1608           // may-written but not covered
1609           addWriteAgeToSet(heapPath, GENSet, new WriteAge(1));
1610         }
1611
1612       }
1613
1614     }
1615
1616   }
1617
1618   private void addWriteAgeToSet(NTuple<Descriptor> heapPath,
1619       Hashtable<NTuple<Descriptor>, Set<WriteAge>> map, WriteAge age) {
1620
1621     Set<WriteAge> currSet = map.get(heapPath);
1622     if (currSet == null) {
1623       currSet = new HashSet<WriteAge>();
1624       map.put(heapPath, currSet);
1625     }
1626
1627     currSet.add(age);
1628   }
1629
1630   private void generateKILLSetForFlatCall(FlatCall fc,
1631       Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr, SharedLocMap sharedLocMap,
1632       Hashtable<NTuple<Descriptor>, Set<WriteAge>> KILLSet) {
1633
1634     Set<NTuple<Descriptor>> boundMustWriteSet = mapFlatNodeToBoundMustWriteSet.get(fc);
1635     // System.out.println("boundMustWriteSet=" + boundMustWriteSet);
1636
1637     for (Iterator iterator = boundMustWriteSet.iterator(); iterator.hasNext();) {
1638       NTuple<Descriptor> heapPath = (NTuple<Descriptor>) iterator.next();
1639
1640       if (isSharedLocation(heapPath)) {
1641         NTuple<Location> locTuple = getLocationTuple(heapPath);
1642
1643         if (isCovered(locTuple, sharedLocMap.get(locTuple))) {
1644           // if it is shared loc and corresponding shared loc has been covered
1645           KILLSet.put(heapPath, curr.get(heapPath));
1646         }
1647       } else {
1648
1649         for (Enumeration<NTuple<Descriptor>> e = curr.keys(); e.hasMoreElements();) {
1650           NTuple<Descriptor> key = e.nextElement();
1651           if (key.startsWith(heapPath)) {
1652             KILLSet.put(key, curr.get(key));
1653           }
1654         }
1655
1656       }
1657
1658     }
1659
1660   }
1661
1662   private int getArrayBaseDescriptorIdx(NTuple<Descriptor> heapPath) {
1663
1664     for (int i = heapPath.size() - 1; i > 1; i--) {
1665       if (!heapPath.get(i).getSymbol().equals(arrayElementFieldName)) {
1666         return i;
1667       }
1668     }
1669
1670     return -1;
1671
1672   }
1673
1674   private boolean isSharedLocation(NTuple<Descriptor> heapPath) {
1675
1676     Descriptor d = heapPath.get(heapPath.size() - 1);
1677
1678     if (d instanceof FieldDescriptor) {
1679
1680       return ssjava
1681           .isSharedLocation(getLocation(heapPath.get(getArrayBaseDescriptorIdx(heapPath))));
1682
1683     } else {
1684       return ssjava.isSharedLocation(getLocation(heapPath.get(heapPath.size() - 1)));
1685     }
1686   }
1687
1688   private NTuple<Location> getLocationTuple(NTuple<Descriptor> heapPath) {
1689
1690     NTuple<Location> locTuple = new NTuple<Location>();
1691
1692     locTuple.addAll(mapDescriptorToLocationPath.get(heapPath.get(0)));
1693
1694     for (int i = 1; i <= getArrayBaseDescriptorIdx(heapPath); i++) {
1695       locTuple.add(getLocation(heapPath.get(i)));
1696     }
1697
1698     return locTuple;
1699   }
1700
1701   private void computeNewMapping(Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr,
1702       Hashtable<NTuple<Descriptor>, Set<WriteAge>> KILLSet,
1703       Hashtable<NTuple<Descriptor>, Set<WriteAge>> GENSet) {
1704
1705     for (Enumeration<NTuple<Descriptor>> e = KILLSet.keys(); e.hasMoreElements();) {
1706       NTuple<Descriptor> key = e.nextElement();
1707
1708       Set<WriteAge> writeAgeSet = curr.get(key);
1709       if (writeAgeSet == null) {
1710         writeAgeSet = new HashSet<WriteAge>();
1711         curr.put(key, writeAgeSet);
1712       }
1713       writeAgeSet.removeAll(KILLSet.get(key));
1714     }
1715
1716     for (Enumeration<NTuple<Descriptor>> e = GENSet.keys(); e.hasMoreElements();) {
1717       NTuple<Descriptor> key = e.nextElement();
1718
1719       Set<WriteAge> currWriteAgeSet = curr.get(key);
1720       if (currWriteAgeSet == null) {
1721         currWriteAgeSet = new HashSet<WriteAge>();
1722         curr.put(key, currWriteAgeSet);
1723       }
1724       currWriteAgeSet.addAll(GENSet.get(key));
1725     }
1726
1727   }
1728
1729   private void computeGENSetForWrite(NTuple<Descriptor> fldHeapPath,
1730       Hashtable<NTuple<Descriptor>, Set<WriteAge>> GENSet) {
1731
1732     // generate write age 0 for the field being written to
1733     Set<WriteAge> writeAgeSet = new HashSet<WriteAge>();
1734     writeAgeSet.add(new WriteAge(0));
1735     GENSet.put(fldHeapPath, writeAgeSet);
1736
1737   }
1738
1739   private void computeKILLSetForWrite(Hashtable<NTuple<Descriptor>, Set<WriteAge>> curr,
1740       NTuple<Descriptor> hp, Hashtable<NTuple<Descriptor>, Set<WriteAge>> KILLSet) {
1741
1742     // removes all of heap path that starts with prefix 'hp'
1743     // since any reference overwrite along heap path gives overwriting side
1744     // effects on the value
1745
1746     Set<NTuple<Descriptor>> keySet = curr.keySet();
1747     for (Iterator<NTuple<Descriptor>> iter = keySet.iterator(); iter.hasNext();) {
1748       NTuple<Descriptor> key = iter.next();
1749       if (key.startsWith(hp)) {
1750         KILLSet.put(key, curr.get(key));
1751       }
1752     }
1753
1754   }
1755
1756   private void bindHeapPathCallerArgWithCalleeParam(FlatCall fc) {
1757     // compute all possible callee set
1758     // transform all READ/WRITE set from the any possible
1759     // callees to the caller
1760     calleeUnionBoundReadSet.clear();
1761     calleeIntersectBoundMustWriteSet.clear();
1762     calleeUnionBoundMayWriteSet.clear();
1763
1764     if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) {
1765       // ssjava util case!
1766       // have write effects on the first argument
1767       TempDescriptor arg = fc.getArg(0);
1768       NTuple<Descriptor> argHeapPath = computePath(arg);
1769       calleeIntersectBoundMustWriteSet.add(argHeapPath);
1770       calleeUnionBoundMayWriteSet.add(argHeapPath);
1771     } else {
1772       MethodDescriptor mdCallee = fc.getMethod();
1773       Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
1774       setPossibleCallees.addAll(callGraph.getMethods(mdCallee));
1775
1776       // create mapping from arg idx to its heap paths
1777       Hashtable<Integer, NTuple<Descriptor>> mapArgIdx2CallerArgHeapPath =
1778           new Hashtable<Integer, NTuple<Descriptor>>();
1779
1780       // arg idx is starting from 'this' arg
1781       if (fc.getThis() != null) {
1782         NTuple<Descriptor> thisHeapPath = mapHeapPath.get(fc.getThis());
1783         if (thisHeapPath == null) {
1784           // method is called without creating new flat node representing 'this'
1785           thisHeapPath = new NTuple<Descriptor>();
1786           thisHeapPath.add(fc.getThis());
1787         }
1788
1789         mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath);
1790       }
1791
1792       for (int i = 0; i < fc.numArgs(); i++) {
1793         TempDescriptor arg = fc.getArg(i);
1794         NTuple<Descriptor> argHeapPath = computePath(arg);
1795         mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath);
1796       }
1797
1798       for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) {
1799         MethodDescriptor callee = (MethodDescriptor) iterator.next();
1800         FlatMethod calleeFlatMethod = state.getMethodFlat(callee);
1801
1802         // binding caller's args and callee's params
1803
1804         Set<NTuple<Descriptor>> calleeReadSet = mapFlatMethodToReadSet.get(calleeFlatMethod);
1805         if (calleeReadSet == null) {
1806           calleeReadSet = new HashSet<NTuple<Descriptor>>();
1807           mapFlatMethodToReadSet.put(calleeFlatMethod, calleeReadSet);
1808         }
1809
1810         Set<NTuple<Descriptor>> calleeMustWriteSet =
1811             mapFlatMethodToMustWriteSet.get(calleeFlatMethod);
1812
1813         if (calleeMustWriteSet == null) {
1814           calleeMustWriteSet = new HashSet<NTuple<Descriptor>>();
1815           mapFlatMethodToMustWriteSet.put(calleeFlatMethod, calleeMustWriteSet);
1816         }
1817
1818         Set<NTuple<Descriptor>> calleeMayWriteSet =
1819             mapFlatMethodToMayWriteSet.get(calleeFlatMethod);
1820
1821         if (calleeMayWriteSet == null) {
1822           calleeMayWriteSet = new HashSet<NTuple<Descriptor>>();
1823           mapFlatMethodToMayWriteSet.put(calleeFlatMethod, calleeMayWriteSet);
1824         }
1825
1826         Hashtable<Integer, TempDescriptor> mapParamIdx2ParamTempDesc =
1827             new Hashtable<Integer, TempDescriptor>();
1828         int offset = 0;
1829         if (calleeFlatMethod.getMethod().isStatic()) {
1830           // static method does not have implicit 'this' arg
1831           offset = 1;
1832         }
1833         for (int i = 0; i < calleeFlatMethod.numParameters(); i++) {
1834           TempDescriptor param = calleeFlatMethod.getParameter(i);
1835           mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param);
1836         }
1837
1838         Set<NTuple<Descriptor>> calleeBoundReadSet =
1839             bindSet(calleeReadSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath);
1840         // union of the current read set and the current callee's
1841         // read set
1842         calleeUnionBoundReadSet.addAll(calleeBoundReadSet);
1843
1844         Set<NTuple<Descriptor>> calleeBoundMustWriteSet =
1845             bindSet(calleeMustWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath);
1846         // intersection of the current overwrite set and the current
1847         // callee's
1848         // overwrite set
1849         merge(calleeIntersectBoundMustWriteSet, calleeBoundMustWriteSet);
1850
1851         Set<NTuple<Descriptor>> boundWriteSetFromCallee =
1852             bindSet(calleeMayWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath);
1853         calleeUnionBoundMayWriteSet.addAll(boundWriteSetFromCallee);
1854       }
1855
1856     }
1857
1858   }
1859
1860   private void bindHeapPathCallerArgWithCaleeParamForSharedLoc(MethodDescriptor mdCaller,
1861       FlatCall fc) {
1862
1863     calleeIntersectBoundSharedSet.clear();
1864     calleeUnionBoundDeleteSet.clear();
1865
1866     if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) {
1867       // ssjava util case!
1868       // have write effects on the first argument
1869       TempDescriptor arg = fc.getArg(0);
1870       NTuple<Descriptor> argHeapPath = computePath(arg);
1871
1872       // convert heap path to location path
1873       NTuple<Location> argLocTuple = new NTuple<Location>();
1874       argLocTuple.addAll(deriveLocationTuple(mdCaller, (TempDescriptor) argHeapPath.get(0)));
1875       for (int i = 1; i < argHeapPath.size(); i++) {
1876         argLocTuple.add(getLocation(argHeapPath.get(i)));
1877       }
1878
1879       calleeIntersectBoundSharedSet.addWrite(argLocTuple, argHeapPath);
1880
1881     } else {
1882
1883       // if arg is not primitive type, we need to propagate maywritten set to
1884       // the caller's location path
1885
1886       MethodDescriptor mdCallee = fc.getMethod();
1887       Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
1888       setPossibleCallees.addAll(callGraph.getMethods(mdCallee));
1889
1890       // create mapping from arg idx to its heap paths
1891       Hashtable<Integer, NTuple<Descriptor>> mapArgIdx2CallerArgHeapPath =
1892           new Hashtable<Integer, NTuple<Descriptor>>();
1893
1894       // arg idx is starting from 'this' arg
1895       if (fc.getThis() != null) {
1896         NTuple<Descriptor> thisHeapPath = mapHeapPath.get(fc.getThis());
1897         if (thisHeapPath == null) {
1898           // method is called without creating new flat node representing 'this'
1899           thisHeapPath = new NTuple<Descriptor>();
1900           thisHeapPath.add(fc.getThis());
1901         }
1902
1903         mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath);
1904       }
1905
1906       for (int i = 0; i < fc.numArgs(); i++) {
1907         TempDescriptor arg = fc.getArg(i);
1908         NTuple<Descriptor> argHeapPath = computePath(arg);
1909         mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath);
1910       }
1911
1912       // create mapping from arg idx to its location paths
1913       Hashtable<Integer, NTuple<Location>> mapArgIdx2CallerAgLocationPath =
1914           new Hashtable<Integer, NTuple<Location>>();
1915
1916       // arg idx is starting from 'this' arg
1917       if (fc.getThis() != null) {
1918         NTuple<Location> thisLocationPath = deriveLocationTuple(mdCaller, fc.getThis());
1919         if (thisLocationPath != null) {
1920           mapArgIdx2CallerAgLocationPath.put(Integer.valueOf(0), thisLocationPath);
1921         }
1922       }
1923
1924       for (int i = 0; i < fc.numArgs(); i++) {
1925         TempDescriptor arg = fc.getArg(i);
1926         NTuple<Location> argLocationPath = deriveLocationTuple(mdCaller, arg);
1927         if (argLocationPath != null) {
1928           mapArgIdx2CallerAgLocationPath.put(Integer.valueOf(i + 1), argLocationPath);
1929         }
1930       }
1931
1932       for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) {
1933         MethodDescriptor callee = (MethodDescriptor) iterator.next();
1934         FlatMethod calleeFlatMethod = state.getMethodFlat(callee);
1935
1936         // binding caller's args and callee's params
1937
1938         Hashtable<Integer, TempDescriptor> mapParamIdx2ParamTempDesc =
1939             new Hashtable<Integer, TempDescriptor>();
1940         int offset = 0;
1941         if (calleeFlatMethod.getMethod().isStatic()) {
1942           // static method does not have implicit 'this' arg
1943           offset = 1;
1944         }
1945         for (int i = 0; i < calleeFlatMethod.numParameters(); i++) {
1946           TempDescriptor param = calleeFlatMethod.getParameter(i);
1947           mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param);
1948         }
1949
1950         Set<Integer> keySet = mapArgIdx2CallerAgLocationPath.keySet();
1951         for (Iterator iterator2 = keySet.iterator(); iterator2.hasNext();) {
1952           Integer idx = (Integer) iterator2.next();
1953           NTuple<Location> callerArgLocationPath = mapArgIdx2CallerAgLocationPath.get(idx);
1954           NTuple<Descriptor> callerArgHeapPath = mapArgIdx2CallerArgHeapPath.get(idx);
1955
1956           TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx);
1957           NTuple<Location> calleeLocationPath = deriveLocationTuple(mdCallee, calleeParam);
1958           SharedLocMap calleeDeleteSet = mapFlatMethodToDeleteSet.get(calleeFlatMethod);
1959           SharedLocMap calleeSharedLocMap = mapFlatMethodToSharedLocMap.get(calleeFlatMethod);
1960
1961           if (calleeDeleteSet != null) {
1962             createNewMappingOfDeleteSet(callerArgLocationPath, callerArgHeapPath,
1963                 calleeLocationPath, calleeDeleteSet);
1964           }
1965
1966           if (calleeSharedLocMap != null) {
1967             createNewMappingOfSharedSet(callerArgLocationPath, callerArgHeapPath,
1968                 calleeLocationPath, calleeSharedLocMap);
1969           }
1970
1971         }
1972
1973       }
1974     }
1975
1976   }
1977
1978   private void createNewMappingOfDeleteSet(NTuple<Location> callerArgLocationPath,
1979       NTuple<Descriptor> callerArgHeapPath, NTuple<Location> calleeLocationPath,
1980       SharedLocMap calleeDeleteSet) {
1981
1982     SharedLocMap calleeParamDeleteSet = calleeDeleteSet.getHeapPathStartedWith(calleeLocationPath);
1983
1984     Set<NTuple<Location>> keySet = calleeParamDeleteSet.keySet();
1985     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
1986       NTuple<Location> calleeLocTupleKey = (NTuple<Location>) iterator.next();
1987       Set<NTuple<Descriptor>> heapPathSet = calleeParamDeleteSet.get(calleeLocTupleKey);
1988       for (Iterator iterator2 = heapPathSet.iterator(); iterator2.hasNext();) {
1989         NTuple<Descriptor> calleeHeapPath = (NTuple<Descriptor>) iterator2.next();
1990         calleeUnionBoundDeleteSet.addWrite(
1991             bindLocationPath(callerArgLocationPath, calleeLocTupleKey),
1992             bindHeapPath(callerArgHeapPath, calleeHeapPath));
1993       }
1994     }
1995
1996   }
1997
1998   private void createNewMappingOfSharedSet(NTuple<Location> callerArgLocationPath,
1999       NTuple<Descriptor> callerArgHeapPath, NTuple<Location> calleeLocationPath,
2000       SharedLocMap calleeSharedLocMap) {
2001
2002     SharedLocMap calleeParamSharedSet =
2003         calleeSharedLocMap.getHeapPathStartedWith(calleeLocationPath);
2004
2005     Set<NTuple<Location>> keySet = calleeParamSharedSet.keySet();
2006     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
2007       NTuple<Location> calleeLocTupleKey = (NTuple<Location>) iterator.next();
2008       Set<NTuple<Descriptor>> heapPathSet = calleeParamSharedSet.get(calleeLocTupleKey);
2009       Set<NTuple<Descriptor>> boundHeapPathSet = new HashSet<NTuple<Descriptor>>();
2010       for (Iterator iterator2 = heapPathSet.iterator(); iterator2.hasNext();) {
2011         NTuple<Descriptor> calleeHeapPath = (NTuple<Descriptor>) iterator2.next();
2012         boundHeapPathSet.add(bindHeapPath(callerArgHeapPath, calleeHeapPath));
2013       }
2014       calleeIntersectBoundSharedSet.intersect(
2015           bindLocationPath(callerArgLocationPath, calleeLocTupleKey), boundHeapPathSet);
2016     }
2017
2018   }
2019
2020   private NTuple<Location> bindLocationPath(NTuple<Location> start, NTuple<Location> end) {
2021     NTuple<Location> locPath = new NTuple<Location>();
2022     locPath.addAll(start);
2023     for (int i = 1; i < end.size(); i++) {
2024       locPath.add(end.get(i));
2025     }
2026     return locPath;
2027   }
2028
2029   private NTuple<Descriptor> bindHeapPath(NTuple<Descriptor> start, NTuple<Descriptor> end) {
2030     NTuple<Descriptor> heapPath = new NTuple<Descriptor>();
2031     heapPath.addAll(start);
2032     for (int i = 1; i < end.size(); i++) {
2033       heapPath.add(end.get(i));
2034     }
2035     return heapPath;
2036   }
2037
2038   private void initialize() {
2039     // First, identify ssjava loop entrace
2040
2041     // no need to analyze method having ssjava loop
2042     methodContainingSSJavaLoop = ssjava.getMethodContainingSSJavaLoop();
2043
2044     FlatMethod fm = state.getMethodFlat(methodContainingSSJavaLoop);
2045     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
2046     flatNodesToVisit.add(fm);
2047
2048     LoopFinder loopFinder = new LoopFinder(fm);
2049
2050     while (!flatNodesToVisit.isEmpty()) {
2051       FlatNode fn = flatNodesToVisit.iterator().next();
2052       flatNodesToVisit.remove(fn);
2053
2054       String label = (String) state.fn2labelMap.get(fn);
2055       if (label != null) {
2056
2057         if (label.equals(ssjava.SSJAVA)) {
2058           ssjava.setSSJavaLoopEntrance(fn);
2059           break;
2060         }
2061       }
2062
2063       for (int i = 0; i < fn.numNext(); i++) {
2064         FlatNode nn = fn.getNext(i);
2065         flatNodesToVisit.add(nn);
2066       }
2067     }
2068
2069     assert ssjava.getSSJavaLoopEntrance() != null;
2070
2071     // assume that ssjava loop is top-level loop in method, not nested loop
2072     Set nestedLoop = loopFinder.nestedLoops();
2073     for (Iterator loopIter = nestedLoop.iterator(); loopIter.hasNext();) {
2074       LoopFinder lf = (LoopFinder) loopIter.next();
2075       if (lf.loopEntrances().iterator().next().equals(ssjava.getSSJavaLoopEntrance())) {
2076         ssjavaLoop = lf;
2077       }
2078     }
2079
2080     assert ssjavaLoop != null;
2081
2082     loopIncElements = (Set<FlatNode>) ssjavaLoop.loopIncElements();
2083
2084     // perform topological sort over the set of methods accessed by the main
2085     // event loop
2086     Set<MethodDescriptor> methodDescriptorsToAnalyze = new HashSet<MethodDescriptor>();
2087     methodDescriptorsToAnalyze.addAll(ssjava.getAnnotationRequireSet());
2088     sortedDescriptors = topologicalSort(methodDescriptorsToAnalyze);
2089   }
2090
2091   private void methodReadWriteSetAnalysis() {
2092     // perform method READ/OVERWRITE analysis
2093     LinkedList<MethodDescriptor> descriptorListToAnalyze =
2094         (LinkedList<MethodDescriptor>) sortedDescriptors.clone();
2095
2096     // current descriptors to visit in fixed-point interprocedural analysis,
2097     // prioritized by
2098     // dependency in the call graph
2099     methodDescriptorsToVisitStack.clear();
2100
2101     descriptorListToAnalyze.removeFirst();
2102
2103     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
2104     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
2105
2106     while (!descriptorListToAnalyze.isEmpty()) {
2107       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
2108       methodDescriptorsToVisitStack.add(md);
2109     }
2110
2111     // analyze scheduled methods until there are no more to visit
2112     while (!methodDescriptorsToVisitStack.isEmpty()) {
2113       // start to analyze leaf node
2114       MethodDescriptor md = methodDescriptorsToVisitStack.pop();
2115       FlatMethod fm = state.getMethodFlat(md);
2116
2117       Set<NTuple<Descriptor>> readSet = new HashSet<NTuple<Descriptor>>();
2118       Set<NTuple<Descriptor>> mustWriteSet = new HashSet<NTuple<Descriptor>>();
2119       Set<NTuple<Descriptor>> mayWriteSet = new HashSet<NTuple<Descriptor>>();
2120
2121       methodReadWriteSet_analyzeMethod(fm, readSet, mustWriteSet, mayWriteSet);
2122
2123       Set<NTuple<Descriptor>> prevRead = mapFlatMethodToReadSet.get(fm);
2124       Set<NTuple<Descriptor>> prevMustWrite = mapFlatMethodToMustWriteSet.get(fm);
2125       Set<NTuple<Descriptor>> prevMayWrite = mapFlatMethodToMayWriteSet.get(fm);
2126
2127       if (!(readSet.equals(prevRead) && mustWriteSet.equals(prevMustWrite) && mayWriteSet
2128           .equals(prevMayWrite))) {
2129         mapFlatMethodToReadSet.put(fm, readSet);
2130         mapFlatMethodToMustWriteSet.put(fm, mustWriteSet);
2131         mapFlatMethodToMayWriteSet.put(fm, mayWriteSet);
2132
2133         // results for callee changed, so enqueue dependents caller for
2134         // further
2135         // analysis
2136         Iterator<MethodDescriptor> depsItr = getDependents(md).iterator();
2137         while (depsItr.hasNext()) {
2138           MethodDescriptor methodNext = depsItr.next();
2139           if (!methodDescriptorsToVisitStack.contains(methodNext)
2140               && methodDescriptorToVistSet.contains(methodNext)) {
2141             methodDescriptorsToVisitStack.add(methodNext);
2142           }
2143
2144         }
2145
2146       }
2147
2148     }
2149
2150     methodReadWriteSetAnalysisToEventLoopBody();
2151
2152   }
2153
2154   private void methodReadWriteSet_analyzeMethod(FlatMethod fm, Set<NTuple<Descriptor>> readSet,
2155       Set<NTuple<Descriptor>> mustWriteSet, Set<NTuple<Descriptor>> mayWriteSet) {
2156     if (state.SSJAVADEBUG) {
2157       System.out.println("SSJAVA: Definitely written Analyzing: " + fm);
2158     }
2159
2160     methodReadWriteSet_analyzeBody(fm, readSet, mustWriteSet, mayWriteSet, false);
2161
2162   }
2163
2164   private void methodReadWriteSetAnalysisToEventLoopBody() {
2165
2166     // perform method read/write analysis for Event Loop Body
2167
2168     FlatMethod flatMethodContainingSSJavaLoop = state.getMethodFlat(methodContainingSSJavaLoop);
2169
2170     if (state.SSJAVADEBUG) {
2171       System.out.println("SSJAVA: Definitely written Event Loop Analyzing: "
2172           + flatMethodContainingSSJavaLoop);
2173     }
2174
2175     Set<NTuple<Descriptor>> readSet = new HashSet<NTuple<Descriptor>>();
2176     Set<NTuple<Descriptor>> mustWriteSet = new HashSet<NTuple<Descriptor>>();
2177     Set<NTuple<Descriptor>> mayWriteSet = new HashSet<NTuple<Descriptor>>();
2178
2179     mapFlatMethodToReadSet.put(flatMethodContainingSSJavaLoop, readSet);
2180     mapFlatMethodToMustWriteSet.put(flatMethodContainingSSJavaLoop, mustWriteSet);
2181     mapFlatMethodToMayWriteSet.put(flatMethodContainingSSJavaLoop, mayWriteSet);
2182
2183     methodReadWriteSet_analyzeBody(ssjava.getSSJavaLoopEntrance(), readSet, mustWriteSet,
2184         mayWriteSet, true);
2185
2186   }
2187
2188   private void methodReadWriteSet_analyzeBody(FlatNode startNode, Set<NTuple<Descriptor>> readSet,
2189       Set<NTuple<Descriptor>> mustWriteSet, Set<NTuple<Descriptor>> mayWriteSet,
2190       boolean isEventLoopBody) {
2191
2192     // intraprocedural analysis
2193     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
2194     flatNodesToVisit.add(startNode);
2195
2196     while (!flatNodesToVisit.isEmpty()) {
2197       FlatNode fn = flatNodesToVisit.iterator().next();
2198       flatNodesToVisit.remove(fn);
2199
2200       Set<NTuple<Descriptor>> currMustWriteSet = new HashSet<NTuple<Descriptor>>();
2201
2202       for (int i = 0; i < fn.numPrev(); i++) {
2203         FlatNode prevFn = fn.getPrev(i);
2204         Set<NTuple<Descriptor>> in = mapFlatNodeToMustWriteSet.get(prevFn);
2205         if (in != null) {
2206           merge(currMustWriteSet, in);
2207         }
2208       }
2209
2210       methodReadWriteSet_nodeActions(fn, currMustWriteSet, readSet, mustWriteSet, mayWriteSet,
2211           isEventLoopBody);
2212
2213       Set<NTuple<Descriptor>> mustSetPrev = mapFlatNodeToMustWriteSet.get(fn);
2214
2215       if (!currMustWriteSet.equals(mustSetPrev)) {
2216         mapFlatNodeToMustWriteSet.put(fn, currMustWriteSet);
2217         for (int i = 0; i < fn.numNext(); i++) {
2218           FlatNode nn = fn.getNext(i);
2219           if ((!isEventLoopBody) || loopIncElements.contains(nn)) {
2220             flatNodesToVisit.add(nn);
2221           }
2222
2223         }
2224       }
2225
2226     }
2227
2228   }
2229
2230   private void methodReadWriteSet_nodeActions(FlatNode fn,
2231       Set<NTuple<Descriptor>> currMustWriteSet, Set<NTuple<Descriptor>> readSet,
2232       Set<NTuple<Descriptor>> mustWriteSet, Set<NTuple<Descriptor>> mayWriteSet,
2233       boolean isEventLoopBody) {
2234
2235     TempDescriptor lhs;
2236     TempDescriptor rhs;
2237     FieldDescriptor fld;
2238
2239     switch (fn.kind()) {
2240     case FKind.FlatMethod: {
2241
2242       // set up initial heap paths for method parameters
2243       FlatMethod fm = (FlatMethod) fn;
2244       for (int i = 0; i < fm.numParameters(); i++) {
2245         TempDescriptor param = fm.getParameter(i);
2246         NTuple<Descriptor> heapPath = new NTuple<Descriptor>();
2247         heapPath.add(param);
2248         mapHeapPath.put(param, heapPath);
2249       }
2250     }
2251       break;
2252
2253     case FKind.FlatOpNode: {
2254       FlatOpNode fon = (FlatOpNode) fn;
2255       // for a normal assign node, need to propagate lhs's heap path to
2256       // rhs
2257
2258       if (fon.getOp().getOp() == Operation.ASSIGN) {
2259         rhs = fon.getLeft();
2260         lhs = fon.getDest();
2261
2262         NTuple<Descriptor> rhsHeapPath = mapHeapPath.get(rhs);
2263
2264         if (lhs.getType().isPrimitive()) {
2265           NTuple<Descriptor> lhsHeapPath = new NTuple<Descriptor>();
2266           lhsHeapPath.add(lhs);
2267           mapHeapPath.put(lhs, lhsHeapPath);
2268         } else if (rhsHeapPath != null) {
2269           mapHeapPath.put(lhs, mapHeapPath.get(rhs));
2270         } else {
2271           NTuple<Descriptor> heapPath = new NTuple<Descriptor>();
2272           heapPath.add(rhs);
2273           mapHeapPath.put(lhs, heapPath);
2274         }
2275
2276         // shared loc extension
2277         if (isEventLoopBody) {
2278           if (!lhs.getSymbol().startsWith("neverused") && rhs.getType().isImmutable()) {
2279
2280             if (rhs.getType().getExtension() instanceof Location
2281                 && lhs.getType().getExtension() instanceof CompositeLocation) {
2282               // rhs is field!
2283               Location rhsLoc = (Location) rhs.getType().getExtension();
2284
2285               CompositeLocation lhsCompLoc = (CompositeLocation) lhs.getType().getExtension();
2286               Location dstLoc = lhsCompLoc.get(lhsCompLoc.getSize() - 1);
2287
2288               NTuple<Descriptor> heapPath = new NTuple<Descriptor>();
2289               for (int i = 0; i < rhsHeapPath.size() - 1; i++) {
2290                 heapPath.add(rhsHeapPath.get(i));
2291               }
2292
2293               NTuple<Descriptor> writeHeapPath = new NTuple<Descriptor>();
2294               writeHeapPath.addAll(heapPath);
2295               writeHeapPath.add(lhs);
2296
2297             }
2298           }
2299         }
2300
2301       }
2302     }
2303       break;
2304
2305     case FKind.FlatElementNode:
2306     case FKind.FlatFieldNode: {
2307
2308       // x=y.f;
2309
2310       if (fn.kind() == FKind.FlatFieldNode) {
2311         FlatFieldNode ffn = (FlatFieldNode) fn;
2312         lhs = ffn.getDst();
2313         rhs = ffn.getSrc();
2314         fld = ffn.getField();
2315       } else {
2316         FlatElementNode fen = (FlatElementNode) fn;
2317         lhs = fen.getDst();
2318         rhs = fen.getSrc();
2319         TypeDescriptor td = rhs.getType().dereference();
2320         fld = getArrayField(td);
2321       }
2322
2323       if (fld.isFinal()) {
2324         // if field is final no need to check
2325         break;
2326       }
2327
2328       // set up heap path
2329       NTuple<Descriptor> srcHeapPath = mapHeapPath.get(rhs);
2330       if (srcHeapPath != null) {
2331         // if lhs srcHeapPath is null, it means that it is not reachable from
2332         // callee's parameters. so just ignore it
2333
2334         NTuple<Descriptor> readingHeapPath = new NTuple<Descriptor>(srcHeapPath.getList());
2335         if (fn.kind() == FKind.FlatFieldNode) {
2336           readingHeapPath.add(fld);
2337         }
2338
2339         mapHeapPath.put(lhs, readingHeapPath);
2340
2341         // read (x.f)
2342         if (fld.getType().isImmutable()) {
2343           // if WT doesnot have hp(x.f), add hp(x.f) to READ
2344           if (!currMustWriteSet.contains(readingHeapPath)) {
2345             readSet.add(readingHeapPath);
2346           }
2347         }
2348
2349         // no need to kill hp(x.f) from WT
2350       }
2351
2352     }
2353       break;
2354
2355     case FKind.FlatSetFieldNode:
2356     case FKind.FlatSetElementNode: {
2357
2358       // x.f=y;
2359
2360       if (fn.kind() == FKind.FlatSetFieldNode) {
2361         FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
2362         lhs = fsfn.getDst();
2363         fld = fsfn.getField();
2364         rhs = fsfn.getSrc();
2365       } else {
2366         FlatSetElementNode fsen = (FlatSetElementNode) fn;
2367         lhs = fsen.getDst();
2368         rhs = fsen.getSrc();
2369         TypeDescriptor td = lhs.getType().dereference();
2370         fld = getArrayField(td);
2371       }
2372
2373       // set up heap path
2374       NTuple<Descriptor> lhsHeapPath = mapHeapPath.get(lhs);
2375
2376       if (lhsHeapPath != null) {
2377         // if lhs heap path is null, it means that it is not reachable from
2378         // callee's parameters. so just ignore it
2379         NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>(lhsHeapPath.getList());
2380         if (fn.kind() != FKind.FlatSetElementNode) {
2381           fldHeapPath.add(fld);
2382         }
2383         // mapHeapPath.put(fld, fldHeapPath);
2384
2385         // write(x.f)
2386         // need to add hp(y) to WT
2387         if (fn.kind() != FKind.FlatSetElementNode) {
2388           currMustWriteSet.add(fldHeapPath);
2389         }
2390         mayWriteSet.add(fldHeapPath);
2391
2392       }
2393
2394     }
2395       break;
2396
2397     case FKind.FlatCall: {
2398
2399       FlatCall fc = (FlatCall) fn;
2400
2401       bindHeapPathCallerArgWithCalleeParam(fc);
2402
2403       Set<NTuple<Descriptor>> boundReadSet = new HashSet<NTuple<Descriptor>>();
2404       boundReadSet.addAll(calleeUnionBoundReadSet);
2405
2406       Set<NTuple<Descriptor>> boundMustWriteSet = new HashSet<NTuple<Descriptor>>();
2407       boundMustWriteSet.addAll(calleeIntersectBoundMustWriteSet);
2408
2409       Set<NTuple<Descriptor>> boundMayWriteSet = new HashSet<NTuple<Descriptor>>();
2410       boundMayWriteSet.addAll(calleeUnionBoundMayWriteSet);
2411
2412       mapFlatNodeToBoundReadSet.put(fn, boundReadSet);
2413       mapFlatNodeToBoundMustWriteSet.put(fn, boundMustWriteSet);
2414       mapFlatNodeToBoundMayWriteSet.put(fn, boundMayWriteSet);
2415
2416       // add heap path, which is an element of READ_bound set and is not
2417       // an
2418       // element of WT set, to the caller's READ set
2419       for (Iterator iterator = calleeUnionBoundReadSet.iterator(); iterator.hasNext();) {
2420         NTuple<Descriptor> read = (NTuple<Descriptor>) iterator.next();
2421         if (!currMustWriteSet.contains(read)) {
2422           readSet.add(read);
2423         }
2424       }
2425
2426       // add heap path, which is an element of OVERWRITE_bound set, to the
2427       // caller's WT set
2428       for (Iterator iterator = calleeIntersectBoundMustWriteSet.iterator(); iterator.hasNext();) {
2429         NTuple<Descriptor> write = (NTuple<Descriptor>) iterator.next();
2430         currMustWriteSet.add(write);
2431       }
2432
2433       // add heap path, which is an element of WRITE_BOUND set, to the
2434       // caller's writeSet
2435       for (Iterator iterator = calleeUnionBoundMayWriteSet.iterator(); iterator.hasNext();) {
2436         NTuple<Descriptor> write = (NTuple<Descriptor>) iterator.next();
2437         mayWriteSet.add(write);
2438       }
2439
2440     }
2441       break;
2442
2443     case FKind.FlatExit: {
2444       // merge the current written set with OVERWRITE set
2445       merge(mustWriteSet, currMustWriteSet);
2446     }
2447       break;
2448
2449     }
2450
2451   }
2452
2453   static public FieldDescriptor getArrayField(TypeDescriptor td) {
2454     FieldDescriptor fd = mapTypeToArrayField.get(td);
2455     if (fd == null) {
2456       fd =
2457           new FieldDescriptor(new Modifiers(Modifiers.PUBLIC), td, arrayElementFieldName, null,
2458               false);
2459       mapTypeToArrayField.put(td, fd);
2460     }
2461     return fd;
2462   }
2463
2464   private void merge(Set<NTuple<Descriptor>> curr, Set<NTuple<Descriptor>> in) {
2465     if (curr.isEmpty()) {
2466       // set has a special initial value which covers all possible
2467       // elements
2468       // For the first time of intersection, we can take all previous set
2469       curr.addAll(in);
2470     } else {
2471       // otherwise, current set is the intersection of the two sets
2472       curr.retainAll(in);
2473     }
2474
2475   }
2476
2477   // combine two heap path
2478   private NTuple<Descriptor> combine(NTuple<Descriptor> callerIn, NTuple<Descriptor> calleeIn) {
2479     NTuple<Descriptor> combined = new NTuple<Descriptor>();
2480
2481     for (int i = 0; i < callerIn.size(); i++) {
2482       combined.add(callerIn.get(i));
2483     }
2484
2485     // the first element of callee's heap path represents parameter
2486     // so we skip the first one since it is already added from caller's heap
2487     // path
2488     for (int i = 1; i < calleeIn.size(); i++) {
2489       combined.add(calleeIn.get(i));
2490     }
2491
2492     return combined;
2493   }
2494
2495   private Set<NTuple<Descriptor>> bindSet(Set<NTuple<Descriptor>> calleeSet,
2496       Hashtable<Integer, TempDescriptor> mapParamIdx2ParamTempDesc,
2497       Hashtable<Integer, NTuple<Descriptor>> mapCallerArgIdx2HeapPath) {
2498
2499     Set<NTuple<Descriptor>> boundedCalleeSet = new HashSet<NTuple<Descriptor>>();
2500
2501     Set<Integer> keySet = mapCallerArgIdx2HeapPath.keySet();
2502     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
2503       Integer idx = (Integer) iterator.next();
2504
2505       NTuple<Descriptor> callerArgHeapPath = mapCallerArgIdx2HeapPath.get(idx);
2506       TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx);
2507       for (Iterator iterator2 = calleeSet.iterator(); iterator2.hasNext();) {
2508         NTuple<Descriptor> element = (NTuple<Descriptor>) iterator2.next();
2509         if (element.startsWith(calleeParam)) {
2510           NTuple<Descriptor> boundElement = combine(callerArgHeapPath, element);
2511           boundedCalleeSet.add(boundElement);
2512         }
2513
2514       }
2515
2516     }
2517     return boundedCalleeSet;
2518
2519   }
2520
2521   // Borrowed it from disjoint analysis
2522   private LinkedList<MethodDescriptor> topologicalSort(Set<MethodDescriptor> toSort) {
2523
2524     Set<MethodDescriptor> discovered = new HashSet<MethodDescriptor>();
2525
2526     LinkedList<MethodDescriptor> sorted = new LinkedList<MethodDescriptor>();
2527
2528     Iterator<MethodDescriptor> itr = toSort.iterator();
2529     while (itr.hasNext()) {
2530       MethodDescriptor d = itr.next();
2531
2532       if (!discovered.contains(d)) {
2533         dfsVisit(d, toSort, sorted, discovered);
2534       }
2535     }
2536
2537     return sorted;
2538   }
2539
2540   // While we're doing DFS on call graph, remember
2541   // dependencies for efficient queuing of methods
2542   // during interprocedural analysis:
2543   //
2544   // a dependent of a method decriptor d for this analysis is:
2545   // 1) a method or task that invokes d
2546   // 2) in the descriptorsToAnalyze set
2547   private void dfsVisit(MethodDescriptor md, Set<MethodDescriptor> toSort,
2548       LinkedList<MethodDescriptor> sorted, Set<MethodDescriptor> discovered) {
2549
2550     discovered.add(md);
2551
2552     Iterator itr = callGraph.getCallerSet(md).iterator();
2553     while (itr.hasNext()) {
2554       MethodDescriptor dCaller = (MethodDescriptor) itr.next();
2555       // only consider callers in the original set to analyze
2556       if (!toSort.contains(dCaller)) {
2557         continue;
2558       }
2559       if (!discovered.contains(dCaller)) {
2560         addDependent(md, // callee
2561             dCaller // caller
2562         );
2563
2564         dfsVisit(dCaller, toSort, sorted, discovered);
2565       }
2566     }
2567
2568     // for leaf-nodes last now!
2569     sorted.addLast(md);
2570   }
2571
2572   // a dependent of a method decriptor d for this analysis is:
2573   // 1) a method or task that invokes d
2574   // 2) in the descriptorsToAnalyze set
2575   private void addDependent(MethodDescriptor callee, MethodDescriptor caller) {
2576     Set<MethodDescriptor> deps = mapDescriptorToSetDependents.get(callee);
2577     if (deps == null) {
2578       deps = new HashSet<MethodDescriptor>();
2579     }
2580     deps.add(caller);
2581     mapDescriptorToSetDependents.put(callee, deps);
2582   }
2583
2584   private Set<MethodDescriptor> getDependents(MethodDescriptor callee) {
2585     Set<MethodDescriptor> deps = mapDescriptorToSetDependents.get(callee);
2586     if (deps == null) {
2587       deps = new HashSet<MethodDescriptor>();
2588       mapDescriptorToSetDependents.put(callee, deps);
2589     }
2590     return deps;
2591   }
2592
2593   private NTuple<Descriptor> computePath(Descriptor td) {
2594     // generate proper path fot input td
2595     // if td is local variable, it just generate one element tuple path
2596     if (mapHeapPath.containsKey(td)) {
2597       NTuple<Descriptor> rtrHeapPath = new NTuple<Descriptor>();
2598       rtrHeapPath.addAll(mapHeapPath.get(td));
2599       return rtrHeapPath;
2600     } else {
2601       NTuple<Descriptor> rtrHeapPath = new NTuple<Descriptor>();
2602       rtrHeapPath.add(td);
2603       return rtrHeapPath;
2604     }
2605   }
2606
2607   private NTuple<Location> deriveThisLocationTuple(MethodDescriptor md) {
2608     String thisLocIdentifier = ssjava.getMethodLattice(md).getThisLoc();
2609     Location thisLoc = new Location(md, thisLocIdentifier);
2610     NTuple<Location> locTuple = new NTuple<Location>();
2611     locTuple.add(thisLoc);
2612     return locTuple;
2613   }
2614
2615   private NTuple<Location> deriveGlobalLocationTuple(MethodDescriptor md) {
2616     String globalLocIdentifier = ssjava.getMethodLattice(md).getGlobalLoc();
2617     Location globalLoc = new Location(md, globalLocIdentifier);
2618     NTuple<Location> locTuple = new NTuple<Location>();
2619     locTuple.add(globalLoc);
2620     return locTuple;
2621   }
2622
2623   private NTuple<Location> deriveLocationTuple(MethodDescriptor md, TempDescriptor td) {
2624
2625     assert td.getType() != null;
2626
2627     if (mapDescriptorToLocationPath.containsKey(td)) {
2628       NTuple<Location> locPath = mapDescriptorToLocationPath.get(td);
2629       NTuple<Location> rtrPath = new NTuple<Location>();
2630       rtrPath.addAll(locPath);
2631       return rtrPath;
2632     } else {
2633       if (td.getSymbol().startsWith("this")) {
2634         NTuple<Location> thisPath = deriveThisLocationTuple(md);
2635
2636         NTuple<Location> rtrPath = new NTuple<Location>();
2637         rtrPath.addAll(thisPath);
2638
2639         return rtrPath;
2640       } else {
2641
2642         if (td.getType().getExtension() != null) {
2643           SSJavaType ssJavaType = (SSJavaType) td.getType().getExtension();
2644           if (ssJavaType.getCompLoc() != null) {
2645             NTuple<Location> rtrPath = new NTuple<Location>();
2646             rtrPath.addAll(ssJavaType.getCompLoc().getTuple());
2647             return rtrPath;
2648           }
2649         }
2650
2651         return null;
2652
2653       }
2654     }
2655   }
2656 }