state.DSMTASK flag is added
[IRC.git] / Robust / src / IR / TypeUtil.java
1 package IR;
2 import java.util.*;
3 import IR.Tree.*;
4 import java.io.File;
5 import Main.Main;
6
7 public class TypeUtil {
8   public static final String StringClass="String";
9   public static final String ObjectClass="Object";
10   public static final String StartupClass="StartupObject";
11   public static final String TagClass="TagDescriptor";
12   public static final String ThreadClass="Thread";
13   public static final String TaskClass="Task";
14   State state;
15   Hashtable supertable;
16   Hashtable subclasstable;
17   BuildIR bir;
18
19   public TypeUtil(State state, BuildIR bir) {
20     this.state=state;
21     this.bir=bir;
22     createTables();
23   }
24
25   public void addNewClass(String cl, Set todo) {
26     for(int i=0;i<state.classpath.size();i++) {
27       String path=(String)state.classpath.get(i);
28       File f=new File(path, cl+".java");
29       if (f.exists()) {
30         try {
31           ParseNode pn=Main.readSourceFile(state, f.getCanonicalPath());
32           bir.buildtree(pn, todo);
33           return;
34         } catch (Exception e) {
35           throw new Error(e);
36         }
37       }
38     }
39     throw new Error("Couldn't find class "+cl);
40   }
41
42
43
44   public ClassDescriptor getClass(String classname) {
45     ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
46     return cd;
47   }
48
49   public ClassDescriptor getClass(String classname, HashSet todo) {
50     ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
51     if (cd==null) {
52       //have to find class
53       addNewClass(classname, todo);
54       cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
55
56       System.out.println("Build class:"+cd);
57       todo.add(cd);
58     }
59     if (!supertable.containsKey(cd)) {
60       String superc=cd.getSuper();
61       if (superc!=null) {
62         ClassDescriptor cd_super=getClass(superc, todo);
63         supertable.put(cd,cd_super);
64       }
65     }
66     return cd;
67   }
68
69   private void createTables() {
70     supertable=new Hashtable();
71   }
72
73   public ClassDescriptor getMainClass() {
74     return getClass(state.main);
75   }
76
77   public MethodDescriptor getRun() {
78     ClassDescriptor cd=getClass(TypeUtil.ThreadClass);
79     for(Iterator methodit=cd.getMethodTable().getSet("run").iterator(); methodit.hasNext();) {
80       MethodDescriptor md=(MethodDescriptor) methodit.next();
81       if (md.numParameters()!=0||md.getModifiers().isStatic())
82         continue;
83       return md;
84     }
85     throw new Error("Can't find Thread.run");
86   }
87   
88   public MethodDescriptor getExecute() {
89     ClassDescriptor cd = getClass(TypeUtil.TaskClass);
90
91     if(cd == null && state.DSMTASK)
92       throw new Error("Task.java is not included");
93
94     for(Iterator methodit = cd.getMethodTable().getSet("execute").iterator(); methodit.hasNext();) {
95       MethodDescriptor md = (MethodDescriptor) methodit.next();
96       if (md.numParameters()!=0 || md.getModifiers().isStatic())
97         continue;
98       return md;
99     }
100     throw new Error("Can't find Task.execute");
101   }
102
103
104   public MethodDescriptor getMain() {
105     ClassDescriptor cd=getMainClass();
106     Set mainset=cd.getMethodTable().getSet("main");
107     for(Iterator mainit=mainset.iterator(); mainit.hasNext();) {
108       MethodDescriptor md=(MethodDescriptor)mainit.next();
109       if (md.numParameters()!=1)
110         continue;
111       Descriptor pd=md.getParameter(0);
112       TypeDescriptor tpd=(pd instanceof TagVarDescriptor) ? ((TagVarDescriptor)pd).getType() : ((VarDescriptor)pd)
113                           .getType();
114       if (tpd.getArrayCount()!=1)
115         continue;
116       if (!tpd.getSymbol().equals("String"))
117         continue;
118
119       if (!md.getModifiers().isStatic())
120         throw new Error("Error: Non static main");
121       return md;
122     }
123     throw new Error(cd+" has no main");
124   }
125
126   /** Check to see if md1 is more specific than md2...  Informally
127       if md2 could always be called given the arguments passed into
128       md1 */
129
130   public boolean isMoreSpecific(MethodDescriptor md1, MethodDescriptor md2) {
131     /* Checks if md1 is more specific than md2 */
132     if (md1.numParameters()!=md2.numParameters())
133       throw new Error();
134     for(int i=0; i<md1.numParameters(); i++) {
135       if (!this.isSuperorType(md2.getParamType(i), md1.getParamType(i)))
136         return false;
137     }
138     if (md1.getReturnType()==null||md2.getReturnType()==null) {
139         if (md1.getReturnType()!=md2.getReturnType())
140             return false;
141     } else
142         if (!this.isSuperorType(md2.getReturnType(), md1.getReturnType()))
143             return false;
144
145     if (!this.isSuperorType(md2.getClassDesc(), md1.getClassDesc()))
146       return false;
147
148     return true;
149   }
150
151   public MethodDescriptor getMethod(ClassDescriptor cd, String name, TypeDescriptor[] types) {
152     Set methoddescriptorset=cd.getMethodTable().getSet(name);
153     MethodDescriptor bestmd=null;
154 NextMethod:
155     for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext();) {
156       MethodDescriptor currmd=(MethodDescriptor)methodit.next();
157       /* Need correct number of parameters */
158       if (types.length!=currmd.numParameters())
159         continue;
160       for(int i=0; i<types.length; i++) {
161         if (!this.isSuperorType(currmd.getParamType(i),types[i]))
162           continue NextMethod;
163       }
164       /* Method okay so far */
165       if (bestmd==null)
166         bestmd=currmd;
167       else {
168         if (isMoreSpecific(currmd,bestmd)) {
169           bestmd=currmd;
170         } else if (!isMoreSpecific(bestmd, currmd))
171           throw new Error("No method is most specific");
172
173         /* Is this more specific than bestmd */
174       }
175     }
176     if (bestmd==null)
177       throw new Error("Could find: "+name + " in "+cd);
178
179     return bestmd;
180   }
181
182   public void createFullTable() {
183     subclasstable=new Hashtable();
184
185     Iterator classit=state.getClassSymbolTable().getDescriptorsIterator();
186     while(classit.hasNext()) {
187       ClassDescriptor cd=(ClassDescriptor)classit.next();
188       ClassDescriptor tmp=cd.getSuperDesc();
189
190       while(tmp!=null) {
191         if (!subclasstable.containsKey(tmp))
192           subclasstable.put(tmp,new HashSet());
193         HashSet hs=(HashSet)subclasstable.get(tmp);
194         hs.add(cd);
195         tmp=tmp.getSuperDesc();
196       }
197     }
198   }
199
200   public Set getSubClasses(ClassDescriptor cd) {
201     return (Set)subclasstable.get(cd);
202   }
203
204   public ClassDescriptor getSuper(ClassDescriptor cd) {
205     return (ClassDescriptor)supertable.get(cd);
206   }
207
208   public boolean isCastable(TypeDescriptor original, TypeDescriptor casttype) {
209     if (original.isChar()&&
210         (casttype.isByte()||
211          casttype.isShort()))
212       return true;
213
214     if (casttype.isChar()&&
215         (original.isByte()||
216          original.isShort()||
217          original.isInt()||
218          original.isLong()||
219          original.isFloat()||
220          original.isDouble()))
221       return true;
222
223     return false;
224   }
225
226   public boolean isSuperorType(TypeDescriptor possiblesuper, TypeDescriptor cd2) {
227     if (possiblesuper.isOffset() || cd2.isOffset()) return true;
228     //Matching type are always okay
229     if (possiblesuper.equals(cd2))
230       return true;
231
232     if ((possiblesuper.isTag() && !cd2.isTag())||
233         (!possiblesuper.isTag() && cd2.isTag()))
234       return false;
235
236     //Handle arrays
237     if (cd2.isArray()||possiblesuper.isArray()) {
238       // Object is super class of all arrays
239       if (possiblesuper.getSymbol().equals(ObjectClass)&&!possiblesuper.isArray())
240         return true;
241
242       // If we have the same dimensionality of arrays & both are classes, we can default to the normal test
243       if (cd2.isClass()&&possiblesuper.isClass()
244           &&(possiblesuper.getArrayCount()==cd2.getArrayCount())&&
245           isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc()))
246         return true;
247
248       // Object is superclass of all array classes
249       if (possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()
250           &&(possiblesuper.getArrayCount()<cd2.getArrayCount()))
251         return true;
252
253       //Allow arraytype=null statements
254       if (possiblesuper.isArray()&&cd2.isNull())
255         return true;
256
257       return false;
258     }
259
260     if (possiblesuper.isClass()&&
261         cd2.isClass())
262       return isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc());
263     else if (possiblesuper.isClass()&&
264              cd2.isNull())
265       return true;
266     else if (possiblesuper.isNull())
267       throw new Error();       //not sure when this case would occur
268     else if (possiblesuper.isPrimitive()&&
269              cd2.isPrimitive()) {
270       ///Primitive widenings from 5.1.2
271       if (cd2.isByte()&&(possiblesuper.isByte()||possiblesuper.isShort()||
272                          possiblesuper.isInt()||possiblesuper.isLong()||
273                          possiblesuper.isFloat()||possiblesuper.isDouble()))
274         return true;
275       if (cd2.isShort()&&(possiblesuper.isShort()||
276                           possiblesuper.isInt()||possiblesuper.isLong()||
277                           possiblesuper.isFloat()||possiblesuper.isDouble()))
278         return true;
279       if (cd2.isChar()&&(possiblesuper.isChar()||
280                          possiblesuper.isInt()||possiblesuper.isLong()||
281                          possiblesuper.isFloat()||possiblesuper.isDouble()))
282         return true;
283       if (cd2.isInt()&&(possiblesuper.isInt()||possiblesuper.isLong()||
284                         possiblesuper.isFloat()||possiblesuper.isDouble()))
285         return true;
286       if (cd2.isLong()&&(possiblesuper.isLong()||
287                          possiblesuper.isFloat()||possiblesuper.isDouble()))
288         return true;
289       if (cd2.isFloat()&&(possiblesuper.isFloat()||possiblesuper.isDouble()))
290         return true;
291       if (cd2.isDouble()&&possiblesuper.isDouble())
292
293         return true;
294       if (cd2.isBoolean()&&possiblesuper.isBoolean())
295         return true;
296
297       return false;
298     } else if (possiblesuper.isPrimitive()&&(!possiblesuper.isArray())&&
299                cd2.isPtr())
300       return false;
301     else if (cd2.isPrimitive()&&(!cd2.isArray())&&
302              possiblesuper.isPtr())
303       return false;
304     else
305       throw new Error("Case not handled:"+possiblesuper+" "+cd2);
306   }
307
308
309   public boolean isSuperorType(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
310     if (possiblesuper==cd2)
311       return true;
312     else
313       return isSuper(possiblesuper, cd2);
314   }
315
316   private boolean isSuper(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
317
318     while(cd2!=null) {
319       cd2=getSuper(cd2);
320       if (cd2==possiblesuper)
321         return true;
322     }
323     return false;
324   }
325 }