//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.vm;
import cmu.conditional.Conditional;
import de.fosd.typechef.featureexpr.FeatureExpr;
import gov.nasa.jpf.util.HashData;
import gov.nasa.jpf.util.IntVector;
import gov.nasa.jpf.util.Misc;
import gov.nasa.jpf.util.ObjectList;
/**
* Represents the variable, hash-collapsed pooled data associated with an object
* that is related to the object values (as opposed to synchronization ->Monitor).
* Contains the values of the fields, not their descriptors. Descriptors are represented
* by gov.nasa.jpf.vm.FieldInfo objects, which are stored in the ClassInfo structure.
*
* @see gov.nasa.jpf.vm.FieldInfo
* @see gov.nasa.jpf.vm.Monitor
*/
public abstract class Fields implements Cloneable {
/**
* we use this to store arbitrary field attributes (like symbolic values),
* but only pushClinit this on demand
*/
protected Object[] fieldAttrs;
/**
* attribute attached to the object as a whole
*/
protected Object objectAttr;
protected Fields() {}
public boolean hasFieldAttr() {
return fieldAttrs != null;
}
public boolean hasFieldAttr (Class<?> attrType){
Object[] fa = fieldAttrs;
if (fa != null){
for (int i=0; i<fa.length; i++){
Object a = fa[i];
if (a != null && ObjectList.containsType(a, attrType)){
return true;
}
}
}
return false;
}
/**
* this returns all of them - use either if you know there will be only
* one attribute at a time, or check/process result with ObjectList
*/
public Object getFieldAttr(int fieldOrElementIndex){
if (fieldAttrs != null){
return fieldAttrs[fieldOrElementIndex];
}
return null;
}
/**
* this replaces all of them - use only if you know
* - there will be only one attribute at a time
* - you obtained the value you set by a previous getXAttr()
* - you constructed a multi value list with ObjectList.createList()
*/
public void setFieldAttr (int nFieldsOrElements, int fieldOrElementIndex, Object attr){
if (fieldAttrs == null){
if (attr == null){
return; // no need to waste an array object for storing null
}
fieldAttrs = new Object[nFieldsOrElements];
}
fieldAttrs[fieldOrElementIndex] = attr;
}
public void addFieldAttr (int nFieldsOrElements, int fieldOrElementIndex, Object attr){
if (attr != null){
if (fieldAttrs == null) {
fieldAttrs = new Object[nFieldsOrElements];
}
fieldAttrs[fieldOrElementIndex] = ObjectList.add(fieldAttrs[fieldOrElementIndex], attr);
}
}
public void removeFieldAttr (int fieldOrElementIndex, Object attr){
if (fieldAttrs != null){
fieldAttrs[fieldOrElementIndex] = ObjectList.remove(fieldAttrs[fieldOrElementIndex], attr);
}
}
public void replaceFieldAttr (int fieldOrElementIndex, Object oldAttr, Object newAttr){
if (fieldAttrs != null){
fieldAttrs[fieldOrElementIndex] = ObjectList.replace(fieldAttrs[fieldOrElementIndex], oldAttr, newAttr);
}
}
public boolean hasFieldAttr (int fieldOrElementIndex, Class<?> type){
if (fieldAttrs != null){
return ObjectList.containsType(fieldAttrs[fieldOrElementIndex], type);
}
return false;
}
/**
* this only returns the first attr of this type, there can be more
* if you don't use client private types or the provided type is too general
*/
public <T> T getFieldAttr (int fieldOrElementIndex, Class<T> type){
if (fieldAttrs != null){
return ObjectList.getFirst(fieldAttrs[fieldOrElementIndex], type);
}
return null;
}
public <T> T getNextFieldAttr (int fieldOrElementIndex, Class<T> type, Object prev){
if (fieldAttrs != null){
return ObjectList.getNext(fieldAttrs[fieldOrElementIndex], type, prev);
}
return null;
}
public ObjectList.Iterator fieldAttrIterator(int fieldOrElementIndex){
Object a = (fieldAttrs != null) ? fieldAttrs[fieldOrElementIndex] : null;
return ObjectList.iterator(a);
}
public <T> ObjectList.TypedIterator<T> fieldAttrIterator(int fieldOrElementIndex, Class<T> type){
Object a = (fieldAttrs != null) ? fieldAttrs[fieldOrElementIndex] : null;
return ObjectList.typedIterator(a, type);
}
//--- object attributes
public boolean hasObjectAttr () {
return (objectAttr != null);
}
public boolean hasObjectAttr (Class<?> attrType){
return ObjectList.containsType(objectAttr, attrType);
}
/**
* this returns all of them - use either if you know there will be only
* one attribute at a time, or check/process result with ObjectList
*/
public Object getObjectAttr(){
return objectAttr;
}
/**
* this replaces all of them - use only if you know
* - there will be only one attribute at a time
* - you obtained the value you set by a previous getXAttr()
* - you constructed a multi value list with ObjectList.createList()
*/
public void setObjectAttr (Object attr){
objectAttr = attr;
}
public void addObjectAttr (Object attr){
objectAttr = ObjectList.add(objectAttr, attr);
}
public void removeObjectAttr (Object attr){
objectAttr = ObjectList.remove(objectAttr, attr);
}
public void replaceObjectAttr (Object oldAttr, Object newAttr){
objectAttr = ObjectList.replace(objectAttr, oldAttr, newAttr);
}
/**
* this only returns the first attr of this type, there can be more
* if you don't use client private types or the provided type is too general
*/
public <T> T getObjectAttr (Class<T> attrType) {
return ObjectList.getFirst(objectAttr, attrType);
}
public <T> T getNextObjectAttr (Class<T> attrType, Object prev) {
return ObjectList.getNext(objectAttr, attrType, prev);
}
public ObjectList.Iterator objectAttrIterator(){
return ObjectList.iterator(objectAttr);
}
public <T> ObjectList.TypedIterator<T> objectAttrIterator(Class<T> attrType){
return ObjectList.typedIterator(objectAttr, attrType);
}
public abstract int[] asFieldSlots();
/**
* give an approximation of the heap size in bytes - we assume fields are word
* aligned, hence the number of values*4 should be good. Note that this is
* overridden by ArrayFields (arrays would be packed)
*/
public abstract int getHeapSize ();
public boolean isReferenceArray () {
return false;
}
// our low level getters and setters
public abstract Conditional<Integer> getIntValue (int index);
// same as getIntValue(), just here to make intentions clear
public abstract Conditional<Integer> getReferenceValue (int index);
public abstract Conditional<Long> getLongValue (int index);
public abstract Conditional<Boolean> getBooleanValue (int index);
public abstract Conditional<Byte> getByteValue (int index);
public abstract Conditional<Character> getCharValue (int index);
public abstract Conditional<Short> getShortValue (int index);
public abstract Conditional<Float> getFloatValue (int index);
public abstract Conditional<Double> getDoubleValue (int index);
//--- the field modifier methods (both instance and static)
public abstract void setReferenceValue (FeatureExpr ctx, int index, Conditional<Integer> newValue);
public abstract void setBooleanValue (FeatureExpr ctx, int index, Conditional<Boolean> newValue);
public abstract void setByteValue (FeatureExpr ctx, int index, Conditional<Byte> newValue);
public abstract void setCharValue (FeatureExpr ctx, int index, Conditional<Character> newValue);
public abstract void setShortValue (FeatureExpr ctx, int index, Conditional<Short> newValue);
public abstract void setFloatValue (FeatureExpr ctx, int index, Conditional<Float> newValue);
public abstract void setIntValue (FeatureExpr ctx, int index, Conditional<Integer> newValue);
public abstract void setLongValue (FeatureExpr ctx, int index, Conditional<Long> newValue);
public abstract void setDoubleValue (FeatureExpr ctx, int index, Conditional<Double> newValue);
public abstract Fields clone ();
protected Fields cloneFields() {
try {
Fields f = (Fields)super.clone();
if (fieldAttrs != null) {
f.fieldAttrs = fieldAttrs.clone();
}
if (objectAttr != null) {
f.objectAttr = objectAttr; //
}
return f;
} catch (CloneNotSupportedException cnsx){
return null;
}
}
public abstract boolean equals(Object o);
// <2do> not multi-attr aware yet
protected boolean compareAttrs(Fields f) {
if (fieldAttrs != null || f.fieldAttrs != null) {
if (!Misc.compare(fieldAttrs, f.fieldAttrs)) {
return false;
}
}
if (!ObjectList.equals(objectAttr, f.objectAttr)){
return false;
}
return true;
}
// serialization interface
public abstract void appendTo(IntVector v);
public int hashCode () {
HashData hd = new HashData();
hash(hd);
hashAttrs(hd);
return hd.getValue();
}
public abstract void hash(HashData hd);
/**
* Adds some data to the computation of an hashcode.
*/
public void hashAttrs (HashData hd) {
// it's debatable if we add the attributes to the state, but whatever it
// is, it should be kept consistent with the StackFrame.hash()
Object[] a = fieldAttrs;
if (a != null) {
for (int i=0, l=a.length; i < l; i++) {
ObjectList.hash(a[i], hd);
}
}
if (objectAttr != null){
ObjectList.hash(objectAttr, hd);
}
}
// <2do> not multi-attr aware yet
public void copyAttrs(Fields other) {
if (other.fieldAttrs != null){
if (fieldAttrs == null){
fieldAttrs = other.fieldAttrs.clone();
} else {
System.arraycopy(other.fieldAttrs, 0, fieldAttrs, 0, fieldAttrs.length);
}
}
objectAttr = other.objectAttr;
}
}