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 System.out.println("$$$cd="+cd+" children="+directSubClassTable.get(cd));
361 return (Set)directSubClassTable.get(cd);
364 public Set getSubClasses(ClassDescriptor cd) {
365 return (Set)subclasstable.get(cd);
368 public ClassDescriptor getSuper(ClassDescriptor cd) {
369 return (ClassDescriptor)supertable.get(cd);
372 public Set<ClassDescriptor> getSuperIFs(ClassDescriptor cd) {
373 return superIFtbl.get(cd);
376 public boolean isCastable(TypeDescriptor original, TypeDescriptor casttype) {
377 if (original.isChar()&&
382 if (casttype.isChar()&&
388 original.isDouble()))
394 public boolean isSuperorType(TypeDescriptor possiblesuper, TypeDescriptor cd2) {
395 if (possiblesuper.isOffset() || cd2.isOffset()) return true;
396 //Matching type are always okay
397 if (possiblesuper.equals(cd2))
400 if ((possiblesuper.isTag() && !cd2.isTag())||
401 (!possiblesuper.isTag() && cd2.isTag()))
405 if (cd2.isArray()||possiblesuper.isArray()) {
406 // Object is super class of all arrays
407 if (possiblesuper.getSymbol().equals(ObjectClass)&&!possiblesuper.isArray())
410 // If we have the same dimensionality of arrays & both are classes, we can default to the normal test
411 if (cd2.isClass()&&possiblesuper.isClass()
412 &&(possiblesuper.getArrayCount()==cd2.getArrayCount())&&
413 isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc()))
416 // Object is superclass of all array classes
417 if (possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()
418 &&(possiblesuper.getArrayCount()<cd2.getArrayCount()))
421 //Allow arraytype=null statements
422 if (possiblesuper.isArray()&&cd2.isNull())
428 // Object is superclass of interfaces
429 if(possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()&&cd2.getClassDesc().isInterface())
432 if (possiblesuper.isClass()&&
434 return isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc());
435 else if (possiblesuper.isClass()&&
438 else if (possiblesuper.isNull())
439 throw new Error(); //not sure when this case would occur
440 else if (possiblesuper.isPrimitive()&&
442 ///Primitive widenings from 5.1.2
443 if (cd2.isByte()&&(possiblesuper.isByte()||possiblesuper.isShort()||
444 possiblesuper.isInt()||possiblesuper.isLong()||
445 possiblesuper.isFloat()||possiblesuper.isDouble()))
447 if (cd2.isShort()&&(possiblesuper.isShort()||
448 possiblesuper.isInt()||possiblesuper.isLong()||
449 possiblesuper.isFloat()||possiblesuper.isDouble()))
451 if (cd2.isChar()&&(possiblesuper.isChar()||
452 possiblesuper.isInt()||possiblesuper.isLong()||
453 possiblesuper.isFloat()||possiblesuper.isDouble()))
455 if (cd2.isInt()&&(possiblesuper.isInt()||possiblesuper.isLong()||
456 possiblesuper.isFloat()||possiblesuper.isDouble()
457 ||possiblesuper.isEnum()))
459 if (cd2.isEnum()&&(possiblesuper.isInt()||possiblesuper.isLong()||
460 possiblesuper.isFloat()||possiblesuper.isDouble()))
462 if(cd2.isEnum()&&possiblesuper.isEnum()&&cd2.class_desc.equals(possiblesuper.class_desc))
464 if (cd2.isLong()&&(possiblesuper.isLong()||
465 possiblesuper.isFloat()||possiblesuper.isDouble()))
467 if (cd2.isFloat()&&(possiblesuper.isFloat()||possiblesuper.isDouble()))
469 if (cd2.isDouble()&&possiblesuper.isDouble())
472 if (cd2.isBoolean()&&possiblesuper.isBoolean())
476 } else if (possiblesuper.isPrimitive()&&(!possiblesuper.isArray())&&
479 else if (cd2.isPrimitive()&&(!cd2.isArray())&&
480 possiblesuper.isPtr())
483 throw new Error("Case not handled:"+possiblesuper+" "+cd2);
486 public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2) {
487 if( isSuperorType(td1, td2) ) {
490 if( isSuperorType(td2, td1) ) {
493 throw new Error(td1+" and "+td2+" have no superclass relationship");
496 public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2, TypeDescriptor td3) {
497 return mostSpecific(td1, mostSpecific(td2, td3) );
500 public boolean isSuperorType(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
501 if (possiblesuper==cd2)
504 return isSuper(possiblesuper, cd2);
507 private boolean isSuper(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
508 HashSet tovisit=new HashSet();
509 HashSet visited=new HashSet();
512 // check cd2's interface ancestors
513 Iterator<ClassDescriptor> it_sifs = getSuperIFs(cd2).iterator();
514 while(it_sifs.hasNext()) {
515 ClassDescriptor cd = it_sifs.next();
516 if(cd == possiblesuper) {
518 } else if(!tovisit.contains(cd)) {
526 if (cd2==possiblesuper)
529 // check cd2's interface ancestors
531 Iterator it_sifs = getSuperIFs(cd2).iterator();
532 while(it_sifs.hasNext()) {
533 ClassDescriptor cd = (ClassDescriptor)it_sifs.next();
534 if(cd == possiblesuper) {
536 } else if(!tovisit.contains(cd)) {
543 while(!tovisit.isEmpty()) {
544 ClassDescriptor cd = (ClassDescriptor)tovisit.iterator().next();
547 if(!visited.contains(cd)) {
548 Iterator it_sifs = getSuperIFs(cd).iterator();
549 while(it_sifs.hasNext()) {
550 ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
551 if(cdt == possiblesuper) {
553 } else if(!tovisit.contains(cdt)) {