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