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