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