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