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
140 // TODO: Fix for Groovy's model-checking
141 // TODO: Change of sid assignment strategy since the previous one caused a bug with SmartThings object filtering
145 // helpers for state storage/restore processing, to avoid explicit iterators on
146 // respective ElementInfo containers (heap,statics)
148 static class Restorer implements Processor<ElementInfo> {
150 public void process (ElementInfo ei) {
151 ei.attributes &= ElementInfo.ATTR_STORE_MASK;
153 ei.updateLockingInfo();
157 static Restorer restorer = new Restorer();
159 static class Storer implements Processor<ElementInfo> {
161 public void process (ElementInfo ei) {
165 static Storer storer = new Storer();
168 static boolean init (Config config) {
172 protected ElementInfo (int id, ClassInfo c, Fields f, Monitor m, ThreadInfo ti) {
178 assert ti != null; // we need that for our POR
181 public abstract ElementInfo getModifiableInstance();
183 // not ideal, a sub-type checker.
184 public abstract boolean isObject();
186 public abstract boolean hasFinalizer();
188 protected ElementInfo() {
191 public boolean hasChanged() {
193 //return (attributes & ATTR_ANY_CHANGED) != 0;
197 public String toString() {
198 return ((ci != null ? ci.getName() : "ElementInfo") + '@' + Integer.toHexString(objRef));
201 public FieldLockInfo getFieldLockInfo (FieldInfo fi) {
202 if (fLockInfo != null){
203 return fLockInfo[fi.getFieldIndex()];
209 public void setFieldLockInfo (FieldInfo fi, FieldLockInfo flInfo) {
212 if (fLockInfo == null){
213 fLockInfo = new FieldLockInfo[getNumberOfFields()];
216 fLockInfo[fi.getFieldIndex()] = flInfo;
217 attributes |= ATTR_FLI_CHANGED;
220 public boolean isLockProtected (FieldInfo fi){
221 if (fLockInfo != null){
222 FieldLockInfo fli = fLockInfo[fi.getFieldIndex()];
224 return fli.isProtected();
232 * object is recycled (after potential finalization)
234 public void processReleaseActions(){
235 // type based release actions
236 ci.processReleaseActions(this);
238 // instance based release actions
239 if (fields.hasObjectAttr()){
240 for (ReleaseAction action : fields.objectAttrIterator(ReleaseAction.class)){
241 action.release(this);
247 * post transition live object cleanup
248 * update all non-fields references used by this object. This is only called
249 * at the end of the gc, and recycled objects should be either null or not marked
251 void cleanUp (Heap heap, boolean isThreadTermination, int tid) {
252 if (fLockInfo != null) {
253 for (int i=0; i<fLockInfo.length; i++) {
254 FieldLockInfo fli = fLockInfo[i];
256 fLockInfo[i] = fli.cleanUp(heap);
263 //--- sids are only supposed to be used by the Serializer
264 public void setSid(long id){
268 public long getSid() {
272 //--- cached mementos are only supposed to be used/set by the Restorer
274 public Memento<ElementInfo> getCachedMemento(){
275 return cachedMemento;
278 public void setCachedMemento (Memento<ElementInfo> memento){
279 cachedMemento = memento;
283 * do we have a reference field with value objRef?
285 public boolean hasRefField (int objRef) {
286 return ci.hasRefField( objRef, fields);
290 public int numberOfUserThreads() {
291 return referencingThreads.size();
296 * the recursive phase2 marker entry, which propagates the attributes set by a
297 * previous phase1. This one is called on all 'root'-marked objects after
298 * phase1 is completed. ElementInfo is not an ideal place for this method, as
299 * it has to access some innards of both ClassInfo (FieldInfo container) and
300 * Fields. But on the other hand, we want to keep the whole heap traversal
301 * business as much centralized in ElementInfo and Heap implementors
303 void markRecursive(Heap heap) {
307 if (fields.isReferenceArray()) {
308 n = ((ArrayFields)fields).arrayLength();
309 for (i = 0; i < n; i++) {
310 int objref = fields.getReferenceValue(i);
311 if (objref != MJIEnv.NULL){
312 heap.queueMark( objref);
317 } else { // not an array
318 ClassInfo ci = getClassInfo();
319 boolean isWeakRef = ci.isWeakReference();
322 n = ci.getNumberOfDeclaredInstanceFields();
323 boolean isRef = isWeakRef && ci.isReferenceClassInfo(); // is this the java.lang.ref.Reference part?
325 for (i = 0; i < n; i++) {
326 FieldInfo fi = ci.getDeclaredInstanceField(i);
327 if (fi.isReference()) {
328 if ((i == 0) && isRef) {
329 // we need to reset the ref field once the referenced object goes away
330 // NOTE: only the *first* WeakReference field is a weak ref
331 // (this is why we have our own implementation)
332 heap.registerWeakReference(this);
334 int objref = fields.getReferenceValue(fi.getStorageOffset());
335 if (objref != MJIEnv.NULL){
336 heap.queueMark( objref);
341 ci = ci.getSuperClass();
342 } while (ci != null);
347 int getAttributes () {
351 int getStoredAttributes() {
352 return attributes & ATTR_STORE_MASK;
355 public boolean isImmutable() {
356 return ((attributes & ATTR_IMMUTABLE) != 0);
359 //--- freeze handling
361 public void freeze() {
362 attributes |= ATTR_IS_FROZEN;
365 public void defreeze() {
366 attributes &= ~ATTR_IS_FROZEN;
369 public boolean isFrozen() {
370 return ((attributes & ATTR_IS_FROZEN) != 0);
373 //--- shared handling
376 * set the referencing threads. Unless you know this is from a non-shared
377 * context, make sure to update sharedness by calling setShared()
379 public void setReferencingThreads (ThreadInfoSet refThreads){
381 referencingThreads = refThreads;
384 public ThreadInfoSet getReferencingThreads (){
385 return referencingThreads;
388 public void freezeSharedness (boolean freeze) {
390 if ((attributes & ATTR_FREEZE_SHARED) == 0) {
392 attributes |= (ATTR_FREEZE_SHARED | ATTR_ATTRIBUTE_CHANGED);
395 if ((attributes & ATTR_FREEZE_SHARED) != 0) {
397 attributes &= ~ATTR_FREEZE_SHARED;
398 attributes |= ATTR_ATTRIBUTE_CHANGED;
403 public boolean isSharednessFrozen () {
404 return (attributes & ATTR_FREEZE_SHARED) != 0;
407 public boolean isShared() {
408 //return usingTi.getNumberOfLiveThreads() > 1;
409 return ((attributes & ATTR_SHARED) != 0);
412 public void setShared (ThreadInfo ti, boolean isShared) {
414 if ((attributes & ATTR_SHARED) == 0) {
416 attributes |= (ATTR_SHARED | ATTR_ATTRIBUTE_CHANGED);
418 // note we don't report the thread here since this is explicitly set via Verify.setShared
419 VM.getVM().notifyObjectShared(ti, this);
422 if ((attributes & ATTR_SHARED) != 0) {
424 attributes &= ~ATTR_SHARED;
425 attributes |= ATTR_ATTRIBUTE_CHANGED;
431 * NOTE - this should only be called internally if we know the object is
432 * modifiable (e.g. from the ctor)
434 void setSharednessFromReferencingThreads () {
435 if (referencingThreads.isShared( null, this)) {
436 if ((attributes & ATTR_SHARED) == 0) {
438 attributes |= (ATTR_SHARED | ATTR_ATTRIBUTE_CHANGED);
443 public boolean isReferencedBySameThreads (ElementInfo eiOther) {
444 return referencingThreads.equals(eiOther.referencingThreads);
447 public boolean isReferencedByThread (ThreadInfo ti) {
448 return referencingThreads.contains(ti);
451 public boolean isExposed(){
452 return (attributes & ATTR_EXPOSED) != 0;
455 public boolean isExposedOrShared(){
456 return (attributes & (ATTR_SHARED | ATTR_EXPOSED)) != 0;
459 public ElementInfo getExposedInstance (ThreadInfo ti, ElementInfo eiFieldOwner){
460 ElementInfo ei = getModifiableInstance();
461 ei.setExposed( ti, eiFieldOwner);
463 // <2do> do we have to traverse every object reachable from here?
464 // (does every reference of an indirectly exposed object have to go through this one?)
469 protected void setExposed (){
470 attributes |= (ATTR_EXPOSED | ATTR_ATTRIBUTE_CHANGED);
473 public void setExposed (ThreadInfo ti, ElementInfo eiFieldOwner){
474 // we actually have to add this to the attributes to avoid endless loops by
475 // re-exposing the same object along a given path
476 attributes |= (ATTR_EXPOSED | ATTR_ATTRIBUTE_CHANGED);
478 ti.getVM().notifyObjectExposed(ti, eiFieldOwner, this);
482 * this is called before the system attempts to reclaim the object. If
483 * we return 'false', the object will *not* be removed
485 protected boolean recycle () {
486 // this is required to avoid loosing field lock assumptions
487 // when the system sequentialized threads with conflicting assumptions,
488 // but the offending object goes out of scope before the system backtracks
489 if (hasVolatileFieldLockInfos()) {
493 setObjectRef(MJIEnv.NULL);
498 boolean hasVolatileFieldLockInfos() {
499 if (fLockInfo != null) {
500 for (int i=0; i<fLockInfo.length; i++) {
501 FieldLockInfo fli = fLockInfo[i];
503 if (fli.needsPindown(this)) {
513 public void hash(HashData hd) {
514 hd.add(ci.getClassLoaderInfo().getId());
518 hd.add(attributes & ATTR_STORE_MASK);
522 public int hashCode() {
523 HashData hd = new HashData();
527 return hd.getValue();
531 public boolean equals(Object o) {
532 if (o != null && o instanceof ElementInfo) {
533 ElementInfo other = (ElementInfo) o;
539 if ((attributes & ATTR_STORE_MASK) != (other.attributes & ATTR_STORE_MASK)){
542 if (!fields.equals(other.fields)) {
545 if (!monitor.equals(other.monitor)){
548 if (referencingThreads != other.referencingThreads){
559 public ClassInfo getClassInfo() {
563 abstract protected FieldInfo getDeclaredFieldInfo(String clsBase, String fname);
565 abstract protected FieldInfo getFieldInfo(String fname);
567 protected abstract int getNumberOfFieldsOrElements();
570 //--- Object attribute accessors
572 public boolean hasObjectAttr(){
573 return fields.hasObjectAttr();
576 public boolean hasObjectAttr(Class<?> attrType) {
577 return fields.hasObjectAttr(attrType);
581 * this returns all of them - use either if you know there will be only
582 * one attribute at a time, or check/process result with ObjectList
584 public Object getObjectAttr(){
585 return fields.getObjectAttr();
589 * this replaces all of them - use only if you know
590 * - there will be only one attribute at a time
591 * - you obtained the value you set by a previous getXAttr()
592 * - you constructed a multi value list with ObjectList.createList()
594 public void setObjectAttr (Object a){
596 fields.setObjectAttr(a);
600 * this replaces all of them - use only if you know
601 * - there will be only one attribute at a time
602 * - you obtained the value you set by a previous getXAttr()
603 * - you constructed a multi value list with ObjectList.createList()
605 public void setObjectAttrNoClone (Object a){
606 fields.setObjectAttr(a);
610 public void addObjectAttr(Object a){
612 fields.addObjectAttr(a);
614 public void removeObjectAttr(Object a){
616 fields.removeObjectAttr(a);
618 public void replaceObjectAttr(Object oldAttr, Object newAttr){
620 fields.replaceObjectAttr(oldAttr, newAttr);
625 * this only returns the first attr of this type, there can be more
626 * if you don't use client private types or the provided type is too general
628 public <T> T getObjectAttr (Class<T> attrType) {
629 return fields.getObjectAttr(attrType);
631 public <T> T getNextObjectAttr (Class<T> attrType, Object prev) {
632 return fields.getNextObjectAttr(attrType, prev);
634 public ObjectList.Iterator objectAttrIterator(){
635 return fields.objectAttrIterator();
637 public <T> ObjectList.TypedIterator<T> objectAttrIterator(Class<T> type){
638 return fields.objectAttrIterator(type);
641 //--- field attribute accessors
643 public boolean hasFieldAttr() {
644 return fields.hasFieldAttr();
647 public boolean hasFieldAttr (Class<?> attrType){
648 return fields.hasFieldAttr(attrType);
652 * this returns all of them - use either if you know there will be only
653 * one attribute at a time, or check/process result with ObjectList
655 public Object getFieldAttr (FieldInfo fi){
656 return fields.getFieldAttr(fi.getFieldIndex());
660 * this replaces all of them - use only if you know
661 * - there will be only one attribute at a time
662 * - you obtained the value you set by a previous getXAttr()
663 * - you constructed a multi value list with ObjectList.createList()
665 public void setFieldAttr (FieldInfo fi, Object attr){
668 int nFields = getNumberOfFieldsOrElements();
669 fields.setFieldAttr( nFields, fi.getFieldIndex(), attr);
673 public void addFieldAttr (FieldInfo fi, Object a){
676 int nFields = getNumberOfFieldsOrElements();
677 fields.addFieldAttr( nFields, fi.getFieldIndex(), a);
679 public void removeFieldAttr (FieldInfo fi, Object a){
681 fields.removeFieldAttr(fi.getFieldIndex(), a);
683 public void replaceFieldAttr (FieldInfo fi, Object oldAttr, Object newAttr){
685 fields.replaceFieldAttr(fi.getFieldIndex(), oldAttr, newAttr);
689 * this only returns the first attr of this type, there can be more
690 * if you don't use client private types or the provided type is too general
692 public <T> T getFieldAttr (FieldInfo fi, Class<T> attrType) {
693 return fields.getFieldAttr(fi.getFieldIndex(), attrType);
695 public <T> T getNextFieldAttr (FieldInfo fi, Class<T> attrType, Object prev) {
696 return fields.getNextFieldAttr(fi.getFieldIndex(), attrType, prev);
698 public ObjectList.Iterator fieldAttrIterator (FieldInfo fi){
699 return fields.fieldAttrIterator(fi.getFieldIndex());
701 public <T> ObjectList.TypedIterator<T> fieldAttrIterator (FieldInfo fi, Class<T> type){
702 return fields.fieldAttrIterator(fi.getFieldIndex(), type);
707 //--- element attribute accessors
709 public boolean hasElementAttr() {
710 return fields.hasFieldAttr();
713 public boolean hasElementAttr (Class<?> attrType){
714 return fields.hasFieldAttr(attrType);
719 * this returns all of them - use either if you know there will be only
720 * one attribute at a time, or check/process result with ObjectList
722 public Object getElementAttr (int idx){
723 return fields.getFieldAttr(idx);
727 * this replaces all of them - use only if you know
728 * - there will be only one attribute at a time
729 * - you obtained the value you set by a previous getXAttr()
730 * - you constructed a multi value list with ObjectList.createList()
732 public void setElementAttr (int idx, Object attr){
733 int nElements = getNumberOfFieldsOrElements();
735 fields.setFieldAttr( nElements, idx, attr);
739 * this replaces all of them - use only if you know
740 * - there will be only one attribute at a time
741 * - you obtained the value you set by a previous getXAttr()
742 * - you constructed a multi value list with ObjectList.createList()
744 public void setElementAttrNoClone (int idx, Object attr){
745 int nElements = getNumberOfFieldsOrElements();
746 fields.setFieldAttr(nElements,idx, attr);
750 public void addElementAttr (int idx, Object a){
753 int nElements = getNumberOfFieldsOrElements();
754 fields.addFieldAttr( nElements, idx, a);
756 public void removeElementAttr (int idx, Object a){
758 fields.removeFieldAttr(idx, a);
760 public void replaceElementAttr (int idx, Object oldAttr, Object newAttr){
762 fields.replaceFieldAttr(idx, oldAttr, newAttr);
765 /** <2do> those will be obsolete */
766 public void addElementAttrNoClone (int idx, Object a){
767 int nElements = getNumberOfFieldsOrElements();
768 fields.addFieldAttr( nElements, idx, a);
770 public void removeElementAttrNoClone (int idx, Object a){
771 fields.removeFieldAttr(idx, a);
773 public void replaceElementAttrNoClone (int idx, Object oldAttr, Object newAttr){
774 fields.replaceFieldAttr(idx, oldAttr, newAttr);
778 * this only returns the first attr of this type, there can be more
779 * if you don't use client private types or the provided type is too general
781 public <T> T getElementAttr (int idx, Class<T> attrType) {
782 return fields.getFieldAttr(idx, attrType);
784 public <T> T getNextElementAttr (int idx, Class<T> attrType, Object prev) {
785 return fields.getNextFieldAttr(idx, attrType, prev);
787 public ObjectList.Iterator elementAttrIterator (int idx){
788 return fields.fieldAttrIterator(idx);
790 public <T> ObjectList.TypedIterator<T> elementAttrIterator (int idx, Class<T> type){
791 return fields.fieldAttrIterator(idx, type);
794 // -- end attributes --
797 public void setDeclaredIntField(String fname, String clsBase, int value) {
798 setIntField(getDeclaredFieldInfo(clsBase, fname), value);
801 public void setBooleanField (String fname, boolean value) {
802 setBooleanField( getFieldInfo(fname), value);
804 public void setByteField (String fname, byte value) {
805 setByteField( getFieldInfo(fname), value);
807 public void setCharField (String fname, char value) {
808 setCharField( getFieldInfo(fname), value);
810 public void setShortField (String fname, short value) {
811 setShortField( getFieldInfo(fname), value);
813 public void setIntField(String fname, int value) {
814 setIntField(getFieldInfo(fname), value);
816 public void setLongField (String fname, long value) {
817 setLongField( getFieldInfo(fname), value);
819 public void setFloatField (String fname, float value) {
820 setFloatField( getFieldInfo(fname), value);
822 public void setDoubleField (String fname, double value) {
823 setDoubleField( getFieldInfo(fname), value);
825 public void setReferenceField (String fname, int value) {
826 setReferenceField( getFieldInfo(fname), value);
830 // <2do> we need to tell 'null' values apart from 'no such field'
831 public Object getFieldValueObject (String fname) {
833 FieldInfo fi = getFieldInfo(fname);
836 ret = fi.getValueObject(fields);
839 // check if there is an enclosing class object
840 ElementInfo eiEnclosing = getEnclosingElementInfo();
841 if (eiEnclosing != null){
842 ret = eiEnclosing.getFieldValueObject(fname);
845 // we should check static fields in enclosing scopes, but there is no
846 // other way than to guess this from the name, and the outer
847 // classes might not even be initialized yet
854 public ElementInfo getEnclosingElementInfo() {
855 return null; // only for DynamicElementInfos
858 public void setBooleanField(FieldInfo fi, boolean newValue) {
861 if (fi.isBooleanField()) {
862 int offset = fi.getStorageOffset();
863 fields.setBooleanValue( offset, newValue);
865 throw new JPFException("not a boolean field: " + fi.getFullName());
869 public void setByteField(FieldInfo fi, byte newValue) {
872 if (fi.isByteField()) {
873 int offset = fi.getStorageOffset();
874 fields.setByteValue( offset, newValue);
876 throw new JPFException("not a byte field: " + fi.getFullName());
880 public void setCharField(FieldInfo fi, char newValue) {
883 if (fi.isCharField()) {
884 int offset = fi.getStorageOffset();
885 fields.setCharValue( offset, newValue);
887 throw new JPFException("not a char field: " + fi.getFullName());
891 public void setShortField(FieldInfo fi, short newValue) {
894 if (fi.isShortField()) {
895 int offset = fi.getStorageOffset();
896 fields.setShortValue( offset, newValue);
898 throw new JPFException("not a short field: " + fi.getFullName());
902 public void setIntField(FieldInfo fi, int newValue) {
905 if (fi.isIntField()) {
906 int offset = fi.getStorageOffset();
907 fields.setIntValue( offset, newValue);
909 throw new JPFException("not an int field: " + fi.getFullName());
913 public void setLongField(FieldInfo fi, long newValue) {
916 if (fi.isLongField()) {
917 int offset = fi.getStorageOffset();
918 fields.setLongValue( offset, newValue);
920 throw new JPFException("not a long field: " + fi.getFullName());
924 public void setFloatField(FieldInfo fi, float newValue) {
927 if (fi.isFloatField()) {
928 int offset = fi.getStorageOffset();
929 fields.setFloatValue( offset, newValue);
931 throw new JPFException("not a float field: " + fi.getFullName());
935 public void setDoubleField(FieldInfo fi, double newValue) {
938 if (fi.isDoubleField()) {
939 int offset = fi.getStorageOffset();
940 fields.setDoubleValue( offset, newValue);
942 throw new JPFException("not a double field: " + fi.getFullName());
946 public void setReferenceField(FieldInfo fi, int newValue) {
949 if (fi.isReference()) {
950 int offset = fi.getStorageOffset();
951 fields.setReferenceValue( offset, newValue);
953 throw new JPFException("not a reference field: " + fi.getFullName());
957 public void set1SlotField(FieldInfo fi, int newValue) {
960 if (fi.is1SlotField()) {
961 int offset = fi.getStorageOffset();
962 fields.setIntValue( offset, newValue);
964 throw new JPFException("not a 1 slot field: " + fi.getFullName());
968 public void set2SlotField(FieldInfo fi, long newValue) {
971 if (fi.is2SlotField()) {
972 int offset = fi.getStorageOffset();
973 fields.setLongValue( offset, newValue);
975 throw new JPFException("not a 2 slot field: " + fi.getFullName());
980 public void setDeclaredReferenceField(String fname, String clsBase, int value) {
981 setReferenceField(getDeclaredFieldInfo(clsBase, fname), value);
984 public int getDeclaredReferenceField(String fname, String clsBase) {
985 FieldInfo fi = getDeclaredFieldInfo(clsBase, fname);
986 return getReferenceField( fi);
989 public int getReferenceField(String fname) {
990 FieldInfo fi = getFieldInfo(fname);
991 return getReferenceField( fi);
995 public int getDeclaredIntField(String fname, String clsBase) {
996 // be aware of that static fields are not flattened (they are unique), i.e.
997 // the FieldInfo might actually refer to another ClassInfo/StaticElementInfo
998 FieldInfo fi = getDeclaredFieldInfo(clsBase, fname);
999 return getIntField( fi);
1002 public int getIntField(String fname) {
1003 // be aware of that static fields are not flattened (they are unique), i.e.
1004 // the FieldInfo might actually refer to another ClassInfo/StaticElementInfo
1005 FieldInfo fi = getFieldInfo(fname);
1006 return getIntField( fi);
1009 public void setDeclaredLongField(String fname, String clsBase, long value) {
1010 checkIsModifiable();
1012 FieldInfo fi = getDeclaredFieldInfo(clsBase, fname);
1013 fields.setLongValue( fi.getStorageOffset(), value);
1016 public long getDeclaredLongField(String fname, String clsBase) {
1017 FieldInfo fi = getDeclaredFieldInfo(clsBase, fname);
1018 return getLongField( fi);
1021 public long getLongField(String fname) {
1022 FieldInfo fi = getFieldInfo(fname);
1023 return getLongField( fi);
1026 public boolean getDeclaredBooleanField(String fname, String refType) {
1027 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1028 return getBooleanField( fi);
1031 public boolean getBooleanField(String fname) {
1032 FieldInfo fi = getFieldInfo(fname);
1033 return getBooleanField( fi);
1036 public byte getDeclaredByteField(String fname, String refType) {
1037 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1038 return getByteField( fi);
1041 public byte getByteField(String fname) {
1042 FieldInfo fi = getFieldInfo(fname);
1043 return getByteField( fi);
1046 public char getDeclaredCharField(String fname, String refType) {
1047 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1048 return getCharField( fi);
1051 public char getCharField(String fname) {
1052 FieldInfo fi = getFieldInfo(fname);
1053 return getCharField( fi);
1056 public double getDeclaredDoubleField(String fname, String refType) {
1057 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1058 return getDoubleField( fi);
1061 public double getDoubleField(String fname) {
1062 FieldInfo fi = getFieldInfo(fname);
1063 return getDoubleField( fi);
1066 public float getDeclaredFloatField(String fname, String refType) {
1067 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1068 return getFloatField( fi);
1071 public float getFloatField(String fname) {
1072 FieldInfo fi = getFieldInfo(fname);
1073 return getFloatField( fi);
1076 public short getDeclaredShortField(String fname, String refType) {
1077 FieldInfo fi = getDeclaredFieldInfo(refType, fname);
1078 return getShortField( fi);
1081 public short getShortField(String fname) {
1082 FieldInfo fi = getFieldInfo(fname);
1083 return getShortField( fi);
1087 * note this only holds for instance fields, and hence the method has to
1088 * be overridden in StaticElementInfo
1090 private void checkFieldInfo(FieldInfo fi) {
1091 if (!getClassInfo().isInstanceOf(fi.getClassInfo())) {
1092 throw new JPFException("wrong FieldInfo : " + fi.getName()
1093 + " , no such field in " + getClassInfo().getName());
1097 // those are the cached field value accessors. The caller is responsible
1098 // for assuring type compatibility
1100 public boolean getBooleanField(FieldInfo fi) {
1101 if (fi.isBooleanField()){
1102 return fields.getBooleanValue(fi.getStorageOffset());
1104 throw new JPFException("not a boolean field: " + fi.getName());
1107 public byte getByteField(FieldInfo fi) {
1108 if (fi.isByteField()){
1109 return fields.getByteValue(fi.getStorageOffset());
1111 throw new JPFException("not a byte field: " + fi.getName());
1114 public char getCharField(FieldInfo fi) {
1115 if (fi.isCharField()){
1116 return fields.getCharValue(fi.getStorageOffset());
1118 throw new JPFException("not a char field: " + fi.getName());
1121 public short getShortField(FieldInfo fi) {
1122 if (fi.isShortField()){
1123 return fields.getShortValue(fi.getStorageOffset());
1125 throw new JPFException("not a short field: " + fi.getName());
1128 public int getIntField(FieldInfo fi) {
1129 if (fi.isIntField()){
1130 return fields.getIntValue(fi.getStorageOffset());
1132 throw new JPFException("not a int field: " + fi.getName());
1135 public long getLongField(FieldInfo fi) {
1136 if (fi.isLongField()){
1137 return fields.getLongValue(fi.getStorageOffset());
1139 throw new JPFException("not a long field: " + fi.getName());
1142 public float getFloatField (FieldInfo fi){
1143 if (fi.isFloatField()){
1144 return fields.getFloatValue(fi.getStorageOffset());
1146 throw new JPFException("not a float field: " + fi.getName());
1149 public double getDoubleField (FieldInfo fi){
1150 if (fi.isDoubleField()){
1151 return fields.getDoubleValue(fi.getStorageOffset());
1153 throw new JPFException("not a double field: " + fi.getName());
1156 public int getReferenceField (FieldInfo fi) {
1157 if (fi.isReference()){
1158 return fields.getReferenceValue(fi.getStorageOffset());
1160 throw new JPFException("not a reference field: " + fi.getName());
1164 public int get1SlotField(FieldInfo fi) {
1165 if (fi.is1SlotField()){
1166 return fields.getIntValue(fi.getStorageOffset());
1168 throw new JPFException("not a 1 slot field: " + fi.getName());
1171 public long get2SlotField(FieldInfo fi) {
1172 if (fi.is2SlotField()){
1173 return fields.getLongValue(fi.getStorageOffset());
1175 throw new JPFException("not a 2 slot field: " + fi.getName());
1179 protected void checkArray(int index) {
1180 if (fields instanceof ArrayFields) { // <2do> should check for !long array
1181 if ((index < 0) || (index >= ((ArrayFields)fields).arrayLength())) {
1182 throw new JPFException("illegal array offset: " + index);
1185 throw new JPFException("cannot access non array objects by index");
1189 public boolean isReferenceArray() {
1190 return getClassInfo().isReferenceArray();
1194 * this is the backend for System.arraycopy implementations, but since it only
1195 * throws general exceptions it can also be used in other contexts that require
1196 * type and objRef checking
1198 * note that we have to do some additional type checking here because we store
1199 * reference arrays as int[], i.e. for reference arrays we can't rely on
1200 * System.arraycopy to do the element type checking for us
1202 * @throws java.lang.ArrayIndexOutOfBoundsException
1203 * @throws java.lang.ArrayStoreException
1205 public void copyElements( ThreadInfo ti, ElementInfo eiSrc, int srcIdx, int dstIdx, int length){
1208 throw new ArrayStoreException("destination object not an array: " + ci.getName());
1210 if (!eiSrc.isArray()){
1211 throw new ArrayStoreException("source object not an array: " + eiSrc.getClassInfo().getName());
1214 boolean isRefArray = isReferenceArray();
1215 if (eiSrc.isReferenceArray() != isRefArray){
1216 throw new ArrayStoreException("array types not compatible: " + eiSrc.getClassInfo().getName() + " and " + ci.getName());
1219 // since the caller has to handle normal ArrayStoreExceptions and
1220 // ArrayIndexOutOfBoundsExceptions, we don't have to explicitly check array length here
1222 // if we copy reference arrays, we first have to check element type compatibility
1223 // (the underlying Fields type is always int[], hence we have to do this explicitly)
1225 ClassInfo dstElementCi = ci.getComponentClassInfo();
1226 int[] srcRefs = ((ArrayFields)eiSrc.fields).asReferenceArray();
1227 int max = srcIdx + length;
1229 for (int i=srcIdx; i<max; i++){
1230 int eref = srcRefs[i];
1231 if (eref != MJIEnv.NULL){
1232 ClassInfo srcElementCi = ti.getClassInfo(eref);
1233 if (!srcElementCi.isInstanceOf(dstElementCi)) {
1234 throw new ArrayStoreException("incompatible reference array element type (required " + dstElementCi.getName() +
1235 ", found " + srcElementCi.getName());
1241 // NOTE - we have to clone the fields even in case System.arraycopy fails, since
1242 // the caller might handle ArrayStore/IndexOutOfBounds, and partial changes
1243 // have to be preserved
1244 // note also this preserves values in case of a self copy
1245 checkIsModifiable();
1247 Object srcVals = ((ArrayFields)eiSrc.getFields()).getValues();
1248 Object dstVals = ((ArrayFields)fields).getValues();
1250 // this might throw ArrayIndexOutOfBoundsExceptions and ArrayStoreExceptions
1251 System.arraycopy(srcVals, srcIdx, dstVals, dstIdx, length);
1253 // now take care of the attributes
1254 // <2do> what in case arraycopy did throw - we should only copy the changed element attrs
1255 if (eiSrc.hasFieldAttr()){
1256 if (eiSrc == this && srcIdx < dstIdx) { // self copy
1257 for (int i = length - 1; i >= 0; i--) {
1258 Object a = eiSrc.getElementAttr( srcIdx+i);
1259 setElementAttr( dstIdx+i, a);
1262 for (int i = 0; i < length; i++) {
1263 Object a = eiSrc.getElementAttr(srcIdx+i);
1264 setElementAttr( dstIdx+i, a);
1270 public void setBooleanElement(int idx, boolean value){
1272 checkIsModifiable();
1273 fields.setBooleanValue(idx, value);
1275 public void setByteElement(int idx, byte value){
1277 checkIsModifiable();
1278 fields.setByteValue(idx, value);
1280 public void setCharElement(int idx, char value){
1282 checkIsModifiable();
1283 fields.setCharValue(idx, value);
1285 public void setShortElement(int idx, short value){
1287 checkIsModifiable();
1288 fields.setShortValue(idx, value);
1290 public void setIntElement(int idx, int value){
1292 checkIsModifiable();
1293 fields.setIntValue(idx, value);
1295 public void setLongElement(int idx, long value) {
1297 checkIsModifiable();
1298 fields.setLongValue(idx, value);
1300 public void setFloatElement(int idx, float value){
1302 checkIsModifiable();
1303 fields.setFloatValue(idx, value);
1305 public void setDoubleElement(int idx, double value){
1307 checkIsModifiable();
1308 fields.setDoubleValue(idx, value);
1310 public void setReferenceElement(int idx, int value){
1312 checkIsModifiable();
1313 fields.setReferenceValue(idx, value);
1317 * NOTE - this doesn't support element type checks or overlapping in-array copy
1319 public void arrayCopy (ElementInfo src, int srcPos, int dstPos, int len){
1320 checkArray(dstPos+len-1);
1321 src.checkArray(srcPos+len-1);
1322 checkIsModifiable();
1324 ArrayFields da = (ArrayFields)fields;
1325 ArrayFields sa = (ArrayFields)src.fields;
1327 da.copyElements(sa, srcPos, dstPos, len);
1330 public boolean getBooleanElement(int idx) {
1332 return fields.getBooleanValue(idx);
1334 public byte getByteElement(int idx) {
1336 return fields.getByteValue(idx);
1338 public char getCharElement(int idx) {
1340 return fields.getCharValue(idx);
1342 public short getShortElement(int idx) {
1344 return fields.getShortValue(idx);
1346 public int getIntElement(int idx) {
1348 return fields.getIntValue(idx);
1350 public long getLongElement(int idx) {
1352 return fields.getLongValue(idx);
1354 public float getFloatElement(int idx) {
1356 return fields.getFloatValue(idx);
1358 public double getDoubleElement(int idx) {
1360 return fields.getDoubleValue(idx);
1362 public int getReferenceElement(int idx) {
1364 return fields.getReferenceValue(idx);
1367 public void setObjectRef(int newObjRef) {
1371 public int getObjectRef() {
1375 /** use getObjectRef() - this is not an index */
1377 public int getIndex(){
1381 public int getLockCount() {
1382 return monitor.getLockCount();
1385 public ThreadInfo getLockingThread() {
1386 return monitor.getLockingThread();
1389 public boolean isLocked() {
1390 return (monitor.getLockCount() > 0);
1393 public boolean isArray() {
1394 return ci.isArray();
1397 public boolean isCharArray(){
1398 return (fields instanceof CharArrayFields);
1401 public boolean isFloatArray(){
1402 return (fields instanceof FloatArrayFields);
1405 public boolean isDoubleArray(){
1406 return (fields instanceof DoubleArrayFields);
1410 public String getArrayType() {
1411 if (!ci.isArray()) {
1412 throw new JPFException("object is not an array");
1415 return Types.getArrayElementType(ci.getType());
1418 public Object getBacktrackData() {
1423 // <2do> these will check for corresponding ArrayFields types
1424 public boolean[] asBooleanArray() {
1425 if (fields instanceof ArrayFields){
1426 return ((ArrayFields)fields).asBooleanArray();
1428 throw new JPFException("not an array: " + ci.getName());
1432 public byte[] asByteArray() {
1433 if (fields instanceof ArrayFields){
1434 return ((ArrayFields)fields).asByteArray();
1436 throw new JPFException("not an array: " + ci.getName());
1440 public short[] asShortArray() {
1441 if (fields instanceof ArrayFields){
1442 return ((ArrayFields)fields).asShortArray();
1444 throw new JPFException("not an array: " + ci.getName());
1448 public char[] asCharArray() {
1449 if (fields instanceof ArrayFields){
1450 return ((ArrayFields)fields).asCharArray();
1452 throw new JPFException("not an array: " + ci.getName());
1456 public int[] asIntArray() {
1457 if (fields instanceof ArrayFields){
1458 return ((ArrayFields)fields).asIntArray();
1460 throw new JPFException("not an array: " + ci.getName());
1464 public long[] asLongArray() {
1465 if (fields instanceof ArrayFields){
1466 return ((ArrayFields)fields).asLongArray();
1468 throw new JPFException("not an array: " + ci.getName());
1472 public float[] asFloatArray() {
1473 if (fields instanceof ArrayFields){
1474 return ((ArrayFields)fields).asFloatArray();
1476 throw new JPFException("not an array: " + ci.getName());
1480 public double[] asDoubleArray() {
1481 if (fields instanceof ArrayFields){
1482 return ((ArrayFields)fields).asDoubleArray();
1484 throw new JPFException("not an array: " + ci.getName());
1488 public int[] asReferenceArray() {
1489 if (fields instanceof ArrayFields){
1490 return ((ArrayFields)fields).asReferenceArray();
1492 throw new JPFException("not an array: " + ci.getName());
1496 public boolean isNull() {
1497 return (objRef == MJIEnv.NULL);
1500 public ElementInfo getDeclaredObjectField(String fname, String referenceType) {
1501 return VM.getVM().getHeap().get(getDeclaredReferenceField(fname, referenceType));
1504 public ElementInfo getObjectField(String fname) {
1505 return VM.getVM().getHeap().get(getReferenceField(fname));
1510 * answer an estimate of the heap size in bytes (this is of course VM
1511 * dependent, but we can give an upper bound for the fields/elements, and that
1512 * should be good in terms of application specific properties)
1514 public int getHeapSize() {
1515 return fields.getHeapSize();
1518 public String getStringField(String fname) {
1519 int ref = getReferenceField(fname);
1521 if (ref != MJIEnv.NULL) {
1522 ElementInfo ei = VM.getVM().getHeap().get(ref);
1523 return ei.asString();
1529 public String getType() {
1530 return ci.getType();
1534 * return all threads that are trying to acquire this lock
1535 * (blocked, waiting, interrupted)
1536 * NOTE - this is not a copy, don't modify the array
1538 public ThreadInfo[] getLockedThreads() {
1539 return monitor.getLockedThreads();
1543 * get a cloned list of the waiters for this object
1545 public ThreadInfo[] getWaitingThreads() {
1546 return monitor.getWaitingThreads();
1549 public boolean hasWaitingThreads() {
1550 return monitor.hasWaitingThreads();
1553 public ThreadInfo[] getBlockedThreads() {
1554 return monitor.getBlockedThreads();
1557 public ThreadInfo[] getBlockedOrWaitingThreads() {
1558 return monitor.getBlockedOrWaitingThreads();
1561 public int arrayLength() {
1562 if (fields instanceof ArrayFields){
1563 return ((ArrayFields)fields).arrayLength();
1565 throw new JPFException("not an array: " + ci.getName());
1569 public boolean isStringObject() {
1570 return ClassInfo.isStringClassInfo(ci);
1573 public String asString() {
1574 throw new JPFException("not a String object: " + this);
1577 public char[] getStringChars(){
1578 throw new JPFException("not a String object: " + this);
1582 * just a helper to avoid creating objects just for the sake of comparing
1584 public boolean equalsString (String s) {
1585 throw new JPFException("not a String object: " + this);
1589 * is this a Number, a Boolean or a Character object
1590 * Note these classes are all final, so we don't have to check for subtypes
1592 * <2do> we should probably use a regular expression here
1594 public boolean isBoxObject(){
1598 public Object asBoxObject(){
1599 throw new JPFException("not a box object: " + this);
1602 void updateLockingInfo() {
1605 ThreadInfo ti = monitor.getLockingThread();
1607 // here we can update ThreadInfo lock object info (so that we don't
1608 // have to store it separately)
1610 // NOTE - the threads need to be restored *before* the ElementInfo containers,
1611 // or this is going to choke
1613 // note that we add only once, i.e. rely on the monitor lockCount to
1614 // determine when to remove an object from our lock set
1615 //assert area.ks.tl.get(ti.objRef) == ti; // covered by verifyLockInfo
1616 ti.updateLockedObject(this);
1619 if (monitor.hasLockedThreads()) {
1620 ThreadInfo[] lockedThreads = monitor.getLockedThreads();
1621 for (i=0; i<lockedThreads.length; i++) {
1622 ti = lockedThreads[i];
1623 //assert area.ks.tl.get(ti.objRef) == ti; // covered by verifyLockInfo
1625 // note that the thread might still be runnable if we have several threads
1626 // competing for the same lock
1627 if (!ti.isRunnable()){
1628 ti.setLockRef(objRef);
1634 public boolean canLock(ThreadInfo th) {
1635 return monitor.canLock(th);
1638 public void checkArrayBounds(int index) throws ArrayIndexOutOfBoundsExecutiveException {
1639 if (fields instanceof ArrayFields) {
1640 if (index < 0 || index >= ((ArrayFields)fields).arrayLength()){
1641 throw new ArrayIndexOutOfBoundsExecutiveException(
1642 ThreadInfo.getCurrentThread().createAndThrowException(
1643 "java.lang.ArrayIndexOutOfBoundsException", Integer.toString(index)));
1646 throw new JPFException("object is not an array: " + this);
1651 public ElementInfo clone() {
1653 ElementInfo ei = (ElementInfo) super.clone();
1654 ei.fields = fields.clone();
1655 ei.monitor = monitor.clone();
1659 } catch (CloneNotSupportedException e) {
1660 throw new InternalError("should not happen");
1664 // this is the one that should be used by heap
1665 public ElementInfo deepClone() {
1667 ElementInfo ei = (ElementInfo) super.clone();
1668 ei.fields = fields.clone();
1669 ei.monitor = monitor.clone();
1671 // referencingThreads is at least subtree global, hence doesn't need to be cloned
1673 ei.cachedMemento = null;
1678 } catch (CloneNotSupportedException e) {
1679 throw new InternalError("should not happen");
1684 public boolean instanceOf(String type) {
1685 return Types.instanceOf(ci.getType(), type);
1688 abstract public int getNumberOfFields();
1690 abstract public FieldInfo getFieldInfo(int fieldIndex);
1693 * threads that will grab our lock on their next execution have to be
1694 * registered, so that they can be blocked in case somebody else gets
1697 public void registerLockContender (ThreadInfo ti) {
1699 assert ti.lockRef == MJIEnv.NULL || ti.lockRef == objRef :
1700 "thread " + ti + " trying to register for : " + this +
1701 " ,but already blocked on: " + ti.getElementInfo(ti.lockRef);
1703 // note that using the lockedThreads list is a bit counter-intuitive
1704 // since the thread is still in RUNNING or UNBLOCKED state, but it will
1705 // remove itself from there once it resumes: lock() calls setMonitorWithoutLocked(ti)
1706 setMonitorWithLocked(ti);
1708 // added to satisfy invariant implied by updateLockingInfo() -peterd
1709 //ti.setLockRef(objRef);
1712 public boolean isRegisteredLockContender (ThreadInfo ti){
1713 return monitor.isLocking(ti);
1717 * somebody made up his mind and decided not to enter a synchronized section
1718 * of code it had registered before (e.g. INVOKECLINIT)
1720 public void unregisterLockContender (ThreadInfo ti) {
1721 setMonitorWithoutLocked(ti);
1723 // moved from INVOKECLINIT -peterd
1724 //ti.resetLockRef();
1727 void blockLockContenders () {
1728 // check if there are any other threads that have to change status because they
1729 // require to lock us in their next exec
1730 ThreadInfo[] lockedThreads = monitor.getLockedThreads();
1731 for (int i=0; i<lockedThreads.length; i++) {
1732 ThreadInfo ti = lockedThreads[i];
1733 if (ti.isRunnable()) {
1734 ti.setBlockedState(objRef);
1740 * from a MONITOR_ENTER or sync INVOKExx if we cannot acquire the lock
1741 * note: this is not called from a NOTIFIED_UNBLOCKED state, so we don't have to restore NOTIFIED
1743 public void block (ThreadInfo ti) {
1744 assert (monitor.getLockingThread() != null) && (monitor.getLockingThread() != ti) :
1745 "attempt to block " + ti.getName() + " on unlocked or own locked object: " + this;
1747 setMonitorWithLocked(ti);
1749 ti.setBlockedState(objRef);
1753 * from a MONITOR_ENTER or sync INVOKExx if we can acquire the lock
1755 public void lock (ThreadInfo ti) {
1756 // if we do unlock consistency checks with JPFExceptions, we should do the same here
1757 if ((monitor.getLockingThread() != null) && (monitor.getLockingThread() != ti)){
1758 throw new JPFException("thread " + ti.getName() + " tries to lock object: "
1759 + this + " which is locked by: " + monitor.getLockingThread().getName());
1762 // the thread might be still in the lockedThreads list if this is the
1763 // first step of a transition
1764 setMonitorWithoutLocked(ti);
1765 monitor.setLockingThread(ti);
1766 monitor.incLockCount();
1768 // before we enter anything else, mark this thread as not being blocked anymore
1771 ThreadInfo.State state = ti.getState();
1772 if (state == ThreadInfo.State.UNBLOCKED) {
1773 ti.setState(ThreadInfo.State.RUNNING);
1776 // don't re-add if we are recursive - the lock count is avaliable in the monitor
1777 if (monitor.getLockCount() == 1) {
1778 ti.addLockedObject(this);
1781 // this might set other threads blocked - make sure we lock first or the sequence
1782 // of notifications is a bit screwed (i.e. the lock would appear *after* the block)
1783 blockLockContenders();
1787 * from a MONITOR_EXIT or sync method RETURN
1788 * release a possibly recursive lock if lockCount goes to zero
1790 * return true if this unblocked any waiters
1792 public boolean unlock (ThreadInfo ti) {
1793 boolean didUnblock = false;
1795 checkIsModifiable();
1797 /* If there is a compiler bug, we need to flag it. Most compilers should
1798 * generate balanced monitorenter and monitorexit instructions for all code
1799 * paths. The VM is being used for more non-Java languages. Some of these
1800 * compilers might be experimental and might generate unbalanced
1801 * instructions. In a more likely case, dynamically generated bytecode is
1802 * more likely to make a mistake and miss a code path.
1804 if ((monitor.getLockCount() <= 0) || (monitor.getLockingThread() != ti)){
1805 throw new JPFException("thread " + ti.getName() + " tries to release non-owned lock for object: " + this);
1808 if (monitor.getLockCount() == 1) {
1809 ti.removeLockedObject(this);
1811 ThreadInfo[] lockedThreads = monitor.getLockedThreads();
1812 for (int i = 0; i < lockedThreads.length; i++) {
1813 ThreadInfo lti = lockedThreads[i];
1814 switch (lti.getState()) {
1820 // Ok, this thread becomes runnable again
1822 lti.setState(ThreadInfo.State.UNBLOCKED);
1827 case TIMEOUT_WAITING:
1828 // nothing to do yet, thread has to timeout, get notified, or interrupted
1832 assert false : "Monitor.lockedThreads<->ThreadData.status inconsistency! " + lockedThreads[i].getStateName();
1833 // why is it in the list - when someone unlocks, all others should have been blocked
1837 // leave the contenders - we need to know whom to block on subsequent lock
1839 monitor.decLockCount();
1840 monitor.setLockingThread(null);
1842 } else { // recursive unlock
1843 monitor.decLockCount();
1850 * notifies one of the waiters. Note this is a potentially non-deterministic action
1851 * if we have several waiters, since we have to try all possible choices.
1852 * Note that even if we notify a thread here, it still remains in the lockedThreads
1853 * list until the lock is released (notified threads cannot run right away)
1855 public boolean notifies(SystemState ss, ThreadInfo ti){
1856 return notifies(ss, ti, true);
1860 private void notifies0 (ThreadInfo tiWaiter){
1861 if (tiWaiter.isWaitingOrTimedOut()){
1862 if (tiWaiter.getLockCount() > 0) {
1863 // waiter did hold the lock, but gave it up in the wait, so it can't run yet
1864 tiWaiter.setNotifiedState();
1867 // waiter didn't hold the lock, set it running
1868 setMonitorWithoutLocked(tiWaiter);
1869 tiWaiter.resetLockRef();
1870 tiWaiter.setRunning();
1876 /** return true if this did notify any waiters */
1877 public boolean notifies (SystemState ss, ThreadInfo ti, boolean hasToHoldLock){
1879 assert monitor.getLockingThread() != null : "notify on unlocked object: " + this;
1882 ThreadInfo[] locked = monitor.getLockedThreads();
1883 int i, nWaiters=0, iWaiter=0;
1885 for (i=0; i<locked.length; i++) {
1886 if (locked[i].isWaitingOrTimedOut() ) {
1892 if (nWaiters == 0) {
1893 // no waiters, nothing to do
1894 } else if (nWaiters == 1) {
1895 // only one waiter, no choice point
1896 notifies0(locked[iWaiter]);
1899 // Ok, this is the non-deterministic case
1900 ThreadChoiceGenerator cg = ss.getCurrentChoiceGeneratorOfType(ThreadChoiceGenerator.class);
1902 assert (cg != null) : "no ThreadChoiceGenerator in notify";
1904 notifies0(cg.getNextChoice());
1907 ti.getVM().notifyObjectNotifies(ti, this);
1908 return (nWaiters > 0);
1912 * notify all waiters. This is a deterministic action
1913 * all waiters remain in the locked list, since they still have to be unblocked,
1914 * which happens in the unlock (monitor_exit or sync return) following the notifyAll()
1916 public boolean notifiesAll() {
1917 assert monitor.getLockingThread() != null : "notifyAll on unlocked object: " + this;
1919 ThreadInfo[] locked = monitor.getLockedThreads();
1920 for (int i=0; i<locked.length; i++) {
1921 // !!!! if there is more than one BLOCKED thread (sync call or monitor enter), only one can be
1923 notifies0(locked[i]);
1926 VM.getVM().notifyObjectNotifiesAll(ThreadInfo.currentThread, this);
1927 return (locked.length > 0);
1932 * wait to be notified. thread has to hold the lock, but gives it up in the wait.
1933 * Make sure lockCount can be restored properly upon notification
1935 public void wait(ThreadInfo ti, long timeout){
1936 wait(ti,timeout,true);
1939 // this is used from a context where we don't require a lock, e.g. Unsafe.park()/unpark()
1940 public void wait (ThreadInfo ti, long timeout, boolean hasToHoldLock){
1941 checkIsModifiable();
1943 boolean holdsLock = monitor.getLockingThread() == ti;
1946 assert holdsLock : "wait on unlocked object: " + this;
1949 setMonitorWithLocked(ti);
1950 ti.setLockRef(objRef);
1953 ti.setState(ThreadInfo.State.WAITING);
1955 ti.setState(ThreadInfo.State.TIMEOUT_WAITING);
1959 ti.setLockCount(monitor.getLockCount());
1961 monitor.setLockingThread(null);
1962 monitor.setLockCount(0);
1964 ti.removeLockedObject(this);
1966 // unblock all runnable threads that are blocked on this lock
1967 ThreadInfo[] lockedThreads = monitor.getLockedThreads();
1968 for (int i = 0; i < lockedThreads.length; i++) {
1969 ThreadInfo lti = lockedThreads[i];
1970 switch (lti.getState()) {
1975 lti.setState(ThreadInfo.State.UNBLOCKED);
1981 // <2do> not sure if this is right if we don't hold the lock
1982 ti.getVM().notifyObjectWait(ti, this);
1987 * re-acquire lock after being notified. This is the notified thread, i.e. the one
1988 * that will come out of a wait()
1990 public void lockNotified (ThreadInfo ti) {
1991 assert ti.isUnblocked() : "resume waiting thread " + ti.getName() + " which is not unblocked";
1993 setMonitorWithoutLocked(ti);
1994 monitor.setLockingThread( ti);
1995 monitor.setLockCount( ti.getLockCount());
1999 ti.setState( ThreadInfo.State.RUNNING);
2001 blockLockContenders();
2003 // this is important, if we later-on backtrack (reset the
2004 // ThreadInfo.lockedObjects set, and then restore from the saved heap), the
2005 // lock set would not include the lock when we continue to enter this thread
2006 ti.addLockedObject(this); //wv: add locked object back here
2010 * this is for waiters that did not own the lock
2012 public void resumeNonlockedWaiter (ThreadInfo ti){
2013 setMonitorWithoutLocked(ti);
2021 void dumpMonitor () {
2022 PrintWriter pw = new PrintWriter(System.out, true);
2023 pw.print( "monitor ");
2024 //pw.print( mIndex);
2025 monitor.printFields(pw);
2030 * updates a pinDown counter. If it is > 0 the object is kept alive regardless
2031 * if it is reachable from live objects or not.
2032 * @return true if the new counter is 1, i.e. the object just became pinned down
2034 * NOTE - this is *not* a public method and you probably want to use
2035 * Heap.register/unregisterPinDown(). Pinning down an object is now
2036 * done through the Heap API, which updates the counter here, but might also
2037 * have to update internal caches
2039 boolean incPinDown() {
2040 int pdCount = (attributes & ATTR_PINDOWN_MASK);
2043 if ((pdCount & ~ATTR_PINDOWN_MASK) != 0){
2044 throw new JPFException("pinDown limit exceeded: " + this);
2046 int a = (attributes & ~ATTR_PINDOWN_MASK);
2048 a |= ATTR_ATTRIBUTE_CHANGED;
2051 return (pdCount == 1);
2058 * @return true if the counter becomes 0, i.e. the object just ceased to be
2061 boolean decPinDown() {
2062 int pdCount = (attributes & ATTR_PINDOWN_MASK);
2066 int a = (attributes & ~ATTR_PINDOWN_MASK);
2068 a |= ATTR_ATTRIBUTE_CHANGED;
2071 return (pdCount == 0);
2078 public int getPinDownCount() {
2079 return (attributes & ATTR_PINDOWN_MASK);
2082 public boolean isPinnedDown() {
2083 return (attributes & ATTR_PINDOWN_MASK) != 0;
2087 public boolean isConstructed() {
2088 return (attributes & ATTR_CONSTRUCTED) != 0;
2091 public void setConstructed() {
2092 attributes |= (ATTR_CONSTRUCTED | ATTR_ATTRIBUTE_CHANGED);
2095 public void restoreFields(Fields f) {
2100 * BEWARE - never change the returned object without knowing about the
2101 * ElementInfo change status, this field is state managed!
2103 public Fields getFields() {
2107 public ArrayFields getArrayFields(){
2108 if (fields instanceof ArrayFields){
2109 return (ArrayFields)fields;
2111 throw new JPFException("not an array: " + ci.getName());
2115 public void restore(int index, int attributes, Fields fields, Monitor monitor){
2118 this.objRef = index;
2119 this.attributes = attributes;
2120 this.fields = fields;
2121 this.monitor = monitor;
2124 public void restoreMonitor(Monitor m) {
2129 * BEWARE - never change the returned object without knowing about the
2130 * ElementInfo change status, this field is state managed!
2132 public Monitor getMonitor() {
2136 public void restoreAttributes(int a) {
2140 public boolean isAlive(boolean liveBitValue) {
2141 return ((attributes & ATTR_LIVE_BIT) == 0) ^ liveBitValue;
2144 public void setAlive(boolean liveBitValue){
2146 attributes |= ATTR_LIVE_BIT;
2148 attributes &= ~ATTR_LIVE_BIT;
2152 public boolean isMarked() {
2153 return (attributes & ATTR_IS_MARKED) != 0;
2156 public boolean isFinalized() {
2157 return (attributes & ATTR_FINALIZED) != 0;
2160 public void setFinalized() {
2161 attributes |= ATTR_FINALIZED;
2164 public void setMarked() {
2165 attributes |= ATTR_IS_MARKED;
2168 public boolean isMarkedOrAlive (boolean liveBitValue){
2169 return ((attributes & ATTR_IS_MARKED) != 0) | (((attributes & ATTR_LIVE_BIT) == 0) ^ liveBitValue);
2172 public void markUnchanged() {
2173 attributes &= ~ATTR_ANY_CHANGED;
2176 public void setUnmarked() {
2177 attributes &= ~ATTR_IS_MARKED;
2181 protected void checkIsModifiable() {
2182 if ((attributes & ATTR_IS_FROZEN) != 0) {
2183 throw new JPFException("attempt to modify frozen object: " + this);
2187 void setMonitorWithLocked( ThreadInfo ti) {
2188 checkIsModifiable();
2189 monitor.addLocked(ti);
2192 void setMonitorWithoutLocked (ThreadInfo ti) {
2193 checkIsModifiable();
2194 monitor.removeLocked(ti);
2197 public boolean isLockedBy(ThreadInfo ti) {
2198 return ((monitor != null) && (monitor.getLockingThread() == ti));
2201 public boolean isLocking(ThreadInfo ti){
2202 return (monitor != null) && monitor.isLocking(ti);
2205 void _printAttributes(String cls, String msg, int oldAttrs) {
2206 if (getClassInfo().getName().equals(cls)) {
2207 System.out.println(msg + " " + this + " attributes: "
2208 + Integer.toHexString(attributes) + " was: "
2209 + Integer.toHexString(oldAttrs));
2214 public void checkConsistency() {
2216 ThreadInfo ti = monitor.getLockingThread();
2218 // object has to be in the lockedObjects list of this thread
2219 checkAssertion( ti.getLockedObjects().contains(this), "locked object not in thread: " + ti);
2222 if (monitor.hasLockedThreads()) {
2223 checkAssertion( refTid.cardinality() > 1, "locked threads without multiple referencing threads");
2225 for (ThreadInfo lti : monitor.getBlockedOrWaitingThreads()){
2226 checkAssertion( lti.lockRef == objRef, "blocked or waiting thread has invalid lockRef: " + lti);
2229 // we can't check for having lock contenders without being shared, since this can happen
2230 // in case an object is behind a FieldInfo shared-ness firewall (e.g. ThreadGroup.threads), or
2231 // is kept/used in native code (listener, peer)
2236 protected void checkAssertion(boolean cond, String failMsg){
2238 System.out.println("!!!!!! failed ElementInfo consistency: " + this + ": " + failMsg);
2240 System.out.println("object: " + this);
2241 System.out.println("usingTi: " + referencingThreads);
2243 ThreadInfo tiLock = getLockingThread();
2244 if (tiLock != null) System.out.println("locked by: " + tiLock);
2246 if (monitor.hasLockedThreads()){
2247 System.out.println("lock contenders:");
2248 for (ThreadInfo ti : monitor.getLockedThreads()){
2249 System.out.println(" " + ti + " = " + ti.getState());
2253 VM.getVM().dumpThreadStates();