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.JPFException;
0022: import gov.nasa.jpf.util.Debug;
0023: import gov.nasa.jpf.util.HashData;
0024: import gov.nasa.jpf.util.HashPool;
0025:
0026: import java.util.HashMap;
0027: import java.util.Vector;
0028:
0029: /**
0030: * Describes an element of memory containing the field values of a class or an
0031: * object. In the case of a class, contains the values of the static fields. For
0032: * an object contains the values of the object fields.
0033: *
0034: * @see gov.nasa.jpf.jvm.FieldInfo
0035: */
0036: public abstract class ElementInfo implements Storable, Reference,
0037: Cloneable {
0038: static final int storingDataLength = 3;
0039:
0040: protected static HashPool fieldsPool = new HashPool();
0041:
0042: protected static HashPool monitorPool = new HashPool();
0043:
0044: protected static HashPool racePool = new HashPool();
0045:
0046: protected Fields fields;
0047:
0048: protected Monitor monitor;
0049:
0050: protected Area area;
0051:
0052: protected int index;
0053:
0054: // object attribute flag values
0055: public static final int ATTR_NONE = 0x0;
0056:
0057: public static final int ATTR_PROP_MASK = 0x0000ffff;
0058:
0059: // the propagated ones - only lower 16 bits can be used
0060:
0061: public static final int ATTR_TSHARED = 0x1; // reachable
0062: // from
0063: // different
0064: // threads
0065:
0066: // this one is redundant if we just base it on the ClassInfo
0067: // (->fields->classinfo)
0068: // but we might use code attrs in the future to set this on a per-instance
0069: // basis
0070: public static final int ATTR_IMMUTABLE = 0x2; // object
0071: // doesn't
0072: // change value
0073:
0074: // don't promote to shared along this path
0075: public static final int ATTR_NO_PROMOTE = 0x4;
0076:
0077: // the non-propagated attributes - use only higher 16 bits
0078:
0079: // to-be-done, would be code attr, too, and could easily be checked at runtime
0080: // (hello, a new property)
0081: public static final int ATTR_SINGLE_WRITER = 0x10000;
0082:
0083: // don't propagate attributes through this object
0084: public static final int ATTR_NO_PROPAGATE = 0x20000;
0085:
0086: // object is assumed to be fully protected (i.e. no field access that is
0087: // not protected by a lock)
0088: public static final int ATTR_PROTECTED = 0x40000;
0089:
0090: // don't reycle this object as long as the flag is set
0091: public static final int ATTR_PINDOWN = 0x80000;
0092:
0093: // these are our state-stored object attributes
0094: // WATCH OUT! only include info that otherwise reflects a state change, so
0095: // that
0096: // we don't introduce new changes. It's value is used to hash the state!
0097: // <2do> what a pity - 32 stored bits for (currently) only 2 bits of
0098: // information,
0099: // but we might use this as a hash for more complex reference info in the
0100: // future.
0101: // We distinguish between propagates and private object attributes, the first
0102: // ones tored in the lower 2 bytes
0103: protected int attributes;
0104:
0105: /*
0106: * The following information is used to cache the value of the indexes so that
0107: * an explicit indexing is not necessary at each storing.
0108: */
0109: protected int fIndex = -1;
0110:
0111: protected int mIndex = -1;
0112:
0113: static HashMap lockDiscipline = new HashMap();
0114:
0115: public ElementInfo(Fields f, Monitor m) {
0116: fields = f;
0117: monitor = m;
0118:
0119: attributes = f.getClassInfo().getElementInfoAttrs();
0120: }
0121:
0122: protected ElementInfo() {
0123: }
0124:
0125: public String toString() {
0126: return (getClassInfo().getName() + '@' + index);
0127: }
0128:
0129: public FieldLockInfo getFieldLockInfo(String fid) {
0130: return (FieldLockInfo) lockDiscipline.get(fid);
0131: }
0132:
0133: public void setFieldLockInfo(String fid, FieldLockInfo flInfo) {
0134: lockDiscipline.put(fid, flInfo);
0135: }
0136:
0137: /**
0138: * do we have a reference field with value objRef?
0139: */
0140: boolean hasRefField(int objRef) {
0141: return fields.hasRefField(objRef);
0142: }
0143:
0144: void setShared() {
0145: attributes |= ATTR_TSHARED;
0146: }
0147:
0148: /**
0149: * set shared, but only if the ATTR_TSHARED bit isn't masked out
0150: */
0151: void setShared(int attrMask) {
0152: attributes |= (attrMask & ATTR_TSHARED);
0153: }
0154:
0155: /**
0156: * the recursive phase2 marker entry, which propagates the attributes set by a
0157: * previous phase1. This one is called on all 'root'-marked objects after
0158: * phase1 is completed. ElementInfo is not an ideal place for this method, as
0159: * it has to access some innards of both ClassInfo (FieldInfo container) and
0160: * Fields. But on the other hand, we want to keep the whole heap traversal
0161: * business as much centralized in ElementInfo and DynamicArea as possible
0162: *
0163: * @aspects: gc
0164: */
0165: void markRecursive(int tid, int attrMask) {
0166: DynamicArea heap = DynamicArea.getHeap();
0167: int i, n;
0168:
0169: if (isArray()) {
0170: if (fields.isReferenceArray()) {
0171: n = fields.arrayLength();
0172: for (i = 0; i < n; i++) {
0173: heap.markRecursive(fields.getIntValue(i), tid,
0174: attributes, attrMask, null);
0175: }
0176: }
0177: } else {
0178: ClassInfo ci = getClassInfo();
0179: boolean isWeakRef = ci.isWeakReference();
0180:
0181: do {
0182: n = ci.getNumberOfDeclaredInstanceFields();
0183: boolean isRef = isWeakRef && ci.isRefClass(); // is this the java.lang.ref.Reference part?
0184:
0185: for (i = 0; i < n; i++) {
0186: FieldInfo fi = ci.getDeclaredInstanceField(i);
0187: if (fi.isReference()) {
0188: if ((i == 0) && isRef) {
0189: // we need to reset the ref field once the referenced object goes away
0190: // NOTE: only the *first* WeakReference field is a weak ref
0191: // (this is why we have our own implementation)
0192: heap.registerWeakReference(fields);
0193: } else {
0194:
0195: // the refAttrs are not immediately masked because we have to
0196: // preserve
0197: // the mask values up to the point where we would promote a
0198: // otherwise
0199: // unshared root object due to a different thread id (in case we
0200: // didn't
0201: // catch a mask on the way that prevents this)
0202: heap.markRecursive(fields
0203: .getReferenceValue(fi
0204: .getStorageOffset()), tid,
0205: attributes, attrMask, fi);
0206: }
0207: }
0208: }
0209: ci = ci.getSuperClass();
0210: } while (ci != null);
0211: }
0212: }
0213:
0214: boolean hasEqualPropagatedAttributes(int refAttrs, int attrMask) {
0215: int mask = ATTR_PROP_MASK & attrMask;
0216: return ((attributes & mask) == (refAttrs & mask));
0217: }
0218:
0219: void propagateAttributes(int refAttr, int attrMask) {
0220: attributes |= ((refAttr & attrMask) & ATTR_PROP_MASK);
0221: }
0222:
0223: public boolean isShared() {
0224: return ((attributes & ATTR_TSHARED) != 0);
0225: }
0226:
0227: public boolean isImmutable() {
0228: return ((attributes & ATTR_IMMUTABLE) != 0);
0229: }
0230:
0231: public boolean isSchedulingRelevant() {
0232: // only mutable, shared objects are relevant
0233: return ((attributes & (ATTR_TSHARED | ATTR_IMMUTABLE)) == ATTR_TSHARED);
0234: }
0235:
0236: /**
0237: * check if there are any propagated attributes in ei we don't have yet
0238: */
0239: public boolean needsAttributePropagationFrom(ElementInfo ei) {
0240: int a = attributes;
0241: int o = ei.attributes;
0242:
0243: if (a != o) {
0244: if ((o & ATTR_PROP_MASK) > (a & ATTR_PROP_MASK))
0245: return true;
0246:
0247: for (int i = 0; i < 16; i++, o >>= 1, a >>= 1) {
0248: if ((o & 0x1) > (a & 0x1)) {
0249: return true;
0250: }
0251: }
0252: }
0253:
0254: return false;
0255: }
0256:
0257: public void setArea(Area newArea) {
0258: area = newArea;
0259: }
0260:
0261: public Area getArea() {
0262: return area;
0263: }
0264:
0265: /** a bit simplistic, but will do for object equalness */
0266: public boolean equals(Object other) {
0267: if (getClass() != other.getClass())
0268: return false;
0269:
0270: ElementInfo ei = (ElementInfo) other;
0271: return fields.equals(ei.fields);
0272: }
0273:
0274: public ClassInfo getClassInfo() {
0275: return fields.getClassInfo();
0276: }
0277:
0278: abstract protected FieldInfo getFieldInfo(String clsBase,
0279: String fname);
0280:
0281: abstract protected ElementInfo getElementInfo(ClassInfo ci);
0282:
0283: protected FieldInfo getFieldInfo(String fname) {
0284: return getFieldInfo(null, fname);
0285: }
0286:
0287: public int getIntField(String fname) {
0288: return getIntField(fname, null);
0289: }
0290:
0291: public long getLongField(String fname) {
0292: return getLongField(fname, null);
0293: }
0294:
0295: public void setIntField(FieldInfo fi, int value) {
0296: //checkFieldInfo(fi); // in case somebody caches and uses the wrong
0297: // FieldInfo
0298: ElementInfo ei = getElementInfo(fi.getClassInfo()); // might not be 'this'
0299: // in case of a static
0300:
0301: if (!fi.isReference()) {
0302: ei.cloneFields().setIntValue(fi.getStorageOffset(), value);
0303: } else {
0304: throw new JPFException("reference field: " + fi.getName());
0305: }
0306: }
0307:
0308: public void setIntField(String fname, String clsBase, int value) {
0309: setIntField(getFieldInfo(clsBase, fname), value);
0310: }
0311:
0312: public void setIntField(String fname, int value) {
0313: setIntField(fname, null, value);
0314: }
0315:
0316: public void setLongField(String fname, long value) {
0317: FieldInfo fi = getFieldInfo(fname);
0318: ElementInfo ei = getElementInfo(fi.getClassInfo());
0319: ei.cloneFields().setLongValue(fi.getStorageOffset(), value);
0320: }
0321:
0322: void updateReachability(int oldRef, int newRef) {
0323: ThreadInfo ti = ThreadInfo.getCurrent(); // might be null if still in VM
0324: // init
0325: if ((ti == null) || ti.isInCtor() || !ti.usePor()) {
0326: return;
0327: }
0328:
0329: if (oldRef != newRef) {
0330: DynamicArea heap = DynamicArea.getHeap();
0331: ElementInfo oei, nei;
0332:
0333: if (isShared()) {
0334: if (oldRef != -1) {
0335: oei = heap.get(oldRef);
0336: if (!oei.isImmutable()) { // it's already shared, anyway
0337: // Ok, give up and do a full mark, the old object might not be
0338: // reachable anymore
0339: heap.analyzeHeap(false); // takes care of the newRef, too
0340: return;
0341: }
0342: }
0343:
0344: if (newRef != -1) {
0345: nei = heap.get(newRef);
0346: if (!nei.isShared() && !nei.isImmutable()) {
0347: // no need to walk the whole heap, just recursively promote nei
0348: // and all its reachables to 'shared'
0349: nei.setShared();
0350: heap.initGc(); // doesn't belong here, should be encapsulated in DA
0351: nei
0352: .markRecursive(ti.getIndex(),
0353: ATTR_PROP_MASK);
0354: }
0355: }
0356: } else { // we are not shared (oldRef can't change status)
0357: if (newRef != -1) {
0358: nei = heap.get(newRef);
0359: if (nei.isSchedulingRelevant()) { // shared and mutable
0360: // give up, nei might become non-shared
0361: heap.analyzeHeap(false);
0362: }
0363: }
0364: }
0365: }
0366:
0367: if (oldRef != -1) {
0368: JVM.getVM().getSystemState().activateGC(); // needs GC at the end of this
0369: // transition
0370: }
0371: }
0372:
0373: public void setReferenceField(FieldInfo fi, int value) {
0374: ElementInfo ei = getElementInfo(fi.getClassInfo()); // might not be 'this'
0375: // in case of a static
0376: Fields f = ei.cloneFields();
0377: int off = fi.getStorageOffset();
0378:
0379: if (fi.isReference()) {
0380: int oldValue = f.getReferenceValue(off);
0381: f.setReferenceValue(off, value);
0382: updateReachability(oldValue, value);
0383: } else {
0384: throw new JPFException("not a reference field: "
0385: + fi.getName());
0386: }
0387: }
0388:
0389: public void setReferenceField(String fname, String clsBase,
0390: int value) {
0391: setReferenceField(getFieldInfo(clsBase, fname), value);
0392: }
0393:
0394: public void setReferenceField(String fname, int value) {
0395: setReferenceField(fname, null, value);
0396: }
0397:
0398: public int getReferenceField(String fname, String clsBase) {
0399: FieldInfo fi = getFieldInfo(clsBase, fname);
0400: ElementInfo ei = getElementInfo(fi.getClassInfo());
0401:
0402: if (!fi.isReference()) {
0403: throw new JPFException("not a reference field: "
0404: + fi.getName());
0405: }
0406: return ei.fields.getIntValue(fi.getStorageOffset());
0407: }
0408:
0409: public int getReferenceField(String fname) {
0410: return getReferenceField(fname, null);
0411: }
0412:
0413: public int getIntField(String fname, String clsBase) {
0414: // be aware of that static fields are not flattened (they are unique), i.e.
0415: // the FieldInfo might actually refer to another ClassInfo/StaticElementInfo
0416: FieldInfo fi = getFieldInfo(clsBase, fname);
0417: ElementInfo ei = getElementInfo(fi.getClassInfo());
0418: return ei.fields.getIntValue(fi.getStorageOffset());
0419: }
0420:
0421: public void setLongField(String fname, String clsBase, long value) {
0422: FieldInfo fi = getFieldInfo(clsBase, fname);
0423: ElementInfo ei = getElementInfo(fi.getClassInfo());
0424: ei.cloneFields().setLongValue(fi.getStorageOffset(), value);
0425: }
0426:
0427: public long getLongField(String fname, String clsBase) {
0428: FieldInfo fi = getFieldInfo(clsBase, fname);
0429: ElementInfo ei = getElementInfo(fi.getClassInfo());
0430: return ei.fields.getLongValue(fi.getStorageOffset());
0431: }
0432:
0433: public boolean getBooleanField(String fname, String refType) {
0434: FieldInfo fi = getFieldInfo(refType, fname);
0435: ElementInfo ei = getElementInfo(fi.getClassInfo());
0436: return ei.fields.getBooleanValue(fi.getStorageOffset());
0437: }
0438:
0439: public byte getByteField(String fname, String refType) {
0440: FieldInfo fi = getFieldInfo(refType, fname);
0441: ElementInfo ei = getElementInfo(fi.getClassInfo());
0442: return ei.fields.getByteValue(fi.getStorageOffset());
0443: }
0444:
0445: public char getCharField(String fname, String refType) {
0446: FieldInfo fi = getFieldInfo(refType, fname);
0447: ElementInfo ei = getElementInfo(fi.getClassInfo());
0448: return ei.fields.getCharValue(fi.getStorageOffset());
0449: }
0450:
0451: public double getDoubleField(String fname, String refType) {
0452: FieldInfo fi = getFieldInfo(refType, fname);
0453: ElementInfo ei = getElementInfo(fi.getClassInfo());
0454: return ei.fields.getDoubleValue(fi.getStorageOffset());
0455: }
0456:
0457: public float getFloatField(String fname, String refType) {
0458: FieldInfo fi = getFieldInfo(refType, fname);
0459: ElementInfo ei = getElementInfo(fi.getClassInfo());
0460: return ei.fields.getFloatValue(fi.getStorageOffset());
0461: }
0462:
0463: public short getShortField(String fname, String refType) {
0464: FieldInfo fi = getFieldInfo(refType, fname);
0465: ElementInfo ei = getElementInfo(fi.getClassInfo());
0466: return ei.fields.getShortValue(fi.getStorageOffset());
0467: }
0468:
0469: private void checkFieldInfo(FieldInfo fi) {
0470: if (!getClassInfo().isInstanceOf(fi.getClassInfo())) {
0471: throw new JPFException("wrong FieldInfo : " + fi.getName()
0472: + " , no such field in " + getClassInfo().getName());
0473: }
0474: }
0475:
0476: // those are the cached field value accessors. The caller is responsible
0477: // for assuring type compatibility
0478: public int getIntField(FieldInfo fi) {
0479: checkFieldInfo(fi);
0480: return fields.getIntValue(fi.getStorageOffset());
0481: }
0482:
0483: public long getLongField(FieldInfo fi) {
0484: checkFieldInfo(fi);
0485: return fields.getLongValue(fi.getStorageOffset());
0486: }
0487:
0488: public void setLongField(FieldInfo fi, long val) {
0489: checkFieldInfo(fi);
0490: cloneFields().setLongValue(fi.getStorageOffset(), val);
0491: }
0492:
0493: private void checkArray(int index) {
0494: if (!isArray()) { // <2do> should check for !long array
0495: throw new JPFException(
0496: "cannot access non array objects by index");
0497: }
0498: if ((index < 0) || (index >= fields.size())) {
0499: throw new JPFException("illegal array offset: " + index);
0500: }
0501: }
0502:
0503: private void checkLongArray(int index) {
0504: if (!isArray()) { // <2do> should check for !int array
0505: throw new JPFException(
0506: "cannot access non array objects by index");
0507: }
0508: if ((index < 0) || (index >= (fields.size() - 1))) {
0509: throw new JPFException("illegal long array offset: "
0510: + index);
0511: }
0512: }
0513:
0514: private boolean isReferenceArray() {
0515: return getClassInfo().isReferenceArray();
0516: }
0517:
0518: // those are not really fields, so treat them differently!
0519: public void setElement(int index, int value) {
0520: checkArray(index);
0521: if (isReferenceArray()) {
0522: cloneFields().setReferenceValue(index, value);
0523: } else {
0524: cloneFields().setIntValue(index, value);
0525: }
0526: }
0527:
0528: public void setLongElement(int index, long value) {
0529: checkArray(index);
0530: cloneFields().setLongValue(index * 2, value);
0531: }
0532:
0533: public int getElement(int index) {
0534: checkArray(index);
0535: return fields.getIntValue(index);
0536: }
0537:
0538: public long getLongElement(int index) {
0539: checkArray(index);
0540: return fields.getLongValue(index * 2);
0541: }
0542:
0543: public void setIndex(int newIndex) {
0544: index = newIndex;
0545: }
0546:
0547: public int getIndex() {
0548: return index;
0549: }
0550:
0551: public int getThisReference() {
0552: return index;
0553: }
0554:
0555: public int getLockCount() {
0556: return monitor.getLockCount();
0557: }
0558:
0559: public int getLockingThread() {
0560: return monitor.getLockingThread();
0561: }
0562:
0563: public boolean isLocked() {
0564: return (monitor.getLockCount() > 0);
0565: }
0566:
0567: public boolean isArray() {
0568: return fields.isArray();
0569: }
0570:
0571: public String getArrayType() {
0572: if (!fields.isArray()) {
0573: throw new JPFException("object is not an array");
0574: }
0575:
0576: return Types.getArrayElementType(fields.getType());
0577: }
0578:
0579: public Object getBacktrackData() {
0580: return null;
0581: }
0582:
0583: public char getCharArrayElement(int index) {
0584: return (char) getElement(index);
0585: }
0586:
0587: public int getIntArrayElement(int findex) {
0588: return getElement(findex);
0589: }
0590:
0591: public long getLongArrayElement(int findex) {
0592: return getLongElement(findex);
0593: }
0594:
0595: public boolean[] asBooleanArray() {
0596: return fields.asBooleanArray();
0597: }
0598:
0599: public byte[] asByteArray() {
0600: return fields.asByteArray();
0601: }
0602:
0603: public short[] asShortArray() {
0604: return fields.asShortArray();
0605: }
0606:
0607: public char[] asCharArray() {
0608: return fields.asCharArray();
0609: }
0610:
0611: public int[] asIntArray() {
0612: return fields.asIntArray();
0613: }
0614:
0615: public long[] asLongArray() {
0616: return fields.asLongArray();
0617: }
0618:
0619: public float[] asFloatArray() {
0620: return fields.asFloatArray();
0621: }
0622:
0623: public double[] asDoubleArray() {
0624: return fields.asDoubleArray();
0625: }
0626:
0627: public boolean isNull() {
0628: return (index == -1);
0629: }
0630:
0631: public Reference getObjectField(String fname, String referenceType) {
0632: return area.ks.da.get(getIntField(fname, referenceType));
0633: }
0634:
0635: // <2do> just here for the Storable interface - it's NOT the one that is
0636: // used for heavy duty state storage, because we want to avoid all the
0637: // small array allocations. Change the Storable interface at some point!
0638: public int[] getStoringData() {
0639: int[] data = new int[3];
0640:
0641: data[0] = getFieldsIndex();
0642: data[1] = getMonitorIndex();
0643: data[2] = attributes;
0644:
0645: return data;
0646: }
0647:
0648: /**
0649: * <2do>pcm - these two will become the new Storable interface (but that has
0650: * a huge fan out)
0651: */
0652: public int getStoringDataLength() {
0653: return 3;
0654: }
0655:
0656: /**
0657: * answer an estimate of the heap size in bytes (this is of course VM
0658: * dependent, but we can give an upper bound for the fields/elements, and that
0659: * should be good in terms of application specific properties)
0660: */
0661: public int getHeapSize() {
0662: return fields.getHeapSize();
0663: }
0664:
0665: public String getStringField(String fname, String referenceType) {
0666: int ref = getIntField(fname, referenceType);
0667:
0668: if (ref != -1) {
0669: ElementInfo ei = area.ks.da.get(ref);
0670: if (ei == null) {
0671: System.out
0672: .println("OUTCH: " + ref + ", this: " + index);
0673: }
0674: return ei.asString();
0675: } else {
0676: return "null";
0677: }
0678: }
0679:
0680: public String getType() {
0681: return fields.getType();
0682: }
0683:
0684: public int[] getWaitingThreads() {
0685: return monitor.getWaitingThreads();
0686: }
0687:
0688: public int arrayLength() {
0689: return fields.arrayLength();
0690: }
0691:
0692: public String asString() {
0693: if (!fields.getClassInfo().instanceOf("java.lang.String")) {
0694: throw new JPFException(
0695: "object is not of type java.lang.String");
0696: }
0697:
0698: int value = getIntField("value", "java.lang.String");
0699: int length = getIntField("count", "java.lang.String");
0700: int offset = getIntField("offset", "java.lang.String");
0701:
0702: ElementInfo e = area.get(value);
0703:
0704: StringBuffer sb = new StringBuffer();
0705:
0706: for (int i = offset; i < (offset + length); i++) {
0707: sb.append((char) e.fields.getIntValue(i));
0708: }
0709:
0710: return sb.toString();
0711: }
0712:
0713: void updateLockingInfo() {
0714: int tid = monitor.getLockingThread();
0715: if (tid != -1) {
0716: // here we can update ThreadInfo lock object info (so that we don't
0717: // have to store it separately)
0718: // NOTE - the threads need to be restored *before* the Areas, or this is
0719: // going to choke
0720: ThreadInfo ti = area.ks.tl.get(tid);
0721: // note that we add only once, i.e. rely on the monitor lockCount to
0722: // determine when to remove an object from our lock set
0723: ti.addLockedObject(this );
0724: }
0725: }
0726:
0727: public void backtrackTo(ArrayOffset storing, Object backtrack) {
0728: setFieldsIndex(storing.get());
0729: setMonitorIndex(storing.get());
0730:
0731: attributes = storing.get();
0732:
0733: updateLockingInfo();
0734: }
0735:
0736: public boolean canLock(ThreadInfo th) {
0737: return monitor.canLock(th);
0738: }
0739:
0740: public void checkArrayBounds(int index)
0741: throws ArrayIndexOutOfBoundsExecutiveException {
0742: if (outOfBounds(index)) {
0743: throw new ArrayIndexOutOfBoundsExecutiveException(
0744: area.ks.ss
0745: .getRunningThread()
0746: .createAndThrowException(
0747: "java.lang.ArrayIndexOutOfBoundsException"));
0748: }
0749: }
0750:
0751: public void checkLongArrayBounds(int index)
0752: throws ArrayIndexOutOfBoundsExecutiveException {
0753: checkArrayBounds(index);
0754: checkArrayBounds(index + 1);
0755: }
0756:
0757: public Object clone() {
0758: try {
0759: ElementInfo ei = (ElementInfo) super .clone();
0760:
0761: if (ei.fIndex == -1) {
0762: ei.fields = (Fields) fields.clone();
0763: }
0764:
0765: if (ei.mIndex == -1) {
0766: ei.monitor = (Monitor) monitor.clone();
0767: }
0768:
0769: area = null;
0770: index = -1;
0771:
0772: return ei;
0773: } catch (CloneNotSupportedException e) {
0774: e.printStackTrace();
0775: throw new InternalError("should not happen");
0776: }
0777: }
0778:
0779: public void hash(HashData hd) {
0780: fields.hash(hd);
0781: monitor.hash(hd);
0782: }
0783:
0784: public int hashCode() {
0785: HashData hd = new HashData();
0786:
0787: hash(hd);
0788:
0789: return hd.getValue();
0790: }
0791:
0792: public boolean instanceOf(String type) {
0793: return Types.instanceOf(fields.getType(), type);
0794: }
0795:
0796: public void interrupt() {
0797: area.ks.tl.locate(index).interrupt();
0798: }
0799:
0800: public void lock(ThreadInfo th) {
0801: cloneMonitor().lock(th, getRef());
0802:
0803: // don't re-add if we are recursive - the lock count is avaliable in
0804: // the monitor
0805: if (monitor.getLockCount() == 1) {
0806: th.addLockedObject(this );
0807: }
0808: }
0809:
0810: public void lockNotified(ThreadInfo th) {
0811: cloneMonitor().lockNotified(th, getRef());
0812:
0813: // pcm - this is important, if we later-on backtrack (reset the
0814: // ThreadInfo.lockedObjects set, and then restore from the saved heap), the
0815: // lock set would not include the lock when we continue to execute this
0816: // thread
0817: th.addLockedObject(this ); //wv: add locked object back here
0818: }
0819:
0820: abstract public int getNumberOfFields();
0821:
0822: abstract public FieldInfo getFieldInfo(int i);
0823:
0824: public void log() {
0825: if (fIndex == -1) {
0826: Debug.println(Debug.MESSAGE, "(fields have changed)");
0827: }
0828:
0829: ClassInfo ci = getClassInfo();
0830: int n = getNumberOfFields();
0831: for (int i = 0; i < n; i++) {
0832: FieldInfo fi = getFieldInfo(i);
0833: Debug.println(Debug.MESSAGE, fi.getName() + ": "
0834: + fi.valueToString(fields));
0835: }
0836:
0837: if (mIndex == -1) {
0838: Debug.println(Debug.MESSAGE, "(monitor has changed)");
0839: }
0840:
0841: monitor.log();
0842: }
0843:
0844: public void notifies() {
0845: cloneMonitor().notify(area.ks.ss);
0846: }
0847:
0848: public void notifiesAll() {
0849: cloneMonitor().notifyAll(area.ks.ss);
0850: }
0851:
0852: public boolean outOfBounds(int index) {
0853: if (!fields.isArray()) {
0854: throw new JPFException("object is not an array");
0855: }
0856:
0857: return (index < 0 || index >= fields.size());
0858: }
0859:
0860: /**
0861: * imperatively set GC status
0862: *
0863: * @param keepAlive -
0864: * true: keep alive no matter what, false: gc normally
0865: */
0866: public void pinDown(boolean keepAlive) {
0867: if (keepAlive) {
0868: attributes |= ATTR_PINDOWN;
0869: } else {
0870: attributes &= ~ATTR_PINDOWN;
0871: }
0872: }
0873:
0874: /**
0875: * this is the heavy duty state storer for ElementInfos
0876: */
0877: public int storeDataTo(int[] buffer, int idx) {
0878: buffer[idx++] = getFieldsIndex();
0879: buffer[idx++] = getMonitorIndex();
0880: buffer[idx] = attributes;
0881:
0882: return 3;
0883: }
0884:
0885: public void unlock(ThreadInfo th) {
0886: cloneMonitor().unlock(th, getRef());
0887:
0888: if (monitor.getLockCount() == 0) {
0889: th.removeLockedObject(this );
0890: }
0891: }
0892:
0893: public void wait(ThreadInfo th) {
0894: cloneMonitor().wait(th, getRef());
0895: th.removeLockedObject(this ); //wv: remove locked object here
0896: }
0897:
0898: protected void setFieldsIndex(int index) {
0899: if (fIndex == index) {
0900: return;
0901: }
0902:
0903: fIndex = index;
0904: fields = (Fields) fieldsPool.getObject(index);
0905: }
0906:
0907: protected int getFieldsIndex() {
0908: if (fIndex != -1) {
0909: return fIndex;
0910: }
0911:
0912: HashPool.PoolEntry e = fieldsPool.getEntry(fields);
0913: fields = (Fields) e.getObject();
0914:
0915: return fIndex = e.getIndex();
0916: }
0917:
0918: protected void setMonitorIndex(int index) {
0919: if (mIndex == index) {
0920: return;
0921: }
0922:
0923: mIndex = index;
0924: monitor = (Monitor) monitorPool.getObject(index);
0925: }
0926:
0927: protected int getMonitorIndex() {
0928: if (mIndex != -1) {
0929: return mIndex;
0930: }
0931:
0932: HashPool.PoolEntry e = monitorPool.getEntry(monitor);
0933: monitor = (Monitor) e.getObject();
0934:
0935: return mIndex = e.getIndex();
0936: }
0937:
0938: /**
0939: * The various lock methods need access to a Ref object to do their work. The
0940: * subclass should return an appropriate type. This is a simple factory
0941: * method.
0942: *
0943: * @return the right kind of Ref object for the given ElementInfo
0944: */
0945: protected abstract Ref getRef();
0946:
0947: protected Fields cloneFields() {
0948: if (fIndex == -1) {
0949: return fields;
0950: }
0951:
0952: fIndex = -1;
0953: area.ks.data = null;
0954: area.hasChanged.set(index);
0955: area.anyChanged = true;
0956:
0957: return fields = (Fields) fields.clone();
0958: }
0959:
0960: protected Monitor cloneMonitor() {
0961: if (mIndex == -1) {
0962: return monitor;
0963: }
0964:
0965: mIndex = -1;
0966: area.ks.data = null;
0967: area.hasChanged.set(index);
0968: area.anyChanged = true;
0969:
0970: monitor = (Monitor) monitor.clone();
0971:
0972: return monitor;
0973: }
0974:
0975: boolean isLockedBy(ThreadInfo ti) {
0976: return ((monitor != null) && (monitor.getLockingThread() == ti.index));
0977: }
0978:
0979: void _printAttributes(String cls, String msg, int oldAttrs) {
0980: if (getClassInfo().getName().equals(cls)) {
0981: System.out.println(msg + " " + this + " attributes: "
0982: + Integer.toHexString(attributes) + " was: "
0983: + Integer.toHexString(oldAttrs));
0984: }
0985: }
0986:
0987: /*
0988: * The following code is used to linearize a rooted structure in the heap
0989: */
0990:
0991: public Vector linearize(Vector result) {
0992: DynamicArea heap = DynamicArea.getHeap();
0993: int i, n;
0994:
0995: if (isArray()) {
0996: if (fields.isReferenceArray()) {
0997: n = fields.arrayLength();
0998: for (i = 0; i < n; i++) {
0999: result = heap.linearize(fields.getIntValue(i),
1000: result);
1001: }
1002: }
1003: } else {
1004: ClassInfo ci = getClassInfo();
1005: do {
1006: n = ci.getNumberOfDeclaredInstanceFields();
1007: for (i = 0; i < n; i++) {
1008: FieldInfo fi = ci.getDeclaredInstanceField(i);
1009: if (fi.isReference()) {
1010: if ((i == 0) && ci.isWeakReference()) {
1011: // we need to reset the ref field once the referenced object goes away
1012: // NOTE: only the *first* WeakReference field is a weak ref
1013: // (this is why we have our own implementation)
1014:
1015: //dont' know what to do here?
1016: return result;
1017:
1018: } else {
1019: // the refAttrs are not immediately masked because we have to preserve
1020: // the mask values up to the point where we would promote a otherwise
1021: // unshared root object due to a different thread id (in case we didn't
1022: // catch a mask on the way that prevents this)
1023: result = heap.linearize(fields
1024: .getReferenceValue(fi
1025: .getStorageOffset()),
1026: result);
1027: }
1028: }
1029: }
1030: ci = ci.getSuperClass();
1031: } while (ci != null);
1032: }
1033: return result;
1034: }
1035: }
|