4 import IR.Flat.FlatNode;
9 public class TypeUtil {
10 public static String StringClass;
11 public static String StringClassValueField;
12 public static String ObjectClass;
13 public static String StartupClass;
14 public static String TagClass;
15 public static String ThreadClass;
16 public static String TaskClass;
19 Hashtable subclasstable;
20 Hashtable directSubClassTable;
24 Hashtable<ClassDescriptor, Set<ClassDescriptor>> superIFtbl;
26 public TypeUtil(State state, BuildIR bir) {
30 StringClass="java.lang.String";
31 StringClassValueField="value";
32 ObjectClass="java.lang.Object";
33 StartupClass="StartupObject";
34 TagClass="TagDescriptor";
35 ThreadClass="java.lang.Thread";
39 StringClassValueField="value";
41 StartupClass="StartupObject";
42 TagClass="TagDescriptor";
49 public void addNewClass(String cl, Set todo) {
50 //search through the default locations for the file.
52 // do not consider package or import when compiling MGC version
53 cl = (cl.lastIndexOf('.')==-1)?cl:cl.substring(cl.lastIndexOf('.')+1);
55 for (int i = 0; i < state.classpath.size(); i++) {
56 String path = (String) state.classpath.get(i);
57 File f = new File(path, cl.replace('.', '/') + ".java");
60 ParseNode pn = Main.readSourceFile(state, f.getCanonicalPath());
61 bir.buildtree(pn, todo, f.getCanonicalPath());
63 } catch (Exception e) {
72 public ClassDescriptor getClass(String classname) {
73 String cl = classname;
75 // do not consider package or import when compiling MGC version
76 cl = (cl.lastIndexOf('.')==-1)?cl:cl.substring(cl.lastIndexOf('.')+1);
78 ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(cl);
82 public ClassDescriptor getClass(ClassDescriptor context, String classnameIn, HashSet todo) {
85 int dotindex=classnameIn.indexOf('.',fileindex);
89 //get entire class name
90 dotindex=classnameIn.length();
93 String classnamestr = classnameIn.substring(0, dotindex);
94 String remainder = classnameIn.substring(dotindex, classnameIn.length());
97 classnamestr = context.getCanonicalImportMapName(classnamestr);
99 ClassDescriptor cd=helperGetClass(classnamestr, remainder, todo);
104 } while(fileindex!=0);
105 throw new Error("Cannot find class: "+classnameIn);
108 private ClassDescriptor helperGetClass(String classname, String remainder, HashSet todo) {
109 String cl = classname;
111 // do not consider package or import when compiling MGC version
112 cl = (cl.lastIndexOf('.')==-1)?cl:cl.substring(cl.lastIndexOf('.')+1);
115 ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(cl);
118 addNewClass(cl, todo);
119 String cl2=cl+remainder.replace('.','$');
120 cd=(ClassDescriptor)state.getClassSymbolTable().get(cl2);
123 System.out.println("Build class:"+cd);
126 String cl2=cl+remainder.replace('.','$');
127 cd=(ClassDescriptor)state.getClassSymbolTable().get(cl2);
131 if (!supertable.containsKey(cd)) {
132 String superc=cd.getSuper();
134 ClassDescriptor cd_super=getClass(cd, superc, todo);
135 supertable.put(cd,cd_super);
138 if (!superIFtbl.containsKey(cd)) {
139 // add inherited interfaces
140 superIFtbl.put(cd,new HashSet());
141 HashSet hs=(HashSet)superIFtbl.get(cd);
142 Vector<String> superifv = cd.getSuperInterface();
143 for(int i = 0; i < superifv.size(); i++) {
144 String superif = superifv.elementAt(i);
145 ClassDescriptor if_super = getClass(cd, superif, todo);
152 private void createTables() {
153 supertable=new Hashtable();
154 superIFtbl = new Hashtable<ClassDescriptor,Set<ClassDescriptor>>();
157 public ClassDescriptor getMainClass() {
158 return getClass(state.main);
161 public MethodDescriptor getRun() {
162 ClassDescriptor cd=getClass(TypeUtil.ThreadClass);
163 for(Iterator methodit=cd.getMethodTable().getSet("run").iterator(); methodit.hasNext(); ) {
164 MethodDescriptor md=(MethodDescriptor) methodit.next();
165 if (md.numParameters()!=0||md.getModifiers().isStatic())
169 throw new Error("Can't find Thread.run");
172 public MethodDescriptor getStaticStart() {
173 ClassDescriptor cd=getClass(TypeUtil.ThreadClass);
174 for(Iterator methodit=cd.getMethodTable().getSet("staticStart").iterator(); methodit.hasNext(); ) {
175 MethodDescriptor md=(MethodDescriptor) methodit.next();
176 if (md.numParameters()!=1||!md.getModifiers().isStatic()||!md.getParamType(0).isClass()||md.getParamType(0).getClassDesc()!=cd)
180 throw new Error("Can't find Thread.run");
183 public MethodDescriptor getExecute() {
184 ClassDescriptor cd = getClass(TypeUtil.TaskClass);
186 if(cd == null && state.DSMTASK)
187 throw new Error("Task.java is not included");
189 for(Iterator methodit = cd.getMethodTable().getSet("execute").iterator(); methodit.hasNext(); ) {
190 MethodDescriptor md = (MethodDescriptor) methodit.next();
191 if (md.numParameters()!=0 || md.getModifiers().isStatic())
195 throw new Error("Can't find Task.execute");
199 public MethodDescriptor getMain() {
200 ClassDescriptor cd=getMainClass();
201 Set mainset=cd.getMethodTable().getSet("main");
203 for(Iterator mainit=mainset.iterator(); mainit.hasNext(); ) {
204 MethodDescriptor md=(MethodDescriptor)mainit.next();
205 if (md.numParameters()!=1)
207 Descriptor pd=md.getParameter(0);
208 TypeDescriptor tpd=(pd instanceof TagVarDescriptor)?((TagVarDescriptor)pd).getType():((VarDescriptor)pd)
210 if (tpd.getArrayCount()!=1)
212 if (!tpd.getSymbol().equals(StringClass))
214 if (!md.getModifiers().isStatic())
215 throw new Error("Error: Non static main");
218 throw new Error(cd+" has no main");
221 /** Check to see if md1 is more specific than md2... Informally
222 if md2 could always be called given the arguments passed into
225 public boolean isMoreSpecific(MethodDescriptor md1, MethodDescriptor md2, boolean checkReturnType) {
226 /* Checks if md1 is more specific than md2 */
227 if (md1.numParameters()!=md2.numParameters())
229 for(int i=0; i<md1.numParameters(); i++) {
230 if (!this.isSuperorType(md2.getParamType(i), md1.getParamType(i))) {
231 if(((!md1.getParamType(i).isArray() &&
232 (md1.getParamType(i).isInt() || md1.getParamType(i).isLong() || md1.getParamType(i).isDouble() || md1.getParamType(i).isFloat()))
233 && md2.getParamType(i).isClass() && md2.getParamType(i).getClassDesc().getSymbol().equals("Object"))) {
234 // primitive parameters vs Object
240 if(checkReturnType) {
241 if (md1.getReturnType()==null||md2.getReturnType()==null) {
242 if (md1.getReturnType()!=md2.getReturnType())
245 if (!this.isSuperorType(md2.getReturnType(), md1.getReturnType()))
249 if (!this.isSuperorType(md2.getClassDesc(), md1.getClassDesc()))
255 public MethodDescriptor getMethod(ClassDescriptor cd, String name, TypeDescriptor[] types) {
256 Set methoddescriptorset=cd.getMethodTable().getSet(name);
257 MethodDescriptor bestmd=null;
259 for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext(); ) {
260 MethodDescriptor currmd=(MethodDescriptor)methodit.next();
261 /* Need correct number of parameters */
262 if (types.length!=currmd.numParameters())
264 for(int i=0; i<types.length; i++) {
265 if (!this.isSuperorType(currmd.getParamType(i),types[i]))
268 /* Method okay so far */
272 if (isMoreSpecific(currmd,bestmd, true)) {
274 } else if (!isMoreSpecific(bestmd, currmd, true))
275 throw new Error("No method is most specific");
277 /* Is this more specific than bestmd */
281 throw new Error("Could find: "+name + " in "+cd);
286 public void createFullTable() {
287 subclasstable=new Hashtable();
288 directSubClassTable=new Hashtable();
289 HashSet tovisit=new HashSet();
290 HashSet visited=new HashSet();
292 Iterator classit=state.getClassSymbolTable().getDescriptorsIterator();
293 while(classit.hasNext()) {
296 ClassDescriptor cd=(ClassDescriptor)classit.next();
297 ClassDescriptor tmp=cd.getSuperDesc();
299 // check cd's interface ancestors
301 Iterator it_sifs = cd.getSuperInterfaces();
302 while(it_sifs.hasNext()) {
303 ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
304 if(!tovisit.contains(cdt)) {
311 if(!directSubClassTable.containsKey(tmp)){
312 directSubClassTable.put(tmp, new HashSet());
314 ((Set)directSubClassTable.get(tmp)).add(cd);
319 if (!subclasstable.containsKey(tmp))
320 subclasstable.put(tmp,new HashSet());
321 HashSet hs=(HashSet)subclasstable.get(tmp);
323 // check tmp's interface ancestors
324 Iterator it_sifs = tmp.getSuperInterfaces();
325 while(it_sifs.hasNext()) {
326 ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
327 if(!tovisit.contains(cdt)) {
332 tmp=tmp.getSuperDesc();
335 while(!tovisit.isEmpty()) {
336 ClassDescriptor sif = (ClassDescriptor)tovisit.iterator().next();
339 if(!visited.contains(sif)) {
340 if(!this.subclasstable.containsKey(sif)) {
341 this.subclasstable.put(sif, new HashSet());
343 HashSet hs = (HashSet) this.subclasstable.get(sif);
346 Iterator it_sifs = sif.getSuperInterfaces();
347 while(it_sifs.hasNext()) {
348 ClassDescriptor siftmp = (ClassDescriptor)it_sifs.next();
349 if(!tovisit.contains(siftmp)) {
359 public Set getDirectSubClasses(ClassDescriptor cd) {
360 return (Set)directSubClassTable.get(cd);
363 public Set getSubClasses(ClassDescriptor cd) {
364 return (Set)subclasstable.get(cd);
367 public ClassDescriptor getSuper(ClassDescriptor cd) {
368 return (ClassDescriptor)supertable.get(cd);
371 public Set<ClassDescriptor> getSuperIFs(ClassDescriptor cd) {
372 return superIFtbl.get(cd);
375 public boolean isCastable(TypeDescriptor original, TypeDescriptor casttype) {
376 if (original.isChar()&&
381 if (casttype.isChar()&&
387 original.isDouble()))
393 public boolean isSuperorType(TypeDescriptor possiblesuper, TypeDescriptor cd2) {
394 if (possiblesuper.isOffset() || cd2.isOffset()) return true;
395 //Matching type are always okay
396 if (possiblesuper.equals(cd2))
399 if ((possiblesuper.isTag() && !cd2.isTag())||
400 (!possiblesuper.isTag() && cd2.isTag()))
404 if (cd2.isArray()||possiblesuper.isArray()) {
405 // Object is super class of all arrays
406 if (possiblesuper.getSymbol().equals(ObjectClass)&&!possiblesuper.isArray())
409 // If we have the same dimensionality of arrays & both are classes, we can default to the normal test
410 if (cd2.isClass()&&possiblesuper.isClass()
411 &&(possiblesuper.getArrayCount()==cd2.getArrayCount())&&
412 isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc()))
415 // Object is superclass of all array classes
416 if (possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()
417 &&(possiblesuper.getArrayCount()<cd2.getArrayCount()))
420 //Allow arraytype=null statements
421 if (possiblesuper.isArray()&&cd2.isNull())
427 // Object is superclass of interfaces
428 if(possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()&&cd2.getClassDesc().isInterface())
431 if (possiblesuper.isClass()&&
433 return isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc());
434 else if (possiblesuper.isClass()&&
437 else if (possiblesuper.isNull())
438 throw new Error(); //not sure when this case would occur
439 else if (possiblesuper.isPrimitive()&&
441 ///Primitive widenings from 5.1.2
442 if (cd2.isByte()&&(possiblesuper.isByte()||possiblesuper.isShort()||
443 possiblesuper.isInt()||possiblesuper.isLong()||
444 possiblesuper.isFloat()||possiblesuper.isDouble()))
446 if (cd2.isShort()&&(possiblesuper.isShort()||
447 possiblesuper.isInt()||possiblesuper.isLong()||
448 possiblesuper.isFloat()||possiblesuper.isDouble()))
450 if (cd2.isChar()&&(possiblesuper.isChar()||
451 possiblesuper.isInt()||possiblesuper.isLong()||
452 possiblesuper.isFloat()||possiblesuper.isDouble()))
454 if (cd2.isInt()&&(possiblesuper.isInt()||possiblesuper.isLong()||
455 possiblesuper.isFloat()||possiblesuper.isDouble()
456 ||possiblesuper.isEnum()))
458 if (cd2.isEnum()&&(possiblesuper.isInt()||possiblesuper.isLong()||
459 possiblesuper.isFloat()||possiblesuper.isDouble()))
461 if(cd2.isEnum()&&possiblesuper.isEnum()&&cd2.class_desc.equals(possiblesuper.class_desc))
463 if (cd2.isLong()&&(possiblesuper.isLong()||
464 possiblesuper.isFloat()||possiblesuper.isDouble()))
466 if (cd2.isFloat()&&(possiblesuper.isFloat()||possiblesuper.isDouble()))
468 if (cd2.isDouble()&&possiblesuper.isDouble())
471 if (cd2.isBoolean()&&possiblesuper.isBoolean())
475 } else if (possiblesuper.isPrimitive()&&(!possiblesuper.isArray())&&
478 else if (cd2.isPrimitive()&&(!cd2.isArray())&&
479 possiblesuper.isPtr())
482 throw new Error("Case not handled:"+possiblesuper+" "+cd2);
485 public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2) {
486 if( isSuperorType(td1, td2) ) {
489 if( isSuperorType(td2, td1) ) {
492 throw new Error(td1+" and "+td2+" have no superclass relationship");
495 public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2, TypeDescriptor td3) {
496 return mostSpecific(td1, mostSpecific(td2, td3) );
499 public boolean isSuperorType(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
500 if (possiblesuper==cd2)
503 return isSuper(possiblesuper, cd2);
506 private boolean isSuper(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
507 HashSet tovisit=new HashSet();
508 HashSet visited=new HashSet();
511 // check cd2's interface ancestors
512 Iterator<ClassDescriptor> it_sifs = getSuperIFs(cd2).iterator();
513 while(it_sifs.hasNext()) {
514 ClassDescriptor cd = it_sifs.next();
515 if(cd == possiblesuper) {
517 } else if(!tovisit.contains(cd)) {
525 if (cd2==possiblesuper)
528 // check cd2's interface ancestors
530 Iterator it_sifs = getSuperIFs(cd2).iterator();
531 while(it_sifs.hasNext()) {
532 ClassDescriptor cd = (ClassDescriptor)it_sifs.next();
533 if(cd == possiblesuper) {
535 } else if(!tovisit.contains(cd)) {
542 while(!tovisit.isEmpty()) {
543 ClassDescriptor cd = (ClassDescriptor)tovisit.iterator().next();
546 if(!visited.contains(cd)) {
547 Iterator it_sifs = getSuperIFs(cd).iterator();
548 while(it_sifs.hasNext()) {
549 ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
550 if(cdt == possiblesuper) {
552 } else if(!tovisit.contains(cdt)) {