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