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