changes.
[IRC.git] / Robust / src / Analysis / SSJava / SSJavaAnalysis.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.ArrayList;
7 import java.util.Collections;
8 import java.util.Comparator;
9 import java.util.HashSet;
10 import java.util.Hashtable;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Set;
14 import java.util.StringTokenizer;
15 import java.util.Vector;
16
17 import Analysis.CallGraph.CallGraph;
18 import Analysis.Loops.GlobalFieldType;
19 import Analysis.Loops.LoopOptimize;
20 import Analysis.Loops.LoopTerminate;
21 import IR.AnnotationDescriptor;
22 import IR.ClassDescriptor;
23 import IR.Descriptor;
24 import IR.MethodDescriptor;
25 import IR.State;
26 import IR.SymbolTable;
27 import IR.TypeUtil;
28 import IR.Flat.BuildFlat;
29 import IR.Flat.FlatMethod;
30 import Util.Pair;
31
32 public class SSJavaAnalysis {
33
34   public static final String SSJAVA = "SSJAVA";
35   public static final String LATTICE = "LATTICE";
36   public static final String METHODDEFAULT = "METHODDEFAULT";
37   public static final String THISLOC = "THISLOC";
38   public static final String GLOBALLOC = "GLOBALLOC";
39   public static final String RETURNLOC = "RETURNLOC";
40   public static final String LOC = "LOC";
41   public static final String DELTA = "DELTA";
42   public static final String TERMINATE = "TERMINATE";
43   public static final String DELEGATE = "DELEGATE";
44   public static final String DELEGATETHIS = "DELEGATETHIS";
45   public static final String TRUST = "TRUST";
46
47   State state;
48   TypeUtil tu;
49   FlowDownCheck flowDownChecker;
50   MethodAnnotationCheck methodAnnotationChecker;
51   BuildFlat bf;
52
53   // set containing method requires to be annoated
54   Set<MethodDescriptor> annotationRequireSet;
55
56   // class -> field lattice
57   Hashtable<ClassDescriptor, SSJavaLattice<String>> cd2lattice;
58
59   // class -> default local variable lattice
60   Hashtable<ClassDescriptor, MethodLattice<String>> cd2methodDefault;
61
62   // method -> local variable lattice
63   Hashtable<MethodDescriptor, MethodLattice<String>> md2lattice;
64
65   // method set that does not want to have loop termination analysis
66   Hashtable<MethodDescriptor, Integer> skipLoopTerminate;
67
68   // map shared location to its descriptors
69   Hashtable<Location, Set<Descriptor>> mapSharedLocation2DescriptorSet;
70
71   // set containing a class that has at least one annoated method
72   Set<ClassDescriptor> annotationRequireClassSet;
73
74   // the set of method descriptor required to check the linear type property
75   Set<MethodDescriptor> linearTypeCheckMethodSet;
76
77   // the set of method descriptors annotated as "TRUST"
78   Set<MethodDescriptor> trustWorthyMDSet;
79
80   // points to method containing SSJAVA Loop
81   private MethodDescriptor methodContainingSSJavaLoop;
82
83   CallGraph callgraph;
84
85   LinearTypeCheck checker;
86
87   public SSJavaAnalysis(State state, TypeUtil tu, BuildFlat bf, CallGraph callgraph) {
88     this.state = state;
89     this.tu = tu;
90     this.callgraph = callgraph;
91     this.cd2lattice = new Hashtable<ClassDescriptor, SSJavaLattice<String>>();
92     this.cd2methodDefault = new Hashtable<ClassDescriptor, MethodLattice<String>>();
93     this.md2lattice = new Hashtable<MethodDescriptor, MethodLattice<String>>();
94     this.annotationRequireSet = new HashSet<MethodDescriptor>();
95     this.annotationRequireClassSet = new HashSet<ClassDescriptor>();
96     this.skipLoopTerminate = new Hashtable<MethodDescriptor, Integer>();
97     this.mapSharedLocation2DescriptorSet = new Hashtable<Location, Set<Descriptor>>();
98     this.linearTypeCheckMethodSet = new HashSet<MethodDescriptor>();
99     this.bf = bf;
100     trustWorthyMDSet = new HashSet<MethodDescriptor>();
101   }
102
103   public void doCheck() {
104     doMethodAnnotationCheck();
105     // computeLinearTypeCheckMethodSet();
106     // doLinearTypeCheck();
107     // if (state.SSJAVADEBUG) {
108     // debugPrint();
109     // }
110     parseLocationAnnotation();
111     // doFlowDownCheck();
112     doDefinitelyWrittenCheck();
113     // debugDoLoopCheck();
114   }
115
116   private void debugDoLoopCheck() {
117     GlobalFieldType gft = new GlobalFieldType(callgraph, state, tu.getMain());
118     LoopOptimize lo = new LoopOptimize(gft, tu);
119
120     SymbolTable classtable = state.getClassSymbolTable();
121
122     List<ClassDescriptor> toanalyzeList = new ArrayList<ClassDescriptor>();
123     List<MethodDescriptor> toanalyzeMethodList = new ArrayList<MethodDescriptor>();
124
125     toanalyzeList.addAll(classtable.getValueSet());
126     Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
127       public int compare(ClassDescriptor o1, ClassDescriptor o2) {
128         return o1.getClassName().compareTo(o2.getClassName());
129       }
130     });
131
132     for (int i = 0; i < toanalyzeList.size(); i++) {
133       ClassDescriptor cd = toanalyzeList.get(i);
134
135       SymbolTable methodtable = cd.getMethodTable();
136       toanalyzeMethodList.clear();
137       toanalyzeMethodList.addAll(methodtable.getValueSet());
138       Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
139         public int compare(MethodDescriptor o1, MethodDescriptor o2) {
140           return o1.getSymbol().compareTo(o2.getSymbol());
141         }
142       });
143
144       for (int mdIdx = 0; mdIdx < toanalyzeMethodList.size(); mdIdx++) {
145         MethodDescriptor md = toanalyzeMethodList.get(mdIdx);
146         if (needTobeAnnotated(md)) {
147           lo.analyze(state.getMethodFlat(md));
148           doLoopTerminationCheck(lo, state.getMethodFlat(md));
149         }
150       }
151
152     }
153
154   }
155
156   public void addTrustMethod(MethodDescriptor md) {
157     trustWorthyMDSet.add(md);
158   }
159
160   public boolean isTrustMethod(MethodDescriptor md) {
161     return trustWorthyMDSet.contains(md);
162   }
163
164   private void computeLinearTypeCheckMethodSet() {
165
166     Set<MethodDescriptor> allCalledSet = callgraph.getMethodCalls(tu.getMain());
167     linearTypeCheckMethodSet.addAll(allCalledSet);
168
169     Set<MethodDescriptor> trustedSet = new HashSet<MethodDescriptor>();
170
171     for (Iterator iterator = trustWorthyMDSet.iterator(); iterator.hasNext();) {
172       MethodDescriptor trustMethod = (MethodDescriptor) iterator.next();
173       Set<MethodDescriptor> calledFromTrustMethodSet = callgraph.getMethodCalls(trustMethod);
174       trustedSet.add(trustMethod);
175       trustedSet.addAll(calledFromTrustMethodSet);
176     }
177
178     linearTypeCheckMethodSet.removeAll(trustedSet);
179
180     // if a method is called only by trusted method, no need to check linear
181     // type & flow down rule
182     for (Iterator iterator = trustedSet.iterator(); iterator.hasNext();) {
183       MethodDescriptor md = (MethodDescriptor) iterator.next();
184       Set<MethodDescriptor> callerSet = callgraph.getCallerSet(md);
185       if (!trustedSet.containsAll(callerSet) && !trustWorthyMDSet.contains(md)) {
186         linearTypeCheckMethodSet.add(md);
187       }
188     }
189
190   }
191
192   private void doLinearTypeCheck() {
193     LinearTypeCheck checker = new LinearTypeCheck(this, state);
194     checker.linearTypeCheck();
195   }
196
197   public void debugPrint() {
198     System.out.println("SSJAVA: SSJava is checking the following methods:");
199     for (Iterator<MethodDescriptor> iterator = annotationRequireSet.iterator(); iterator.hasNext();) {
200       MethodDescriptor md = iterator.next();
201       System.out.print(" " + md);
202     }
203     System.out.println();
204   }
205
206   private void doMethodAnnotationCheck() {
207     methodAnnotationChecker = new MethodAnnotationCheck(this, state, tu);
208     methodAnnotationChecker.methodAnnoatationCheck();
209     methodAnnotationChecker.methodAnnoataionInheritanceCheck();
210   }
211
212   public void doFlowDownCheck() {
213     flowDownChecker = new FlowDownCheck(this, state);
214     flowDownChecker.flowDownCheck();
215   }
216
217   public void doDefinitelyWrittenCheck() {
218     DefinitelyWrittenCheck checker = new DefinitelyWrittenCheck(this, state);
219     checker.definitelyWrittenCheck();
220   }
221
222   private void parseLocationAnnotation() {
223     Iterator it = state.getClassSymbolTable().getDescriptorsIterator();
224     while (it.hasNext()) {
225       ClassDescriptor cd = (ClassDescriptor) it.next();
226       // parsing location hierarchy declaration for the class
227       Vector<AnnotationDescriptor> classAnnotations = cd.getModifier().getAnnotations();
228       for (int i = 0; i < classAnnotations.size(); i++) {
229         AnnotationDescriptor an = classAnnotations.elementAt(i);
230         String marker = an.getMarker();
231         if (marker.equals(LATTICE)) {
232           SSJavaLattice<String> locOrder =
233               new SSJavaLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM);
234           cd2lattice.put(cd, locOrder);
235           parseClassLatticeDefinition(cd, an.getValue(), locOrder);
236
237           if (state.SSJAVADEBUG) {
238             // generate lattice dot file
239             writeLatticeDotFile(cd, locOrder);
240           }
241
242         } else if (marker.equals(METHODDEFAULT)) {
243           MethodLattice<String> locOrder =
244               new MethodLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM);
245           cd2methodDefault.put(cd, locOrder);
246           parseMethodDefaultLatticeDefinition(cd, an.getValue(), locOrder);
247         }
248       }
249
250       for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
251         MethodDescriptor md = (MethodDescriptor) method_it.next();
252         // parsing location hierarchy declaration for the method
253
254         if (needTobeAnnotated(md)) {
255           Vector<AnnotationDescriptor> methodAnnotations = md.getModifiers().getAnnotations();
256           if (methodAnnotations != null) {
257             for (int i = 0; i < methodAnnotations.size(); i++) {
258               AnnotationDescriptor an = methodAnnotations.elementAt(i);
259               if (an.getMarker().equals(LATTICE)) {
260                 // developer explicitly defines method lattice
261                 MethodLattice<String> locOrder =
262                     new MethodLattice<String>(SSJavaLattice.TOP, SSJavaLattice.BOTTOM);
263                 md2lattice.put(md, locOrder);
264                 parseMethodDefaultLatticeDefinition(cd, an.getValue(), locOrder);
265               } else if (an.getMarker().equals(TERMINATE)) {
266                 // developer explicitly wants to skip loop termination analysis
267                 String value = an.getValue();
268                 int maxIteration = 0;
269                 if (value != null) {
270                   maxIteration = Integer.parseInt(value);
271                 }
272                 skipLoopTerminate.put(md, new Integer(maxIteration));
273               }
274             }
275           }
276         }
277
278       }
279
280     }
281   }
282
283   private void writeLatticeDotFile(ClassDescriptor cd, SSJavaLattice<String> locOrder) {
284
285     String className = cd.getSymbol().replaceAll("[\\W_]", "");
286
287     Set<Pair<String, String>> pairSet = locOrder.getOrderingPairSet();
288
289     try {
290       BufferedWriter bw = new BufferedWriter(new FileWriter(className + ".dot"));
291
292       bw.write("digraph " + className + " {\n");
293
294       for (Iterator iterator = pairSet.iterator(); iterator.hasNext();) {
295         // pair is in the form of <higher, lower>
296         Pair<String, String> pair = (Pair<String, String>) iterator.next();
297
298         String highLocId = pair.getFirst();
299         if (locOrder.isSharedLoc(highLocId)) {
300           highLocId = "\"" + highLocId + "*\"";
301         }
302         String lowLocId = pair.getSecond();
303         if (locOrder.isSharedLoc(lowLocId)) {
304           lowLocId = "\"" + lowLocId + "*\"";
305         }
306         bw.write(highLocId + " -> " + lowLocId + ";\n");
307       }
308       bw.write("}\n");
309       bw.close();
310
311     } catch (IOException e) {
312       e.printStackTrace();
313     }
314
315   }
316
317   private void parseMethodDefaultLatticeDefinition(ClassDescriptor cd, String value,
318       MethodLattice<String> locOrder) {
319
320     value = value.replaceAll(" ", ""); // remove all blank spaces
321
322     StringTokenizer tokenizer = new StringTokenizer(value, ",");
323
324     while (tokenizer.hasMoreTokens()) {
325       String orderElement = tokenizer.nextToken();
326       int idx = orderElement.indexOf("<");
327       if (idx > 0) {// relative order element
328         String lowerLoc = orderElement.substring(0, idx);
329         String higherLoc = orderElement.substring(idx + 1);
330         locOrder.put(higherLoc, lowerLoc);
331         if (locOrder.isIntroducingCycle(higherLoc)) {
332           throw new Error("Error: the order relation " + lowerLoc + " < " + higherLoc
333               + " introduces a cycle.");
334         }
335       } else if (orderElement.startsWith(THISLOC + "=")) {
336         String thisLoc = orderElement.substring(8);
337         locOrder.setThisLoc(thisLoc);
338       } else if (orderElement.startsWith(GLOBALLOC + "=")) {
339         String globalLoc = orderElement.substring(10);
340         locOrder.setGlobalLoc(globalLoc);
341       } else if (orderElement.startsWith(RETURNLOC + "=")) {
342         String returnLoc = orderElement.substring(10);
343         locOrder.setReturnLoc(returnLoc);
344       } else if (orderElement.endsWith("*")) {
345         // spin loc definition
346         locOrder.addSharedLoc(orderElement.substring(0, orderElement.length() - 1));
347       } else {
348         // single element
349         locOrder.put(orderElement);
350       }
351     }
352
353     // sanity checks
354     if (locOrder.getThisLoc() != null && !locOrder.containsKey(locOrder.getThisLoc())) {
355       throw new Error("Variable 'this' location '" + locOrder.getThisLoc()
356           + "' is not defined in the default local variable lattice at " + cd.getSourceFileName());
357     }
358
359     if (locOrder.getGlobalLoc() != null && !locOrder.containsKey(locOrder.getGlobalLoc())) {
360       throw new Error("Variable global location '" + locOrder.getGlobalLoc()
361           + "' is not defined in the default local variable lattice at " + cd.getSourceFileName());
362     }
363   }
364
365   private void parseClassLatticeDefinition(ClassDescriptor cd, String value,
366       SSJavaLattice<String> locOrder) {
367
368     value = value.replaceAll(" ", ""); // remove all blank spaces
369
370     StringTokenizer tokenizer = new StringTokenizer(value, ",");
371
372     while (tokenizer.hasMoreTokens()) {
373       String orderElement = tokenizer.nextToken();
374       int idx = orderElement.indexOf("<");
375
376       if (idx > 0) {// relative order element
377         String lowerLoc = orderElement.substring(0, idx);
378         String higherLoc = orderElement.substring(idx + 1);
379         locOrder.put(higherLoc, lowerLoc);
380         if (locOrder.isIntroducingCycle(higherLoc)) {
381           throw new Error("Error: the order relation " + lowerLoc + " < " + higherLoc
382               + " introduces a cycle.");
383         }
384       } else if (orderElement.contains("*")) {
385         // spin loc definition
386         locOrder.addSharedLoc(orderElement.substring(0, orderElement.length() - 1));
387       } else {
388         // single element
389         locOrder.put(orderElement);
390       }
391     }
392
393     // sanity check
394     Set<String> spinLocSet = locOrder.getSharedLocSet();
395     for (Iterator iterator = spinLocSet.iterator(); iterator.hasNext();) {
396       String spinLoc = (String) iterator.next();
397       if (!locOrder.containsKey(spinLoc)) {
398         throw new Error("Spin location '" + spinLoc
399             + "' is not defined in the default local variable lattice at " + cd.getSourceFileName());
400       }
401     }
402   }
403
404   public Hashtable<ClassDescriptor, SSJavaLattice<String>> getCd2lattice() {
405     return cd2lattice;
406   }
407
408   public Hashtable<ClassDescriptor, MethodLattice<String>> getCd2methodDefault() {
409     return cd2methodDefault;
410   }
411
412   public Hashtable<MethodDescriptor, MethodLattice<String>> getMd2lattice() {
413     return md2lattice;
414   }
415
416   public SSJavaLattice<String> getClassLattice(ClassDescriptor cd) {
417     return cd2lattice.get(cd);
418   }
419
420   public MethodLattice<String> getMethodDefaultLattice(ClassDescriptor cd) {
421     return cd2methodDefault.get(cd);
422   }
423
424   public MethodLattice<String> getMethodLattice(MethodDescriptor md) {
425     if (md2lattice.containsKey(md)) {
426       return md2lattice.get(md);
427     } else {
428       return cd2methodDefault.get(md.getClassDesc());
429     }
430   }
431
432   public boolean needToCheckLinearType(MethodDescriptor md) {
433     return linearTypeCheckMethodSet.contains(md);
434   }
435
436   public boolean needTobeAnnotated(MethodDescriptor md) {
437     return annotationRequireSet.contains(md);
438   }
439
440   public boolean needToBeAnnoated(ClassDescriptor cd) {
441     return annotationRequireClassSet.contains(cd);
442   }
443
444   public void addAnnotationRequire(ClassDescriptor cd) {
445     annotationRequireClassSet.add(cd);
446   }
447
448   public void addAnnotationRequire(MethodDescriptor md) {
449
450     ClassDescriptor cd = md.getClassDesc();
451     // if a method requires to be annotated, class containg that method also
452     // requires to be annotated
453     annotationRequireClassSet.add(cd);
454     annotationRequireSet.add(md);
455   }
456
457   public Set<MethodDescriptor> getAnnotationRequireSet() {
458     return annotationRequireSet;
459   }
460
461   public void doLoopTerminationCheck(LoopOptimize lo, FlatMethod fm) {
462     LoopTerminate lt = new LoopTerminate(this, state);
463     if (needTobeAnnotated(fm.getMethod())) {
464       lt.terminateAnalysis(fm, lo.getLoopInvariant(fm));
465     }
466   }
467
468   public CallGraph getCallGraph() {
469     return callgraph;
470   }
471
472   public SSJavaLattice<String> getLattice(Descriptor d) {
473
474     if (d instanceof MethodDescriptor) {
475       return getMethodLattice((MethodDescriptor) d);
476     } else {
477       return getClassLattice((ClassDescriptor) d);
478     }
479
480   }
481
482   public boolean isSharedLocation(Location loc) {
483     SSJavaLattice<String> lattice = getLattice(loc.getDescriptor());
484     return lattice.getSharedLocSet().contains(loc.getLocIdentifier());
485   }
486
487   public void mapSharedLocation2Descriptor(Location loc, Descriptor d) {
488     Set<Descriptor> set = mapSharedLocation2DescriptorSet.get(loc);
489     if (set == null) {
490       set = new HashSet<Descriptor>();
491       mapSharedLocation2DescriptorSet.put(loc, set);
492     }
493     set.add(d);
494   }
495
496   public BuildFlat getBuildFlat() {
497     return bf;
498   }
499
500   public MethodDescriptor getMethodContainingSSJavaLoop() {
501     return methodContainingSSJavaLoop;
502   }
503
504   public void setMethodContainingSSJavaLoop(MethodDescriptor methodContainingSSJavaLoop) {
505     this.methodContainingSSJavaLoop = methodContainingSSJavaLoop;
506   }
507 }