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