2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package gov.nasa.jpf.vm;
20 import gov.nasa.jpf.Config;
21 import gov.nasa.jpf.JPFException;
22 import gov.nasa.jpf.util.HashData;
23 import gov.nasa.jpf.util.ObjectList;
24 import gov.nasa.jpf.util.Processor;
26 import java.io.PrintWriter;
29 * Describes an element of memory containing the field values of a class or an
30 * object. In the case of a class, contains the values of the static fields. For
31 * an object contains the values of the object fields.
33 * @see gov.nasa.jpf.vm.FieldInfo
35 public abstract class ElementInfo implements Cloneable {
38 //--- the lower 2 bytes of the attribute field are sticky (state stored/restored)
40 // object attribute flag values
42 // the first 8 bits constitute an unsigned pinDown count
43 public static final int ATTR_PINDOWN_MASK = 0xff;
45 // this ElementInfo is not allowed to be modified anymore since it has been state stored
46 // ElementInfos are constructed in a non-frozen state, and will be frozen upon
47 // heap store (usuall in the heap or ElementInfo memento ctor)
48 // This is the basis for lifting the change management from the fields level (fields,monitor,attributes)
49 // to the ElementInfo object level
50 public static final int ATTR_IS_FROZEN = 0x100;
52 // object has an immutable type (no field value change)
53 public static final int ATTR_IMMUTABLE = 0x200;
55 // The constructor for the object has returned. Final fields can no longer break POR
56 // This attribute is set in gov.nasa.jpf.vm.bytecode.RETURN.enter().
57 // If ThreadInfo.usePorSyncDetection() is false, then this attribute is never set.
58 public static final int ATTR_CONSTRUCTED = 0x400;
60 // object has been added to finalizer queue
61 public static final int ATTR_FINALIZED = 0x800;
63 public static final int ATTR_EXPOSED = 0x1000;
65 // object is shared between threads
66 public static final int ATTR_SHARED = 0x4000;
68 // ATTR_SHARED is frozen (has to be changed explicitly, will not be updated by checkUpdatedSharedness)
69 public static final int ATTR_FREEZE_SHARED = 0x8000;
72 //--- the upper two bytes are for transient (heap internal) use only, and are not stored
74 // BEWARE if you add or change values, make sure these are not used in derived classes !
75 // <2do> this is efficient but fragile
77 public static final int ATTR_TREF_CHANGED = 0x10000; // referencingThreads have changed
78 public static final int ATTR_FLI_CHANGED = 0x20000; // fieldLockInfos changed
79 public static final int ATTR_ATTRIBUTE_CHANGED = 0x80000; // refers only to sticky bits
82 //--- useful flag sets & masks
84 static final int ATTR_STORE_MASK = 0x0000ffff;
86 static final int ATTR_ANY_CHANGED = (ATTR_TREF_CHANGED | ATTR_FLI_CHANGED | ATTR_ATTRIBUTE_CHANGED);
88 // transient flag set if object is reachable from root object, i.e. can't be recycled
89 public static final int ATTR_IS_MARKED = 0x80000000;
91 // this bit is set/unset by the heap in order to identify live objects that have
92 // already been unmarked. This is to avoid additional passes over the whole heap in
93 // order to clean up dangling references etc.
94 // NOTE - this bit should never be state stored - restored ElementInfo should never have it set
95 public static final int ATTR_LIVE_BIT = 0x40000000;
97 public static final int ATTR_MARKED_OR_LIVE_BIT = (ATTR_IS_MARKED | ATTR_LIVE_BIT);
100 //--- instance fields
102 protected ClassInfo ci;
103 protected Fields fields;
104 protected Monitor monitor;
106 // the set of threads using this object. Note this is not used for state matching
107 // so that order or thread id do not have a direct impact on heap symmetry
108 protected ThreadInfoSet referencingThreads;
110 // this is where we keep track of lock sets that potentially protect field access
111 // of shared objects. Since usually only a subset of objects are shared, we
112 // initialize this on demand
113 protected FieldLockInfo[] fLockInfo;
116 // this is the reference value for the object represented by this ElementInfo
117 // (note this is a slight misnomer for StaticElementInfos, which don't really
118 // represent objects but collections of static fields belonging to the same class)
119 protected int objRef;
121 // these are our state-stored object attributes
122 // WATCH OUT! only include info that otherwise reflects a state change, so
123 // that we don't introduce new changes. Its value is used to hash the state!
124 // <2do> what a pity - 32 stored bits for (currently) only 2 bits of
125 // information,but we might use this as a hash for more complex reference
126 // info in the future.
127 // We distinguish between propagates and private object attributes, the first
128 // one stored in the lower 2 bytes
129 protected int attributes;
131 //--- the following fields are transient or search global, i.e. their values
132 // are not state-stored, but might be set during state restoration
134 // cache for unchanged ElementInfos, so that we don't have to re-create cachedMemento
135 // objects all the time
136 protected Memento<ElementInfo> cachedMemento;
138 // cache for a serialized representation of the object, which can be used
139 // by state-matching. Value interpretation depends on the configured Serializer
143 // helpers for state storage/restore processing, to avoid explicit iterators on
144 // respective ElementInfo containers (heap,statics)
146 static class Restorer implements Processor<ElementInfo> {
148 public void process (ElementInfo ei) {
149 ei.attributes &= ElementInfo.ATTR_STORE_MASK;
151 ei.updateLockingInfo();
155 static Restorer restorer = new Restorer();
157 static class Storer implements Processor<ElementInfo> {
159 public void process (ElementInfo ei) {
163 static Storer storer = new Storer();
166 static boolean init (Config config) {
170 protected ElementInfo (int id, ClassInfo c, Fields f, Monitor m, ThreadInfo ti) {
176 assert ti != null; // we need that for our POR
179 public abstract ElementInfo getModifiableInstance();
181 // not ideal, a sub-type checker.
182 public abstract boolean isObject();
184 public abstract boolean hasFinalizer();
186 protected ElementInfo() {
189 public boolean hasChanged() {
191 //return (attributes & ATTR_ANY_CHANGED) != 0;
195 public String toString() {
196 return ((ci != null ? ci.getName() : "ElementInfo") + '@' + Integer.toHexString(objRef));
199 public FieldLockInfo getFieldLockInfo (FieldInfo fi) {
200 if (fLockInfo != null){
201 return fLockInfo[fi.getFieldIndex()];
207 public void setFieldLockInfo (FieldInfo fi, FieldLockInfo flInfo) {
210 if (fLockInfo == null){
211 fLockInfo = new FieldLockInfo[getNumberOfFields()];
214 fLockInfo[fi.getFieldIndex()] = flInfo;
215 attributes |= ATTR_FLI_CHANGED;
218 public boolean isLockProtected (FieldInfo fi){
219 if (fLockInfo != null){
220 FieldLockInfo fli = fLockInfo[fi.getFieldIndex()];
222 return fli.isProtected();
230 * object is recycled (after potential finalization)
232 public void processReleaseActions(){
233 // type based release actions
234 ci.processReleaseActions(this);
236 // instance based release actions
237 if (fields.hasObjectAttr()){
238 for (ReleaseAction action : fields.objectAttrIterator(ReleaseAction.class)){
239 action.release(this);
245 * post transition live object cleanup
246 * update all non-fields references used by this object. This is only called
247 * at the end of the gc, and recycled objects should be either null or not marked
249 void cleanUp (Heap heap, boolean isThreadTermination, int tid) {
250 if (fLockInfo != null) {
251 for (int i=0; i<fLockInfo.length; i++) {
252 FieldLockInfo fli = fLockInfo[i];
254 fLockInfo[i] = fli.cleanUp(heap);
261 //--- sids are only supposed to be used by the Serializer
262 public void setSid(int id){
266 public int getSid() {
270 //--- cached mementos are only supposed to be used/set by the Restorer
272 public Memento<ElementInfo> getCachedMemento(){
273 return cachedMemento;
276 public void setCachedMemento (Memento<ElementInfo> memento){
277 cachedMemento = memento;
281 * do we have a reference field with value objRef?
283 public boolean hasRefField (int objRef) {
284 return ci.hasRefField( objRef, fields);
288 public int numberOfUserThreads() {
289 return referencingThreads.size();
294 * the recursive phase2 marker entry, which propagates the attributes set by a
295 * previous phase1. This one is called on all 'root'-marked objects after
296 * phase1 is completed. ElementInfo is not an ideal place for this method, as
297 * it has to access some innards of both ClassInfo (FieldInfo container) and
298 * Fields. But on the other hand, we want to keep the whole heap traversal
299 * business as much centralized in ElementInfo and Heap implementors
301 void markRecursive(Heap heap) {
305 if (fields.isReferenceArray()) {
306 n = ((ArrayFields)fields).arrayLength();
307 for (i = 0; i < n; i++) {
308 int objref = fields.getReferenceValue(i);
309 if (objref != MJIEnv.NULL){
310 heap.queueMark( objref);
315 } else { // not an array
316 ClassInfo ci = getClassInfo();
317 boolean isWeakRef = ci.isWeakReference();
320 n = ci.getNumberOfDeclaredInstanceFields();
321 boolean isRef = isWeakRef && ci.isReferenceClassInfo(); // is this the java.lang.ref.Reference part?
323 for (i = 0; i < n; i++) {
324 FieldInfo fi = ci.getDeclaredInstanceField(i);
325 if (fi.isReference()) {
326 if ((i == 0) && isRef) {
327 // we need to reset the ref field once the referenced object goes away
328 // NOTE: only the *first* WeakReference field is a weak ref
329 // (this is why we have our own implementation)
330 heap.registerWeakReference(this);
332 int objref = fields.getReferenceValue(fi.getStorageOffset());
333 if (objref != MJIEnv.NULL){
334 heap.queueMark( objref);
339 ci = ci.getSuperClass();
340 } while (ci != null);
345 int getAttributes () {
349 int getStoredAttributes() {
350 return attributes & ATTR_STORE_MASK;
353 public boolean isImmutable() {
354 return ((attributes & ATTR_IMMUTABLE) != 0);
357 //--- freeze handling
359 public void freeze() {
360 attributes |= ATTR_IS_FROZEN;
363 public void defreeze() {
364 attributes &= ~ATTR_IS_FROZEN;
367 public boolean isFrozen() {
368 return ((attributes & ATTR_IS_FROZEN) != 0);
371 //--- shared handling
374 * set the referencing threads. Unless you know this is from a non-shared
375 * context, make sure to update sharedness by calling setShared()
377 public void setReferencingThreads (ThreadInfoSet refThreads){
379 referencingThreads = refThreads;
382 public ThreadInfoSet getReferencingThreads (){
383 return referencingThreads;
386 public void freezeSharedness (boolean freeze) {
388 if ((attributes & ATTR_FREEZE_SHARED) == 0) {
390 attributes |= (ATTR_FREEZE_SHARED | ATTR_ATTRIBUTE_CHANGED);
393 if ((attributes & ATTR_FREEZE_SHARED) != 0) {
395 attributes &= ~ATTR_FREEZE_SHARED;
396 attributes |= ATTR_ATTRIBUTE_CHANGED;
401 public boolean isSharednessFrozen () {
402 return (attributes & ATTR_FREEZE_SHARED) != 0;
405 public boolean isShared() {
406 //return usingTi.getNumberOfLiveThreads() > 1;
407 return ((attributes & ATTR_SHARED) != 0);
410 public void setShared (ThreadInfo ti, boolean isShared) {
412 if ((attributes & ATTR_SHARED) == 0) {
414 attributes |= (ATTR_SHARED | ATTR_ATTRIBUTE_CHANGED);
416 // note we don't report the thread here since this is explicitly set via Verify.setShared
417 VM.getVM().notifyObjectShared(ti, this);
420 if ((attributes & ATTR_SHARED) != 0) {
422 attributes &= ~ATTR_SHARED;
423 attributes |= ATTR_ATTRIBUTE_CHANGED;
429 * NOTE - this should only be called internally if we know the object is
430 * modifiable (e.g. from the ctor)
432 void setSharednessFromReferencingThreads () {
433 if (referencingThreads.isShared( null, this)) {
434 if ((attributes & ATTR_SHARED) == 0) {
436 attributes |= (ATTR_SHARED | ATTR_ATTRIBUTE_CHANGED);
441 public boolean isReferencedBySameThreads (ElementInfo eiOther) {
442 return referencingThreads.equals(eiOther.referencingThreads);
445 public boolean isReferencedByThread (ThreadInfo ti) {
446 return referencingThreads.contains(ti);
449 public boolean isExposed(){
450 return (attributes & ATTR_EXPOSED) != 0;
453 public boolean isExposedOrShared(){
454 return (attributes & (ATTR_SHARED | ATTR_EXPOSED)) != 0;
457 public ElementInfo getExposedInstance (ThreadInfo ti, ElementInfo eiFieldOwner){
458 ElementInfo ei = getModifiableInstance();
459 ei.setExposed( ti, eiFieldOwner);
461 // <2do> do we have to traverse every object reachable from here?
462 // (does every reference of an indirectly exposed object have to go through this one?)
467 protected void setExposed (){
468 attributes |= (ATTR_EXPOSED | ATTR_ATTRIBUTE_CHANGED);
471 public void setExposed (ThreadInfo ti, ElementInfo eiFieldOwner){
472 // we actually have to add this to the attributes to avoid endless loops by
473 // re-exposing the same object along a given path
474 attributes |= (ATTR_EXPOSED | ATTR_ATTRIBUTE_CHANGED);
476 ti.getVM().notifyObjectExposed(ti, eiFieldOwner, this);
480 * this is called before the system attempts to reclaim the object. If
481 * we return 'false', the object will *not* be removed
483 protected boolean recycle () {
484 // this is required to avoid loosing field lock assumptions
485 // when the system sequentialized threads with conflicting assumptions,
486 // but the offending object goes out of scope before the system backtracks
487 if (hasVolatileFieldLockInfos()) {
491 setObjectRef(MJIEnv.NULL);
496 boolean hasVolatileFieldLockInfos() {
497 if (fLockInfo != null) {
498 for (int i=0; i<fLockInfo.length; i++) {
499 FieldLockInfo fli = fLockInfo[i];
501 if (fli.needsPindown(this)) {
511 public void hash(HashData hd) {
512 hd.add(ci.getClassLoaderInfo().getId());
516 hd.add(attributes & ATTR_STORE_MASK);
520 public int hashCode() {
521 HashData hd = new HashData();
525 return hd.getValue();
529 public boolean equals(Object o) {
530 if (o != null && o instanceof ElementInfo) {
531 ElementInfo other = (ElementInfo) o;
537 if ((attributes & ATTR_STORE_MASK) != (other.attributes & ATTR_STORE_MASK)){
540 if (!fields.equals(other.fields)) {
543 if (!monitor.equals(other.monitor)){
546 if (referencingThreads != other.referencingThreads){
557 public ClassInfo getClassInfo() {
561 abstract protected FieldInfo getDeclaredFieldInfo(String clsBase, String fname);
563 abstract protected FieldInfo getFieldInfo(String fname);
565 protected abstract int getNumberOfFieldsOrElements();
568 //--- Object attribute accessors
570 public boolean hasObjectAttr(){
571 return fields.hasObjectAttr();
574 public boolean hasObjectAttr(Class<?> attrType) {
575 return fields.hasObjectAttr(attrType);
579 * this returns all of them - use either if you know there will be only
580 * one attribute at a time, or check/process result with ObjectList
582 public Object getObjectAttr(){
583 return fields.getObjectAttr();
587 * this replaces all of them - use only if you know
588 * - there will be only one attribute at a time
589 * - you obtained the value you set by a previous getXAttr()
590 * - you constructed a multi value list with ObjectList.createList()
592 public void setObjectAttr (Object a){
594 fields.setObjectAttr(a);
598 * this replaces all of them - use only if you know
599 * - there will be only one attribute at a time
600 * - you obtained the value you set by a previous getXAttr()
601 * - you constructed a multi value list with ObjectList.createList()
603 public void setObjectAttrNoClone (Object a){
604 fields.setObjectAttr(a);
608 public void addObjectAttr(Object a){
610 fields.addObjectAttr(a);
612 public void removeObjectAttr(Object a){
614 fields.removeObjectAttr(a);
616 public void replaceObjectAttr(Object oldAttr, Object newAttr){
618 fields.replaceObjectAttr(oldAttr, newAttr);
623 * this only returns the first attr of this type, there can be more
624 * if you don't use client private types or the provided type is too general
626 public <T> T getObjectAttr (Class<T> attrType) {
627 return fields.getObjectAttr(attrType);
629 public <T> T getNextObjectAttr (Class<T> attrType, Object prev) {
630 return fields.getNextObjectAttr(attrType, prev);
632 public ObjectList.Iterator objectAttrIterator(){
633 return fields.objectAttrIterator();
635 public <T> ObjectList.TypedIterator<T> objectAttrIterator(Class<T> type){
636 return fields.objectAttrIterator(type);
639 //--- field attribute accessors
641 public boolean hasFieldAttr() {
642 return fields.hasFieldAttr();
645 public boolean hasFieldAttr (Class<?> attrType){
646 return fields.hasFieldAttr(attrType);
650 * this returns all of them - use either if you know there will be only
651 * one attribute at a time, or check/process result with ObjectList
653 public Object getFieldAttr (FieldInfo fi){
654 return fields.getFieldAttr(fi.getFieldIndex());
658 * this replaces all of them - use only if you know
659 * - there will be only one attribute at a time
660 * - you obtained the value you set by a previous getXAttr()
661 * - you constructed a multi value list with ObjectList.createList()
663 public void setFieldAttr (FieldInfo fi, Object attr){
666 int nFields = getNumberOfFieldsOrElements();
667 fields.setFieldAttr( nFields, fi.getFieldIndex(), attr);
671 public void addFieldAttr (FieldInfo fi, Object a){
674 int nFields = getNumberOfFieldsOrElements();
675 fields.addFieldAttr( nFields, fi.getFieldIndex(), a);
677 public void removeFieldAttr (FieldInfo fi, Object a){
679 fields.removeFieldAttr(fi.getFieldIndex(), a);
681 public void replaceFieldAttr (FieldInfo fi, Object oldAttr, Object newAttr){
683 fields.replaceFieldAttr(fi.getFieldIndex(), oldAttr, newAttr);
687 * this only returns the first attr of this type, there can be more
688 * if you don't use client private types or the provided type is too general
690 public <T> T getFieldAttr (FieldInfo fi, Class<T> attrType) {
691 return fields.getFieldAttr(fi.getFieldIndex(), attrType);
693 public <T> T getNextFieldAttr (FieldInfo fi, Class<T> attrType, Object prev) {
694 return fields.getNextFieldAttr(fi.getFieldIndex(), attrType, prev);
696 public ObjectList.Iterator fieldAttrIterator (FieldInfo fi){
697 return fields.fieldAttrIterator(fi.getFieldIndex());
699 public <T> ObjectList.TypedIterator<T> fieldAttrIterator (FieldInfo fi, Class<T> type){
700 return fields.fieldAttrIterator(fi.getFieldIndex(), type);
705 //--- element attribute accessors
707 public boolean hasElementAttr() {
708 return fields.hasFieldAttr();
711 public boolean hasElementAttr (Class<?> attrType){
712 return fields.hasFieldAttr(attrType);
717 * this returns all of them - use either if you know there will be only
718 * one attribute at a time, or check/process result with ObjectList
720 public Object getElementAttr (int idx){
721 return fields.getFieldAttr(idx);
725 * this replaces all of them - use only if you know
726 * - there will be only one attribute at a time
727 * - you obtained the value you set by a previous getXAttr()
728 * - you constructed a multi value list with ObjectList.createList()
730 public void setElementAttr (int idx, Object attr){
731 int nElements = getNumberOfFieldsOrElements();
733 fields.setFieldAttr( nElements, idx, attr);
737 * this replaces all of them - use only if you know
738 * - there will be only one attribute at a time
739 * - you obtained the value you set by a previous getXAttr()
740 * - you constructed a multi value list with ObjectList.createList()
742 public void setElementAttrNoClone (int idx, Object attr){
743 int nElements = getNumberOfFieldsOrElements();
744 fields.setFieldAttr(nElements,idx, attr);
748 public void addElementAttr (int idx, Object a){
751 int nElements = getNumberOfFieldsOrElements();
752 fields.addFieldAttr( nElements, idx, a);
754 public void removeElementAttr (int idx, Object a){
756 fields.removeFieldAttr(idx, a);
758 public void replaceElementAttr (int idx, Object oldAttr, Object newAttr){
760 fields.replaceFieldAttr(idx, oldAttr, newAttr);
763 /** <2do> those will be obsolete */
764 public void addElementAttrNoClone (int idx, Object a){
765 int nElements = getNumberOfFieldsOrElements();
766 fields.addFieldAttr( nElements, idx, a);
768 public void removeElementAttrNoClone (int idx, Object a){
769 fields.removeFieldAttr(idx, a);
771 public void replaceElementAttrNoClone (int idx, Object oldAttr, Object newAttr){
772 fields.replaceFieldAttr(idx, oldAttr, newAttr);
776 * this only returns the first attr of this type, there can be more
777 * if you don't use client private types or the provided type is too general
779 public <T> T getElementAttr (int idx, Class<T> attrType) {
780 return fields.getFieldAttr(idx, attrType);
782 public <T> T getNextElementAttr (int idx, Class<T> attrType, Object prev) {
783 return fields.getNextFieldAttr(idx, attrType, prev);
785 public ObjectList.Iterator elementAttrIterator (int idx){
786 return fields.fieldAttrIterator(idx);
788 public <T> ObjectList.TypedIterator<T> elementAttrIterator (int idx, Class<T> type){
789 return fields.fieldAttrIterator(idx, type);
792 // -- end attributes --
795 public void setDeclaredIntField(String fname, String clsBase, int value) {
796 setIntField(getDeclaredFieldInfo(clsBase, fname), value);
799 public void setBooleanField (String fname, boolean value) {
800 setBooleanField( getFieldInfo(fname), value);
802 public void setByteField (String fname, byte value) {
803 setByteField( getFieldInfo(fname), value);
805 public void setCharField (String fname, char value) {
806 setCharField( getFieldInfo(fname), value);
808 public void setShortField (String fname, short value) {
809 setShortField( getFieldInfo(fname), value);
811 public void setIntField(String fname, int value) {
812 setIntField(getFieldInfo(fname), value);
814 public void setLongField (String fname, long value) {
815 setLongField( getFieldInfo(fname), value);
817 public void setFloatField (String fname, float value) {
818 setFloatField( getFieldInfo(fname), value);
820 public void setDoubleField (String fname, double value) {
821 setDoubleField( getFieldInfo(fname), value);
823 public void setReferenceField (String fname, int value) {
824 setReferenceField( getFieldInfo(fname), value);
828 // <2do> we need to tell 'null' values apart from 'no such field'
829 public Object getFieldValueObject (String fname) {
831 FieldInfo fi = getFieldInfo(fname);
834 ret = fi.getValueObject(fields);
837 // check if there is an enclosing class object
838 ElementInfo eiEnclosing = getEnclosingElementInfo();
839 if (eiEnclosing != null){
840 ret = eiEnclosing.getFieldValueObject(fname);
843 // we should check static fields in enclosing scopes, but there is no
844 // other way than to guess this from the name, and the outer
845 // classes might not even be initialized yet
852 public ElementInfo getEnclosingElementInfo() {
853 return null; // only for DynamicElementInfos
856 public void setBooleanField(FieldInfo fi, boolean newValue) {
859 if (fi.isBooleanField()) {
860 int offset = fi.getStorageOffset();
861 fields.setBooleanValue( offset, newValue);
863 throw new JPFException("not a boolean field: " + fi.getFullName());
867 public void setByteField(FieldInfo fi, byte newValue) {
870 if (fi.isByteField()) {
871 int offset = fi.getStorageOffset();
872 fields.setByteValue( offset, newValue);
874 throw new JPFException("not a byte field: " + fi.getFullName());
878 public void setCharField(FieldInfo fi, char newValue) {
881 if (fi.isCharField()) {
882 int offset = fi.getStorageOffset();
883 fields.setCharValue( offset, newValue);
885 throw new JPFException("not a char field: " + fi.getFullName());
889 public void setShortField(FieldInfo fi, short newValue) {
892 if (fi.isShortField()) {
893 int offset = fi.getStorageOffset();
894 fields.setShortValue( offset, newValue);
896 throw new JPFException("not a short field: " + fi.getFullName());
900 public void setIntField(FieldInfo fi, int newValue) {
903 if (fi.isIntField()) {
904 int offset = fi.getStorageOffset();
905 fields.setIntValue( offset, newValue);
907 throw new JPFException("not an int field: " + fi.getFullName());
911 public void setLongField(FieldInfo fi, long newValue) {
914 if (fi.isLongField()) {
915 int offset = fi.getStorageOffset();
916 fields.setLongValue( offset, newValue);
918 throw new JPFException("not a long field: " + fi.getFullName());
922 public void setFloatField(FieldInfo fi, float newValue) {
925 if (fi.isFloatField()) {
926 int offset = fi.getStorageOffset();
927 fields.setFloatValue( offset, newValue);
929 throw new JPFException("not a float field: " + fi.getFullName());
933 public void setDoubleField(FieldInfo fi, double newValue) {
936 if (fi.isDoubleField()) {
937 int offset = fi.getStorageOffset();
938 fields.setDoubleValue( offset, newValue);
940 throw new JPFException("not a double field: " + fi.getFullName());
944 public void setReferenceField(FieldInfo fi, int newValue) {
947 if (fi.isReference()) {
948 int offset = fi.getStorageOffset();
949 fields.setReferenceValue( offset, newValue);
951 throw new JPFException("not a reference field: " + fi.getFullName());
955 public void set1SlotField(FieldInfo fi, int newValue) {
958 if (fi.is1SlotField()) {
959 int offset = fi.getStorageOffset();
960 fields.setIntValue( offset, newValue);
962 throw new JPFException("not a 1 slot field: " + fi.getFullName());
966 public void set2SlotField(FieldInfo fi, long newValue) {
969 if (fi.is2SlotField()) {
970 int offset = fi.getStorageOffset();
971 fields.setLongValue( offset, newValue);
973 throw new JPFException("not a 2 slot field: " + fi.getFullName());
978 public void setDeclaredReferenceField(String fname, String clsBase, int value) {
979 setReferenceField(getDeclaredFieldInfo(clsBase, fname), value);
982 public int getDeclaredReferenceField(String fname, String clsBase) {
983 FieldInfo fi = getDeclaredFieldInfo(clsBase, fname);
984 return getReferenceField( fi);
987 public int getReferenceField(String fname) {
988 FieldInfo fi = getFieldInfo(fname);
989 return getReferenceField( fi);
993 public int getDeclaredIntField(String fname, String clsBase) {
994 // be aware of that static fields are not flattened (they are unique), i.e.
995 // the FieldInfo might actually refer to another ClassInfo/StaticElementInfo
996 FieldInfo fi = getDeclaredFieldInfo(clsBase, fname);
997 return getIntField( fi);
1000 public int getIntField(String fname) {
1001 // be aware of that static fields are not flattened (they are unique), i.e.
1002 // the FieldInfo might actually refer to another ClassInfo/StaticElementInfo
1003 FieldInfo fi = getFieldInfo(fname);
1004 return getIntField( fi);
1007 public void setDeclaredLongField(String fname, String clsBase, long value) {
1008 checkIsModifiable();
1010 FieldInfo fi = getDeclaredFieldInfo(clsBase, fname);
1011 fields.setLongValue( fi.getStorageOffset(), value);
1014 public long getDeclaredLongField(String fname, String clsBase) {
1015 FieldInfo fi = getDeclaredFieldInfo(clsBase, fname);
1016 return getLongField( fi);
1019 public long getLongField(String fname) {
1020 FieldInfo fi = getFieldInfo(fname);
1021 return getLongField( fi);
1024 public boolean getDeclaredBooleanField(String fname, String refType) {
1025 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1026 return getBooleanField( fi);
1029 public boolean getBooleanField(String fname) {
1030 FieldInfo fi = getFieldInfo(fname);
1031 return getBooleanField( fi);
1034 public byte getDeclaredByteField(String fname, String refType) {
1035 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1036 return getByteField( fi);
1039 public byte getByteField(String fname) {
1040 FieldInfo fi = getFieldInfo(fname);
1041 return getByteField( fi);
1044 public char getDeclaredCharField(String fname, String refType) {
1045 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1046 return getCharField( fi);
1049 public char getCharField(String fname) {
1050 FieldInfo fi = getFieldInfo(fname);
1051 return getCharField( fi);
1054 public double getDeclaredDoubleField(String fname, String refType) {
1055 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1056 return getDoubleField( fi);
1059 public double getDoubleField(String fname) {
1060 FieldInfo fi = getFieldInfo(fname);
1061 return getDoubleField( fi);
1064 public float getDeclaredFloatField(String fname, String refType) {
1065 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1066 return getFloatField( fi);
1069 public float getFloatField(String fname) {
1070 FieldInfo fi = getFieldInfo(fname);
1071 return getFloatField( fi);
1074 public short getDeclaredShortField(String fname, String refType) {
1075 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1076 return getShortField( fi);
1079 public short getShortField(String fname) {
1080 FieldInfo fi = getFieldInfo(fname);
1081 return getShortField( fi);
1085 * note this only holds for instance fields, and hence the method has to
1086 * be overridden in StaticElementInfo
1088 private void checkFieldInfo(FieldInfo fi) {
1089 if (!getClassInfo().isInstanceOf(fi.getClassInfo())) {
1090 throw new JPFException("wrong FieldInfo : " + fi.getName()
1091 + " , no such field in " + getClassInfo().getName());
1095 // those are the cached field value accessors. The caller is responsible
1096 // for assuring type compatibility
1098 public boolean getBooleanField(FieldInfo fi) {
1099 if (fi.isBooleanField()){
1100 return fields.getBooleanValue(fi.getStorageOffset());
1102 throw new JPFException("not a boolean field: " + fi.getName());
1105 public byte getByteField(FieldInfo fi) {
1106 if (fi.isByteField()){
1107 return fields.getByteValue(fi.getStorageOffset());
1109 throw new JPFException("not a byte field: " + fi.getName());
1112 public char getCharField(FieldInfo fi) {
1113 if (fi.isCharField()){
1114 return fields.getCharValue(fi.getStorageOffset());
1116 throw new JPFException("not a char field: " + fi.getName());
1119 public short getShortField(FieldInfo fi) {
1120 if (fi.isShortField()){
1121 return fields.getShortValue(fi.getStorageOffset());
1123 throw new JPFException("not a short field: " + fi.getName());
1126 public int getIntField(FieldInfo fi) {
1127 if (fi.isIntField()){
1128 return fields.getIntValue(fi.getStorageOffset());
1130 throw new JPFException("not a int field: " + fi.getName());
1133 public long getLongField(FieldInfo fi) {
1134 if (fi.isLongField()){
1135 return fields.getLongValue(fi.getStorageOffset());
1137 throw new JPFException("not a long field: " + fi.getName());
1140 public float getFloatField (FieldInfo fi){
1141 if (fi.isFloatField()){
1142 return fields.getFloatValue(fi.getStorageOffset());
1144 throw new JPFException("not a float field: " + fi.getName());
1147 public double getDoubleField (FieldInfo fi){
1148 if (fi.isDoubleField()){
1149 return fields.getDoubleValue(fi.getStorageOffset());
1151 throw new JPFException("not a double field: " + fi.getName());
1154 public int getReferenceField (FieldInfo fi) {
1155 if (fi.isReference()){
1156 return fields.getReferenceValue(fi.getStorageOffset());
1158 throw new JPFException("not a reference field: " + fi.getName());
1162 public int get1SlotField(FieldInfo fi) {
1163 if (fi.is1SlotField()){
1164 return fields.getIntValue(fi.getStorageOffset());
1166 throw new JPFException("not a 1 slot field: " + fi.getName());
1169 public long get2SlotField(FieldInfo fi) {
1170 if (fi.is2SlotField()){
1171 return fields.getLongValue(fi.getStorageOffset());
1173 throw new JPFException("not a 2 slot field: " + fi.getName());
1177 protected void checkArray(int index) {
1178 if (fields instanceof ArrayFields) { // <2do> should check for !long array
1179 if ((index < 0) || (index >= ((ArrayFields)fields).arrayLength())) {
1180 throw new JPFException("illegal array offset: " + index);
1183 throw new JPFException("cannot access non array objects by index");
1187 public boolean isReferenceArray() {
1188 return getClassInfo().isReferenceArray();
1192 * this is the backend for System.arraycopy implementations, but since it only
1193 * throws general exceptions it can also be used in other contexts that require
1194 * type and objRef checking
1196 * note that we have to do some additional type checking here because we store
1197 * reference arrays as int[], i.e. for reference arrays we can't rely on
1198 * System.arraycopy to do the element type checking for us
1200 * @throws java.lang.ArrayIndexOutOfBoundsException
1201 * @throws java.lang.ArrayStoreException
1203 public void copyElements( ThreadInfo ti, ElementInfo eiSrc, int srcIdx, int dstIdx, int length){
1206 throw new ArrayStoreException("destination object not an array: " + ci.getName());
1208 if (!eiSrc.isArray()){
1209 throw new ArrayStoreException("source object not an array: " + eiSrc.getClassInfo().getName());
1212 boolean isRefArray = isReferenceArray();
1213 if (eiSrc.isReferenceArray() != isRefArray){
1214 throw new ArrayStoreException("array types not compatible: " + eiSrc.getClassInfo().getName() + " and " + ci.getName());
1217 // since the caller has to handle normal ArrayStoreExceptions and
1218 // ArrayIndexOutOfBoundsExceptions, we don't have to explicitly check array length here
1220 // if we copy reference arrays, we first have to check element type compatibility
1221 // (the underlying Fields type is always int[], hence we have to do this explicitly)
1223 ClassInfo dstElementCi = ci.getComponentClassInfo();
1224 int[] srcRefs = ((ArrayFields)eiSrc.fields).asReferenceArray();
1225 int max = srcIdx + length;
1227 for (int i=srcIdx; i<max; i++){
1228 int eref = srcRefs[i];
1229 if (eref != MJIEnv.NULL){
1230 ClassInfo srcElementCi = ti.getClassInfo(eref);
1231 if (!srcElementCi.isInstanceOf(dstElementCi)) {
1232 throw new ArrayStoreException("incompatible reference array element type (required " + dstElementCi.getName() +
1233 ", found " + srcElementCi.getName());
1239 // NOTE - we have to clone the fields even in case System.arraycopy fails, since
1240 // the caller might handle ArrayStore/IndexOutOfBounds, and partial changes
1241 // have to be preserved
1242 // note also this preserves values in case of a self copy
1243 checkIsModifiable();
1245 Object srcVals = ((ArrayFields)eiSrc.getFields()).getValues();
1246 Object dstVals = ((ArrayFields)fields).getValues();
1248 // this might throw ArrayIndexOutOfBoundsExceptions and ArrayStoreExceptions
1249 System.arraycopy(srcVals, srcIdx, dstVals, dstIdx, length);
1251 // now take care of the attributes
1252 // <2do> what in case arraycopy did throw - we should only copy the changed element attrs
1253 if (eiSrc.hasFieldAttr()){
1254 if (eiSrc == this && srcIdx < dstIdx) { // self copy
1255 for (int i = length - 1; i >= 0; i--) {
1256 Object a = eiSrc.getElementAttr( srcIdx+i);
1257 setElementAttr( dstIdx+i, a);
1260 for (int i = 0; i < length; i++) {
1261 Object a = eiSrc.getElementAttr(srcIdx+i);
1262 setElementAttr( dstIdx+i, a);
1268 public void setBooleanElement(int idx, boolean value){
1270 checkIsModifiable();
1271 fields.setBooleanValue(idx, value);
1273 public void setByteElement(int idx, byte value){
1275 checkIsModifiable();
1276 fields.setByteValue(idx, value);
1278 public void setCharElement(int idx, char value){
1280 checkIsModifiable();
1281 fields.setCharValue(idx, value);
1283 public void setShortElement(int idx, short value){
1285 checkIsModifiable();
1286 fields.setShortValue(idx, value);
1288 public void setIntElement(int idx, int value){
1290 checkIsModifiable();
1291 fields.setIntValue(idx, value);
1293 public void setLongElement(int idx, long value) {
1295 checkIsModifiable();
1296 fields.setLongValue(idx, value);
1298 public void setFloatElement(int idx, float value){
1300 checkIsModifiable();
1301 fields.setFloatValue(idx, value);
1303 public void setDoubleElement(int idx, double value){
1305 checkIsModifiable();
1306 fields.setDoubleValue(idx, value);
1308 public void setReferenceElement(int idx, int value){
1310 checkIsModifiable();
1311 fields.setReferenceValue(idx, value);
1315 * NOTE - this doesn't support element type checks or overlapping in-array copy
1317 public void arrayCopy (ElementInfo src, int srcPos, int dstPos, int len){
1318 checkArray(dstPos+len-1);
1319 src.checkArray(srcPos+len-1);
1320 checkIsModifiable();
1322 ArrayFields da = (ArrayFields)fields;
1323 ArrayFields sa = (ArrayFields)src.fields;
1325 da.copyElements(sa, srcPos, dstPos, len);
1328 public boolean getBooleanElement(int idx) {
1330 return fields.getBooleanValue(idx);
1332 public byte getByteElement(int idx) {
1334 return fields.getByteValue(idx);
1336 public char getCharElement(int idx) {
1338 return fields.getCharValue(idx);
1340 public short getShortElement(int idx) {
1342 return fields.getShortValue(idx);
1344 public int getIntElement(int idx) {
1346 return fields.getIntValue(idx);
1348 public long getLongElement(int idx) {
1350 return fields.getLongValue(idx);
1352 public float getFloatElement(int idx) {
1354 return fields.getFloatValue(idx);
1356 public double getDoubleElement(int idx) {
1358 return fields.getDoubleValue(idx);
1360 public int getReferenceElement(int idx) {
1362 return fields.getReferenceValue(idx);
1365 public void setObjectRef(int newObjRef) {
1369 public int getObjectRef() {
1373 /** use getObjectRef() - this is not an index */
1375 public int getIndex(){
1379 public int getLockCount() {
1380 return monitor.getLockCount();
1383 public ThreadInfo getLockingThread() {
1384 return monitor.getLockingThread();
1387 public boolean isLocked() {
1388 return (monitor.getLockCount() > 0);
1391 public boolean isArray() {
1392 return ci.isArray();
1395 public boolean isCharArray(){
1396 return (fields instanceof CharArrayFields);
1399 public boolean isFloatArray(){
1400 return (fields instanceof FloatArrayFields);
1403 public boolean isDoubleArray(){
1404 return (fields instanceof DoubleArrayFields);
1408 public String getArrayType() {
1409 if (!ci.isArray()) {
1410 throw new JPFException("object is not an array");
1413 return Types.getArrayElementType(ci.getType());
1416 public Object getBacktrackData() {
1421 // <2do> these will check for corresponding ArrayFields types
1422 public boolean[] asBooleanArray() {
1423 if (fields instanceof ArrayFields){
1424 return ((ArrayFields)fields).asBooleanArray();
1426 throw new JPFException("not an array: " + ci.getName());
1430 public byte[] asByteArray() {
1431 if (fields instanceof ArrayFields){
1432 return ((ArrayFields)fields).asByteArray();
1434 throw new JPFException("not an array: " + ci.getName());
1438 public short[] asShortArray() {
1439 if (fields instanceof ArrayFields){
1440 return ((ArrayFields)fields).asShortArray();
1442 throw new JPFException("not an array: " + ci.getName());
1446 public char[] asCharArray() {
1447 if (fields instanceof ArrayFields){
1448 return ((ArrayFields)fields).asCharArray();
1450 throw new JPFException("not an array: " + ci.getName());
1454 public int[] asIntArray() {
1455 if (fields instanceof ArrayFields){
1456 return ((ArrayFields)fields).asIntArray();
1458 throw new JPFException("not an array: " + ci.getName());
1462 public long[] asLongArray() {
1463 if (fields instanceof ArrayFields){
1464 return ((ArrayFields)fields).asLongArray();
1466 throw new JPFException("not an array: " + ci.getName());
1470 public float[] asFloatArray() {
1471 if (fields instanceof ArrayFields){
1472 return ((ArrayFields)fields).asFloatArray();
1474 throw new JPFException("not an array: " + ci.getName());
1478 public double[] asDoubleArray() {
1479 if (fields instanceof ArrayFields){
1480 return ((ArrayFields)fields).asDoubleArray();
1482 throw new JPFException("not an array: " + ci.getName());
1486 public int[] asReferenceArray() {
1487 if (fields instanceof ArrayFields){
1488 return ((ArrayFields)fields).asReferenceArray();
1490 throw new JPFException("not an array: " + ci.getName());
1494 public boolean isNull() {
1495 return (objRef == MJIEnv.NULL);
1498 public ElementInfo getDeclaredObjectField(String fname, String referenceType) {
1499 return VM.getVM().getHeap().get(getDeclaredReferenceField(fname, referenceType));
1502 public ElementInfo getObjectField(String fname) {
1503 return VM.getVM().getHeap().get(getReferenceField(fname));
1508 * answer an estimate of the heap size in bytes (this is of course VM
1509 * dependent, but we can give an upper bound for the fields/elements, and that
1510 * should be good in terms of application specific properties)
1512 public int getHeapSize() {
1513 return fields.getHeapSize();
1516 public String getStringField(String fname) {
1517 int ref = getReferenceField(fname);
1519 if (ref != MJIEnv.NULL) {
1520 ElementInfo ei = VM.getVM().getHeap().get(ref);
1521 return ei.asString();
1527 public String getType() {
1528 return ci.getType();
1532 * return all threads that are trying to acquire this lock
1533 * (blocked, waiting, interrupted)
1534 * NOTE - this is not a copy, don't modify the array
1536 public ThreadInfo[] getLockedThreads() {
1537 return monitor.getLockedThreads();
1541 * get a cloned list of the waiters for this object
1543 public ThreadInfo[] getWaitingThreads() {
1544 return monitor.getWaitingThreads();
1547 public boolean hasWaitingThreads() {
1548 return monitor.hasWaitingThreads();
1551 public ThreadInfo[] getBlockedThreads() {
1552 return monitor.getBlockedThreads();
1555 public ThreadInfo[] getBlockedOrWaitingThreads() {
1556 return monitor.getBlockedOrWaitingThreads();
1559 public int arrayLength() {
1560 if (fields instanceof ArrayFields){
1561 return ((ArrayFields)fields).arrayLength();
1563 throw new JPFException("not an array: " + ci.getName());
1567 public boolean isStringObject() {
1568 return ClassInfo.isStringClassInfo(ci);
1571 public String asString() {
1572 throw new JPFException("not a String object: " + this);
1575 public char[] getStringChars(){
1576 throw new JPFException("not a String object: " + this);
1580 * just a helper to avoid creating objects just for the sake of comparing
1582 public boolean equalsString (String s) {
1583 throw new JPFException("not a String object: " + this);
1587 * is this a Number, a Boolean or a Character object
1588 * Note these classes are all final, so we don't have to check for subtypes
1590 * <2do> we should probably use a regular expression here
1592 public boolean isBoxObject(){
1596 public Object asBoxObject(){
1597 throw new JPFException("not a box object: " + this);
1600 void updateLockingInfo() {
1603 ThreadInfo ti = monitor.getLockingThread();
1605 // here we can update ThreadInfo lock object info (so that we don't
1606 // have to store it separately)
1608 // NOTE - the threads need to be restored *before* the ElementInfo containers,
1609 // or this is going to choke
1611 // note that we add only once, i.e. rely on the monitor lockCount to
1612 // determine when to remove an object from our lock set
1613 //assert area.ks.tl.get(ti.objRef) == ti; // covered by verifyLockInfo
1614 ti.updateLockedObject(this);
1617 if (monitor.hasLockedThreads()) {
1618 ThreadInfo[] lockedThreads = monitor.getLockedThreads();
1619 for (i=0; i<lockedThreads.length; i++) {
1620 ti = lockedThreads[i];
1621 //assert area.ks.tl.get(ti.objRef) == ti; // covered by verifyLockInfo
1623 // note that the thread might still be runnable if we have several threads
1624 // competing for the same lock
1625 if (!ti.isRunnable()){
1626 ti.setLockRef(objRef);
1632 public boolean canLock(ThreadInfo th) {
1633 return monitor.canLock(th);
1636 public void checkArrayBounds(int index) throws ArrayIndexOutOfBoundsExecutiveException {
1637 if (fields instanceof ArrayFields) {
1638 if (index < 0 || index >= ((ArrayFields)fields).arrayLength()){
1639 throw new ArrayIndexOutOfBoundsExecutiveException(
1640 ThreadInfo.getCurrentThread().createAndThrowException(
1641 "java.lang.ArrayIndexOutOfBoundsException", Integer.toString(index)));
1644 throw new JPFException("object is not an array: " + this);
1649 public ElementInfo clone() {
1651 ElementInfo ei = (ElementInfo) super.clone();
1652 ei.fields = fields.clone();
1653 ei.monitor = monitor.clone();
1657 } catch (CloneNotSupportedException e) {
1658 throw new InternalError("should not happen");
1662 // this is the one that should be used by heap
1663 public ElementInfo deepClone() {
1665 ElementInfo ei = (ElementInfo) super.clone();
1666 ei.fields = fields.clone();
1667 ei.monitor = monitor.clone();
1669 // referencingThreads is at least subtree global, hence doesn't need to be cloned
1671 ei.cachedMemento = null;
1676 } catch (CloneNotSupportedException e) {
1677 throw new InternalError("should not happen");
1682 public boolean instanceOf(String type) {
1683 return Types.instanceOf(ci.getType(), type);
1686 abstract public int getNumberOfFields();
1688 abstract public FieldInfo getFieldInfo(int fieldIndex);
1691 * threads that will grab our lock on their next execution have to be
1692 * registered, so that they can be blocked in case somebody else gets
1695 public void registerLockContender (ThreadInfo ti) {
1697 assert ti.lockRef == MJIEnv.NULL || ti.lockRef == objRef :
1698 "thread " + ti + " trying to register for : " + this +
1699 " ,but already blocked on: " + ti.getElementInfo(ti.lockRef);
1701 // note that using the lockedThreads list is a bit counter-intuitive
1702 // since the thread is still in RUNNING or UNBLOCKED state, but it will
1703 // remove itself from there once it resumes: lock() calls setMonitorWithoutLocked(ti)
1704 setMonitorWithLocked(ti);
1706 // added to satisfy invariant implied by updateLockingInfo() -peterd
1707 //ti.setLockRef(objRef);
1710 public boolean isRegisteredLockContender (ThreadInfo ti){
1711 return monitor.isLocking(ti);
1715 * somebody made up his mind and decided not to enter a synchronized section
1716 * of code it had registered before (e.g. INVOKECLINIT)
1718 public void unregisterLockContender (ThreadInfo ti) {
1719 setMonitorWithoutLocked(ti);
1721 // moved from INVOKECLINIT -peterd
1722 //ti.resetLockRef();
1725 void blockLockContenders () {
1726 // check if there are any other threads that have to change status because they
1727 // require to lock us in their next exec
1728 ThreadInfo[] lockedThreads = monitor.getLockedThreads();
1729 for (int i=0; i<lockedThreads.length; i++) {
1730 ThreadInfo ti = lockedThreads[i];
1731 if (ti.isRunnable()) {
1732 ti.setBlockedState(objRef);
1738 * from a MONITOR_ENTER or sync INVOKExx if we cannot acquire the lock
1739 * note: this is not called from a NOTIFIED_UNBLOCKED state, so we don't have to restore NOTIFIED
1741 public void block (ThreadInfo ti) {
1742 assert (monitor.getLockingThread() != null) && (monitor.getLockingThread() != ti) :
1743 "attempt to block " + ti.getName() + " on unlocked or own locked object: " + this;
1745 setMonitorWithLocked(ti);
1747 ti.setBlockedState(objRef);
1751 * from a MONITOR_ENTER or sync INVOKExx if we can acquire the lock
1753 public void lock (ThreadInfo ti) {
1754 // if we do unlock consistency checks with JPFExceptions, we should do the same here
1755 if ((monitor.getLockingThread() != null) && (monitor.getLockingThread() != ti)){
1756 throw new JPFException("thread " + ti.getName() + " tries to lock object: "
1757 + this + " which is locked by: " + monitor.getLockingThread().getName());
1760 // the thread might be still in the lockedThreads list if this is the
1761 // first step of a transition
1762 setMonitorWithoutLocked(ti);
1763 monitor.setLockingThread(ti);
1764 monitor.incLockCount();
1766 // before we enter anything else, mark this thread as not being blocked anymore
1769 ThreadInfo.State state = ti.getState();
1770 if (state == ThreadInfo.State.UNBLOCKED) {
1771 ti.setState(ThreadInfo.State.RUNNING);
1774 // don't re-add if we are recursive - the lock count is avaliable in the monitor
1775 if (monitor.getLockCount() == 1) {
1776 ti.addLockedObject(this);
1779 // this might set other threads blocked - make sure we lock first or the sequence
1780 // of notifications is a bit screwed (i.e. the lock would appear *after* the block)
1781 blockLockContenders();
1785 * from a MONITOR_EXIT or sync method RETURN
1786 * release a possibly recursive lock if lockCount goes to zero
1788 * return true if this unblocked any waiters
1790 public boolean unlock (ThreadInfo ti) {
1791 boolean didUnblock = false;
1793 checkIsModifiable();
1795 /* If there is a compiler bug, we need to flag it. Most compilers should
1796 * generate balanced monitorenter and monitorexit instructions for all code
1797 * paths. The VM is being used for more non-Java languages. Some of these
1798 * compilers might be experimental and might generate unbalanced
1799 * instructions. In a more likely case, dynamically generated bytecode is
1800 * more likely to make a mistake and miss a code path.
1802 if ((monitor.getLockCount() <= 0) || (monitor.getLockingThread() != ti)){
1803 throw new JPFException("thread " + ti.getName() + " tries to release non-owned lock for object: " + this);
1806 if (monitor.getLockCount() == 1) {
1807 ti.removeLockedObject(this);
1809 ThreadInfo[] lockedThreads = monitor.getLockedThreads();
1810 for (int i = 0; i < lockedThreads.length; i++) {
1811 ThreadInfo lti = lockedThreads[i];
1812 switch (lti.getState()) {
1818 // Ok, this thread becomes runnable again
1820 lti.setState(ThreadInfo.State.UNBLOCKED);
1825 case TIMEOUT_WAITING:
1826 // nothing to do yet, thread has to timeout, get notified, or interrupted
1830 assert false : "Monitor.lockedThreads<->ThreadData.status inconsistency! " + lockedThreads[i].getStateName();
1831 // why is it in the list - when someone unlocks, all others should have been blocked
1835 // leave the contenders - we need to know whom to block on subsequent lock
1837 monitor.decLockCount();
1838 monitor.setLockingThread(null);
1840 } else { // recursive unlock
1841 monitor.decLockCount();
1848 * notifies one of the waiters. Note this is a potentially non-deterministic action
1849 * if we have several waiters, since we have to try all possible choices.
1850 * Note that even if we notify a thread here, it still remains in the lockedThreads
1851 * list until the lock is released (notified threads cannot run right away)
1853 public boolean notifies(SystemState ss, ThreadInfo ti){
1854 return notifies(ss, ti, true);
1858 private void notifies0 (ThreadInfo tiWaiter){
1859 if (tiWaiter.isWaitingOrTimedOut()){
1860 if (tiWaiter.getLockCount() > 0) {
1861 // waiter did hold the lock, but gave it up in the wait, so it can't run yet
1862 tiWaiter.setNotifiedState();
1865 // waiter didn't hold the lock, set it running
1866 setMonitorWithoutLocked(tiWaiter);
1867 tiWaiter.resetLockRef();
1868 tiWaiter.setRunning();
1874 /** return true if this did notify any waiters */
1875 public boolean notifies (SystemState ss, ThreadInfo ti, boolean hasToHoldLock){
1877 assert monitor.getLockingThread() != null : "notify on unlocked object: " + this;
1880 ThreadInfo[] locked = monitor.getLockedThreads();
1881 int i, nWaiters=0, iWaiter=0;
1883 for (i=0; i<locked.length; i++) {
1884 if (locked[i].isWaitingOrTimedOut() ) {
1890 if (nWaiters == 0) {
1891 // no waiters, nothing to do
1892 } else if (nWaiters == 1) {
1893 // only one waiter, no choice point
1894 notifies0(locked[iWaiter]);
1897 // Ok, this is the non-deterministic case
1898 ThreadChoiceGenerator cg = ss.getCurrentChoiceGeneratorOfType(ThreadChoiceGenerator.class);
1900 assert (cg != null) : "no ThreadChoiceGenerator in notify";
1902 notifies0(cg.getNextChoice());
1905 ti.getVM().notifyObjectNotifies(ti, this);
1906 return (nWaiters > 0);
1910 * notify all waiters. This is a deterministic action
1911 * all waiters remain in the locked list, since they still have to be unblocked,
1912 * which happens in the unlock (monitor_exit or sync return) following the notifyAll()
1914 public boolean notifiesAll() {
1915 assert monitor.getLockingThread() != null : "notifyAll on unlocked object: " + this;
1917 ThreadInfo[] locked = monitor.getLockedThreads();
1918 for (int i=0; i<locked.length; i++) {
1919 // !!!! if there is more than one BLOCKED thread (sync call or monitor enter), only one can be
1921 notifies0(locked[i]);
1924 VM.getVM().notifyObjectNotifiesAll(ThreadInfo.currentThread, this);
1925 return (locked.length > 0);
1930 * wait to be notified. thread has to hold the lock, but gives it up in the wait.
1931 * Make sure lockCount can be restored properly upon notification
1933 public void wait(ThreadInfo ti, long timeout){
1934 wait(ti,timeout,true);
1937 // this is used from a context where we don't require a lock, e.g. Unsafe.park()/unpark()
1938 public void wait (ThreadInfo ti, long timeout, boolean hasToHoldLock){
1939 checkIsModifiable();
1941 boolean holdsLock = monitor.getLockingThread() == ti;
1944 assert holdsLock : "wait on unlocked object: " + this;
1947 setMonitorWithLocked(ti);
1948 ti.setLockRef(objRef);
1951 ti.setState(ThreadInfo.State.WAITING);
1953 ti.setState(ThreadInfo.State.TIMEOUT_WAITING);
1957 ti.setLockCount(monitor.getLockCount());
1959 monitor.setLockingThread(null);
1960 monitor.setLockCount(0);
1962 ti.removeLockedObject(this);
1964 // unblock all runnable threads that are blocked on this lock
1965 ThreadInfo[] lockedThreads = monitor.getLockedThreads();
1966 for (int i = 0; i < lockedThreads.length; i++) {
1967 ThreadInfo lti = lockedThreads[i];
1968 switch (lti.getState()) {
1973 lti.setState(ThreadInfo.State.UNBLOCKED);
1979 // <2do> not sure if this is right if we don't hold the lock
1980 ti.getVM().notifyObjectWait(ti, this);
1985 * re-acquire lock after being notified. This is the notified thread, i.e. the one
1986 * that will come out of a wait()
1988 public void lockNotified (ThreadInfo ti) {
1989 assert ti.isUnblocked() : "resume waiting thread " + ti.getName() + " which is not unblocked";
1991 setMonitorWithoutLocked(ti);
1992 monitor.setLockingThread( ti);
1993 monitor.setLockCount( ti.getLockCount());
1997 ti.setState( ThreadInfo.State.RUNNING);
1999 blockLockContenders();
2001 // this is important, if we later-on backtrack (reset the
2002 // ThreadInfo.lockedObjects set, and then restore from the saved heap), the
2003 // lock set would not include the lock when we continue to enter this thread
2004 ti.addLockedObject(this); //wv: add locked object back here
2008 * this is for waiters that did not own the lock
2010 public void resumeNonlockedWaiter (ThreadInfo ti){
2011 setMonitorWithoutLocked(ti);
2019 void dumpMonitor () {
2020 PrintWriter pw = new PrintWriter(System.out, true);
2021 pw.print( "monitor ");
2022 //pw.print( mIndex);
2023 monitor.printFields(pw);
2028 * updates a pinDown counter. If it is > 0 the object is kept alive regardless
2029 * if it is reachable from live objects or not.
2030 * @return true if the new counter is 1, i.e. the object just became pinned down
2032 * NOTE - this is *not* a public method and you probably want to use
2033 * Heap.register/unregisterPinDown(). Pinning down an object is now
2034 * done through the Heap API, which updates the counter here, but might also
2035 * have to update internal caches
2037 boolean incPinDown() {
2038 int pdCount = (attributes & ATTR_PINDOWN_MASK);
2041 if ((pdCount & ~ATTR_PINDOWN_MASK) != 0){
2042 throw new JPFException("pinDown limit exceeded: " + this);
2044 int a = (attributes & ~ATTR_PINDOWN_MASK);
2046 a |= ATTR_ATTRIBUTE_CHANGED;
2049 return (pdCount == 1);
2056 * @return true if the counter becomes 0, i.e. the object just ceased to be
2059 boolean decPinDown() {
2060 int pdCount = (attributes & ATTR_PINDOWN_MASK);
2064 int a = (attributes & ~ATTR_PINDOWN_MASK);
2066 a |= ATTR_ATTRIBUTE_CHANGED;
2069 return (pdCount == 0);
2076 public int getPinDownCount() {
2077 return (attributes & ATTR_PINDOWN_MASK);
2080 public boolean isPinnedDown() {
2081 return (attributes & ATTR_PINDOWN_MASK) != 0;
2085 public boolean isConstructed() {
2086 return (attributes & ATTR_CONSTRUCTED) != 0;
2089 public void setConstructed() {
2090 attributes |= (ATTR_CONSTRUCTED | ATTR_ATTRIBUTE_CHANGED);
2093 public void restoreFields(Fields f) {
2098 * BEWARE - never change the returned object without knowing about the
2099 * ElementInfo change status, this field is state managed!
2101 public Fields getFields() {
2105 public ArrayFields getArrayFields(){
2106 if (fields instanceof ArrayFields){
2107 return (ArrayFields)fields;
2109 throw new JPFException("not an array: " + ci.getName());
2113 public void restore(int index, int attributes, Fields fields, Monitor monitor){
2116 this.objRef = index;
2117 this.attributes = attributes;
2118 this.fields = fields;
2119 this.monitor = monitor;
2122 public void restoreMonitor(Monitor m) {
2127 * BEWARE - never change the returned object without knowing about the
2128 * ElementInfo change status, this field is state managed!
2130 public Monitor getMonitor() {
2134 public void restoreAttributes(int a) {
2138 public boolean isAlive(boolean liveBitValue) {
2139 return ((attributes & ATTR_LIVE_BIT) == 0) ^ liveBitValue;
2142 public void setAlive(boolean liveBitValue){
2144 attributes |= ATTR_LIVE_BIT;
2146 attributes &= ~ATTR_LIVE_BIT;
2150 public boolean isMarked() {
2151 return (attributes & ATTR_IS_MARKED) != 0;
2154 public boolean isFinalized() {
2155 return (attributes & ATTR_FINALIZED) != 0;
2158 public void setFinalized() {
2159 attributes |= ATTR_FINALIZED;
2162 public void setMarked() {
2163 attributes |= ATTR_IS_MARKED;
2166 public boolean isMarkedOrAlive (boolean liveBitValue){
2167 return ((attributes & ATTR_IS_MARKED) != 0) | (((attributes & ATTR_LIVE_BIT) == 0) ^ liveBitValue);
2170 public void markUnchanged() {
2171 attributes &= ~ATTR_ANY_CHANGED;
2174 public void setUnmarked() {
2175 attributes &= ~ATTR_IS_MARKED;
2179 protected void checkIsModifiable() {
2180 if ((attributes & ATTR_IS_FROZEN) != 0) {
2181 throw new JPFException("attempt to modify frozen object: " + this);
2185 void setMonitorWithLocked( ThreadInfo ti) {
2186 checkIsModifiable();
2187 monitor.addLocked(ti);
2190 void setMonitorWithoutLocked (ThreadInfo ti) {
2191 checkIsModifiable();
2192 monitor.removeLocked(ti);
2195 public boolean isLockedBy(ThreadInfo ti) {
2196 return ((monitor != null) && (monitor.getLockingThread() == ti));
2199 public boolean isLocking(ThreadInfo ti){
2200 return (monitor != null) && monitor.isLocking(ti);
2203 void _printAttributes(String cls, String msg, int oldAttrs) {
2204 if (getClassInfo().getName().equals(cls)) {
2205 System.out.println(msg + " " + this + " attributes: "
2206 + Integer.toHexString(attributes) + " was: "
2207 + Integer.toHexString(oldAttrs));
2212 public void checkConsistency() {
2214 ThreadInfo ti = monitor.getLockingThread();
2216 // object has to be in the lockedObjects list of this thread
2217 checkAssertion( ti.getLockedObjects().contains(this), "locked object not in thread: " + ti);
2220 if (monitor.hasLockedThreads()) {
2221 checkAssertion( refTid.cardinality() > 1, "locked threads without multiple referencing threads");
2223 for (ThreadInfo lti : monitor.getBlockedOrWaitingThreads()){
2224 checkAssertion( lti.lockRef == objRef, "blocked or waiting thread has invalid lockRef: " + lti);
2227 // we can't check for having lock contenders without being shared, since this can happen
2228 // in case an object is behind a FieldInfo shared-ness firewall (e.g. ThreadGroup.threads), or
2229 // is kept/used in native code (listener, peer)
2234 protected void checkAssertion(boolean cond, String failMsg){
2236 System.out.println("!!!!!! failed ElementInfo consistency: " + this + ": " + failMsg);
2238 System.out.println("object: " + this);
2239 System.out.println("usingTi: " + referencingThreads);
2241 ThreadInfo tiLock = getLockingThread();
2242 if (tiLock != null) System.out.println("locked by: " + tiLock);
2244 if (monitor.hasLockedThreads()){
2245 System.out.println("lock contenders:");
2246 for (ThreadInfo ti : monitor.getLockedThreads()){
2247 System.out.println(" " + ti + " = " + ti.getState());
2251 VM.getVM().dumpThreadStates();