+ if (bestmd==null)
+ throw new Error("Could find: "+name + " in "+cd);
+
+ return bestmd;
+ }
+
+ public void createFullTable() {
+ subclasstable=new Hashtable();
+ HashSet tovisit=new HashSet();
+ HashSet visited=new HashSet();
+
+ Iterator classit=state.getClassSymbolTable().getDescriptorsIterator();
+ while(classit.hasNext()) {
+ tovisit.clear();
+ visited.clear();
+ ClassDescriptor cd=(ClassDescriptor)classit.next();
+ ClassDescriptor tmp=cd.getSuperDesc();
+
+ // check cd's interface ancestors
+ {
+ Iterator it_sifs = cd.getSuperInterfaces();
+ while(it_sifs.hasNext()) {
+ ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
+ if(!tovisit.contains(cdt)) {
+ tovisit.add(cdt);
+ }
+ }
+ }
+
+ while(tmp!=null) {
+ if (!subclasstable.containsKey(tmp))
+ subclasstable.put(tmp,new HashSet());
+ HashSet hs=(HashSet)subclasstable.get(tmp);
+ hs.add(cd);
+ // check tmp's interface ancestors
+ Iterator it_sifs = tmp.getSuperInterfaces();
+ while(it_sifs.hasNext()) {
+ ClassDescriptor cdt = (ClassDescriptor)it_sifs.next();
+ if(!tovisit.contains(cdt)) {
+ tovisit.add(cdt);
+ }
+ }
+
+ tmp=tmp.getSuperDesc();
+ }
+
+ while(!tovisit.isEmpty()) {
+ ClassDescriptor sif = (ClassDescriptor)tovisit.iterator().next();
+ tovisit.remove(sif);
+
+ if(!visited.contains(sif)) {
+ if(!this.subclasstable.containsKey(sif)) {
+ this.subclasstable.put(sif, new HashSet());
+ }
+ HashSet hs = (HashSet) this.subclasstable.get(sif);
+ hs.add(cd);
+
+ Iterator it_sifs = sif.getSuperInterfaces();
+ while(it_sifs.hasNext()) {
+ ClassDescriptor siftmp = (ClassDescriptor)it_sifs.next();
+ if(!tovisit.contains(siftmp)) {
+ tovisit.add(siftmp);
+ }
+ }
+ visited.add(sif);
+ }
+ }
+ }
+ }
+
+ public Set getSubClasses(ClassDescriptor cd) {
+ return (Set)subclasstable.get(cd);
+ }
+
+ public ClassDescriptor getSuper(ClassDescriptor cd) {
+ return (ClassDescriptor)supertable.get(cd);
+ }
+
+ public Set<ClassDescriptor> getSuperIFs(ClassDescriptor cd) {
+ return superIFtbl.get(cd);
+ }
+
+ public boolean isCastable(TypeDescriptor original, TypeDescriptor casttype) {
+ if (original.isChar()&&
+ (casttype.isByte()||
+ casttype.isShort()))
+ return true;
+
+ if (casttype.isChar()&&
+ (original.isByte()||
+ original.isShort()||
+ original.isInt()||
+ original.isLong()||
+ original.isFloat()||
+ original.isDouble()))
+ return true;
+
+ return false;
+ }
+
+ public boolean isSuperorType(TypeDescriptor possiblesuper, TypeDescriptor cd2) {
+ if (possiblesuper.isOffset() || cd2.isOffset()) return true;
+ //Matching type are always okay
+ if (possiblesuper.equals(cd2))
+ return true;
+
+ if ((possiblesuper.isTag() && !cd2.isTag())||
+ (!possiblesuper.isTag() && cd2.isTag()))
+ return false;
+
+ //Handle arrays
+ if (cd2.isArray()||possiblesuper.isArray()) {
+ // Object is super class of all arrays
+ if (possiblesuper.getSymbol().equals(ObjectClass)&&!possiblesuper.isArray())
+ return true;
+
+ // If we have the same dimensionality of arrays & both are classes, we can default to the normal test
+ if (cd2.isClass()&&possiblesuper.isClass()
+ &&(possiblesuper.getArrayCount()==cd2.getArrayCount())&&
+ isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc()))
+ return true;
+
+ // Object is superclass of all array classes
+ if (possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()
+ &&(possiblesuper.getArrayCount()<cd2.getArrayCount()))
+ return true;
+
+ //Allow arraytype=null statements
+ if (possiblesuper.isArray()&&cd2.isNull())
+ return true;
+
+ return false;
+ }
+
+ if (possiblesuper.isClass()&&
+ cd2.isClass())
+ return isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc());
+ else if (possiblesuper.isClass()&&
+ cd2.isNull())
+ return true;
+ else if (possiblesuper.isNull())
+ throw new Error(); //not sure when this case would occur
+ else if (possiblesuper.isPrimitive()&&
+ cd2.isPrimitive()) {
+ ///Primitive widenings from 5.1.2
+ if (cd2.isByte()&&(possiblesuper.isByte()||possiblesuper.isShort()||
+ possiblesuper.isInt()||possiblesuper.isLong()||
+ possiblesuper.isFloat()||possiblesuper.isDouble()))
+ return true;
+ if (cd2.isShort()&&(possiblesuper.isShort()||
+ possiblesuper.isInt()||possiblesuper.isLong()||
+ possiblesuper.isFloat()||possiblesuper.isDouble()))
+ return true;
+ if (cd2.isChar()&&(possiblesuper.isChar()||
+ possiblesuper.isInt()||possiblesuper.isLong()||
+ possiblesuper.isFloat()||possiblesuper.isDouble()))
+ return true;
+ if (cd2.isInt()&&(possiblesuper.isInt()||possiblesuper.isLong()||
+ possiblesuper.isFloat()||possiblesuper.isDouble()
+ ||possiblesuper.isEnum()))
+ return true;
+ if (cd2.isEnum()&&(possiblesuper.isInt()||possiblesuper.isLong()||
+ possiblesuper.isFloat()||possiblesuper.isDouble()))
+ return true;
+ if(cd2.isEnum()&&possiblesuper.isEnum()&&cd2.class_desc.equals(possiblesuper.class_desc))
+ return true;
+ if (cd2.isLong()&&(possiblesuper.isLong()||
+ possiblesuper.isFloat()||possiblesuper.isDouble()))
+ return true;
+ if (cd2.isFloat()&&(possiblesuper.isFloat()||possiblesuper.isDouble()))
+ return true;
+ if (cd2.isDouble()&&possiblesuper.isDouble())
+
+ return true;
+ if (cd2.isBoolean()&&possiblesuper.isBoolean())
+ return true;
+
+ return false;
+ } else if (possiblesuper.isPrimitive()&&(!possiblesuper.isArray())&&
+ cd2.isPtr())
+ return false;
+ else if (cd2.isPrimitive()&&(!cd2.isArray())&&
+ possiblesuper.isPtr())
+ return false;
+ else
+ throw new Error("Case not handled:"+possiblesuper+" "+cd2);
+ }
+
+ public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2) {
+ if( isSuperorType(td1, td2) ) {
+ return td2;
+ }
+ if( isSuperorType(td2, td1) ) {
+ return td1;
+ }
+ throw new Error(td1+" and "+td2+" have no superclass relationship");
+ }
+
+ public TypeDescriptor mostSpecific(TypeDescriptor td1, TypeDescriptor td2, TypeDescriptor td3) {
+ return mostSpecific(td1, mostSpecific(td2, td3) );
+ }
+
+ public boolean isSuperorType(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
+ if (possiblesuper==cd2)
+ return true;
+ else
+ return isSuper(possiblesuper, cd2);
+ }
+
+ private boolean isSuper(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
+ HashSet tovisit=new HashSet();
+ HashSet visited=new HashSet();
+
+ {
+ // check cd2's interface ancestors
+ Iterator<ClassDescriptor> it_sifs = getSuperIFs(cd2).iterator();
+ while(it_sifs.hasNext()) {
+ ClassDescriptor cd = it_sifs.next();
+ if(cd == possiblesuper) {
+ return true;
+ } else if(!tovisit.contains(cd)) {
+ tovisit.add(cd);
+ }
+ }
+ }
+
+ while(cd2!=null) {
+ cd2=getSuper(cd2);
+ if (cd2==possiblesuper)
+ return true;
+
+ // check cd2's interface ancestors
+ if(cd2 != null) {
+ Iterator it_sifs = getSuperIFs(cd2).iterator();
+ while(it_sifs.hasNext()) {
+ ClassDescriptor cd = (ClassDescriptor)it_sifs.next();
+ if(cd == possiblesuper) {
+ return true;
+ } else if(!tovisit.contains(cd)) {
+ tovisit.add(cd);
+ }
+ }
+ }
+ }
+
+ while(!tovisit.isEmpty()) {
+ ClassDescriptor cd = (ClassDescriptor)tovisit.iterator().next();
+ tovisit.remove(cd);