model the allocation of string literals in heap analysis
[IRC.git] / Robust / src / IR / TypeUtil.java
1 package IR;
2 import java.util.*;
3
4 import IR.Flat.FlatNode;
5 import IR.Tree.*;
6 import java.io.File;
7 import Main.Main;
8
9 public class TypeUtil {
10   public static String StringClass;
11   public static String StringClassValueField;
12   public static String ObjectClass;
13   public static String StartupClass;
14   public static String TagClass;
15   public static String ThreadClass;
16   public static String TaskClass;
17   State state;
18   Hashtable supertable;
19   Hashtable subclasstable;
20   BuildIR bir;
21
22   // for interfaces
23   Hashtable<ClassDescriptor, Set<ClassDescriptor>> superIFtbl;
24
25   public TypeUtil(State state, BuildIR bir) {
26     this.state=state;
27     this.bir=bir;
28     if (state.JNI) {
29       StringClass="java.lang.String";
30       StringClassValueField="value";
31       ObjectClass="java.lang.Object";
32       StartupClass="StartupObject";
33       TagClass="TagDescriptor";
34       ThreadClass="java.lang.Thread";
35       TaskClass="Task";
36     } else {
37       StringClass="String";
38       StringClassValueField="value";
39       ObjectClass="Object";
40       StartupClass="StartupObject";
41       TagClass="TagDescriptor";
42       ThreadClass="Thread";
43       TaskClass="Task";
44     }
45     createTables();
46   }
47
48   public void addNewClass(String cl, Set todo) {
49     //search through the default locations for the file.
50     if(state.MGC) {
51       // do not consider package or import when compiling MGC version
52       cl = (cl.lastIndexOf('.')==-1)?cl:cl.substring(cl.lastIndexOf('.')+1);
53     }
54     for (int i = 0; i < state.classpath.size(); i++) {
55       String path = (String) state.classpath.get(i);
56       File f = new File(path, cl.replace('.', '/') + ".java");
57       if (f.exists()) {
58         try {
59           ParseNode pn = Main.readSourceFile(state, f.getCanonicalPath());
60           bir.buildtree(pn, todo, f.getCanonicalPath());
61           return;
62         } catch (Exception e) {
63           throw new Error(e);
64         }
65       }
66     }
67     throw new Error("Couldn't find class " + cl);
68   }
69
70
71
72   public ClassDescriptor getClass(String classname) {
73     String cl = classname;
74     if(state.MGC) {
75       // do not consider package or import when compiling MGC version
76       cl = (cl.lastIndexOf('.')==-1)?cl:cl.substring(cl.lastIndexOf('.')+1);
77     }
78     ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(cl);
79     return cd;
80   }
81
82   public ClassDescriptor getClass(String classname, HashSet todo) {
83     String cl = classname;
84     if(state.MGC) {
85       // do not consider package or import when compiling MGC version
86       cl = (cl.lastIndexOf('.')==-1)?cl:cl.substring(cl.lastIndexOf('.')+1);
87     }
88     ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(cl);
89     if (cd==null) {
90       //have to find class
91       addNewClass(cl, todo);
92       cd=(ClassDescriptor)state.getClassSymbolTable().get(cl);
93
94       System.out.println("Build class:"+cd);
95       todo.add(cd);
96     }
97     if (!supertable.containsKey(cd)) {
98       String superc=cd.getSuper();
99       if (superc!=null) {
100         ClassDescriptor cd_super=getClass(superc, todo);
101         supertable.put(cd,cd_super);
102       }
103     }
104     if (!superIFtbl.containsKey(cd)) {
105       // add inherited interfaces
106       superIFtbl.put(cd,new HashSet());
107       HashSet hs=(HashSet)superIFtbl.get(cd);
108       Vector<String> superifv = cd.getSuperInterface();
109       for(int i = 0; i < superifv.size(); i++) {
110         String superif = superifv.elementAt(i);
111         ClassDescriptor if_super = getClass(superif, todo);
112         hs.add(if_super);
113       }
114     }
115     return cd;
116   }
117
118   private void createTables() {
119     supertable=new Hashtable();
120     superIFtbl = new Hashtable<ClassDescriptor,Set<ClassDescriptor>>();
121   }
122
123   public ClassDescriptor getMainClass() {
124     return getClass(state.main);
125   }
126
127   public MethodDescriptor getRun() {
128     ClassDescriptor cd=getClass(TypeUtil.ThreadClass);
129     for(Iterator methodit=cd.getMethodTable().getSet("run").iterator(); methodit.hasNext(); ) {
130       MethodDescriptor md=(MethodDescriptor) methodit.next();
131       if (md.numParameters()!=0||md.getModifiers().isStatic())
132         continue;
133       return md;
134     }
135     throw new Error("Can't find Thread.run");
136   }
137
138   public MethodDescriptor getStaticStart() {
139     ClassDescriptor cd=getClass(TypeUtil.ThreadClass);
140     for(Iterator methodit=cd.getMethodTable().getSet("staticStart").iterator(); methodit.hasNext(); ) {
141       MethodDescriptor md=(MethodDescriptor) methodit.next();
142       if (md.numParameters()!=1||!md.getModifiers().isStatic()||!md.getParamType(0).isClass()||md.getParamType(0).getClassDesc()!=cd)
143         continue;
144       return md;
145     }
146     throw new Error("Can't find Thread.run");
147   }
148
149   public MethodDescriptor getExecute() {
150     ClassDescriptor cd = getClass(TypeUtil.TaskClass);
151
152     if(cd == null && state.DSMTASK)
153       throw new Error("Task.java is not included");
154
155     for(Iterator methodit = cd.getMethodTable().getSet("execute").iterator(); methodit.hasNext(); ) {
156       MethodDescriptor md = (MethodDescriptor) methodit.next();
157       if (md.numParameters()!=0 || md.getModifiers().isStatic())
158         continue;
159       return md;
160     }
161     throw new Error("Can't find Task.execute");
162   }
163
164
165   public MethodDescriptor getMain() {
166     ClassDescriptor cd=getMainClass();
167     Set mainset=cd.getMethodTable().getSet("main");
168
169     for(Iterator mainit=mainset.iterator(); mainit.hasNext(); ) {
170       MethodDescriptor md=(MethodDescriptor)mainit.next();
171       if (md.numParameters()!=1)
172         continue;
173       Descriptor pd=md.getParameter(0);
174       TypeDescriptor tpd=(pd instanceof TagVarDescriptor)?((TagVarDescriptor)pd).getType():((VarDescriptor)pd)
175                           .getType();
176       if (tpd.getArrayCount()!=1)
177         continue;
178       if (!tpd.getSymbol().equals(StringClass))
179         continue;
180       if (!md.getModifiers().isStatic())
181         throw new Error("Error: Non static main");
182       return md;
183     }
184     throw new Error(cd+" has no main");
185   }
186
187   /** Check to see if md1 is more specific than md2...  Informally
188       if md2 could always be called given the arguments passed into
189       md1 */
190
191   public boolean isMoreSpecific(MethodDescriptor md1, MethodDescriptor md2) {
192     /* Checks if md1 is more specific than md2 */
193     if (md1.numParameters()!=md2.numParameters())
194       throw new Error();
195     for(int i=0; i<md1.numParameters(); i++) {
196       if (!this.isSuperorType(md2.getParamType(i), md1.getParamType(i))) {
197         if(((!md1.getParamType(i).isArray() &&
198              (md1.getParamType(i).isInt() || md1.getParamType(i).isLong() || md1.getParamType(i).isDouble() || md1.getParamType(i).isFloat()))
199             && md2.getParamType(i).isClass() && md2.getParamType(i).getClassDesc().getSymbol().equals("Object"))) {
200           // primitive parameters vs Object
201         } else {
202           return false;
203         }
204       }
205     }
206     if (md1.getReturnType()==null||md2.getReturnType()==null) {
207       if (md1.getReturnType()!=md2.getReturnType())
208         return false;
209     } else
210     if (!this.isSuperorType(md2.getReturnType(), md1.getReturnType()))
211       return false;
212
213     if (!this.isSuperorType(md2.getClassDesc(), md1.getClassDesc()))
214       return false;
215
216     return true;
217   }
218
219   public MethodDescriptor getMethod(ClassDescriptor cd, String name, TypeDescriptor[] types) {
220     Set methoddescriptorset=cd.getMethodTable().getSet(name);
221     MethodDescriptor bestmd=null;
222 NextMethod:
223     for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext(); ) {
224       MethodDescriptor currmd=(MethodDescriptor)methodit.next();
225       /* Need correct number of parameters */
226       if (types.length!=currmd.numParameters())
227         continue;
228       for(int i=0; i<types.length; i++) {
229         if (!this.isSuperorType(currmd.getParamType(i),types[i]))
230           continue NextMethod;
231       }
232       /* Method okay so far */
233       if (bestmd==null)
234         bestmd=currmd;
235       else {
236         if (isMoreSpecific(currmd,bestmd)) {
237           bestmd=currmd;
238         } else if (!isMoreSpecific(bestmd, currmd))
239           throw new Error("No method is most specific");
240
241         /* Is this more specific than bestmd */
242       }
243     }
244     if (bestmd==null)
245       throw new Error("Could find: "+name + " in "+cd);
246
247     return bestmd;
248   }
249
250   public void createFullTable() {
251     subclasstable=new Hashtable();
252     HashSet tovisit=new HashSet();
253     HashSet visited=new HashSet();
254
255     Iterator classit=state.getClassSymbolTable().getDescriptorsIterator();
256     while(classit.hasNext()) {
257       tovisit.clear();
258       visited.clear();
259       ClassDescriptor cd=(ClassDescriptor)classit.next();
260       ClassDescriptor tmp=cd.getSuperDesc();
261
262       // check cd's interface ancestors
263       {
264         Iterator it_sifs = cd.getSuperInterfaces();
265         while(it_sifs.hasNext()) {
266           ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
267           if(!tovisit.contains(cdt)) {
268             tovisit.add(cdt);
269           }
270         }
271       }
272
273       while(tmp!=null) {
274         if (!subclasstable.containsKey(tmp))
275           subclasstable.put(tmp,new HashSet());
276         HashSet hs=(HashSet)subclasstable.get(tmp);
277         hs.add(cd);
278         // check tmp's interface ancestors
279         Iterator it_sifs = tmp.getSuperInterfaces();
280         while(it_sifs.hasNext()) {
281           ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
282           if(!tovisit.contains(cdt)) {
283             tovisit.add(cdt);
284           }
285         }
286
287         tmp=tmp.getSuperDesc();
288       }
289
290       while(!tovisit.isEmpty()) {
291         ClassDescriptor sif = (ClassDescriptor)tovisit.iterator().next();
292         tovisit.remove(sif);
293
294         if(!visited.contains(sif)) {
295           if(!this.subclasstable.containsKey(sif)) {
296             this.subclasstable.put(sif, new HashSet());
297           }
298           HashSet hs = (HashSet) this.subclasstable.get(sif);
299           hs.add(cd);
300
301           Iterator it_sifs = sif.getSuperInterfaces();
302           while(it_sifs.hasNext()) {
303             ClassDescriptor siftmp = (ClassDescriptor)it_sifs.next();
304             if(!tovisit.contains(siftmp)) {
305               tovisit.add(siftmp);
306             }
307           }
308           visited.add(sif);
309         }
310       }
311     }
312   }
313
314   public Set getSubClasses(ClassDescriptor cd) {
315     return (Set)subclasstable.get(cd);
316   }
317
318   public ClassDescriptor getSuper(ClassDescriptor cd) {
319     return (ClassDescriptor)supertable.get(cd);
320   }
321
322   public Set<ClassDescriptor> getSuperIFs(ClassDescriptor cd) {
323     return superIFtbl.get(cd);
324   }
325
326   public boolean isCastable(TypeDescriptor original, TypeDescriptor casttype) {
327     if (original.isChar()&&
328         (casttype.isByte()||
329          casttype.isShort()))
330       return true;
331
332     if (casttype.isChar()&&
333         (original.isByte()||
334          original.isShort()||
335          original.isInt()||
336          original.isLong()||
337          original.isFloat()||
338          original.isDouble()))
339       return true;
340
341     return false;
342   }
343
344   public boolean isSuperorType(TypeDescriptor possiblesuper, TypeDescriptor cd2) {
345     if (possiblesuper.isOffset() || cd2.isOffset()) return true;
346     //Matching type are always okay
347     if (possiblesuper.equals(cd2))
348       return true;
349
350     if ((possiblesuper.isTag() && !cd2.isTag())||
351         (!possiblesuper.isTag() && cd2.isTag()))
352       return false;
353
354     //Handle arrays
355     if (cd2.isArray()||possiblesuper.isArray()) {
356       // Object is super class of all arrays
357       if (possiblesuper.getSymbol().equals(ObjectClass)&&!possiblesuper.isArray())
358         return true;
359
360       // If we have the same dimensionality of arrays & both are classes, we can default to the normal test
361       if (cd2.isClass()&&possiblesuper.isClass()
362           &&(possiblesuper.getArrayCount()==cd2.getArrayCount())&&
363           isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc()))
364         return true;
365
366       // Object is superclass of all array classes
367       if (possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()
368           &&(possiblesuper.getArrayCount()<cd2.getArrayCount()))
369         return true;
370
371       //Allow arraytype=null statements
372       if (possiblesuper.isArray()&&cd2.isNull())
373         return true;
374
375       return false;
376     }
377
378     if (possiblesuper.isClass()&&
379         cd2.isClass())
380       return isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc());
381     else if (possiblesuper.isClass()&&
382              cd2.isNull())
383       return true;
384     else if (possiblesuper.isNull())
385       throw new Error();       //not sure when this case would occur
386     else if (possiblesuper.isPrimitive()&&
387              cd2.isPrimitive()) {
388       ///Primitive widenings from 5.1.2
389       if (cd2.isByte()&&(possiblesuper.isByte()||possiblesuper.isShort()||
390                          possiblesuper.isInt()||possiblesuper.isLong()||
391                          possiblesuper.isFloat()||possiblesuper.isDouble()))
392         return true;
393       if (cd2.isShort()&&(possiblesuper.isShort()||
394                           possiblesuper.isInt()||possiblesuper.isLong()||
395                           possiblesuper.isFloat()||possiblesuper.isDouble()))
396         return true;
397       if (cd2.isChar()&&(possiblesuper.isChar()||
398                          possiblesuper.isInt()||possiblesuper.isLong()||
399                          possiblesuper.isFloat()||possiblesuper.isDouble()))
400         return true;
401       if (cd2.isInt()&&(possiblesuper.isInt()||possiblesuper.isLong()||
402                         possiblesuper.isFloat()||possiblesuper.isDouble()
403                         ||possiblesuper.isEnum()))
404         return true;
405       if (cd2.isEnum()&&(possiblesuper.isInt()||possiblesuper.isLong()||
406                          possiblesuper.isFloat()||possiblesuper.isDouble()))
407         return true;
408       if(cd2.isEnum()&&possiblesuper.isEnum()&&cd2.class_desc.equals(possiblesuper.class_desc))
409         return true;
410       if (cd2.isLong()&&(possiblesuper.isLong()||
411                          possiblesuper.isFloat()||possiblesuper.isDouble()))
412         return true;
413       if (cd2.isFloat()&&(possiblesuper.isFloat()||possiblesuper.isDouble()))
414         return true;
415       if (cd2.isDouble()&&possiblesuper.isDouble())
416
417         return true;
418       if (cd2.isBoolean()&&possiblesuper.isBoolean())
419         return true;
420
421       return false;
422     } else if (possiblesuper.isPrimitive()&&(!possiblesuper.isArray())&&
423                cd2.isPtr())
424       return false;
425     else if (cd2.isPrimitive()&&(!cd2.isArray())&&
426              possiblesuper.isPtr())
427       return false;
428     else
429       throw new Error("Case not handled:"+possiblesuper+" "+cd2);
430   }
431
432   public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2) {
433     if( isSuperorType(td1, td2) ) {
434       return td2;
435     }
436     if( isSuperorType(td2, td1) ) {
437       return td1;
438     }
439     throw new Error(td1+" and "+td2+" have no superclass relationship");
440   }
441
442   public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2, TypeDescriptor td3) {
443     return mostSpecific(td1, mostSpecific(td2, td3) );
444   }
445
446   public boolean isSuperorType(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
447     if (possiblesuper==cd2)
448       return true;
449     else
450       return isSuper(possiblesuper, cd2);
451   }
452
453   private boolean isSuper(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
454     HashSet tovisit=new HashSet();
455     HashSet visited=new HashSet();
456
457     {
458       // check cd2's interface ancestors
459       Iterator<ClassDescriptor> it_sifs = getSuperIFs(cd2).iterator();
460       while(it_sifs.hasNext()) {
461         ClassDescriptor cd = it_sifs.next();
462         if(cd == possiblesuper) {
463           return true;
464         } else if(!tovisit.contains(cd)) {
465           tovisit.add(cd);
466         }
467       }
468     }
469
470     while(cd2!=null) {
471       cd2=getSuper(cd2);
472       if (cd2==possiblesuper)
473          return true;
474
475       // check cd2's interface ancestors
476       if(cd2 != null) {
477         Iterator it_sifs = getSuperIFs(cd2).iterator();
478         while(it_sifs.hasNext()) {
479           ClassDescriptor cd = (ClassDescriptor)it_sifs.next();
480           if(cd == possiblesuper) {
481             return true;
482           } else if(!tovisit.contains(cd)) {
483             tovisit.add(cd);
484           }
485         }
486       }
487     }
488
489     while(!tovisit.isEmpty()) {
490       ClassDescriptor cd = (ClassDescriptor)tovisit.iterator().next();
491       tovisit.remove(cd);
492
493       if(!visited.contains(cd)) {
494         Iterator it_sifs = getSuperIFs(cd).iterator();
495         while(it_sifs.hasNext()) {
496           ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
497           if(cdt == possiblesuper) {
498             return true;
499           } else if(!tovisit.contains(cdt)) {
500             tovisit.add(cdt);
501           }
502         }
503         visited.add(cd);
504       }
505     }
506     return false;
507   }
508 }