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