0001: //
0002: // Copyright (C) 2005 United States Government as represented by the
0003: // Administrator of the National Aeronautics and Space Administration
0004: // (NASA). All Rights Reserved.
0005: //
0006: // This software is distributed under the NASA Open Source Agreement
0007: // (NOSA), version 1.3. The NOSA has been approved by the Open Source
0008: // Initiative. See the file NOSA-1.3-JPF at the top of the distribution
0009: // directory tree for the complete NOSA document.
0010: //
0011: // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
0012: // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
0013: // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
0014: // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
0015: // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
0016: // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
0017: // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
0018: //
0019: package gov.nasa.jpf.jvm;
0020:
0021: import gov.nasa.jpf.*;
0022: import gov.nasa.jpf.jvm.bytecode.Instruction;
0023: import gov.nasa.jpf.util.*;
0024: import gov.nasa.jpf.util.Debug;
0025:
0026: import java.io.*;
0027:
0028: import java.util.*;
0029:
0030: import org.apache.bcel.classfile.*;
0031: import org.apache.bcel.util.SyntheticRepository;
0032: import org.apache.bcel.generic.ConstantPoolGen;
0033:
0034: /**
0035: * Describes the JVM's view of a java class. Contains descriptions of the
0036: * static and dynamic fields, methods, and information relevant to the
0037: * class.
0038: */
0039: public class ClassInfo {
0040: /**
0041: * this is our BCEL class repository. Note that this actually might be
0042: * turned into a call or ClassInfo instance field if we ever support
0043: * ClassLoaders (for now we keep it simple)
0044: */
0045: protected static SyntheticRepository repository;
0046:
0047: /**
0048: * Map of the loaded classes.
0049: */
0050: protected static Hashtable loadedClasses;
0051:
0052: /**
0053: * optionally used to determine atomic methods of a class (during class loading)
0054: */
0055: protected static Attributor attributor;
0056:
0057: /**
0058: * here we get infinitly recursive, so keep it around for
0059: * identity checks
0060: */
0061: static ClassInfo classClassInfo;
0062:
0063: /*
0064: * some distinguished classInfos we keep around for efficiency reasons
0065: */
0066: static ClassInfo objectClassInfo;
0067: static ClassInfo stringClassInfo;
0068: static ClassInfo weakRefClassInfo;
0069: static ClassInfo refClassInfo;
0070:
0071: static FieldInfo[] emptyFields = new FieldInfo[0];
0072:
0073: /**
0074: * Initializes a class. A class is initialized atomically without being
0075: * interleaved with any other thread.
0076: *
0077: * <2do> pcm - wrong. static init of a class is only synced on the class
0078: * object itself
0079: */
0080: static int level;
0081:
0082: /**
0083: * Name of the class.
0084: */
0085: protected final String name;
0086:
0087: // various class attributes
0088: protected boolean isClass = true;
0089: protected boolean isWeakReference = false;
0090: protected MethodInfo finalizer = null;
0091: protected boolean isArray = false;
0092: protected boolean isReferenceArray = false;
0093:
0094: /** type based object attributes (for GC, partial order reduction and
0095: * property checks)
0096: */
0097: protected int elementInfoAttrs = 0;
0098:
0099: /**
0100: * all our declared methods (we don't flatten, this is not
0101: * a high-performance VM)
0102: */
0103: protected final Map methods;
0104:
0105: /**
0106: * our instance fields.
0107: * Note these are NOT flattened, i.e. only contain the declared ones
0108: */
0109: protected FieldInfo[] iFields;
0110:
0111: /** the storage size of instances of this class (stored as an int[]) */
0112: protected int instanceDataSize;
0113:
0114: /** where in the instance data array (int[]) do our declared fields start */
0115: protected int instanceDataOffset;
0116:
0117: /** total number of instance fields (flattened, not only declared ones) */
0118: protected int nInstanceFields;
0119:
0120: /**
0121: * our static fields. Again, not flattened
0122: */
0123: protected FieldInfo[] sFields;
0124:
0125: /** the storage size of static fields of this class (stored as an int[]) */
0126: protected int staticDataSize;
0127:
0128: protected final ClassInfo super Class;
0129:
0130: /**
0131: * Interfaces implemented by the class.
0132: */
0133: protected final Set interfaces;
0134:
0135: /** all interfaces (parent interfaces and interface parents) - lazy eval */
0136: protected Set allInterfaces;
0137:
0138: /** Name of the package. */
0139: protected final String packageName;
0140:
0141: /** Name of the file which contains the source of this class. */
0142: protected String sourceFileName;
0143:
0144: /**
0145: * this is the object we use to execute methods in the underlying JVM
0146: * (it replaces Reflection)
0147: * <2do> pcm - set this private once MethodInfo is cleaned up
0148: */
0149: NativePeer nativePeer;
0150:
0151: /** Source file associated with the class.*/
0152: protected Source source;
0153:
0154: static String[] assertionPatterns;
0155: boolean enableAssertions;
0156:
0157: static boolean init(Config config) throws Config.Exception {
0158: loadedClasses = new Hashtable();
0159: classClassInfo = null;
0160: objectClassInfo = null;
0161: stringClassInfo = null;
0162: weakRefClassInfo = null;
0163:
0164: setSourceRoots(config);
0165: repository = createRepository(config);
0166:
0167: attributor = (Attributor) config.getEssentialInstance(
0168: "vm.attributor.class", Attributor.class);
0169:
0170: assertionPatterns = config
0171: .getStringArray("vm.enable_assertions");
0172:
0173: return true;
0174: }
0175:
0176: /**
0177: * ClassInfo ctor used for builtin types (arrays and primitive types)
0178: * i.e. classes we don't have class files for
0179: */
0180: protected ClassInfo(String builtinClassName) {
0181: isArray = (builtinClassName.charAt(0) == '[');
0182: isReferenceArray = isArray && builtinClassName.endsWith(";");
0183:
0184: name = builtinClassName;
0185:
0186: Debug.print(Debug.DEBUG, "generating builtin class ");
0187: Debug.println(Debug.DEBUG, name);
0188:
0189: packageName = ""; // builtin classes don't reside in java.lang !
0190: sourceFileName = null;
0191: source = null;
0192:
0193: // no fields
0194: iFields = emptyFields;
0195: sFields = emptyFields;
0196:
0197: if (isArray) {
0198: super Class = objectClassInfo;
0199: interfaces = loadArrayInterfaces();
0200: methods = loadArrayMethods();
0201: } else {
0202: super Class = null; // strange, but true, a 'no object' class
0203: interfaces = loadBuiltinInterfaces(name);
0204: methods = loadBuiltinMethods(name);
0205: }
0206:
0207: enableAssertions = true; // doesn't really matter - no code associated
0208:
0209: loadedClasses.put(name, this );
0210: }
0211:
0212: /**
0213: * Creates a new class from the JavaClass information.
0214: */
0215: protected ClassInfo(JavaClass jc) {
0216: name = jc.getClassName();
0217:
0218: Debug.print(Debug.DEBUG, "loading class ");
0219: Debug.println(Debug.DEBUG, name);
0220:
0221: loadedClasses.put(name, this );
0222:
0223: if ((objectClassInfo == null)
0224: && name.equals("java.lang.Object")) {
0225: objectClassInfo = this ;
0226: } else if ((classClassInfo == null)
0227: && name.equals("java.lang.Class")) {
0228: classClassInfo = this ;
0229: } else if ((stringClassInfo == null)
0230: && name.equals("java.lang.String")) {
0231: stringClassInfo = this ;
0232: } else if ((weakRefClassInfo == null)
0233: && name.equals("java.lang.ref.WeakReference")) {
0234: weakRefClassInfo = this ;
0235: } else if ((refClassInfo == null)
0236: && name.equals("java.lang.ref.Reference")) {
0237: refClassInfo = this ;
0238: }
0239:
0240: isClass = jc.isClass();
0241: super Class = loadSuperClass(jc);
0242:
0243: interfaces = loadInterfaces(jc);
0244: packageName = jc.getPackageName();
0245:
0246: iFields = loadInstanceFields(jc);
0247: instanceDataSize = computeInstanceDataSize();
0248: instanceDataOffset = computeInstanceDataOffset();
0249: nInstanceFields = (super Class != null) ? super Class.nInstanceFields
0250: + iFields.length
0251: : iFields.length;
0252:
0253: sFields = loadStaticFields(jc);
0254: staticDataSize = computeStaticDataSize();
0255:
0256: methods = loadMethods(jc);
0257:
0258: // Used to execute native methods (in JVM land).
0259: // This needs to be initialized AFTER we get our
0260: // MethodInfos, since it does a reverse lookup to determine which
0261: // ones are handled by the peer (by means of setting MethodInfo attributes)
0262: nativePeer = NativePeer.getNativePeer(this );
0263:
0264: sourceFileName = jc.getSourceFileName();
0265:
0266: // bcel seems to behave differently on Windows, returning <Unknown>,
0267: // which gives us problems when writing/reading XML traces
0268: if (sourceFileName.equalsIgnoreCase("<Unknown>")) {
0269: sourceFileName = "Unkown";
0270: }
0271:
0272: if (packageName.length() > 0) {
0273: sourceFileName = packageName.replace('.',
0274: File.separatorChar)
0275: + File.separator + sourceFileName;
0276: }
0277:
0278: source = null;
0279:
0280: isWeakReference = isWeakReference0();
0281: finalizer = getFinalizer0();
0282:
0283: // get type specific object and field attributes
0284: elementInfoAttrs = loadElementInfoAttrs(jc);
0285:
0286: // the corresponding java.lang.Class object gets set when we initialize
0287: // this class from StaticArea.newClass() - we don't know the
0288: // DynamicArea (Heap) here, until we turn this into a global object
0289:
0290: enableAssertions = getAssertionStatus();
0291:
0292: // be advised - we don't have fields initialized yet
0293: JVM.getVM().notifyClassLoaded(this );
0294: }
0295:
0296: boolean getAssertionStatus() {
0297: if ((assertionPatterns == null)
0298: || (assertionPatterns.length == 0)) {
0299: return false;
0300: } else if ("*".equals(assertionPatterns[0])) {
0301: return true;
0302: } else {
0303: for (int i = 0; i < assertionPatterns.length; i++) {
0304: if (name.matches(assertionPatterns[i])) { // Ok, not very efficient
0305: return true;
0306: }
0307: }
0308:
0309: return false;
0310: }
0311: }
0312:
0313: public boolean isArray() {
0314: return isArray;
0315: }
0316:
0317: public boolean isReferenceArray() {
0318: return isReferenceArray;
0319: }
0320:
0321: /**
0322: * Loads the class specified.
0323: * @param cname The fully qualified name of the class to load.
0324: * @return Returns the ClassInfo for the classname passed in,
0325: * or null.
0326: */
0327: public static synchronized ClassInfo getClassInfo(String cname) {
0328: JavaClass jc = null;
0329:
0330: if (cname == null) {
0331: return null;
0332: }
0333:
0334: cname = cname.replace('/', '.');
0335:
0336: ClassInfo ci = (ClassInfo) loadedClasses.get(cname);
0337:
0338: if (ci == null) {
0339: if (isBuiltinClass(cname)) {
0340: // this is a array class - there's no class file for this, it
0341: // gets automatically generated by the VM
0342: ci = new ClassInfo(cname);
0343: } else {
0344: try {
0345: jc = repository.loadClass(cname);
0346: } catch (ClassNotFoundException x) {
0347: throw new JPFException("could not load class "
0348: + cname);
0349: }
0350:
0351: // <?> pm - looks like a memory housekeeping issue (since we cache
0352: // ourselves). Might have to be changed with JavaClass/ClassInfo unification
0353: // and/or ClassLoader support
0354: repository.clear();
0355:
0356: ci = new ClassInfo(jc);
0357: }
0358: }
0359:
0360: return ci;
0361: }
0362:
0363: public boolean areAssertionsEnabled() {
0364: return enableAssertions;
0365: }
0366:
0367: public int getClassObjectRef() {
0368: // NOTE - we can't simply store our classObject, because this can be
0369: // backtracked to a state where the class wasn't loaded yet, and hence
0370: // the classObject would be different. Maybe we should pin classObjects
0371: // down and store them here
0372: StaticArea sa = JVM.getVM().getStaticArea();
0373:
0374: // <2do> Watch out, it's never null, is that what we want?
0375: StaticElementInfo sei = sa.get(name);
0376:
0377: return (sei != null) ? sei.getClassObjectRef() : -1;
0378: }
0379:
0380: /**
0381: * Note that 'uniqueName' is the name plus the argument type part of the
0382: * signature, i.e. everything that's relevant for overloading
0383: * (besides saving some const space, we also ease reverse lookup
0384: * of natives that way).
0385: * Note also that we don't have to make any difference between
0386: * class and instance methods, because that just matters in the
0387: * INVOKExx instruction, when looking up the relevant ClassInfo to start
0388: * searching in (either by means of the object type, or by means of the
0389: * constpool classname entry).
0390: */
0391: public MethodInfo getMethod(String uniqueName,
0392: boolean isRecursiveLookup) {
0393: MethodInfo mi = null;
0394:
0395: if (uniqueName.charAt(uniqueName.length() - 1) != ')') {
0396: // somebody slipped us a full signature?
0397: uniqueName = uniqueName.substring(0, uniqueName
0398: .indexOf(')') + 1);
0399: }
0400:
0401: mi = (MethodInfo) methods.get(uniqueName);
0402:
0403: if ((mi == null) && isRecursiveLookup && (super Class != null)) {
0404: mi = super Class.getMethod(uniqueName, true);
0405: }
0406:
0407: return mi;
0408: }
0409:
0410: public FieldInfo getStaticField(String clsBase, String fName) {
0411: FieldInfo fi;
0412: ClassInfo c = getClassBase(clsBase);
0413:
0414: while (c != null) {
0415: fi = c.getDeclaredStaticField(fName);
0416: if (fi != null)
0417: return fi;
0418: c = c.super Class;
0419: }
0420:
0421: return null;
0422: }
0423:
0424: public FieldInfo getStaticField(String fname) {
0425: return getStaticField(null, fname);
0426: }
0427:
0428: /**
0429: * FieldInfo lookup in the static fields that are declared in this class
0430: * <2do> pcm - should employ a map at some point, but it's usually not that
0431: * important since we can cash the returned FieldInfo in the PUT/GET_STATIC insns
0432: */
0433: public FieldInfo getDeclaredStaticField(String fName) {
0434: for (int i = 0; i < sFields.length; i++) {
0435: if (sFields[i].getName().equals(fName))
0436: return sFields[i];
0437: }
0438:
0439: return null;
0440: }
0441:
0442: /**
0443: * base relative FieldInfo lookup - the workhorse
0444: * <2do> again, should eventually use Maps
0445: * @param clsBase - the class where we start the lookup (self or some super)
0446: * @param fName - the field name
0447: */
0448: public FieldInfo getInstanceField(String clsBase, String fName) {
0449: FieldInfo fi;
0450: ClassInfo c = getClassBase(clsBase);
0451:
0452: while (c != null) {
0453: fi = c.getDeclaredInstanceField(fName);
0454: if (fi != null)
0455: return fi;
0456: c = c.super Class;
0457: }
0458:
0459: return null;
0460: }
0461:
0462: /**
0463: * complete bottom-up FieldInfo lookup
0464: */
0465: public FieldInfo getInstanceField(String fName) {
0466: return getInstanceField(null, fName);
0467: }
0468:
0469: /**
0470: * FieldInfo lookup in the fields that are declared in this class
0471: */
0472: public FieldInfo getDeclaredInstanceField(String fName) {
0473: for (int i = 0; i < iFields.length; i++) {
0474: if (iFields[i].getName().equals(fName))
0475: return iFields[i];
0476: }
0477:
0478: return null;
0479: }
0480:
0481: /**
0482: * consult nativePeer to check if method is deterministic
0483: */
0484: public boolean isMethodCondDeterministic(ThreadInfo th,
0485: MethodInfo mi) {
0486: if (nativePeer != null) {
0487: return nativePeer.isMethodCondDeterministic(th, mi);
0488: }
0489:
0490: return false;
0491: }
0492:
0493: /**
0494: * consult nativePeer to check if method is executable
0495: */
0496: public boolean isMethodCondExecutable(ThreadInfo th, MethodInfo mi) {
0497: if (nativePeer != null) {
0498: return nativePeer.isMethodCondExecutable(th, mi);
0499: }
0500:
0501: return false;
0502: }
0503:
0504: /**
0505: * Returns the name of the class.
0506: */
0507: public String getName() {
0508: return name;
0509: }
0510:
0511: public String getPackageName() {
0512: return packageName;
0513: }
0514:
0515: public int getFieldAttrs(int fieldIndex) {
0516: return 0;
0517: }
0518:
0519: public int getElementInfoAttrs() {
0520: return elementInfoAttrs;
0521: }
0522:
0523: public Source getSource() {
0524: if (source == null) {
0525: source = loadSource();
0526: }
0527:
0528: return source;
0529: }
0530:
0531: public String getSourceFileName() {
0532: return sourceFileName;
0533: }
0534:
0535: /**
0536: * Returns the information about a static field.
0537: */
0538: public FieldInfo getStaticField(int index) {
0539: return sFields[index];
0540: }
0541:
0542: /**
0543: * Returns the name of a static field.
0544: */
0545: public String getStaticFieldName(int index) {
0546: return getStaticField(index).getName();
0547: }
0548:
0549: /**
0550: * Checks if a static method call is deterministic, but only for
0551: * abtraction based determinism, due to Bandera.choose() calls
0552: */
0553: public boolean isStaticMethodAbstractionDeterministic(
0554: ThreadInfo th, MethodInfo mi) {
0555: // Reflection r = reflection.instantiate();
0556: // return r.isStaticMethodAbstractionDeterministic(th, mi);
0557: // <2do> - still has to be implemented
0558: return true;
0559: }
0560:
0561: /**
0562: * Return the super class.
0563: */
0564: public ClassInfo getSuperClass() {
0565: return super Class;
0566: }
0567:
0568: /**
0569: * return the ClassInfo for the provided superclass name. If this is equal
0570: * to ourself, return this (a little bit strange if we hit it in the first place)
0571: */
0572: public ClassInfo getSuperClass(String clsName) {
0573: if (clsName.equals(name))
0574: return this ;
0575:
0576: if (super Class != null) {
0577: return super Class.getSuperClass(clsName);
0578: } else {
0579: return null;
0580: }
0581: }
0582:
0583: public boolean isInstanceOf(ClassInfo ci) {
0584: ClassInfo c = this ;
0585: do {
0586: if (c == ci) {
0587: return true;
0588: }
0589: c = c.super Class;
0590: } while (c != null);
0591:
0592: return false;
0593: }
0594:
0595: /**
0596: * Returns true if the class is a system class.
0597: */
0598: public boolean isSystemClass() {
0599: return name.startsWith("java.") || name.startsWith("javax.");
0600: }
0601:
0602: /**
0603: * Returns the type of a class.
0604: */
0605: public String getType() {
0606: return "L" + name.replace('.', '/') + ";";
0607: }
0608:
0609: /**
0610: * is this a (subclass of) WeakReference? this must be efficient, since it's
0611: * called in the mark phase on all live objects
0612: */
0613: public boolean isWeakReference() {
0614: return isWeakReference;
0615: }
0616:
0617: /**
0618: * note this only returns true is this is really the java.lang.ref.Reference classInfo
0619: */
0620: public boolean isRefClass() {
0621: return (this == refClassInfo);
0622: }
0623:
0624: /**
0625: * Creates the fields for an object.
0626: */
0627: public Fields createInstanceFields() {
0628: return new DynamicFields(getType(), this );
0629: }
0630:
0631: boolean hasRefField(int ref, Fields fv) {
0632: ClassInfo c = this ;
0633:
0634: do {
0635: FieldInfo[] fia = c.iFields;
0636: for (int i = 0; i < fia.length; i++) {
0637: FieldInfo fi = c.iFields[i];
0638: if (fi.isReference()
0639: && (fv.getIntValue(fi.getStorageOffset()) == ref))
0640: return true;
0641: }
0642: c = c.super Class;
0643: } while (c != null);
0644:
0645: return false;
0646: }
0647:
0648: boolean hasImmutableInstances() {
0649: return ((elementInfoAttrs & ElementInfo.ATTR_IMMUTABLE) != 0);
0650: }
0651:
0652: public Instruction executeNativeMethod(ThreadInfo th, MethodInfo mi) {
0653: if (nativePeer != null) {
0654: return nativePeer.executeMethod(th, mi);
0655: }
0656:
0657: return th.createAndThrowException(
0658: "java.lang.UnsatisfiedLinkError", name + '.'
0659: + mi.getName() + " (no peer)");
0660: }
0661:
0662: public static boolean exists(String cname) {
0663: // <?> pcm - is this really intended to load the thing?
0664: // (I assume not, and therefor replace repository.lookupClass())
0665: return (repository.findClass(cname) != null);
0666: }
0667:
0668: public void initializeClass(ThreadInfo th) {
0669: if (th == null) {
0670: return; // no thread stack, nothing we can execute (called from vm.init)
0671: }
0672:
0673: Debug.print(Debug.DEBUG, "initializing class ");
0674: Debug.println(Debug.DEBUG, name);
0675:
0676: MethodInfo mi = getMethod("<clinit>()", false); // only local lookup
0677:
0678: if (mi != null) {
0679: // <2do> sync on class object here
0680: // no args
0681: th.executeMethod(mi);
0682: // <2do> unsync
0683: }
0684: }
0685:
0686: /**
0687: * Returns true if the given class is an instance of the class
0688: * or interface specified.
0689: */
0690: public boolean instanceOf(String cname) {
0691: cname = cname.replace('/', '.');
0692:
0693: // trivial case - ourself
0694: if (name.equals(cname)) {
0695: return true;
0696: }
0697:
0698: // (recursive) parent
0699: if ((super Class != null) && (super Class.instanceOf(cname))) {
0700: return true;
0701: }
0702:
0703: // direct interface
0704: if (interfaces.contains(cname)) {
0705: return true;
0706: }
0707:
0708: // now it's getting more expensive - look for all interfaces
0709: if (getAllInterfaces().contains(cname)) {
0710: return true;
0711: }
0712:
0713: // Ok, we give up
0714: return false;
0715: }
0716:
0717: /**
0718: * clean up statics for another 'main' run
0719: */
0720: public static void reset() {
0721: if (repository != null) {
0722: repository.clear();
0723: }
0724:
0725: loadedClasses = new Hashtable();
0726:
0727: classClassInfo = null;
0728: objectClassInfo = null;
0729: stringClassInfo = null;
0730: }
0731:
0732: /**
0733: * provide a default path from where to load essential model classes
0734: * (associated with native peers that JPF needs)
0735: */
0736: static String getDefaultBootClassPath() {
0737: StringBuffer sb = new StringBuffer();
0738:
0739: // assuming we are in the JPF root dir, add build/env/jpf for explicit classes
0740: sb.append("build");
0741: sb.append(File.separatorChar);
0742: sb.append("env");
0743: sb.append(File.separatorChar);
0744: sb.append("jpf");
0745:
0746: // but maybe this is a binary distrib, so add lib/env_jpf.jar
0747: sb.append(File.pathSeparatorChar);
0748: sb.append("lib");
0749: sb.append(File.separatorChar);
0750: sb.append("env_jpf.jar");
0751:
0752: return sb.toString();
0753: }
0754:
0755: /**
0756: * this is for application specific classes that should not be seen by the host VM
0757: */
0758: static String getDefaultClassPath() {
0759: return null;
0760: }
0761:
0762: protected static SyntheticRepository createRepository(Config config) {
0763: // <2do> pm - we have a collision with jpf.ClassPath (PCM)
0764: // unfortunately, it's different enough to the JPF counterpart so that we
0765: // have to keep both versions for now
0766: org.apache.bcel.util.ClassPath cpath;
0767: StringBuffer buf = new StringBuffer(128);
0768: String sep = System.getProperty("path.separator");
0769: String v;
0770:
0771: // this is where we get our essential model classes from (java.lang.Thread etc)
0772: if ((v = config.getExpandedString("vm.bootclasspath")) == null) {
0773: v = getDefaultBootClassPath();
0774: }
0775: buf.append(v);
0776:
0777: // that's where the application specific environment should be loaded from
0778: if ((v = config.getExpandedString("vm.classpath")) == null) {
0779: v = getDefaultClassPath();
0780: }
0781:
0782: if (v != null) {
0783: buf.append(sep);
0784: buf.append(v);
0785: }
0786:
0787: // now we look into the system classpath (all stuff loaded from here is
0788: // the same codebase that's also used by the host VM)
0789: if (buf.length() > 0) {
0790: buf.append(sep);
0791: }
0792:
0793: buf.append(System.getProperty("java.class.path"));
0794:
0795: // finally, we load from the standard Java libraries
0796: if (buf.length() > 0) {
0797: buf.append(sep);
0798: }
0799:
0800: buf.append(System.getProperty("sun.boot.class.path"));
0801:
0802: cpath = new org.apache.bcel.util.ClassPath(buf.toString());
0803:
0804: return SyntheticRepository.getInstance(cpath);
0805: }
0806:
0807: protected static Set loadArrayInterfaces() {
0808: Set interfaces;
0809:
0810: interfaces = new HashSet();
0811: interfaces.add("java.lang.Cloneable");
0812: interfaces.add("java.io.Serializable");
0813:
0814: return Collections.unmodifiableSet(interfaces);
0815: }
0816:
0817: protected static Set loadBuiltinInterfaces(String type) {
0818: return Collections.unmodifiableSet(new HashSet(0));
0819: }
0820:
0821: /**
0822: * Loads the interfaces of a class.
0823: */
0824: protected static Set loadInterfaces(JavaClass jc) {
0825: Set interfaces;
0826: String[] interfaceNames;
0827:
0828: interfaceNames = jc.getInterfaceNames();
0829: interfaces = new HashSet();
0830:
0831: for (int i = 0, l = interfaceNames.length; i < l; i++) {
0832: interfaces.add(interfaceNames[i]);
0833: }
0834:
0835: return Collections.unmodifiableSet(interfaces);
0836: }
0837:
0838: FieldInfo[] loadInstanceFields(JavaClass jc) {
0839: Field[] fields = jc.getFields();
0840: int i, j, n;
0841: int off = (super Class != null) ? super Class.instanceDataSize
0842: : 0;
0843:
0844: for (i = 0, n = 0; i < fields.length; i++) {
0845: if (!fields[i].isStatic())
0846: n++;
0847: }
0848:
0849: int idx = (super Class != null) ? super Class.nInstanceFields : 0;
0850: FieldInfo[] ifa = new FieldInfo[n];
0851:
0852: for (i = 0, j = 0; i < fields.length; i++) {
0853: Field f = fields[i];
0854: if (!f.isStatic()) {
0855: FieldInfo fi = FieldInfo.create(f, this , idx, off);
0856: ifa[j++] = fi;
0857: off += fi.getStorageSize();
0858: idx++;
0859:
0860: if (attributor != null) {
0861: fi.setAttributes(attributor.getFieldAttributes(jc,
0862: f));
0863: }
0864: }
0865: }
0866:
0867: return ifa;
0868: }
0869:
0870: int computeInstanceDataOffset() {
0871: if (super Class == null) {
0872: return 0;
0873: } else {
0874: return super Class.getInstanceDataSize();
0875: }
0876: }
0877:
0878: int getInstanceDataOffset() {
0879: return instanceDataOffset;
0880: }
0881:
0882: ClassInfo getClassBase(String clsBase) {
0883: if ((clsBase == null) || (name.equals(clsBase)))
0884: return this ;
0885:
0886: if (super Class != null) {
0887: return super Class.getClassBase(clsBase);
0888: }
0889:
0890: return null; // Eeek - somebody asked for a class that isn't in the base list
0891: }
0892:
0893: int computeInstanceDataSize() {
0894: int n = getDataSize(iFields);
0895:
0896: for (ClassInfo c = super Class; c != null; c = c.super Class) {
0897: n += c.getDataSize(c.iFields);
0898: }
0899:
0900: return n;
0901: }
0902:
0903: int getInstanceDataSize() {
0904: return instanceDataSize;
0905: }
0906:
0907: int getDataSize(FieldInfo[] fields) {
0908: int n = 0;
0909: for (int i = 0; i < fields.length; i++) {
0910: n += fields[i].getStorageSize();
0911: }
0912:
0913: return n;
0914: }
0915:
0916: public int getNumberOfDeclaredInstanceFields() {
0917: return iFields.length;
0918: }
0919:
0920: FieldInfo getDeclaredInstanceField(int i) {
0921: return iFields[i];
0922: }
0923:
0924: public int getNumberOfInstanceFields() {
0925: return nInstanceFields;
0926: }
0927:
0928: FieldInfo getInstanceField(int i) {
0929: int idx = i - (nInstanceFields - iFields.length);
0930: if (idx >= 0) {
0931: return ((idx < iFields.length) ? iFields[idx] : null);
0932: } else {
0933: return ((super Class != null) ? super Class
0934: .getInstanceField(i) : null);
0935: }
0936: }
0937:
0938: FieldInfo[] loadStaticFields(JavaClass jc) {
0939: Field[] fields = jc.getFields();
0940: int i, j, n;
0941: int off = 0;
0942:
0943: for (i = 0, n = 0; i < fields.length; i++) {
0944: if (fields[i].isStatic())
0945: n++;
0946: }
0947:
0948: FieldInfo[] sfa = new FieldInfo[n];
0949: int idx = 0;
0950:
0951: for (i = 0; i < fields.length; i++) {
0952: Field f = fields[i];
0953: if (f.isStatic()) {
0954: FieldInfo fi = FieldInfo.create(f, this , idx, off);
0955: sfa[idx] = fi;
0956: idx++;
0957: off += fi.getStorageSize();
0958: }
0959: }
0960:
0961: return sfa;
0962: }
0963:
0964: int getStaticDataSize() {
0965: return staticDataSize;
0966: }
0967:
0968: int computeStaticDataSize() {
0969: return getDataSize(sFields);
0970: }
0971:
0972: public int getNumberOfStaticFields() {
0973: return sFields.length;
0974: }
0975:
0976: protected Source loadSource() {
0977: return Source.getSource(sourceFileName);
0978: }
0979:
0980: static boolean isBuiltinClass(String cname) {
0981: char c = cname.charAt(0);
0982:
0983: // array class
0984: if (c == '[') {
0985: return true;
0986: }
0987:
0988: // primitive type class
0989: if (Character.isLowerCase(c)) {
0990: if ("int".equals(cname) || "byte".equals(cname)
0991: || "boolean".equals(cname)
0992: || "double".equals(cname) || "long".equals(cname)
0993: || "char".equals(cname) || "short".equals(cname)
0994: || "float".equals(cname)) {
0995: return true;
0996: }
0997: }
0998:
0999: return false;
1000: }
1001:
1002: /**
1003: * set the locations where we look up sources
1004: */
1005: static void setSourceRoots(Config config) {
1006: String srcPath = config.getExpandedString("vm.sourcepath");
1007: if (srcPath == null) { // our fallbacks, assuming we are in the JPF root dir
1008: Source.addSourceRoot("examples");
1009: Source.addSourceRoot("test");
1010: } else {
1011: StringTokenizer st = new StringTokenizer(srcPath,
1012: File.pathSeparator);
1013: while (st.hasMoreTokens()) {
1014: String sroot = st.nextToken();
1015:
1016: if ((sroot.length() > 0) && !sroot.endsWith(".jar")) {
1017: Source.addSourceRoot(sroot);
1018: }
1019: }
1020: }
1021: }
1022:
1023: Set getAllInterfaces() {
1024: if (allInterfaces == null) {
1025: HashSet set = new HashSet();
1026:
1027: // load all own interfaces
1028: loadInterfaceRec(set, this );
1029:
1030: // all parent class interfaces
1031: loadInterfaceRec(set, super Class);
1032:
1033: allInterfaces = Collections.unmodifiableSet(set);
1034: }
1035:
1036: return allInterfaces;
1037: }
1038:
1039: ClassInfo getComponentClassInfo() {
1040: if (isArray()) {
1041: String cn = name.substring(1);
1042:
1043: if (cn.charAt(0) != '[') {
1044: cn = Types.getTypeName(cn);
1045: }
1046:
1047: ClassInfo cci = getClassInfo(cn);
1048:
1049: return cci;
1050: }
1051:
1052: return null;
1053: }
1054:
1055: /**
1056: * most definitely not a public method, but handy for the NativePeer
1057: */
1058: Map getDeclaredMethods() {
1059: return methods;
1060: }
1061:
1062: MethodInfo getFinalizer() {
1063: return finalizer;
1064: }
1065:
1066: int createClassObject(ThreadInfo th, int cref) {
1067: int objref;
1068: int cnref;
1069: DynamicArea da = JVM.getVM().getDynamicArea();
1070:
1071: objref = da.newObject(classClassInfo, th);
1072: cnref = da.newString(name, th);
1073:
1074: // we can't execute methods nicely for which we don't have caller bytecode
1075: // (would run into a (pc == null) assertion), so we have to bite the bullet
1076: // and init the java.lang.Class object explicitly. But that's probably Ok
1077: // since it is a very special beast, anyway
1078: ElementInfo e = da.get(objref);
1079:
1080: try {
1081: e.setReferenceField("name", cnref);
1082:
1083: // this is the StaticArea ElementInfo index of what we refer to
1084: e.setIntField("cref", cref);
1085: } catch (Exception x) {
1086: // if we don't have the right (JPF specific) java.lang.Class version,
1087: // we are screwed in terms of java.lang.Class usage
1088: if (classClassInfo == null) { // report it just once
1089: Debug.println(Debug.ERROR);
1090: Debug.println(Debug.ERROR,
1091: "FATAL ERROR: wrong java.lang.Class version");
1092: Debug.println(Debug.ERROR,
1093: " you need to set 'vm.classpath'");
1094: Debug
1095: .println(Debug.ERROR,
1096: " or start jpf from its root directory");
1097: Debug.println(Debug.ERROR);
1098: Debug
1099: .println(Debug.ERROR,
1100: " !! assertions or java.lang.Class usage will fail !!");
1101: Debug.println(Debug.ERROR);
1102: }
1103:
1104: return -1;
1105: }
1106:
1107: return objref;
1108: }
1109:
1110: /**
1111: * Creates the fields for a class. This gets called by the StaticArea
1112: * when a class is loaded.
1113: */
1114: Fields createStaticFields(StaticArea staticArea) {
1115: return new StaticFields(this );
1116: }
1117:
1118: void initializeStaticData(Fields f) {
1119: for (int i = 0; i < sFields.length; i++) {
1120: FieldInfo fi = sFields[i];
1121: fi.initialize(f);
1122: }
1123: }
1124:
1125: void initializeInstanceData(Fields f) {
1126: // Note this is only used for field inits, and array elements are not fields!
1127: // Since Java has only limited element init requirements (either 0 or null),
1128: // we do this ad hoc in the ArrayFields ctor
1129:
1130: // the order of inits should not matter, since this is only
1131: // for constant inits. In case of a "class X { int a=42; int b=a; ..}"
1132: // we have a explicit "GETFIELD a, PUTFIELD b" in the ctor
1133: for (int i = 0; i < iFields.length; i++) {
1134: FieldInfo fi = iFields[i];
1135: fi.initialize(f);
1136: }
1137: if (super Class != null) {
1138: super Class.initializeInstanceData(f);
1139: }
1140: }
1141:
1142: Map loadArrayMethods() {
1143: return new HashMap(0);
1144: }
1145:
1146: Map loadBuiltinMethods(String type) {
1147: return new HashMap(0);
1148: }
1149:
1150: void loadInterfaceRec(Set set, ClassInfo ci) {
1151: if (ci != null) {
1152: Iterator it = ci.interfaces.iterator();
1153:
1154: while (it.hasNext()) {
1155: String iname = (String) it.next();
1156: set.add(iname);
1157:
1158: ci = getClassInfo(iname);
1159: loadInterfaceRec(set, ci);
1160: }
1161: }
1162: }
1163:
1164: /**
1165: * this is a optimization to work around the BCEL strangeness that some
1166: * insn info (types etc.) are only accessible with modifiable ConstPools
1167: * (the ConstantPoolGen, which is costly to create), and some others
1168: * (toString) are only provided via ConstPools. It's way to expensive
1169: * to create this always on the fly, for each relevant insn, so we cache it
1170: * here
1171: */
1172: static ConstantPool cpCache;
1173: static ConstantPoolGen cpgCache;
1174:
1175: public static ConstantPoolGen getConstantPoolGen(ConstantPool cp) {
1176: if (cp != cpCache) {
1177: cpCache = cp;
1178: cpgCache = new ConstantPoolGen(cp);
1179: }
1180:
1181: return cpgCache;
1182: }
1183:
1184: /** avoid memory leaks */
1185: static void resetCPCache() {
1186: cpCache = null;
1187: cpgCache = null;
1188: }
1189:
1190: Map loadMethods(JavaClass jc) {
1191: Method[] ms = jc.getMethods();
1192: HashMap map = new HashMap(ms.length);
1193:
1194: for (int i = 0; i < ms.length; i++) {
1195: MethodInfo mi = MethodInfo.newInstance(ms[i], this );
1196: String id = mi.getUniqueName();
1197: map.put(id, mi);
1198:
1199: if (attributor != null) {
1200: mi.setAtomic(attributor.isMethodAtomic(jc, ms[i], id));
1201: mi.setSchedulingRelevance(attributor
1202: .getSchedulingRelevance(jc, ms[i], id));
1203: }
1204: }
1205:
1206: resetCPCache(); // no memory leaks
1207:
1208: return map;
1209: }
1210:
1211: ClassInfo loadSuperClass(JavaClass jc) {
1212: if (this == objectClassInfo) {
1213: return null;
1214: } else {
1215: String super Name = jc.getSuperclassName();
1216:
1217: return getClassInfo(super Name);
1218: }
1219: }
1220:
1221: int loadElementInfoAttrs(JavaClass jc) {
1222: // we use the atomicizer for it because the only attribute for now is the
1223: // immutability, and it is used to determine if a field insn should be
1224: // a step boundary. Otherwise it's a bit artificial, but we don't want
1225: // to intro another load time class attributor for now
1226: if (attributor != null) {
1227: return attributor.getObjectAttributes(jc);
1228: }
1229:
1230: return 0;
1231: }
1232:
1233: private MethodInfo getFinalizer0() {
1234: MethodInfo mi = getMethod("finalize()", true);
1235:
1236: // we are only interested in non-empty method bodies, Object.finalize()
1237: // is a dummy
1238: if ((mi != null) && (mi.getClassInfo() != objectClassInfo)) {
1239: return mi;
1240: }
1241:
1242: return null;
1243: }
1244:
1245: private boolean isWeakReference0() {
1246: for (ClassInfo ci = this ; ci != objectClassInfo; ci = ci.super Class) {
1247: if (ci == weakRefClassInfo) {
1248: return true;
1249: }
1250: }
1251:
1252: return false;
1253: }
1254: }
|