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