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