Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

ClassInfo.java

00001 package gov.nasa.arc.ase.jpf.jvm;
00002 
00003 import de.fub.bytecode.Repository;
00004 import de.fub.bytecode.classfile.Field;
00005 import de.fub.bytecode.classfile.JavaClass;
00006 import de.fub.bytecode.classfile.Method;
00007 import gov.nasa.arc.ase.jpf.Engine;
00008 import gov.nasa.arc.ase.jpf.InternalErrorException;
00009 import gov.nasa.arc.ase.jpf.JPFErrorException;
00010 import gov.nasa.arc.ase.jpf.SafeBlocks;
00011 import gov.nasa.arc.ase.jpf.jvm.bytecode.Instruction;
00012 import gov.nasa.arc.ase.jpf.jvm.reflection.Reflection;
00013 import gov.nasa.arc.ase.util.Debug;
00014 import java.io.BufferedReader;
00015 import java.io.File;
00016 import java.io.FileNotFoundException;
00017 import java.io.FileReader;
00018 import java.util.Hashtable;
00019 //#ifdef MARK_N_SWEEP || REFERENCE_COUNT
00020 import gov.nasa.arc.ase.util.BSet;
00021 import gov.nasa.arc.ase.util.ArrayBSet;
00022 //#endif MARK_N_SWEEP || REFERENCE_COUNT
00023 //#ifdef RACE
00024 
00025 //#endif RACE
00026 
00027 public class ClassInfo {
00028   /**
00029    * Map of the loaded classes.
00030    */
00031   private static Hashtable loadedClasses = new Hashtable();
00032 
00033   /**
00034    * Map of the loaded safe blocks.
00035    */
00036   private static Hashtable safeBlocksPool = new Hashtable();
00037 
00038   /**
00039    * Name of the class.
00040    */
00041   private String name;
00042 
00043   /**
00044    * List of static methods.
00045    */
00046   private MethodInfo[] staticMethods;
00047 
00048   /**
00049    * List of dynamic methods.
00050    */
00051   private MethodInfo[] dynamicMethods;
00052 
00053   /**
00054    * List of static fields.
00055    */
00056   private FieldInfo[] staticFields;
00057 
00058   /**
00059    * List of dynamic fields.
00060    */
00061   private FieldInfo[] dynamicFields;
00062 
00063   /**
00064    * Information about safe blocks in the code.
00065    */
00066   private SafeBlocks safeBlocks;
00067 
00068   /**
00069    * Reference to the super class.
00070    */
00071   private ClassInfo superClass;
00072 
00073   /**
00074    * Interfaces implemented by the class.
00075    */
00076   private String[] interfaces;
00077 
00078   /**
00079    * Name of the package.
00080    */
00081   private String packageName;
00082 
00083   /**
00084    * Name of the file which contains the source of this class.
00085    */
00086   private String sourceFileName;
00087 
00088   /**
00089    * Reflection object for this class.
00090    */
00091   private Reflection reflection;
00092 
00093   /**
00094    * Source file associated with the class.
00095    */
00096   private Source source;
00097 
00098 //#ifdef MARK_N_SWEEP || REFERENCE_COUNT
00099 
00100   /**
00101    * Which fields are references.
00102    */
00103   private BSet dRefs;
00104 
00105   /**
00106    * Which static fields are references.
00107    */
00108   private BSet sRefs;
00109 
00110 //#endif MARK_N_SWEEP || REFERENCE_COUNT
00111 //#endif MARK_N_SWEEP || REFERENCE_COUNT
00112 
00113   /**
00114    * Creates a new class from the JavaClass information.
00115    */
00116   private ClassInfo(JavaClass jc) {
00117     name = jc.getClassName();
00118 
00119     loadedClasses.put(name, this);
00120 
00121     superClass = loadSuperClass(jc);
00122     staticMethods = loadStaticMethods(jc);
00123     dynamicMethods = loadDynamicMethods(jc);
00124     staticFields = loadStaticFields(jc);
00125     dynamicFields = loadDynamicFields(jc);
00126     interfaces = loadInterfaces(jc);
00127     packageName = jc.getPackageName();
00128     sourceFileName = jc.getSourceFileName();
00129 
00130     safeBlocks = loadSafeBlocks();
00131     reflection = loadReflection();
00132     reflection.setClassInfo(this);
00133 //#ifdef MARK_N_SWEEP || REFERENCE_COUNT
00134     dRefs = loadRefs(dynamicFields);
00135     sRefs = loadRefs(staticFields);
00136 //#endif MARK_N_SWEEP || REFERENCE_COUNT
00137 
00138     source = null;
00139   }  
00140   /**
00141    * Creates the fields for a class.
00142    */
00143   public Fields createClassFields() {
00144     FieldInfo[] fs = staticFields;
00145     int size = fs.length;
00146     int length = 0;
00147     for(int i = 0; i < size; i++)
00148       if(fs[i] != null)
00149     length++;
00150 
00151     Fields f = new Fields(getType(), this, size, length, true
00152 //#ifdef MARK_N_SWEEP || REFERENCE_COUNT
00153     , sRefs
00154 //#endif MARK_N_SWEEP || REFERENCE_COUNT
00155     );
00156     for(int i = 0; i < length; ) {
00157       String t = fs[i].getType();
00158       switch(Types.getBaseType(t)) {
00159     case Types.T_BYTE:
00160     case Types.T_CHAR:
00161     case Types.T_FLOAT:
00162     case Types.T_INT:
00163     case Types.T_SHORT:
00164     case Types.T_BOOLEAN:
00165       f.setField(i, 0);
00166       break;
00167 
00168     case Types.T_DOUBLE:
00169     case Types.T_LONG:
00170       f.setLongField(i, 0);
00171       break;
00172 
00173     case Types.T_REFERENCE:
00174     case Types.T_ARRAY:
00175       f.setField(i, -1);
00176       break;
00177 
00178     default:
00179       throw new InternalErrorException("invalid type");
00180       }
00181       i += Types.getTypeSize(t);
00182     }
00183 
00184     return f;
00185   }  
00186   /**
00187    * Creates the environment to execute the main method.
00188    */
00189   public ThreadInfo createMainThread(SystemState ss, String[] args) {
00190     int tObjref = ss.ks.da.newObject(
00191     ClassInfo.getClassInfo("java/lang/Thread"),
00192     null);
00193     ThreadInfo th = ss.ks.newThread(tObjref);
00194 
00195     MethodInfo mi = getStaticMethod("main([Ljava/lang/String;)V");
00196 
00197     if(mi == null)
00198       throw new JPFErrorException("main method not defined in " + name);
00199 
00200     th.newFrame(mi);
00201 
00202     int argsObjref = ss.ks.da.newArray(
00203     "Ljava/lang/String;",
00204     args.length,
00205     null);
00206     ElementInfo argsElement = ss.ks.da.get(argsObjref);
00207 
00208     for(int i = 0; i < args.length; i++) {
00209       int stringObjref = ss.ks.da.newString(args[i], null);
00210       argsElement.setField(i, stringObjref);
00211     }
00212 
00213     th.setLocalVariable(0, argsObjref, true);
00214 
00215     th.setStatus(ThreadInfo.RUNNING);
00216 
00217 //#ifdef RACE
00218 
00219 
00220 //#endif RACE
00221 
00222     return th;
00223   }  
00224   /**
00225    * Creates the fields for an object.
00226    */
00227   public Fields createObjectFields() {
00228     FieldInfo[] fs = dynamicFields;
00229     int size = fs.length;
00230     int length = 0;
00231     for(int i = 0; i < size; i++)
00232       if(fs[i] != null)
00233     length++;
00234 
00235     Fields f = new Fields(getType(), this, size, length, false
00236 //#ifdef MARK_N_SWEEP || REFERENCE_COUNT
00237     , dRefs
00238 //#endif MARK_N_SWEEP || REFERENCE_COUNT
00239     );
00240     for(int i = 0; i < length; i++) {
00241       if(fs[i] != null) {
00242     switch(Types.getBaseType(fs[i].getType())) {
00243       case Types.T_BYTE:
00244       case Types.T_CHAR:
00245       case Types.T_FLOAT:
00246       case Types.T_INT:
00247       case Types.T_SHORT:
00248       case Types.T_BOOLEAN:
00249         f.setField(i, 0);
00250         break;
00251 
00252       case Types.T_DOUBLE:
00253       case Types.T_LONG:
00254         f.setLongField(i, 0);
00255         break;
00256 
00257       case Types.T_REFERENCE:
00258       case Types.T_ARRAY:
00259         f.setField(i, -1);
00260         break;
00261 
00262       default:
00263         throw new InternalErrorException("invalid type");
00264     }
00265       }
00266     }
00267 
00268     return f;
00269   }  
00270   /**
00271    * Returns the index for a dynamic field.
00272    */
00273   public int dynamicFieldIndex(String fname) {
00274     int length = dynamicFields.length;
00275 
00276     for(int i = 0; i < length; i++)
00277       if(dynamicFields[i] != null && dynamicFields[i].getName().equals(fname))
00278     return i;
00279 
00280     throw new InternalErrorException("class " + getName() + "does not have field `" + fname + "'");
00281   }  
00282   /**
00283    * Executes a method.
00284    */
00285   public Instruction executeMethod(ThreadInfo th, String mname) {
00286     MethodInfo mi = getDynamicMethod(mname);
00287 
00288     Reflection r = reflection.instantiate(th.getCalleeThis(mi));
00289     th.createMethodStackFrame(mi);
00290 
00291     return r.executeMethod(th, mi);
00292   }  
00293   /**
00294    * Executes a static method.
00295    */
00296   public Instruction executeStaticMethod(ThreadInfo th, String mname) {
00297     MethodInfo mi = getStaticMethod(mname);
00298 
00299     Reflection r = reflection.instantiate();
00300     th.createMethodStackFrame(mi);
00301 
00302     return r.executeStaticMethod(th, mi);
00303   }  
00304   public static boolean exists(String cname) {
00305     return Repository.lookupClass(cname) != null;
00306   }  
00307   /**
00308    * Loads a class.
00309    */
00310   public static synchronized ClassInfo getClassInfo(String cname) {
00311     if(cname == null) return null;
00312 
00313     cname = cname.replace('/', '.');
00314     
00315     ClassInfo ci = (ClassInfo)loadedClasses.get(cname);
00316 
00317     if(ci == null) {
00318       JavaClass jc = Repository.lookupClass(cname);
00319 
00320       if(jc == null)
00321     throw new JPFErrorException("could not load class " + cname);
00322 
00323       Repository.clearCache();
00324 
00325       ci = new ClassInfo(jc);
00326     }
00327 
00328     return ci;
00329   }  
00330   /**
00331    * Returns the information about a dynamic field.
00332    */
00333   public FieldInfo getDynamicField(int index) {
00334     return dynamicFields[index];
00335   }  
00336   /**
00337    * Returns the name of a dynamic field.
00338    */
00339   public String getDynamicFieldName(int index) {
00340     return dynamicFields[index].getName();
00341   }  
00342   /**
00343    * Returns the method info a given dynamic method.
00344    */
00345   public MethodInfo getDynamicMethod(String mname) {
00346     for(int i = 0, l = dynamicMethods.length; i < l; i++)
00347       if(dynamicMethods[i].getFullName().equals(mname))
00348     return dynamicMethods[i];
00349 
00350     if(superClass != null)
00351       return superClass.getDynamicMethod(mname);
00352 
00353     return null;
00354   }  
00355   /**
00356    * Returns the name of the class.
00357    */
00358   public String getName() {
00359     return name;
00360   }  
00361   /**
00362    * Returns the reflection object associated with the class.
00363    */
00364   public Reflection getReflection() {
00365     return reflection;
00366   }  
00367   public Source getSource() {
00368     if(source == null)
00369       source = loadSource();
00370 
00371     return source;
00372   }  
00373   public String getSourceFileName() {
00374     return sourceFileName;
00375   }  
00376   /**
00377    * Returns the information about a static field.
00378    */
00379   public FieldInfo getStaticField(int index) {
00380     return staticFields[index];
00381   }  
00382   /**
00383    * Returns the name of a static field.
00384    */
00385   public String getStaticFieldName(int index) {
00386     return staticFields[index].getName();
00387   }  
00388   /**
00389    * Returns the method info for a given static method.
00390    */
00391   public MethodInfo getStaticMethod(String mname) {
00392     for(int i = 0, l = staticMethods.length; i < l; i++)
00393       if(staticMethods[i].getFullName().equals(mname))
00394     return staticMethods[i];
00395 
00396     // class init is never inherited from super class
00397     if(mname.equals("<clinit>()V"))
00398       return null;
00399 
00400     if(superClass != null)
00401       return superClass.getStaticMethod(mname);
00402 
00403     return null;
00404   }  
00405   /**
00406    * Return the super class.
00407    */
00408   public ClassInfo getSuperClass() {
00409     return superClass;
00410   }  
00411   /**
00412    * Returns the type of a class.
00413    */
00414   public String getType() {
00415     return "L" + name.replace('.', '/') + ";";
00416   }  
00417   /**
00418    * Returns true if this class is an instance of the given class.
00419    */
00420   public boolean instanceOf(ClassInfo ci) {
00421     if(this == ci) return true;
00422 
00423     if(superClass != null)
00424       return superClass.instanceOf(ci);
00425 
00426     return false;
00427   }  
00428   /**
00429    * Returns true if the given class is an instance of the class
00430    * or interface specified.
00431    */
00432   public boolean instanceOf(String cname) {
00433     cname = cname.replace('/', '.');
00434 
00435     if(name.equals(cname)) return true;
00436 
00437     for(int i = 0, l = interfaces.length; i < l; i++)
00438       if(interfaces[i].equals(cname))
00439     return true;
00440 
00441     if(superClass != null)
00442       return superClass.instanceOf(cname);
00443 
00444     return false;
00445   }  
00446   /**
00447    * Checks if a method call is deterministic.
00448    */
00449   public boolean isMethodDeterministic(ThreadInfo th, String mname) {
00450     MethodInfo mi = getDynamicMethod(mname);
00451 
00452     Reflection r = reflection.instantiate(th.getCalleeThis(mi));
00453 
00454     return r.isMethodDeterministic(th, mi);
00455   }  
00456   /**
00457    * Checks if a method is executable.
00458    */
00459   public boolean isMethodExecutable(ThreadInfo th, String mname) {
00460     MethodInfo mi = getDynamicMethod(mname);
00461 
00462     Reflection r = reflection.instantiate(th.getCalleeThis(mi));
00463 
00464     return r.isMethodExecutable(th, mi);
00465   }  
00466   /**
00467    * Returns true if a line is defined as safe.
00468    */
00469   public boolean isSafe(int line) {
00470     if (safeBlocks == null)
00471       return false;
00472     else
00473       return safeBlocks.isSafe(line);
00474   }  
00475   /**
00476    * Checks if a static method call is deterministic.
00477    */
00478   public boolean isStaticMethodDeterministic(ThreadInfo th, String mname) {
00479     MethodInfo mi = getStaticMethod(mname);
00480 
00481     Reflection r = reflection.instantiate();
00482 
00483     return r.isStaticMethodDeterministic(th, mi);
00484   }  
00485   /**
00486    * Checks if a static method is executable.
00487    */
00488   public boolean isStaticMethodExecutable(ThreadInfo th, String mname) {
00489     MethodInfo mi = getStaticMethod(mname);
00490 
00491     Reflection r = reflection.instantiate();
00492 
00493     return r.isStaticMethodExecutable(th, mi);
00494   }  
00495   /**
00496    * Returns true if the class is a system class.
00497    */
00498   public boolean isSystemClass() {
00499     return name.startsWith("java.lang.") || name.startsWith("java.util.");
00500   }  
00501   /**
00502    * Loads the dynamic fields of a class.
00503    */
00504   private FieldInfo[] loadDynamicFields(JavaClass jc) {
00505     Field[] fields = jc.getFields();
00506 
00507     int counter = 0;
00508 
00509     for(int i = 0, l = fields.length; i < l; i++)
00510       if(!fields[i].isStatic())
00511     counter += Types.getTypeSize(fields[i].getSignature().toString());
00512 
00513     if(superClass != null)
00514       counter += superClass.dynamicFields.length;
00515 
00516     FieldInfo[] dFields = new FieldInfo[counter];
00517 
00518     if(superClass != null) {
00519       counter = superClass.dynamicFields.length;
00520       System.arraycopy(superClass.dynamicFields, 0, dFields, 0, counter);
00521     } else
00522       counter = 0;
00523 
00524     for(int i = 0, l = fields.length; i < l; i++)
00525       if(!fields[i].isStatic()) {
00526     dFields[counter] = new FieldInfo(fields[i], this);
00527     counter += Types.getTypeSize(fields[i].getSignature().toString());
00528       }
00529 
00530     return dFields;
00531   }  
00532   /**
00533    * Loads the dynamic methods of a class.
00534    */
00535   private MethodInfo[] loadDynamicMethods(JavaClass jc) {
00536     Method[] methods = jc.getMethods();
00537 
00538     int counter = 0;
00539     for(int i = 0, l = methods.length; i < l; i++)
00540       if(!methods[i].isStatic())
00541     counter++;
00542 
00543     MethodInfo[] dMethods = new MethodInfo[counter];
00544     
00545     counter = 0;
00546     for(int i = 0, l = methods.length; i < l; i++)
00547       if(!methods[i].isStatic())
00548     dMethods[counter++] = new MethodInfo(methods[i], this);
00549 
00550     return dMethods;
00551   }  
00552   /**
00553    * Loads the interfaces of a class.
00554    */
00555   private static String[] loadInterfaces(JavaClass jc) {
00556     int[] intInterfaces = jc.getInterfaces();
00557 
00558     String[] stringInterfaces = new String[intInterfaces.length];
00559 
00560     for(int i = 0, l = intInterfaces.length; i < l; i++)
00561       stringInterfaces[i] =
00562     jc.getConstantPool().getConstant(
00563         intInterfaces[i]
00564                     ).toString().replace('/', '.');
00565 
00566     return stringInterfaces;
00567   }  
00568   /**
00569    * Loads the reflection class.
00570    */
00571   private Reflection loadReflection() {
00572     return Reflection.load(name);
00573   }  
00574 //#ifdef MARK_N_SWEEP || REFERENCE_COUNT
00575 
00576   private static BSet loadRefs(FieldInfo[] f) {
00577     int l = f.length;
00578     boolean[] refs = new boolean[l];
00579 
00580     for(int i = 0; i < l; i++)
00581       refs[i] = f[i] != null && Types.isReference(f[i].getType());
00582 
00583     return new ArrayBSet(refs);
00584   }  
00585   /**
00586    * Loads the safe blocks.
00587    */
00588   private SafeBlocks loadSafeBlocks() {
00589     if(!Engine.options.po_reduction) return null;
00590 
00591     String fname = packageName.replace('.', File.separatorChar) +
00592     File.separator + sourceFileName.substring(0, sourceFileName.length() - 5);
00593 
00594     for(int i = 0, l = ClassPath.length(); i < l; i++) {
00595       String filename = ClassPath.get(i) + File.separator + fname + ".safe";
00596       SafeBlocks s = loadSafeBlocks(filename);
00597 
00598       if(s != null) return s;
00599     }
00600 
00601     return null;
00602   }  
00603   private SafeBlocks loadSafeBlocks(String fname) {
00604     SafeBlocks s = (SafeBlocks)safeBlocksPool.get(fname);
00605 
00606     if(s == null) {
00607       try {
00608     BufferedReader in = new BufferedReader(new FileReader(fname));
00609     Debug.println(Debug.WARNING, "Loading " + fname);
00610     safeBlocksPool.put(fname, s = new SafeBlocks(in));
00611       } catch (FileNotFoundException e) {
00612       }
00613     }
00614 
00615     return s;
00616   }  
00617   private Source loadSource() {
00618     return Source.getSource(packageName.replace('.', File.separatorChar) +
00619     File.separator + sourceFileName);
00620   }  
00621   /**
00622    * Loads the static fields of a class.
00623    */
00624   private FieldInfo[] loadStaticFields(JavaClass jc) {
00625     Field[] fields = jc.getFields();
00626 
00627     int counter = 0;
00628 
00629     for(int i = 0, l = fields.length; i < l; i++)
00630       if(fields[i].isStatic())
00631     counter += Types.getTypeSize(fields[i].getSignature().toString());
00632 
00633     FieldInfo[] sFields = new FieldInfo[counter];
00634 
00635     counter = 0;
00636     for(int i = 0, l = fields.length; i < l; i++)
00637       if(fields[i].isStatic()) {
00638     sFields[counter] = new FieldInfo(fields[i], this);
00639     counter += Types.getTypeSize(fields[i].getSignature().toString());
00640       }
00641 
00642     return sFields;
00643   }  
00644   /**
00645    * Loads the static methods of a class.
00646    */
00647   private MethodInfo[] loadStaticMethods(JavaClass jc) {
00648     Method[] methods = jc.getMethods();
00649 
00650     int counter = 0;
00651     for(int i = 0, l = methods.length; i < l; i++)
00652       if(methods[i].isStatic())
00653     counter++;
00654 
00655     MethodInfo[] sMethods = new MethodInfo[counter];
00656     
00657     counter = 0;
00658     for(int i = 0, l = methods.length; i < l; i++)
00659       if(methods[i].isStatic())
00660     sMethods[counter++] = new MethodInfo(methods[i], this);
00661 
00662     return sMethods;
00663   }  
00664   /**
00665    * Loads the super class of a class.
00666    */
00667   private static ClassInfo loadSuperClass(JavaClass jc) {
00668     if(jc.getClassName().equals("java.lang.Object"))
00669       return null;
00670 
00671     return ClassInfo.getClassInfo(jc.getSuperclassName());
00672   }  
00673   /**
00674    * Returns the index for a static field.
00675    */
00676   public int staticFieldIndex(String fname) {
00677     int length = staticFields.length;
00678 
00679     for(int i = 0; i < length; i++)
00680       if(staticFields[i] != null && staticFields[i].getName().equals(fname))
00681     return i;
00682 
00683     throw new InternalErrorException("class " + getName() + " does not have static field `" + fname + "'");
00684   }  
00685 }

Generated at Thu Feb 7 06:42:23 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001