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