changes.
[IRC.git] / Robust / src / Analysis / SSJava / DefinitelyWrittenCheck.java
1 package Analysis.SSJava;
2
3 import java.util.HashSet;
4 import java.util.Hashtable;
5 import java.util.Iterator;
6 import java.util.LinkedList;
7 import java.util.Set;
8 import java.util.Stack;
9
10 import Analysis.CallGraph.CallGraph;
11 import Analysis.Loops.LoopFinder;
12 import IR.Descriptor;
13 import IR.FieldDescriptor;
14 import IR.MethodDescriptor;
15 import IR.Operation;
16 import IR.State;
17 import IR.TypeDescriptor;
18 import IR.TypeExtension;
19 import IR.Flat.FKind;
20 import IR.Flat.FlatCall;
21 import IR.Flat.FlatElementNode;
22 import IR.Flat.FlatFieldNode;
23 import IR.Flat.FlatLiteralNode;
24 import IR.Flat.FlatMethod;
25 import IR.Flat.FlatNode;
26 import IR.Flat.FlatOpNode;
27 import IR.Flat.FlatSetElementNode;
28 import IR.Flat.FlatSetFieldNode;
29 import IR.Flat.TempDescriptor;
30 import IR.Tree.Modifiers;
31 import Util.Pair;
32
33 public class DefinitelyWrittenCheck {
34
35   SSJavaAnalysis ssjava;
36   State state;
37   CallGraph callGraph;
38
39   int debugcount = 0;
40
41   // maps a descriptor to its known dependents: namely
42   // methods or tasks that call the descriptor's method
43   // AND are part of this analysis (reachable from main)
44   private Hashtable<Descriptor, Set<MethodDescriptor>> mapDescriptorToSetDependents;
45
46   // maps a flat node to its WrittenSet: this keeps all heap path overwritten
47   // previously.
48   private Hashtable<FlatNode, Set<NTuple<Descriptor>>> mapFlatNodeToWrittenSet;
49
50   // maps a temp descriptor to its heap path
51   // each temp descriptor has a unique heap path since we do not allow any
52   // alias.
53   private Hashtable<Descriptor, NTuple<Descriptor>> mapHeapPath;
54
55   // maps a flat method to the READ that is the set of heap path that is
56   // expected to be written before method invocation
57   private Hashtable<FlatMethod, Set<NTuple<Descriptor>>> mapFlatMethodToRead;
58
59   // maps a flat method to the OVERWRITE that is the set of heap path that is
60   // overwritten on every possible path during method invocation
61   private Hashtable<FlatMethod, Set<NTuple<Descriptor>>> mapFlatMethodToOverWrite;
62
63   // maps a flat method to the WRITE that is the set of heap path that is
64   // written to
65   private Hashtable<FlatMethod, Set<NTuple<Descriptor>>> mapFlatMethodToWrite;
66
67   // points to method containing SSJAVA Loop
68   private MethodDescriptor methodContainingSSJavaLoop;
69
70   // maps a flatnode to definitely written analysis mapping M
71   private Hashtable<FlatNode, Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>>> definitelyWrittenResults;
72
73   // maps a method descriptor to its current summary during the analysis
74   // then analysis reaches fixed-point, this mapping will have the final summary
75   // for each method descriptor
76   private Hashtable<MethodDescriptor, ClearingSummary> mapMethodDescriptorToCompleteClearingSummary;
77
78   // maps a method descriptor to the merged incoming caller's current
79   // overwritten status
80   private Hashtable<MethodDescriptor, ClearingSummary> mapMethodDescriptorToInitialClearingSummary;
81
82   // maps a flat node to current partial results
83   private Hashtable<FlatNode, ClearingSummary> mapFlatNodeToClearingSummary;
84
85   // maps shared location to the set of descriptors which belong to the shared
86   // location
87
88   // keep current descriptors to visit in fixed-point interprocedural analysis,
89   private Stack<MethodDescriptor> methodDescriptorsToVisitStack;
90
91   // when analyzing flatcall, need to re-schedule set of callee
92   private Set<MethodDescriptor> calleesToEnqueue;
93
94   // maps heap path to the mapping of a shared location and the set of reading
95   // descriptors
96   // it is for setting clearance flag when all read set is overwritten
97   private Hashtable<NTuple<Descriptor>, Hashtable<Location, Set<Descriptor>>> mapHeapPathToLocSharedDescReadSet;
98
99   public static final String arrayElementFieldName = "___element_";
100   static protected Hashtable<TypeDescriptor, FieldDescriptor> mapTypeToArrayField;
101
102   private Set<ClearingSummary> possibleCalleeCompleteSummarySetToCaller;
103
104   private LinkedList<MethodDescriptor> sortedDescriptors;
105
106   private FlatNode ssjavaLoopEntrance;
107   private LoopFinder ssjavaLoop;
108   private Set<FlatNode> loopIncElements;
109
110   private Set<NTuple<Descriptor>> calleeUnionBoundReadSet;
111   private Set<NTuple<Descriptor>> calleeIntersectBoundOverWriteSet;
112   private Set<NTuple<Descriptor>> calleeBoundWriteSet;
113
114   private Hashtable<Descriptor, Location> mapDescToLocation;
115
116   private TempDescriptor LOCAL;
117
118   public DefinitelyWrittenCheck(SSJavaAnalysis ssjava, State state) {
119     this.state = state;
120     this.ssjava = ssjava;
121     this.callGraph = ssjava.getCallGraph();
122     this.mapFlatNodeToWrittenSet = new Hashtable<FlatNode, Set<NTuple<Descriptor>>>();
123     this.mapDescriptorToSetDependents = new Hashtable<Descriptor, Set<MethodDescriptor>>();
124     this.mapHeapPath = new Hashtable<Descriptor, NTuple<Descriptor>>();
125     this.mapFlatMethodToRead = new Hashtable<FlatMethod, Set<NTuple<Descriptor>>>();
126     this.mapFlatMethodToOverWrite = new Hashtable<FlatMethod, Set<NTuple<Descriptor>>>();
127     this.mapFlatMethodToWrite = new Hashtable<FlatMethod, Set<NTuple<Descriptor>>>();
128     this.definitelyWrittenResults =
129         new Hashtable<FlatNode, Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>>>();
130     this.calleeUnionBoundReadSet = new HashSet<NTuple<Descriptor>>();
131     this.calleeIntersectBoundOverWriteSet = new HashSet<NTuple<Descriptor>>();
132     this.calleeBoundWriteSet = new HashSet<NTuple<Descriptor>>();
133
134     this.mapMethodDescriptorToCompleteClearingSummary =
135         new Hashtable<MethodDescriptor, ClearingSummary>();
136     this.mapMethodDescriptorToInitialClearingSummary =
137         new Hashtable<MethodDescriptor, ClearingSummary>();
138     this.methodDescriptorsToVisitStack = new Stack<MethodDescriptor>();
139     this.calleesToEnqueue = new HashSet<MethodDescriptor>();
140     this.possibleCalleeCompleteSummarySetToCaller = new HashSet<ClearingSummary>();
141     this.mapTypeToArrayField = new Hashtable<TypeDescriptor, FieldDescriptor>();
142     this.LOCAL = new TempDescriptor("LOCAL");
143     this.mapDescToLocation = new Hashtable<Descriptor, Location>();
144     this.mapHeapPathToLocSharedDescReadSet =
145         new Hashtable<NTuple<Descriptor>, Hashtable<Location, Set<Descriptor>>>();
146   }
147
148   public void definitelyWrittenCheck() {
149     if (!ssjava.getAnnotationRequireSet().isEmpty()) {
150       methodReadOverWriteAnalysis();
151       writtenAnalyis();
152       sharedLocationAnalysis();
153       checkSharedLocationResult();
154     }
155   }
156
157   private void checkSharedLocationResult() {
158
159     // mapping of method containing ssjava loop has the final result of
160     // shared location analysis
161
162     ClearingSummary result =
163         mapMethodDescriptorToCompleteClearingSummary.get(methodContainingSSJavaLoop);
164
165     System.out.println("\n\n#RESULT=" + result);
166
167     Set<NTuple<Descriptor>> hpKeySet = result.keySet();
168     for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) {
169       NTuple<Descriptor> hpKey = (NTuple<Descriptor>) iterator.next();
170       SharedStatus state = result.get(hpKey);
171       Set<Location> locKeySet = state.getLocationSet();
172       for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) {
173         Location locKey = (Location) iterator2.next();
174         if (!state.getFlag(locKey)) {
175           printNotClearedResult(result);
176           throw new Error(
177               "Some concrete locations of the shared abstract location are not cleared at the same time:");
178         }
179       }
180     }
181
182   }
183
184   private void printNotClearedResult(ClearingSummary result) {
185     Set<NTuple<Descriptor>> keySet = result.keySet();
186
187     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
188       NTuple<Descriptor> hpKey = (NTuple<Descriptor>) iterator.next();
189       SharedStatus status = result.get(hpKey);
190       Hashtable<Location, Pair<Set<Descriptor>, Boolean>> map = status.getMap();
191       Set<Location> locKeySet = map.keySet();
192       for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) {
193         Location locKey = (Location) iterator2.next();
194         if (status.haveWriteEffect(locKey)) {
195           Pair<Set<Descriptor>, Boolean> pair = map.get(locKey);
196           if (!pair.getSecond().booleanValue()) {
197             // not cleared!
198             System.out.println("Concrete locations of the shared location '" + locKey
199                 + "' are not cleared out, which are reachable through the heap path '" + hpKey
200                 + "'");
201           }
202         }
203       }
204     }
205
206   }
207
208   private void sharedLocationAnalysis() {
209     // verify that all concrete locations of shared location are cleared out at
210     // the same time once per the out-most loop
211
212     computeReadSharedDescriptorSet();
213
214     System.out.println("###");
215     System.out.println("READ SHARED=" + mapHeapPathToLocSharedDescReadSet);
216
217     // methodDescriptorsToVisitStack.clear();
218     // methodDescriptorsToVisitStack.add(sortedDescriptors.peekFirst());
219
220     LinkedList<MethodDescriptor> descriptorListToAnalyze =
221         (LinkedList<MethodDescriptor>) sortedDescriptors.clone();
222
223     // current descriptors to visit in fixed-point interprocedural analysis,
224     // prioritized by
225     // dependency in the call graph
226     methodDescriptorsToVisitStack.clear();
227
228     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
229     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
230
231     while (!descriptorListToAnalyze.isEmpty()) {
232       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
233       methodDescriptorsToVisitStack.add(md);
234     }
235
236     // analyze scheduled methods until there are no more to visit
237     while (!methodDescriptorsToVisitStack.isEmpty()) {
238       MethodDescriptor md = methodDescriptorsToVisitStack.pop();
239
240       ClearingSummary completeSummary =
241           sharedLocation_analyzeMethod(md, (md.equals(methodContainingSSJavaLoop)));
242
243       ClearingSummary prevCompleteSummary = mapMethodDescriptorToCompleteClearingSummary.get(md);
244
245       if (!completeSummary.equals(prevCompleteSummary)) {
246
247         ClearingSummary summaryFromCaller = mapMethodDescriptorToInitialClearingSummary.get(md);
248         // System.out.println("###");
249         // System.out.println("# summaryFromCaller=" + summaryFromCaller);
250         // System.out.println("# completeSummary=" + completeSummary);
251         // System.out.println("# prev=" + prevCompleteSummary);
252         // System.out.println("# changed!\n");
253
254         mapMethodDescriptorToCompleteClearingSummary.put(md, completeSummary);
255
256         // results for callee changed, so enqueue dependents caller for
257         // further analysis
258         Iterator<MethodDescriptor> depsItr = getDependents(md).iterator();
259         while (depsItr.hasNext()) {
260           MethodDescriptor methodNext = depsItr.next();
261           if (!methodDescriptorsToVisitStack.contains(methodNext)) {
262             methodDescriptorsToVisitStack.add(methodNext);
263           }
264         }
265
266         // if there is set of callee to be analyzed,
267         // add this set into the top of stack
268         Iterator<MethodDescriptor> calleeIter = calleesToEnqueue.iterator();
269         while (calleeIter.hasNext()) {
270           MethodDescriptor mdNext = calleeIter.next();
271           if (!methodDescriptorsToVisitStack.contains(mdNext)) {
272             methodDescriptorsToVisitStack.add(mdNext);
273           }
274         }
275         calleesToEnqueue.clear();
276
277       }
278
279     }
280
281   }
282
283   private ClearingSummary sharedLocation_analyzeMethod(MethodDescriptor md,
284       boolean onlyVisitSSJavaLoop) {
285
286     if (state.SSJAVADEBUG) {
287       System.out.println("Definite clearance for shared locations Analyzing: " + md + " "
288           + onlyVisitSSJavaLoop);
289     }
290
291     FlatMethod fm = state.getMethodFlat(md);
292
293     // intraprocedural analysis
294     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
295
296     // start a new mapping of partial results for each flat node
297     mapFlatNodeToClearingSummary = new Hashtable<FlatNode, ClearingSummary>();
298
299     if (onlyVisitSSJavaLoop) {
300       flatNodesToVisit.add(ssjavaLoopEntrance);
301     } else {
302       flatNodesToVisit.add(fm);
303     }
304
305     Set<FlatNode> returnNodeSet = new HashSet<FlatNode>();
306
307     while (!flatNodesToVisit.isEmpty()) {
308       FlatNode fn = flatNodesToVisit.iterator().next();
309       flatNodesToVisit.remove(fn);
310
311       ClearingSummary curr = new ClearingSummary();
312
313       Set<ClearingSummary> prevSet = new HashSet<ClearingSummary>();
314       for (int i = 0; i < fn.numPrev(); i++) {
315         FlatNode prevFn = fn.getPrev(i);
316         ClearingSummary in = mapFlatNodeToClearingSummary.get(prevFn);
317         if (in != null) {
318           prevSet.add(in);
319         }
320       }
321       mergeSharedLocationAnaylsis(curr, prevSet);
322
323       sharedLocation_nodeActions(md, fn, curr, returnNodeSet, onlyVisitSSJavaLoop);
324       ClearingSummary clearingPrev = mapFlatNodeToClearingSummary.get(fn);
325
326       if (!curr.equals(clearingPrev)) {
327         mapFlatNodeToClearingSummary.put(fn, curr);
328
329         for (int i = 0; i < fn.numNext(); i++) {
330           FlatNode nn = fn.getNext(i);
331
332           if (!onlyVisitSSJavaLoop || (onlyVisitSSJavaLoop && loopIncElements.contains(nn))) {
333             flatNodesToVisit.add(nn);
334           }
335
336         }
337       }
338
339     }
340
341     ClearingSummary completeSummary = new ClearingSummary();
342     Set<ClearingSummary> summarySet = new HashSet<ClearingSummary>();
343
344     if (onlyVisitSSJavaLoop) {
345       // when analyzing ssjava loop,
346       // complete summary is merging of all previous nodes of ssjava loop
347       // entrance
348       for (int i = 0; i < ssjavaLoopEntrance.numPrev(); i++) {
349         ClearingSummary frnSummary =
350             mapFlatNodeToClearingSummary.get(ssjavaLoopEntrance.getPrev(i));
351         if (frnSummary != null) {
352           summarySet.add(frnSummary);
353         }
354       }
355     } else {
356       // merging all exit node summary into the complete summary
357       if (!returnNodeSet.isEmpty()) {
358         for (Iterator iterator = returnNodeSet.iterator(); iterator.hasNext();) {
359           FlatNode frn = (FlatNode) iterator.next();
360           ClearingSummary frnSummary = mapFlatNodeToClearingSummary.get(frn);
361           summarySet.add(frnSummary);
362         }
363       }
364     }
365     mergeSharedLocationAnaylsis(completeSummary, summarySet);
366
367     if (md.getSymbol().startsWith("decodeFrame")) {
368       System.out.println("#");
369       System.out.println("# method=" + md);
370       System.out.println("XXXXX summarySet=" + summarySet);
371       System.out.println("XXXXX completeSummary=" + completeSummary);
372       System.out.println("#");
373     }
374
375     return completeSummary;
376   }
377
378   private void sharedLocation_nodeActions(MethodDescriptor caller, FlatNode fn,
379       ClearingSummary curr, Set<FlatNode> returnNodeSet, boolean isSSJavaLoop) {
380
381     TempDescriptor lhs;
382     TempDescriptor rhs;
383     FieldDescriptor fld;
384     switch (fn.kind()) {
385
386     case FKind.FlatMethod: {
387       FlatMethod fm = (FlatMethod) fn;
388
389       ClearingSummary summaryFromCaller =
390           mapMethodDescriptorToInitialClearingSummary.get(fm.getMethod());
391
392       Set<ClearingSummary> inSet = new HashSet<ClearingSummary>();
393       if (summaryFromCaller != null) {
394         inSet.add(summaryFromCaller);
395         mergeSharedLocationAnaylsis(curr, inSet);
396       }
397
398     }
399       break;
400
401     case FKind.FlatOpNode: {
402       FlatOpNode fon = (FlatOpNode) fn;
403       lhs = fon.getDest();
404       rhs = fon.getLeft();
405
406       if (fon.getOp().getOp() == Operation.ASSIGN) {
407         if (rhs.getType().isImmutable() && isSSJavaLoop) {
408           // in ssjavaloop, we need to take care about reading local variables!
409           NTuple<Descriptor> rhsHeapPath = new NTuple<Descriptor>();
410           NTuple<Descriptor> lhsHeapPath = new NTuple<Descriptor>();
411           rhsHeapPath.add(LOCAL);
412           lhsHeapPath.add(LOCAL);
413           if (!lhs.getSymbol().startsWith("neverused")) {
414             readLocation(curr, rhsHeapPath, getLocation(rhs), rhs);
415             writeLocation(curr, lhsHeapPath, getLocation(lhs), lhs);
416           }
417         }
418       }
419
420     }
421       break;
422
423     case FKind.FlatFieldNode:
424     case FKind.FlatElementNode: {
425
426       if (fn.kind() == FKind.FlatFieldNode) {
427         FlatFieldNode ffn = (FlatFieldNode) fn;
428         lhs = ffn.getDst();
429         rhs = ffn.getSrc();
430         fld = ffn.getField();
431       } else {
432         FlatElementNode fen = (FlatElementNode) fn;
433         lhs = fen.getDst();
434         rhs = fen.getSrc();
435         TypeDescriptor td = rhs.getType().dereference();
436         fld = getArrayField(td);
437       }
438
439       // read field
440       NTuple<Descriptor> srcHeapPath = mapHeapPath.get(rhs);
441
442       if (srcHeapPath != null) {
443         // if lhs srcHeapPath is null, it means that it is not reachable from
444         // callee's parameters. so just ignore it
445         NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>(srcHeapPath.getList());
446
447         // if (!fld.getType().isArray() && fld.getType().isImmutable()) {
448         // addReadDescriptor(fldHeapPath, getLocation(fld), fld);
449         // } else {
450         // if (fn.kind() == FKind.FlatFieldNode) {
451         // mapDescToLocation.put(lhs, getLocation(fld));
452         // readLocation(curr, fldHeapPath, getLocation(fld), fld);
453         // } else {
454         // fldHeapPath.add(fld);
455         // }
456         // mapHeapPath.put(lhs, fldHeapPath);
457         // }
458
459         if (!fld.getType().isArray() && fld.getType().isImmutable()) {
460           Location loc;
461           if (fn.kind() == FKind.FlatElementNode) {
462             // array element read case
463             loc = mapDescToLocation.get(rhs);
464             NTuple<Descriptor> newHeapPath = new NTuple<Descriptor>();
465             for (int i = 0; i < fldHeapPath.size() - 1; i++) {
466               newHeapPath.add(fldHeapPath.get(i));
467             }
468
469             Descriptor desc = fldHeapPath.get(fldHeapPath.size() - 1);
470             if (desc instanceof FieldDescriptor) {
471               fld = (FieldDescriptor) desc;
472               fldHeapPath = newHeapPath;
473               readLocation(curr, fldHeapPath, loc, fld);
474             }
475           } else {
476             loc = getLocation(fld);
477             readLocation(curr, fldHeapPath, loc, fld);
478           }
479         } else {
480
481           if (fn.kind() != FKind.FlatElementNode) {
482             // if it is multi dimensional array, do not need to add heap path
483             // because all accesses from the same array is represented by
484             // "_element_"
485             fldHeapPath.add(fld);
486           }
487           mapHeapPath.put(lhs, fldHeapPath);
488         }
489
490       }
491
492       // }
493
494     }
495       break;
496
497     case FKind.FlatSetFieldNode:
498     case FKind.FlatSetElementNode: {
499
500       if (fn.kind() == FKind.FlatSetFieldNode) {
501         FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
502         lhs = fsfn.getDst();
503         fld = fsfn.getField();
504         rhs = fsfn.getSrc();
505       } else {
506         FlatSetElementNode fsen = (FlatSetElementNode) fn;
507         lhs = fsen.getDst();
508         rhs = fsen.getSrc();
509         TypeDescriptor td = lhs.getType().dereference();
510         fld = getArrayField(td);
511       }
512
513       // write(field)
514       NTuple<Descriptor> lhsHeapPath = computePath(lhs);
515       NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>(lhsHeapPath.getList());
516       if (fld.getType().isImmutable()) {
517         writeLocation(curr, fldHeapPath, getLocation(fld), fld);
518
519         Descriptor desc = fldHeapPath.get(fldHeapPath.size() - 1);
520         if (desc instanceof FieldDescriptor) {
521           NTuple<Descriptor> arrayPath = new NTuple<Descriptor>();
522           for (int i = 0; i < fldHeapPath.size() - 1; i++) {
523             arrayPath.add(fldHeapPath.get(i));
524           }
525           SharedStatus state = getState(curr, arrayPath);
526           state.setWriteEffect(getLocation(desc));
527         }
528
529       } else {
530         // updates reference field case:
531         fldHeapPath.add(fld);
532         updateWriteEffectOnReferenceField(curr, fldHeapPath);
533       }
534
535     }
536       break;
537
538     case FKind.FlatCall: {
539
540       FlatCall fc = (FlatCall) fn;
541
542       if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) {
543         // ssjava util case!
544         // have write effects on the first argument
545
546         if (fc.getArg(0).getType().isArray()) {
547           // updates reference field case:
548           // 2. if there exists a tuple t in sharing summary that starts with
549           // hp(x) then, set flag of tuple t to 'true'
550           NTuple<Descriptor> argHeapPath = computePath(fc.getArg(0));
551
552           Location loc = getLocation(fc.getArg(0));
553           NTuple<Descriptor> newHeapPath = new NTuple<Descriptor>();
554           for (int i = 0; i < argHeapPath.size() - 1; i++) {
555             newHeapPath.add(argHeapPath.get(i));
556           }
557           fld = (FieldDescriptor) argHeapPath.get(argHeapPath.size() - 1);
558           argHeapPath = newHeapPath;
559
560           writeLocation(curr, argHeapPath, loc, fld);
561         }
562
563       } else {
564         // find out the set of callees
565         MethodDescriptor mdCallee = fc.getMethod();
566         FlatMethod fmCallee = state.getMethodFlat(mdCallee);
567         Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
568         // TypeDescriptor typeDesc = fc.getThis().getType();
569         setPossibleCallees.addAll(callGraph.getMethods(mdCallee));
570
571         possibleCalleeCompleteSummarySetToCaller.clear();
572
573         for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) {
574           MethodDescriptor mdPossibleCallee = (MethodDescriptor) iterator.next();
575           FlatMethod calleeFlatMethod = state.getMethodFlat(mdPossibleCallee);
576
577           addDependent(mdPossibleCallee, // callee
578               caller); // caller
579
580           calleesToEnqueue.add(mdPossibleCallee);
581
582           // updates possible callee's initial summary using caller's current
583           // writing status
584           ClearingSummary prevCalleeInitSummary =
585               mapMethodDescriptorToInitialClearingSummary.get(mdPossibleCallee);
586
587           ClearingSummary calleeInitSummary =
588               bindHeapPathOfCalleeCallerEffects(fc, calleeFlatMethod, curr);
589
590           Set<ClearingSummary> inSet = new HashSet<ClearingSummary>();
591           if (prevCalleeInitSummary != null) {
592             inSet.add(prevCalleeInitSummary);
593             mergeSharedLocationAnaylsis(calleeInitSummary, inSet);
594           }
595
596           // if changes, update the init summary
597           // and reschedule the callee for analysis
598           if (!calleeInitSummary.equals(prevCalleeInitSummary)) {
599             // System.out.println("#CALLEE INIT CHANGED=" + mdPossibleCallee);
600             // System.out.println("# prev=" + prevCalleeInitSummary);
601             // System.out.println("# current=" + calleeInitSummary);
602             // System.out.println("#");
603
604             if (!methodDescriptorsToVisitStack.contains(mdPossibleCallee)) {
605               methodDescriptorsToVisitStack.add(mdPossibleCallee);
606             }
607
608             mapMethodDescriptorToInitialClearingSummary.put(mdPossibleCallee, calleeInitSummary);
609           }
610
611         }
612
613         // contribute callee's writing effects to the caller
614         mergeSharedLocationAnaylsis(curr, possibleCalleeCompleteSummarySetToCaller);
615         if (fc.getMethod().getSymbol().startsWith("decode")) {
616           System.out.println("XXXXX callee " + fc + " summary="
617               + possibleCalleeCompleteSummarySetToCaller);
618           System.out.println("XXXXX curr=" + curr);
619         }
620
621       }
622
623     }
624       break;
625
626     case FKind.FlatReturnNode: {
627       returnNodeSet.add(fn);
628     }
629       break;
630
631     }
632
633   }
634
635   private void updateWriteEffectOnReferenceField(ClearingSummary curr, NTuple<Descriptor> heapPath) {
636
637     // DEBUG!
638     // System.out.println("UPDATE WRITE REF=" + heapPath);
639     // Descriptor d = heapPath.get(heapPath.size() - 1);
640     // boolean print = false;
641     // if (d instanceof FieldDescriptor) {
642     // FieldDescriptor fd = (FieldDescriptor) d;
643     // if (fd.getSymbol().equals("si")) {
644     // System.out.println("UPDATE PREV CURR=" + curr);
645     // print = true;
646     // }
647     // }
648     // 2. if there exists a tuple t in sharing summary that starts with
649     // hp(x) then, set flag of tuple t to 'true'
650     Set<NTuple<Descriptor>> hpKeySet = curr.keySet();
651     for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) {
652       NTuple<Descriptor> hpKey = (NTuple<Descriptor>) iterator.next();
653       if (hpKey.startsWith(heapPath)) {
654         curr.get(hpKey).updateFlag(true);
655       }
656     }
657
658     // if (print) {
659     // System.out.println("UPDATE CURR=" + curr);
660     // }
661   }
662
663   private ClearingSummary bindHeapPathOfCalleeCallerEffects(FlatCall fc,
664       FlatMethod calleeFlatMethod, ClearingSummary curr) {
665
666     ClearingSummary boundSet = new ClearingSummary();
667
668     // create mapping from arg idx to its heap paths
669     Hashtable<Integer, NTuple<Descriptor>> mapArgIdx2CallerArgHeapPath =
670         new Hashtable<Integer, NTuple<Descriptor>>();
671
672     if (fc.getThis() != null) {
673       // arg idx is starting from 'this' arg
674       NTuple<Descriptor> thisHeapPath = mapHeapPath.get(fc.getThis());
675       if (thisHeapPath == null) {
676         // method is called without creating new flat node representing 'this'
677         thisHeapPath = new NTuple<Descriptor>();
678         thisHeapPath.add(fc.getThis());
679       }
680
681       mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath);
682     }
683
684     for (int i = 0; i < fc.numArgs(); i++) {
685       TempDescriptor arg = fc.getArg(i);
686       NTuple<Descriptor> argHeapPath = computePath(arg);
687       mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath);
688     }
689
690     Hashtable<Integer, TempDescriptor> mapParamIdx2ParamTempDesc =
691         new Hashtable<Integer, TempDescriptor>();
692     int offset = 0;
693     if (calleeFlatMethod.getMethod().isStatic()) {
694       // static method does not have implicit 'this' arg
695       offset = 1;
696     }
697     for (int i = 0; i < calleeFlatMethod.numParameters(); i++) {
698       TempDescriptor param = calleeFlatMethod.getParameter(i);
699       mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param);
700     }
701
702     // binding caller's writing effects to callee's params
703     for (int i = 0; i < calleeFlatMethod.numParameters(); i++) {
704       NTuple<Descriptor> argHeapPath = mapArgIdx2CallerArgHeapPath.get(Integer.valueOf(i));
705
706       if (argHeapPath != null) {
707         // if method is static, the first argument is nulll because static
708         // method does not have implicit "THIS" arg
709         TempDescriptor calleeParamHeapPath = mapParamIdx2ParamTempDesc.get(Integer.valueOf(i));
710
711         // iterate over caller's writing effect set
712         Set<NTuple<Descriptor>> hpKeySet = curr.keySet();
713         for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) {
714           NTuple<Descriptor> hpKey = (NTuple<Descriptor>) iterator.next();
715           // current element is reachable caller's arg
716           // so need to bind it to the caller's side and add it to the
717           // callee's
718           // init summary
719           if (hpKey.startsWith(argHeapPath)) {
720             NTuple<Descriptor> boundHeapPath = replace(hpKey, argHeapPath, calleeParamHeapPath);
721             boundSet.put(boundHeapPath, curr.get(hpKey).clone());
722           }
723
724         }
725       }
726
727     }
728
729     // contribute callee's complete summary into the caller's current summary
730     ClearingSummary calleeCompleteSummary =
731         mapMethodDescriptorToCompleteClearingSummary.get(calleeFlatMethod.getMethod());
732     if (calleeCompleteSummary != null) {
733       ClearingSummary boundCalleeEfffects = new ClearingSummary();
734       for (int i = 0; i < calleeFlatMethod.numParameters(); i++) {
735         // for (int i = 0; i < fc.numArgs(); i++) {
736         NTuple<Descriptor> argHeapPath = mapArgIdx2CallerArgHeapPath.get(Integer.valueOf(i));
737
738         if (argHeapPath != null) {
739           // if method is static, the first argument is nulll because static
740           // method does not have implicit "THIS" arg
741           TempDescriptor calleeParamHeapPath = mapParamIdx2ParamTempDesc.get(Integer.valueOf(i));
742
743           // iterate over callee's writing effect set
744           Set<NTuple<Descriptor>> hpKeySet = calleeCompleteSummary.keySet();
745           for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) {
746             NTuple<Descriptor> hpKey = (NTuple<Descriptor>) iterator.next();
747             // current element is reachable caller's arg
748             // so need to bind it to the caller's side and add it to the
749             // callee's
750             // init summary
751             if (hpKey.startsWith(calleeParamHeapPath)) {
752
753               NTuple<Descriptor> boundHeapPathForCaller = replace(hpKey, argHeapPath);
754
755               boundCalleeEfffects.put(boundHeapPathForCaller, calleeCompleteSummary.get(hpKey)
756                   .clone());
757
758             }
759           }
760
761         }
762
763       }
764       possibleCalleeCompleteSummarySetToCaller.add(boundCalleeEfffects);
765     }
766
767     return boundSet;
768   }
769
770   private NTuple<Descriptor> replace(NTuple<Descriptor> hpKey, NTuple<Descriptor> argHeapPath) {
771
772     // replace the head of heap path with caller's arg path
773     // for example, heap path 'param.a.b' in callee's side will be replaced with
774     // (corresponding arg heap path).a.b for caller's side
775
776     NTuple<Descriptor> bound = new NTuple<Descriptor>();
777
778     for (int i = 0; i < argHeapPath.size(); i++) {
779       bound.add(argHeapPath.get(i));
780     }
781
782     for (int i = 1; i < hpKey.size(); i++) {
783       bound.add(hpKey.get(i));
784     }
785
786     return bound;
787   }
788
789   private NTuple<Descriptor> replace(NTuple<Descriptor> effectHeapPath,
790       NTuple<Descriptor> argHeapPath, TempDescriptor calleeParamHeapPath) {
791     // replace the head of caller's heap path with callee's param heap path
792
793     NTuple<Descriptor> boundHeapPath = new NTuple<Descriptor>();
794     boundHeapPath.add(calleeParamHeapPath);
795
796     for (int i = argHeapPath.size(); i < effectHeapPath.size(); i++) {
797       boundHeapPath.add(effectHeapPath.get(i));
798     }
799
800     return boundHeapPath;
801   }
802
803   private void computeReadSharedDescriptorSet() {
804     Set<MethodDescriptor> methodDescriptorsToAnalyze = new HashSet<MethodDescriptor>();
805     methodDescriptorsToAnalyze.addAll(ssjava.getAnnotationRequireSet());
806
807     for (Iterator iterator = methodDescriptorsToAnalyze.iterator(); iterator.hasNext();) {
808       MethodDescriptor md = (MethodDescriptor) iterator.next();
809       FlatMethod fm = state.getMethodFlat(md);
810       computeReadSharedDescriptorSet_analyzeMethod(fm, md.equals(methodContainingSSJavaLoop));
811     }
812
813   }
814
815   private void computeReadSharedDescriptorSet_analyzeMethod(FlatMethod fm,
816       boolean onlyVisitSSJavaLoop) {
817
818     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
819     Set<FlatNode> visited = new HashSet<FlatNode>();
820
821     if (onlyVisitSSJavaLoop) {
822       flatNodesToVisit.add(ssjavaLoopEntrance);
823     } else {
824       flatNodesToVisit.add(fm);
825     }
826
827     while (!flatNodesToVisit.isEmpty()) {
828       FlatNode fn = flatNodesToVisit.iterator().next();
829       flatNodesToVisit.remove(fn);
830       visited.add(fn);
831
832       computeReadSharedDescriptorSet_nodeActions(fn, onlyVisitSSJavaLoop);
833
834       for (int i = 0; i < fn.numNext(); i++) {
835         FlatNode nn = fn.getNext(i);
836         if (!visited.contains(nn)) {
837           if (!onlyVisitSSJavaLoop || (onlyVisitSSJavaLoop && loopIncElements.contains(nn))) {
838             flatNodesToVisit.add(nn);
839           }
840         }
841       }
842
843     }
844
845   }
846
847   private void computeReadSharedDescriptorSet_nodeActions(FlatNode fn, boolean isSSJavaLoop) {
848
849     TempDescriptor lhs;
850     TempDescriptor rhs;
851     FieldDescriptor fld;
852
853     switch (fn.kind()) {
854     case FKind.FlatOpNode: {
855       FlatOpNode fon = (FlatOpNode) fn;
856       lhs = fon.getDest();
857       rhs = fon.getLeft();
858
859       if (fon.getOp().getOp() == Operation.ASSIGN) {
860         if (rhs.getType().isImmutable() && isSSJavaLoop && (!rhs.getSymbol().startsWith("srctmp"))) {
861           // in ssjavaloop, we need to take care about reading local variables!
862           NTuple<Descriptor> rhsHeapPath = new NTuple<Descriptor>();
863           NTuple<Descriptor> lhsHeapPath = new NTuple<Descriptor>();
864           rhsHeapPath.add(LOCAL);
865           Location loc = getLocation(rhs);
866           addReadDescriptor(rhsHeapPath, loc, rhs);
867         }
868       }
869
870     }
871       break;
872
873     case FKind.FlatFieldNode:
874     case FKind.FlatElementNode: {
875
876       if (fn.kind() == FKind.FlatFieldNode) {
877         FlatFieldNode ffn = (FlatFieldNode) fn;
878         lhs = ffn.getDst();
879         rhs = ffn.getSrc();
880         fld = ffn.getField();
881       } else {
882         FlatElementNode fen = (FlatElementNode) fn;
883         lhs = fen.getDst();
884         rhs = fen.getSrc();
885         TypeDescriptor td = rhs.getType().dereference();
886         fld = getArrayField(td);
887       }
888
889       if (fld.isStatic() && fld.isFinal()) {
890         break;
891       }
892
893       // read field
894       NTuple<Descriptor> srcHeapPath = mapHeapPath.get(rhs);
895       if (srcHeapPath != null) {
896         // if srcHeapPath is null, it means that it is not reachable from
897         // callee's parameters. so just ignore it
898
899         NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>(srcHeapPath.getList());
900
901         if (!fld.getType().isArray() && fld.getType().isImmutable()) {
902
903           Location loc;
904           if (fn.kind() == FKind.FlatElementNode) {
905             // array element read case
906             loc = mapDescToLocation.get(rhs);
907             NTuple<Descriptor> newHeapPath = new NTuple<Descriptor>();
908             for (int i = 0; i < fldHeapPath.size() - 1; i++) {
909               newHeapPath.add(fldHeapPath.get(i));
910             }
911
912             Descriptor desc = fldHeapPath.get(fldHeapPath.size() - 1);
913             if (desc instanceof FieldDescriptor) {
914               fld = (FieldDescriptor) desc;
915               fldHeapPath = newHeapPath;
916               addReadDescriptor(fldHeapPath, loc, fld);
917             }
918           } else {
919             loc = getLocation(fld);
920             addReadDescriptor(fldHeapPath, loc, fld);
921           }
922         } else {
923           // propagate rhs's heap path to the lhs
924
925           if (fn.kind() == FKind.FlatElementNode) {
926             mapDescToLocation.put(lhs, getLocation(rhs));
927           } else {
928             fldHeapPath.add(fld);
929           }
930           mapHeapPath.put(lhs, fldHeapPath);
931         }
932
933       }
934
935     }
936       break;
937
938     case FKind.FlatSetFieldNode:
939     case FKind.FlatSetElementNode: {
940
941       if (fn.kind() == FKind.FlatSetFieldNode) {
942         FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
943         lhs = fsfn.getDst();
944         fld = fsfn.getField();
945       } else {
946         FlatSetElementNode fsen = (FlatSetElementNode) fn;
947         lhs = fsen.getDst();
948         rhs = fsen.getSrc();
949         TypeDescriptor td = lhs.getType().dereference();
950         fld = getArrayField(td);
951       }
952
953       // write(field)
954       NTuple<Descriptor> lhsHeapPath = computePath(lhs);
955       NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>(lhsHeapPath.getList());
956       // writeLocation(curr, fldHeapPath, fld, getLocation(fld));
957
958     }
959       break;
960
961     }
962   }
963
964   private boolean hasReadingEffectOnSharedLocation(NTuple<Descriptor> hp, Location loc, Descriptor d) {
965
966     Hashtable<Location, Set<Descriptor>> mapLocToDescSet =
967         mapHeapPathToLocSharedDescReadSet.get(hp);
968     if (mapLocToDescSet == null) {
969       return false;
970     } else {
971       Set<Descriptor> setDesc = mapLocToDescSet.get(loc);
972       if (setDesc == null) {
973         return false;
974       } else {
975         return setDesc.contains(d);
976       }
977     }
978
979   }
980
981   private void addReadDescriptor(NTuple<Descriptor> hp, Location loc, Descriptor d) {
982
983     if (loc != null && ssjava.isSharedLocation(loc)) {
984       Hashtable<Location, Set<Descriptor>> mapLocToDescSet =
985           mapHeapPathToLocSharedDescReadSet.get(hp);
986       if (mapLocToDescSet == null) {
987         mapLocToDescSet = new Hashtable<Location, Set<Descriptor>>();
988         mapHeapPathToLocSharedDescReadSet.put(hp, mapLocToDescSet);
989       }
990       Set<Descriptor> descSet = mapLocToDescSet.get(loc);
991       if (descSet == null) {
992         descSet = new HashSet<Descriptor>();
993         mapLocToDescSet.put(loc, descSet);
994       }
995       descSet.add(d);
996     }
997
998   }
999
1000   private Location getLocation(Descriptor d) {
1001
1002     if (d instanceof FieldDescriptor) {
1003       TypeExtension te = ((FieldDescriptor) d).getType().getExtension();
1004       if (te != null) {
1005         return (Location) te;
1006       }
1007     } else {
1008       assert d instanceof TempDescriptor;
1009       TempDescriptor td = (TempDescriptor) d;
1010
1011       TypeExtension te = td.getType().getExtension();
1012       if (te != null) {
1013         if (te instanceof CompositeLocation) {
1014           CompositeLocation comp = (CompositeLocation) te;
1015
1016           return comp.get(comp.getSize() - 1);
1017         } else {
1018           return (Location) te;
1019         }
1020       }
1021     }
1022
1023     return mapDescToLocation.get(d);
1024   }
1025
1026   private void writeLocation(ClearingSummary curr, NTuple<Descriptor> hp, Location loc, Descriptor d) {
1027
1028     // System.out.println("# WRITE LOC hp=" + hp + " d=" + d + " loc=" + loc);
1029     SharedStatus state = getState(curr, hp);
1030     if (loc != null && hasReadingEffectOnSharedLocation(hp, loc, d)) {
1031       // 1. add field x to the clearing set
1032
1033       state.addVar(loc, d);
1034
1035       // 3. if the set v contains all of variables belonging to the shared
1036       // location, set flag to true
1037       if (overwrittenAllSharedConcreteLocation(hp, loc, state.getVarSet(loc))) {
1038         state.updateFlag(loc, true);
1039       }
1040     }
1041     state.setWriteEffect(loc);
1042     // System.out.println("# WRITE CURR=" + curr);
1043
1044   }
1045
1046   private boolean overwrittenAllSharedConcreteLocation(NTuple<Descriptor> hp, Location loc,
1047       Set<Descriptor> writtenSet) {
1048
1049     Hashtable<Location, Set<Descriptor>> mapLocToDescSet =
1050         mapHeapPathToLocSharedDescReadSet.get(hp);
1051
1052     if (mapLocToDescSet != null) {
1053       Set<Descriptor> descSet = mapLocToDescSet.get(loc);
1054       if (writtenSet.containsAll(descSet)) {
1055         return true;
1056       } else {
1057         return false;
1058       }
1059     } else {
1060       return false;
1061     }
1062   }
1063
1064   private void readLocation(ClearingSummary curr, NTuple<Descriptor> hp, Location loc, Descriptor d) {
1065     // remove reading var x from written set
1066     // System.out.println("# READ LOC hp=" + hp + " d=" + d + " loc=" + loc);
1067     if (loc != null && hasReadingEffectOnSharedLocation(hp, loc, d)) {
1068       SharedStatus state = getState(curr, hp);
1069       state.removeVar(loc, d);
1070     }
1071     // System.out.println("# READ CURR=" + curr);
1072   }
1073
1074   private SharedStatus getState(ClearingSummary curr, NTuple<Descriptor> hp) {
1075     SharedStatus state = curr.get(hp);
1076     if (state == null) {
1077       state = new SharedStatus();
1078       curr.put(hp, state);
1079     }
1080     return state;
1081   }
1082
1083   private void writtenAnalyis() {
1084     // perform second stage analysis: intraprocedural analysis ensure that
1085     // all
1086     // variables are definitely written in-between the same read
1087
1088     // First, identify ssjava loop entrace
1089     FlatMethod fm = state.getMethodFlat(methodContainingSSJavaLoop);
1090     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
1091     flatNodesToVisit.add(fm);
1092
1093     LoopFinder loopFinder = new LoopFinder(fm);
1094
1095     while (!flatNodesToVisit.isEmpty()) {
1096       FlatNode fn = flatNodesToVisit.iterator().next();
1097       flatNodesToVisit.remove(fn);
1098
1099       String label = (String) state.fn2labelMap.get(fn);
1100       if (label != null) {
1101
1102         if (label.equals(ssjava.SSJAVA)) {
1103           ssjavaLoopEntrance = fn;
1104           break;
1105         }
1106       }
1107
1108       for (int i = 0; i < fn.numNext(); i++) {
1109         FlatNode nn = fn.getNext(i);
1110         flatNodesToVisit.add(nn);
1111       }
1112     }
1113
1114     assert ssjavaLoopEntrance != null;
1115
1116     // assume that ssjava loop is top-level loop in method, not nested loop
1117     Set nestedLoop = loopFinder.nestedLoops();
1118     for (Iterator loopIter = nestedLoop.iterator(); loopIter.hasNext();) {
1119       LoopFinder lf = (LoopFinder) loopIter.next();
1120       if (lf.loopEntrances().iterator().next().equals(ssjavaLoopEntrance)) {
1121         ssjavaLoop = lf;
1122       }
1123     }
1124
1125     assert ssjavaLoop != null;
1126
1127     writtenAnalysis_analyzeLoop();
1128
1129     if (debugcount > 0) {
1130       throw new Error();
1131     }
1132
1133   }
1134
1135   private void writtenAnalysis_analyzeLoop() {
1136
1137     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
1138     flatNodesToVisit.add(ssjavaLoopEntrance);
1139
1140     loopIncElements = (Set<FlatNode>) ssjavaLoop.loopIncElements();
1141
1142     while (!flatNodesToVisit.isEmpty()) {
1143       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
1144       flatNodesToVisit.remove(fn);
1145
1146       Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>> prev =
1147           definitelyWrittenResults.get(fn);
1148
1149       Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>> curr =
1150           new Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>>();
1151       for (int i = 0; i < fn.numPrev(); i++) {
1152         FlatNode nn = fn.getPrev(i);
1153         Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>> dwIn =
1154             definitelyWrittenResults.get(nn);
1155         if (dwIn != null) {
1156           merge(curr, dwIn);
1157         }
1158       }
1159
1160       writtenAnalysis_nodeAction(fn, curr, ssjavaLoopEntrance);
1161
1162       // if a new result, schedule forward nodes for analysis
1163       if (!curr.equals(prev)) {
1164         definitelyWrittenResults.put(fn, curr);
1165
1166         for (int i = 0; i < fn.numNext(); i++) {
1167           FlatNode nn = fn.getNext(i);
1168           if (loopIncElements.contains(nn)) {
1169             flatNodesToVisit.add(nn);
1170           }
1171
1172         }
1173       }
1174     }
1175   }
1176
1177   private void writtenAnalysis_nodeAction(FlatNode fn,
1178       Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>> curr, FlatNode loopEntrance) {
1179
1180     if (fn.equals(loopEntrance)) {
1181       // it reaches loop entrance: changes all flag to true
1182       Set<NTuple<Descriptor>> keySet = curr.keySet();
1183       for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
1184         NTuple<Descriptor> key = (NTuple<Descriptor>) iterator.next();
1185         Hashtable<FlatNode, Boolean> pair = curr.get(key);
1186         if (pair != null) {
1187           Set<FlatNode> pairKeySet = pair.keySet();
1188           for (Iterator iterator2 = pairKeySet.iterator(); iterator2.hasNext();) {
1189             FlatNode pairKey = (FlatNode) iterator2.next();
1190             pair.put(pairKey, Boolean.TRUE);
1191           }
1192         }
1193       }
1194     } else {
1195       TempDescriptor lhs;
1196       TempDescriptor rhs;
1197       FieldDescriptor fld;
1198
1199       switch (fn.kind()) {
1200       case FKind.FlatOpNode: {
1201         FlatOpNode fon = (FlatOpNode) fn;
1202         lhs = fon.getDest();
1203         rhs = fon.getLeft();
1204
1205         NTuple<Descriptor> rhsHeapPath = computePath(rhs);
1206         if (!rhs.getType().isImmutable()) {
1207           mapHeapPath.put(lhs, rhsHeapPath);
1208         } else {
1209           if (fon.getOp().getOp() == Operation.ASSIGN) {
1210             // read(rhs)
1211             readValue(fn, rhsHeapPath, curr);
1212           }
1213           // write(lhs)
1214           NTuple<Descriptor> lhsHeapPath = computePath(lhs);
1215           removeHeapPath(curr, lhsHeapPath);
1216         }
1217       }
1218         break;
1219
1220       case FKind.FlatLiteralNode: {
1221         FlatLiteralNode fln = (FlatLiteralNode) fn;
1222         lhs = fln.getDst();
1223
1224         // write(lhs)
1225         NTuple<Descriptor> lhsHeapPath = computePath(lhs);
1226         removeHeapPath(curr, lhsHeapPath);
1227
1228       }
1229         break;
1230
1231       case FKind.FlatFieldNode:
1232       case FKind.FlatElementNode: {
1233
1234         if (fn.kind() == FKind.FlatFieldNode) {
1235           FlatFieldNode ffn = (FlatFieldNode) fn;
1236           lhs = ffn.getDst();
1237           rhs = ffn.getSrc();
1238           fld = ffn.getField();
1239         } else {
1240           FlatElementNode fen = (FlatElementNode) fn;
1241           lhs = fen.getDst();
1242           rhs = fen.getSrc();
1243           TypeDescriptor td = rhs.getType().dereference();
1244           fld = getArrayField(td);
1245         }
1246
1247         if (fld.isFinal() /* && fld.isStatic() */) {
1248           // if field is final and static, no need to check
1249           break;
1250         }
1251
1252         // read field
1253         NTuple<Descriptor> srcHeapPath = mapHeapPath.get(rhs);
1254         NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>(srcHeapPath.getList());
1255         fldHeapPath.add(fld);
1256
1257         if (fld.getType().isImmutable()) {
1258           readValue(fn, fldHeapPath, curr);
1259         }
1260
1261         // propagate rhs's heap path to the lhs
1262         mapHeapPath.put(lhs, fldHeapPath);
1263
1264       }
1265         break;
1266
1267       case FKind.FlatSetFieldNode:
1268       case FKind.FlatSetElementNode: {
1269
1270         if (fn.kind() == FKind.FlatSetFieldNode) {
1271           FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
1272           lhs = fsfn.getDst();
1273           fld = fsfn.getField();
1274         } else {
1275           FlatSetElementNode fsen = (FlatSetElementNode) fn;
1276           lhs = fsen.getDst();
1277           rhs = fsen.getSrc();
1278           TypeDescriptor td = lhs.getType().dereference();
1279           fld = getArrayField(td);
1280         }
1281
1282         // write(field)
1283         NTuple<Descriptor> lhsHeapPath = computePath(lhs);
1284         NTuple<Descriptor> fldHeapPath = new NTuple<Descriptor>(lhsHeapPath.getList());
1285         fldHeapPath.add(fld);
1286         removeHeapPath(curr, fldHeapPath);
1287
1288       }
1289         break;
1290
1291       case FKind.FlatCall: {
1292         FlatCall fc = (FlatCall) fn;
1293
1294         bindHeapPathCallerArgWithCaleeParam(fc);
1295         // add <hp,statement,false> in which hp is an element of
1296         // READ_bound set
1297         // of callee: callee has 'read' requirement!
1298
1299         for (Iterator iterator = calleeUnionBoundReadSet.iterator(); iterator.hasNext();) {
1300           NTuple<Descriptor> read = (NTuple<Descriptor>) iterator.next();
1301           Hashtable<FlatNode, Boolean> gen = curr.get(read);
1302           if (gen == null) {
1303             gen = new Hashtable<FlatNode, Boolean>();
1304             curr.put(read, gen);
1305           }
1306           Boolean currentStatus = gen.get(fn);
1307           if (currentStatus == null) {
1308             gen.put(fn, Boolean.FALSE);
1309           } else {
1310             checkFlag(currentStatus.booleanValue(), fn, read);
1311           }
1312         }
1313
1314         // removes <hp,statement,flag> if hp is an element of
1315         // OVERWRITE_bound
1316         // set of callee. it means that callee will overwrite it
1317         for (Iterator iterator = calleeIntersectBoundOverWriteSet.iterator(); iterator.hasNext();) {
1318           NTuple<Descriptor> write = (NTuple<Descriptor>) iterator.next();
1319           removeHeapPath(curr, write);
1320         }
1321       }
1322         break;
1323
1324       }
1325     }
1326
1327   }
1328
1329   private void readValue(FlatNode fn, NTuple<Descriptor> hp,
1330       Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>> curr) {
1331     Hashtable<FlatNode, Boolean> gen = curr.get(hp);
1332     if (gen == null) {
1333       gen = new Hashtable<FlatNode, Boolean>();
1334       curr.put(hp, gen);
1335     }
1336     Boolean currentStatus = gen.get(fn);
1337     if (currentStatus == null) {
1338       gen.put(fn, Boolean.FALSE);
1339     } else {
1340       checkFlag(currentStatus.booleanValue(), fn, hp);
1341     }
1342
1343   }
1344
1345   private void removeHeapPath(Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>> curr,
1346       NTuple<Descriptor> hp) {
1347
1348     // removes all of heap path that starts with prefix 'hp'
1349     // since any reference overwrite along heap path gives overwriting side
1350     // effects on the value
1351
1352     Set<NTuple<Descriptor>> keySet = curr.keySet();
1353     for (Iterator<NTuple<Descriptor>> iter = keySet.iterator(); iter.hasNext();) {
1354       NTuple<Descriptor> key = iter.next();
1355       if (key.startsWith(hp)) {
1356         curr.put(key, new Hashtable<FlatNode, Boolean>());
1357       }
1358     }
1359
1360   }
1361
1362   private void bindHeapPathCallerArgWithCaleeParam(FlatCall fc) {
1363     // compute all possible callee set
1364     // transform all READ/OVERWRITE set from the any possible
1365     // callees to the
1366     // caller
1367     calleeUnionBoundReadSet.clear();
1368     calleeIntersectBoundOverWriteSet.clear();
1369     calleeBoundWriteSet.clear();
1370
1371     if (ssjava.isSSJavaUtil(fc.getMethod().getClassDesc())) {
1372       // ssjava util case!
1373       // have write effects on the first argument
1374       TempDescriptor arg = fc.getArg(0);
1375       NTuple<Descriptor> argHeapPath = computePath(arg);
1376       calleeIntersectBoundOverWriteSet.add(argHeapPath);
1377     } else {
1378       MethodDescriptor mdCallee = fc.getMethod();
1379       // FlatMethod fmCallee = state.getMethodFlat(mdCallee);
1380       Set<MethodDescriptor> setPossibleCallees = new HashSet<MethodDescriptor>();
1381       // setPossibleCallees.addAll(callGraph.getMethods(mdCallee, typeDesc));
1382       setPossibleCallees.addAll(callGraph.getMethods(mdCallee));
1383
1384       // create mapping from arg idx to its heap paths
1385       Hashtable<Integer, NTuple<Descriptor>> mapArgIdx2CallerArgHeapPath =
1386           new Hashtable<Integer, NTuple<Descriptor>>();
1387
1388       // arg idx is starting from 'this' arg
1389       if (fc.getThis() != null) {
1390         NTuple<Descriptor> thisHeapPath = mapHeapPath.get(fc.getThis());
1391         if (thisHeapPath == null) {
1392           // method is called without creating new flat node representing 'this'
1393           thisHeapPath = new NTuple<Descriptor>();
1394           thisHeapPath.add(fc.getThis());
1395         }
1396
1397         mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(0), thisHeapPath);
1398       }
1399
1400       for (int i = 0; i < fc.numArgs(); i++) {
1401         TempDescriptor arg = fc.getArg(i);
1402         NTuple<Descriptor> argHeapPath = computePath(arg);
1403         mapArgIdx2CallerArgHeapPath.put(Integer.valueOf(i + 1), argHeapPath);
1404       }
1405
1406       for (Iterator iterator = setPossibleCallees.iterator(); iterator.hasNext();) {
1407         MethodDescriptor callee = (MethodDescriptor) iterator.next();
1408         FlatMethod calleeFlatMethod = state.getMethodFlat(callee);
1409
1410         // binding caller's args and callee's params
1411
1412         Set<NTuple<Descriptor>> calleeReadSet = mapFlatMethodToRead.get(calleeFlatMethod);
1413         if (calleeReadSet == null) {
1414           calleeReadSet = new HashSet<NTuple<Descriptor>>();
1415           mapFlatMethodToRead.put(calleeFlatMethod, calleeReadSet);
1416         }
1417
1418         Set<NTuple<Descriptor>> calleeOverWriteSet = mapFlatMethodToOverWrite.get(calleeFlatMethod);
1419
1420         if (calleeOverWriteSet == null) {
1421           calleeOverWriteSet = new HashSet<NTuple<Descriptor>>();
1422           mapFlatMethodToOverWrite.put(calleeFlatMethod, calleeOverWriteSet);
1423         }
1424
1425         Set<NTuple<Descriptor>> calleeWriteSet = mapFlatMethodToWrite.get(calleeFlatMethod);
1426
1427         if (calleeWriteSet == null) {
1428           calleeWriteSet = new HashSet<NTuple<Descriptor>>();
1429           mapFlatMethodToWrite.put(calleeFlatMethod, calleeWriteSet);
1430         }
1431
1432         Hashtable<Integer, TempDescriptor> mapParamIdx2ParamTempDesc =
1433             new Hashtable<Integer, TempDescriptor>();
1434         int offset = 0;
1435         if (calleeFlatMethod.getMethod().isStatic()) {
1436           // static method does not have implicit 'this' arg
1437           offset = 1;
1438         }
1439         for (int i = 0; i < calleeFlatMethod.numParameters(); i++) {
1440           TempDescriptor param = calleeFlatMethod.getParameter(i);
1441           mapParamIdx2ParamTempDesc.put(Integer.valueOf(i + offset), param);
1442         }
1443
1444         Set<NTuple<Descriptor>> calleeBoundReadSet =
1445             bindSet(calleeReadSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath);
1446         // union of the current read set and the current callee's
1447         // read set
1448         calleeUnionBoundReadSet.addAll(calleeBoundReadSet);
1449         Set<NTuple<Descriptor>> calleeBoundOverWriteSet =
1450             bindSet(calleeOverWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath);
1451         // intersection of the current overwrite set and the current
1452         // callee's
1453         // overwrite set
1454         merge(calleeIntersectBoundOverWriteSet, calleeBoundOverWriteSet);
1455
1456         Set<NTuple<Descriptor>> boundWriteSetFromCallee =
1457             bindSet(calleeWriteSet, mapParamIdx2ParamTempDesc, mapArgIdx2CallerArgHeapPath);
1458         calleeBoundWriteSet.addAll(boundWriteSetFromCallee);
1459       }
1460
1461     }
1462
1463   }
1464
1465   private void checkFlag(boolean booleanValue, FlatNode fn, NTuple<Descriptor> hp) {
1466     if (booleanValue) {
1467       // the definitely written analysis only takes care about locations that
1468       // are written to inside of the SSJava loop
1469       for (Iterator iterator = calleeBoundWriteSet.iterator(); iterator.hasNext();) {
1470         NTuple<Descriptor> write = (NTuple<Descriptor>) iterator.next();
1471         if (hp.startsWith(write)) {
1472           // it has write effect!
1473           // throw new Error(
1474           System.out
1475               .println("###"
1476                   + "There is a variable, which is reachable through references "
1477                   + hp
1478                   + ", who comes back to the same read statement without being overwritten at the out-most iteration at "
1479                   + methodContainingSSJavaLoop.getClassDesc().getSourceFileName() + "::"
1480                   + fn.getNumLine());
1481           debugcount++;
1482         }
1483       }
1484     }
1485   }
1486
1487   private void merge(Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>> curr,
1488       Hashtable<NTuple<Descriptor>, Hashtable<FlatNode, Boolean>> in) {
1489
1490     Set<NTuple<Descriptor>> inKeySet = in.keySet();
1491     for (Iterator iterator = inKeySet.iterator(); iterator.hasNext();) {
1492       NTuple<Descriptor> inKey = (NTuple<Descriptor>) iterator.next();
1493       Hashtable<FlatNode, Boolean> inPair = in.get(inKey);
1494
1495       Set<FlatNode> pairKeySet = inPair.keySet();
1496       for (Iterator iterator2 = pairKeySet.iterator(); iterator2.hasNext();) {
1497         FlatNode pairKey = (FlatNode) iterator2.next();
1498         Boolean inFlag = inPair.get(pairKey);
1499
1500         Hashtable<FlatNode, Boolean> currPair = curr.get(inKey);
1501         if (currPair == null) {
1502           currPair = new Hashtable<FlatNode, Boolean>();
1503           curr.put(inKey, currPair);
1504         }
1505
1506         Boolean currFlag = currPair.get(pairKey);
1507         // by default, flag is set by false
1508         if (currFlag == null) {
1509           currFlag = Boolean.FALSE;
1510         }
1511         currFlag = Boolean.valueOf(inFlag.booleanValue() | currFlag.booleanValue());
1512         currPair.put(pairKey, currFlag);
1513       }
1514
1515     }
1516
1517   }
1518
1519   private void methodReadOverWriteAnalysis() {
1520     // perform method READ/OVERWRITE analysis
1521     Set<MethodDescriptor> methodDescriptorsToAnalyze = new HashSet<MethodDescriptor>();
1522     methodDescriptorsToAnalyze.addAll(ssjava.getAnnotationRequireSet());
1523
1524     sortedDescriptors = topologicalSort(methodDescriptorsToAnalyze);
1525
1526     LinkedList<MethodDescriptor> descriptorListToAnalyze =
1527         (LinkedList<MethodDescriptor>) sortedDescriptors.clone();
1528
1529     // no need to analyze method having ssjava loop
1530     // methodContainingSSJavaLoop = descriptorListToAnalyze.removeFirst();
1531     methodContainingSSJavaLoop = ssjava.getMethodContainingSSJavaLoop();
1532
1533     // current descriptors to visit in fixed-point interprocedural analysis,
1534     // prioritized by
1535     // dependency in the call graph
1536     methodDescriptorsToVisitStack.clear();
1537
1538     Set<MethodDescriptor> methodDescriptorToVistSet = new HashSet<MethodDescriptor>();
1539     methodDescriptorToVistSet.addAll(descriptorListToAnalyze);
1540
1541     while (!descriptorListToAnalyze.isEmpty()) {
1542       MethodDescriptor md = descriptorListToAnalyze.removeFirst();
1543       methodDescriptorsToVisitStack.add(md);
1544     }
1545
1546     // analyze scheduled methods until there are no more to visit
1547     while (!methodDescriptorsToVisitStack.isEmpty()) {
1548       // start to analyze leaf node
1549       MethodDescriptor md = methodDescriptorsToVisitStack.pop();
1550       FlatMethod fm = state.getMethodFlat(md);
1551
1552       Set<NTuple<Descriptor>> readSet = new HashSet<NTuple<Descriptor>>();
1553       Set<NTuple<Descriptor>> overWriteSet = new HashSet<NTuple<Descriptor>>();
1554       Set<NTuple<Descriptor>> writeSet = new HashSet<NTuple<Descriptor>>();
1555
1556       methodReadOverWrite_analyzeMethod(fm, readSet, overWriteSet, writeSet);
1557
1558       Set<NTuple<Descriptor>> prevRead = mapFlatMethodToRead.get(fm);
1559       Set<NTuple<Descriptor>> prevOverWrite = mapFlatMethodToOverWrite.get(fm);
1560       Set<NTuple<Descriptor>> prevWrite = mapFlatMethodToWrite.get(fm);
1561
1562       if (!(readSet.equals(prevRead) && overWriteSet.equals(prevOverWrite) && writeSet
1563           .equals(prevWrite))) {
1564         mapFlatMethodToRead.put(fm, readSet);
1565         mapFlatMethodToOverWrite.put(fm, overWriteSet);
1566         mapFlatMethodToWrite.put(fm, writeSet);
1567
1568         // results for callee changed, so enqueue dependents caller for
1569         // further
1570         // analysis
1571         Iterator<MethodDescriptor> depsItr = getDependents(md).iterator();
1572         while (depsItr.hasNext()) {
1573           MethodDescriptor methodNext = depsItr.next();
1574           if (!methodDescriptorsToVisitStack.contains(methodNext)
1575               && methodDescriptorToVistSet.contains(methodNext)) {
1576             methodDescriptorsToVisitStack.add(methodNext);
1577           }
1578
1579         }
1580
1581       }
1582
1583     }
1584
1585   }
1586
1587   private void methodReadOverWrite_analyzeMethod(FlatMethod fm, Set<NTuple<Descriptor>> readSet,
1588       Set<NTuple<Descriptor>> overWriteSet, Set<NTuple<Descriptor>> writeSet) {
1589     if (state.SSJAVADEBUG) {
1590       System.out.println("Definitely written Analyzing: " + fm);
1591     }
1592
1593     // intraprocedural analysis
1594     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
1595     flatNodesToVisit.add(fm);
1596
1597     while (!flatNodesToVisit.isEmpty()) {
1598       FlatNode fn = flatNodesToVisit.iterator().next();
1599       flatNodesToVisit.remove(fn);
1600
1601       Set<NTuple<Descriptor>> curr = new HashSet<NTuple<Descriptor>>();
1602
1603       for (int i = 0; i < fn.numPrev(); i++) {
1604         FlatNode prevFn = fn.getPrev(i);
1605         Set<NTuple<Descriptor>> in = mapFlatNodeToWrittenSet.get(prevFn);
1606         if (in != null) {
1607           merge(curr, in);
1608         }
1609       }
1610
1611       methodReadOverWrite_nodeActions(fn, curr, readSet, overWriteSet, writeSet);
1612
1613       Set<NTuple<Descriptor>> writtenSetPrev = mapFlatNodeToWrittenSet.get(fn);
1614       if (!curr.equals(writtenSetPrev)) {
1615         mapFlatNodeToWrittenSet.put(fn, curr);
1616         for (int i = 0; i < fn.numNext(); i++) {
1617           FlatNode nn = fn.getNext(i);
1618           flatNodesToVisit.add(nn);
1619         }
1620       }
1621
1622     }
1623
1624   }
1625
1626   private void methodReadOverWrite_nodeActions(FlatNode fn, Set<NTuple<Descriptor>> writtenSet,
1627       Set<NTuple<Descriptor>> readSet, Set<NTuple<Descriptor>> overWriteSet,
1628       Set<NTuple<Descriptor>> writeSet) {
1629     TempDescriptor lhs;
1630     TempDescriptor rhs;
1631     FieldDescriptor fld;
1632
1633     switch (fn.kind()) {
1634     case FKind.FlatMethod: {
1635
1636       // set up initial heap paths for method parameters
1637       FlatMethod fm = (FlatMethod) fn;
1638       for (int i = 0; i < fm.numParameters(); i++) {
1639         TempDescriptor param = fm.getParameter(i);
1640         NTuple<Descriptor> heapPath = new NTuple<Descriptor>();
1641         heapPath.add(param);
1642         mapHeapPath.put(param, heapPath);
1643       }
1644     }
1645       break;
1646
1647     case FKind.FlatOpNode: {
1648       FlatOpNode fon = (FlatOpNode) fn;
1649       // for a normal assign node, need to propagate lhs's heap path to
1650       // rhs
1651       if (fon.getOp().getOp() == Operation.ASSIGN) {
1652         rhs = fon.getLeft();
1653         lhs = fon.getDest();
1654
1655         NTuple<Descriptor> rhsHeapPath = mapHeapPath.get(rhs);
1656         if (rhsHeapPath != null) {
1657           mapHeapPath.put(lhs, mapHeapPath.get(rhs));
1658         }
1659
1660       }
1661     }
1662       break;
1663
1664     case FKind.FlatElementNode:
1665     case FKind.FlatFieldNode: {
1666
1667       // y=x.f;
1668
1669       if (fn.kind() == FKind.FlatFieldNode) {
1670         FlatFieldNode ffn = (FlatFieldNode) fn;
1671         lhs = ffn.getDst();
1672         rhs = ffn.getSrc();
1673         fld = ffn.getField();
1674       } else {
1675         FlatElementNode fen = (FlatElementNode) fn;
1676         lhs = fen.getDst();
1677         rhs = fen.getSrc();
1678         TypeDescriptor td = rhs.getType().dereference();
1679         fld = getArrayField(td);
1680       }
1681
1682       if (fld.isFinal() /* && fld.isStatic() */) {
1683         // if field is final and static, no need to check
1684         break;
1685       }
1686
1687       // set up heap path
1688       NTuple<Descriptor> srcHeapPath = mapHeapPath.get(rhs);
1689       if (srcHeapPath != null) {
1690         // if lhs srcHeapPath is null, it means that it is not reachable from
1691         // callee's parameters. so just ignore it
1692
1693         NTuple<Descriptor> readingHeapPath = new NTuple<Descriptor>(srcHeapPath.getList());
1694         readingHeapPath.add(fld);
1695         mapHeapPath.put(lhs, readingHeapPath);
1696
1697         // read (x.f)
1698         if (fld.getType().isImmutable()) {
1699           // if WT doesnot have hp(x.f), add hp(x.f) to READ
1700           if (!writtenSet.contains(readingHeapPath)) {
1701             readSet.add(readingHeapPath);
1702           }
1703         }
1704
1705         // no need to kill hp(x.f) from WT
1706       }
1707
1708     }
1709       break;
1710
1711     case FKind.FlatSetFieldNode:
1712     case FKind.FlatSetElementNode: {
1713
1714       // x.f=y;
1715
1716       if (fn.kind() == FKind.FlatSetFieldNode) {
1717         FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
1718         lhs = fsfn.getDst();
1719         fld = fsfn.getField();
1720         rhs = fsfn.getSrc();
1721       } else {
1722         FlatSetElementNode fsen = (FlatSetElementNode) fn;
1723         lhs = fsen.getDst();
1724         rhs = fsen.getSrc();
1725         TypeDescriptor td = lhs.getType().dereference();
1726         fld = getArrayField(td);
1727       }
1728
1729       // set up heap path
1730       NTuple<Descriptor> lhsHeapPath = mapHeapPath.get(lhs);
1731       if (lhsHeapPath != null) {
1732         // if lhs heap path is null, it means that it is not reachable from
1733         // callee's parameters. so just ignore it
1734         NTuple<Descriptor> newHeapPath = new NTuple<Descriptor>(lhsHeapPath.getList());
1735         newHeapPath.add(fld);
1736         mapHeapPath.put(fld, newHeapPath);
1737
1738         // write(x.f)
1739         // need to add hp(y) to WT
1740         writtenSet.add(newHeapPath);
1741
1742         writeSet.add(newHeapPath);
1743       }
1744
1745     }
1746       break;
1747
1748     case FKind.FlatCall: {
1749
1750       FlatCall fc = (FlatCall) fn;
1751
1752       bindHeapPathCallerArgWithCaleeParam(fc);
1753
1754       // add heap path, which is an element of READ_bound set and is not
1755       // an
1756       // element of WT set, to the caller's READ set
1757       for (Iterator iterator = calleeUnionBoundReadSet.iterator(); iterator.hasNext();) {
1758         NTuple<Descriptor> read = (NTuple<Descriptor>) iterator.next();
1759         if (!writtenSet.contains(read)) {
1760           readSet.add(read);
1761         }
1762       }
1763
1764       // add heap path, which is an element of OVERWRITE_bound set, to the
1765       // caller's WT set
1766       for (Iterator iterator = calleeIntersectBoundOverWriteSet.iterator(); iterator.hasNext();) {
1767         NTuple<Descriptor> write = (NTuple<Descriptor>) iterator.next();
1768         writtenSet.add(write);
1769       }
1770
1771       // add heap path, which is an element of WRITE_BOUND set, to the
1772       // caller's writeSet
1773       for (Iterator iterator = calleeBoundWriteSet.iterator(); iterator.hasNext();) {
1774         NTuple<Descriptor> write = (NTuple<Descriptor>) iterator.next();
1775         writeSet.add(write);
1776       }
1777
1778     }
1779       break;
1780
1781     case FKind.FlatExit: {
1782       // merge the current written set with OVERWRITE set
1783       merge(overWriteSet, writtenSet);
1784     }
1785       break;
1786
1787     }
1788
1789   }
1790
1791   static public FieldDescriptor getArrayField(TypeDescriptor td) {
1792     FieldDescriptor fd = mapTypeToArrayField.get(td);
1793     if (fd == null) {
1794       fd =
1795           new FieldDescriptor(new Modifiers(Modifiers.PUBLIC), td, arrayElementFieldName, null,
1796               false);
1797       mapTypeToArrayField.put(td, fd);
1798     }
1799     return fd;
1800   }
1801
1802   private void mergeSharedLocationAnaylsis(ClearingSummary curr, Set<ClearingSummary> inSet) {
1803     if (inSet.size() == 0) {
1804       return;
1805     }
1806     Hashtable<Pair<NTuple<Descriptor>, Location>, Boolean> mapHeapPathLoc2Flag =
1807         new Hashtable<Pair<NTuple<Descriptor>, Location>, Boolean>();
1808
1809     for (Iterator inIterator = inSet.iterator(); inIterator.hasNext();) {
1810
1811       ClearingSummary inTable = (ClearingSummary) inIterator.next();
1812
1813       Set<NTuple<Descriptor>> keySet = inTable.keySet();
1814
1815       for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
1816         NTuple<Descriptor> hpKey = (NTuple<Descriptor>) iterator.next();
1817         SharedStatus inState = inTable.get(hpKey);
1818         SharedStatus currState = curr.get(hpKey);
1819         if (currState == null) {
1820           currState = new SharedStatus();
1821           curr.put(hpKey, currState);
1822         }
1823
1824         currState.merge(inState);
1825
1826         Set<Location> locSet = inState.getMap().keySet();
1827         for (Iterator iterator2 = locSet.iterator(); iterator2.hasNext();) {
1828           Location loc = (Location) iterator2.next();
1829           Pair<Set<Descriptor>, Boolean> pair = inState.getMap().get(loc);
1830           boolean inFlag = pair.getSecond().booleanValue();
1831
1832           Pair<NTuple<Descriptor>, Location> flagKey =
1833               new Pair<NTuple<Descriptor>, Location>(hpKey, loc);
1834           Boolean current = mapHeapPathLoc2Flag.get(flagKey);
1835           if (current == null) {
1836             current = new Boolean(true);
1837           }
1838           boolean newInFlag = current.booleanValue() & inFlag;
1839           mapHeapPathLoc2Flag.put(flagKey, Boolean.valueOf(newInFlag));
1840         }
1841
1842       }
1843
1844     }
1845
1846     // merge flag status
1847     Set<NTuple<Descriptor>> hpKeySet = curr.keySet();
1848     for (Iterator iterator = hpKeySet.iterator(); iterator.hasNext();) {
1849       NTuple<Descriptor> hpKey = (NTuple<Descriptor>) iterator.next();
1850       SharedStatus currState = curr.get(hpKey);
1851       Set<Location> locKeySet = currState.getMap().keySet();
1852       for (Iterator iterator2 = locKeySet.iterator(); iterator2.hasNext();) {
1853         Location locKey = (Location) iterator2.next();
1854         Pair<Set<Descriptor>, Boolean> pair = currState.getMap().get(locKey);
1855         boolean currentFlag = pair.getSecond().booleanValue();
1856         Boolean inFlag = mapHeapPathLoc2Flag.get(new Pair(hpKey, locKey));
1857         if (inFlag != null) {
1858           boolean newFlag = currentFlag | inFlag.booleanValue();
1859           if (currentFlag != newFlag) {
1860             currState.getMap().put(locKey, new Pair(pair.getFirst(), new Boolean(newFlag)));
1861           }
1862         }
1863       }
1864     }
1865
1866   }
1867
1868   private void merge(Set<NTuple<Descriptor>> curr, Set<NTuple<Descriptor>> in) {
1869     if (curr.isEmpty()) {
1870       // WrittenSet has a special initial value which covers all possible
1871       // elements
1872       // For the first time of intersection, we can take all previous set
1873       curr.addAll(in);
1874     } else {
1875       // otherwise, current set is the intersection of the two sets
1876       curr.retainAll(in);
1877     }
1878
1879   }
1880
1881   // combine two heap path
1882   private NTuple<Descriptor> combine(NTuple<Descriptor> callerIn, NTuple<Descriptor> calleeIn) {
1883     NTuple<Descriptor> combined = new NTuple<Descriptor>();
1884
1885     for (int i = 0; i < callerIn.size(); i++) {
1886       combined.add(callerIn.get(i));
1887     }
1888
1889     // the first element of callee's heap path represents parameter
1890     // so we skip the first one since it is already added from caller's heap
1891     // path
1892     for (int i = 1; i < calleeIn.size(); i++) {
1893       combined.add(calleeIn.get(i));
1894     }
1895
1896     return combined;
1897   }
1898
1899   private Set<NTuple<Descriptor>> bindSet(Set<NTuple<Descriptor>> calleeSet,
1900       Hashtable<Integer, TempDescriptor> mapParamIdx2ParamTempDesc,
1901       Hashtable<Integer, NTuple<Descriptor>> mapCallerArgIdx2HeapPath) {
1902
1903     Set<NTuple<Descriptor>> boundedCalleeSet = new HashSet<NTuple<Descriptor>>();
1904
1905     Set<Integer> keySet = mapCallerArgIdx2HeapPath.keySet();
1906     for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
1907       Integer idx = (Integer) iterator.next();
1908
1909       NTuple<Descriptor> callerArgHeapPath = mapCallerArgIdx2HeapPath.get(idx);
1910       TempDescriptor calleeParam = mapParamIdx2ParamTempDesc.get(idx);
1911       for (Iterator iterator2 = calleeSet.iterator(); iterator2.hasNext();) {
1912         NTuple<Descriptor> element = (NTuple<Descriptor>) iterator2.next();
1913         if (element.startsWith(calleeParam)) {
1914           NTuple<Descriptor> boundElement = combine(callerArgHeapPath, element);
1915           boundedCalleeSet.add(boundElement);
1916         }
1917
1918       }
1919
1920     }
1921     return boundedCalleeSet;
1922
1923   }
1924
1925   // Borrowed it from disjoint analysis
1926   private LinkedList<MethodDescriptor> topologicalSort(Set<MethodDescriptor> toSort) {
1927
1928     Set<MethodDescriptor> discovered = new HashSet<MethodDescriptor>();
1929
1930     LinkedList<MethodDescriptor> sorted = new LinkedList<MethodDescriptor>();
1931
1932     Iterator<MethodDescriptor> itr = toSort.iterator();
1933     while (itr.hasNext()) {
1934       MethodDescriptor d = itr.next();
1935
1936       if (!discovered.contains(d)) {
1937         dfsVisit(d, toSort, sorted, discovered);
1938       }
1939     }
1940
1941     return sorted;
1942   }
1943
1944   // While we're doing DFS on call graph, remember
1945   // dependencies for efficient queuing of methods
1946   // during interprocedural analysis:
1947   //
1948   // a dependent of a method decriptor d for this analysis is:
1949   // 1) a method or task that invokes d
1950   // 2) in the descriptorsToAnalyze set
1951   private void dfsVisit(MethodDescriptor md, Set<MethodDescriptor> toSort,
1952       LinkedList<MethodDescriptor> sorted, Set<MethodDescriptor> discovered) {
1953
1954     discovered.add(md);
1955
1956     Iterator itr = callGraph.getCallerSet(md).iterator();
1957     while (itr.hasNext()) {
1958       MethodDescriptor dCaller = (MethodDescriptor) itr.next();
1959       // only consider callers in the original set to analyze
1960       if (!toSort.contains(dCaller)) {
1961         continue;
1962       }
1963       if (!discovered.contains(dCaller)) {
1964         addDependent(md, // callee
1965             dCaller // caller
1966         );
1967
1968         dfsVisit(dCaller, toSort, sorted, discovered);
1969       }
1970     }
1971
1972     // for leaf-nodes last now!
1973     sorted.addLast(md);
1974   }
1975
1976   // a dependent of a method decriptor d for this analysis is:
1977   // 1) a method or task that invokes d
1978   // 2) in the descriptorsToAnalyze set
1979   private void addDependent(MethodDescriptor callee, MethodDescriptor caller) {
1980     Set<MethodDescriptor> deps = mapDescriptorToSetDependents.get(callee);
1981     if (deps == null) {
1982       deps = new HashSet<MethodDescriptor>();
1983     }
1984     deps.add(caller);
1985     mapDescriptorToSetDependents.put(callee, deps);
1986   }
1987
1988   private Set<MethodDescriptor> getDependents(MethodDescriptor callee) {
1989     Set<MethodDescriptor> deps = mapDescriptorToSetDependents.get(callee);
1990     if (deps == null) {
1991       deps = new HashSet<MethodDescriptor>();
1992       mapDescriptorToSetDependents.put(callee, deps);
1993     }
1994     return deps;
1995   }
1996
1997   private NTuple<Descriptor> computePath(TempDescriptor td) {
1998     // generate proper path fot input td
1999     // if td is local variable, it just generate one element tuple path
2000     if (mapHeapPath.containsKey(td)) {
2001       return mapHeapPath.get(td);
2002     } else {
2003       NTuple<Descriptor> path = new NTuple<Descriptor>();
2004       path.add(td);
2005       return path;
2006     }
2007   }
2008
2009 }