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