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