4 import IR.Flat.FlatNode;
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";
18 Hashtable subclasstable;
22 Hashtable<ClassDescriptor, Set<ClassDescriptor>> superIFtbl;
24 public TypeUtil(State state, BuildIR bir) {
30 public void addNewClass(String cl, Set todo) {
31 //search through the default locations for the file.
32 for (int i = 0; i < state.classpath.size(); i++) {
33 String path = (String) state.classpath.get(i);
34 //The name has ___________ to separate out packages
35 File f = new File(path, cl.replaceAll("___________", "/") + ".java");
38 ParseNode pn = Main.readSourceFile(state, f.getCanonicalPath());
39 bir.buildtree(pn, todo, f.getCanonicalPath());
41 } catch (Exception e) {
46 throw new Error("Couldn't find class " + cl);
51 public ClassDescriptor getClass(String classname) {
52 ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
56 public ClassDescriptor getClass(String classname, HashSet todo) {
57 ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
60 addNewClass(classname, todo);
61 cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
64 System.out.println("Build class:"+cd);
67 if (!supertable.containsKey(cd)) {
68 String superc=cd.getSuper();
70 ClassDescriptor cd_super=getClass(superc, todo);
71 supertable.put(cd,cd_super);
74 if (!superIFtbl.containsKey(cd)) {
75 // add inherited interfaces
76 superIFtbl.put(cd,new HashSet());
77 HashSet hs=(HashSet)superIFtbl.get(cd);
78 Vector<String> superifv = cd.getSuperInterface();
79 for(int i = 0; i < superifv.size(); i++) {
80 String superif = superifv.elementAt(i);
81 ClassDescriptor if_super = getClass(superif, todo);
88 private void createTables() {
89 supertable=new Hashtable();
90 superIFtbl = new Hashtable<ClassDescriptor,Set<ClassDescriptor>>();
93 public ClassDescriptor getMainClass() {
94 return getClass(state.main);
97 public MethodDescriptor getRun() {
98 ClassDescriptor cd=getClass(TypeUtil.ThreadClass);
99 for(Iterator methodit=cd.getMethodTable().getSet("run").iterator(); methodit.hasNext();) {
100 MethodDescriptor md=(MethodDescriptor) methodit.next();
101 if (md.numParameters()!=0||md.getModifiers().isStatic())
105 throw new Error("Can't find Thread.run");
108 public MethodDescriptor getStaticStart() {
109 ClassDescriptor cd=getClass(TypeUtil.ThreadClass);
110 for(Iterator methodit=cd.getMethodTable().getSet("staticStart").iterator(); methodit.hasNext();) {
111 MethodDescriptor md=(MethodDescriptor) methodit.next();
112 if (md.numParameters()!=1||!md.getModifiers().isStatic()||!md.getParamType(0).isClass()||md.getParamType(0).getClassDesc()!=cd)
116 throw new Error("Can't find Thread.run");
119 public MethodDescriptor getExecute() {
120 ClassDescriptor cd = getClass(TypeUtil.TaskClass);
122 if(cd == null && state.DSMTASK)
123 throw new Error("Task.java is not included");
125 for(Iterator methodit = cd.getMethodTable().getSet("execute").iterator(); methodit.hasNext();) {
126 MethodDescriptor md = (MethodDescriptor) methodit.next();
127 if (md.numParameters()!=0 || md.getModifiers().isStatic())
131 throw new Error("Can't find Task.execute");
135 public MethodDescriptor getMain() {
136 ClassDescriptor cd=getMainClass();
137 Set mainset=cd.getMethodTable().getSet("main");
138 for(Iterator mainit=mainset.iterator(); mainit.hasNext();) {
139 MethodDescriptor md=(MethodDescriptor)mainit.next();
140 if (md.numParameters()!=1)
142 Descriptor pd=md.getParameter(0);
143 TypeDescriptor tpd=(pd instanceof TagVarDescriptor) ? ((TagVarDescriptor)pd).getType() : ((VarDescriptor)pd)
145 if (tpd.getArrayCount()!=1)
147 if (!tpd.getSymbol().equals("String"))
150 if (!md.getModifiers().isStatic())
151 throw new Error("Error: Non static main");
154 throw new Error(cd+" has no main");
157 /** Check to see if md1 is more specific than md2... Informally
158 if md2 could always be called given the arguments passed into
161 public boolean isMoreSpecific(MethodDescriptor md1, MethodDescriptor md2) {
162 /* Checks if md1 is more specific than md2 */
163 if (md1.numParameters()!=md2.numParameters())
165 for(int i=0; i<md1.numParameters(); i++) {
166 if (!this.isSuperorType(md2.getParamType(i), md1.getParamType(i))) {
167 if(((!md1.getParamType(i).isArray() &&
168 (md1.getParamType(i).isInt() || md1.getParamType(i).isLong() || md1.getParamType(i).isDouble() || md1.getParamType(i).isFloat()))
169 && md2.getParamType(i).isClass() && md2.getParamType(i).getClassDesc().getSymbol().equals("Object"))) {
170 // primitive parameters vs Object
176 if (md1.getReturnType()==null||md2.getReturnType()==null) {
177 if (md1.getReturnType()!=md2.getReturnType())
180 if (!this.isSuperorType(md2.getReturnType(), md1.getReturnType()))
183 if (!this.isSuperorType(md2.getClassDesc(), md1.getClassDesc()))
189 public MethodDescriptor getMethod(ClassDescriptor cd, String name, TypeDescriptor[] types) {
190 Set methoddescriptorset=cd.getMethodTable().getSet(name);
191 MethodDescriptor bestmd=null;
193 for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext();) {
194 MethodDescriptor currmd=(MethodDescriptor)methodit.next();
195 /* Need correct number of parameters */
196 if (types.length!=currmd.numParameters())
198 for(int i=0; i<types.length; i++) {
199 if (!this.isSuperorType(currmd.getParamType(i),types[i]))
202 /* Method okay so far */
206 if (isMoreSpecific(currmd,bestmd)) {
208 } else if (!isMoreSpecific(bestmd, currmd))
209 throw new Error("No method is most specific");
211 /* Is this more specific than bestmd */
215 throw new Error("Could find: "+name + " in "+cd);
220 public void createFullTable() {
221 subclasstable=new Hashtable();
222 HashSet tovisit=new HashSet();
223 HashSet visited=new HashSet();
225 Iterator classit=state.getClassSymbolTable().getDescriptorsIterator();
226 while(classit.hasNext()) {
229 ClassDescriptor cd=(ClassDescriptor)classit.next();
230 ClassDescriptor tmp=cd.getSuperDesc();
232 // check cd's interface ancestors
234 Iterator it_sifs = cd.getSuperInterfaces();
235 while(it_sifs.hasNext()) {
236 ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
237 if(!tovisit.contains(cdt)){
244 if (!subclasstable.containsKey(tmp))
245 subclasstable.put(tmp,new HashSet());
246 HashSet hs=(HashSet)subclasstable.get(tmp);
248 // check tmp's interface ancestors
249 Iterator it_sifs = tmp.getSuperInterfaces();
250 while(it_sifs.hasNext()) {
251 ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
252 if(!tovisit.contains(cdt)){
257 tmp=tmp.getSuperDesc();
260 while(!tovisit.isEmpty()) {
261 ClassDescriptor sif = (ClassDescriptor)tovisit.iterator().next();
264 if(!visited.contains(sif)) {
265 if(!this.subclasstable.containsKey(sif)) {
266 this.subclasstable.put(sif, new HashSet());
268 HashSet hs = (HashSet)this.subclasstable.get(sif);
271 Iterator it_sifs = sif.getSuperInterfaces();
272 while(it_sifs.hasNext()) {
273 ClassDescriptor siftmp = (ClassDescriptor)it_sifs.next();
274 if(!tovisit.contains(siftmp)){
284 public Set getSubClasses(ClassDescriptor cd) {
285 return (Set)subclasstable.get(cd);
288 public ClassDescriptor getSuper(ClassDescriptor cd) {
289 return (ClassDescriptor)supertable.get(cd);
292 public Set<ClassDescriptor> getSuperIFs(ClassDescriptor cd) {
293 return superIFtbl.get(cd);
296 public boolean isCastable(TypeDescriptor original, TypeDescriptor casttype) {
297 if (original.isChar()&&
302 if (casttype.isChar()&&
308 original.isDouble()))
314 public boolean isSuperorType(TypeDescriptor possiblesuper, TypeDescriptor cd2) {
315 if (possiblesuper.isOffset() || cd2.isOffset()) return true;
316 //Matching type are always okay
317 if (possiblesuper.equals(cd2))
320 if ((possiblesuper.isTag() && !cd2.isTag())||
321 (!possiblesuper.isTag() && cd2.isTag()))
325 if (cd2.isArray()||possiblesuper.isArray()) {
326 // Object is super class of all arrays
327 if (possiblesuper.getSymbol().equals(ObjectClass)&&!possiblesuper.isArray())
330 // If we have the same dimensionality of arrays & both are classes, we can default to the normal test
331 if (cd2.isClass()&&possiblesuper.isClass()
332 &&(possiblesuper.getArrayCount()==cd2.getArrayCount())&&
333 isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc()))
336 // Object is superclass of all array classes
337 if (possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()
338 &&(possiblesuper.getArrayCount()<cd2.getArrayCount()))
341 //Allow arraytype=null statements
342 if (possiblesuper.isArray()&&cd2.isNull())
348 if (possiblesuper.isClass()&&
350 return isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc());
351 else if (possiblesuper.isClass()&&
354 else if (possiblesuper.isNull())
355 throw new Error(); //not sure when this case would occur
356 else if (possiblesuper.isPrimitive()&&
358 ///Primitive widenings from 5.1.2
359 if (cd2.isByte()&&(possiblesuper.isByte()||possiblesuper.isShort()||
360 possiblesuper.isInt()||possiblesuper.isLong()||
361 possiblesuper.isFloat()||possiblesuper.isDouble()))
363 if (cd2.isShort()&&(possiblesuper.isShort()||
364 possiblesuper.isInt()||possiblesuper.isLong()||
365 possiblesuper.isFloat()||possiblesuper.isDouble()))
367 if (cd2.isChar()&&(possiblesuper.isChar()||
368 possiblesuper.isInt()||possiblesuper.isLong()||
369 possiblesuper.isFloat()||possiblesuper.isDouble()))
371 if (cd2.isInt()&&(possiblesuper.isInt()||possiblesuper.isLong()||
372 possiblesuper.isFloat()||possiblesuper.isDouble()
373 ||possiblesuper.isEnum()))
375 if (cd2.isEnum()&&(possiblesuper.isInt()||possiblesuper.isLong()||
376 possiblesuper.isFloat()||possiblesuper.isDouble()))
378 if(cd2.isEnum()&&possiblesuper.isEnum()&&cd2.class_desc.equals(possiblesuper.class_desc))
380 if (cd2.isLong()&&(possiblesuper.isLong()||
381 possiblesuper.isFloat()||possiblesuper.isDouble()))
383 if (cd2.isFloat()&&(possiblesuper.isFloat()||possiblesuper.isDouble()))
385 if (cd2.isDouble()&&possiblesuper.isDouble())
388 if (cd2.isBoolean()&&possiblesuper.isBoolean())
392 } else if (possiblesuper.isPrimitive()&&(!possiblesuper.isArray())&&
395 else if (cd2.isPrimitive()&&(!cd2.isArray())&&
396 possiblesuper.isPtr())
399 throw new Error("Case not handled:"+possiblesuper+" "+cd2);
402 public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2) {
403 if( isSuperorType( td1, td2 ) ) {
406 if( isSuperorType( td2, td1 ) ) {
409 throw new Error( td1+" and "+td2+" have no superclass relationship" );
412 public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2, TypeDescriptor td3) {
413 return mostSpecific( td1, mostSpecific( td2, td3 ) );
416 public boolean isSuperorType(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
417 if (possiblesuper==cd2)
420 return isSuper(possiblesuper, cd2);
423 private boolean isSuper(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
424 HashSet tovisit=new HashSet();
425 HashSet visited=new HashSet();
428 // check cd2's interface ancestors
429 Iterator<ClassDescriptor> it_sifs = getSuperIFs(cd2).iterator();
430 while(it_sifs.hasNext()) {
431 ClassDescriptor cd = it_sifs.next();
432 if(cd == possiblesuper) {
434 } else if(!tovisit.contains(cd)){
442 if (cd2==possiblesuper)
445 // check cd2's interface ancestors
447 Iterator it_sifs = getSuperIFs(cd2).iterator();
448 while(it_sifs.hasNext()) {
449 ClassDescriptor cd = (ClassDescriptor)it_sifs.next();
450 if(cd == possiblesuper) {
452 } else if(!tovisit.contains(cd)){
459 while(!tovisit.isEmpty()) {
460 ClassDescriptor cd = (ClassDescriptor)tovisit.iterator().next();
463 if(!visited.contains(cd)) {
464 Iterator it_sifs = getSuperIFs(cd).iterator();
465 while(it_sifs.hasNext()) {
466 ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
467 if(cdt == possiblesuper) {
469 } else if(!tovisit.contains(cdt)){