view src/main/gov/nasa/jpf/vm/Fields.java @ 2:b920e6b1be83

second part of the jpf-statechart motivated event interface overhaul, providing dynamic (context specific) expansion of EventTrees from within EventChoiceGenerators. This adds a EventContext mechanism that can replace events on-the-fly during advance() (e.g. expand wildcard patterns) this also included the refined 'vm.extend.transitions' property, which is now a list of TypeSpecs (glob notation plus bounds) for CG types that should be subject to transition extension. We also support CheckExtendTransition attrs for CGs, which can be used to dynamically mark CGs. Note that each matching CG is still tested for non-rescheduling single choices small Type/FeatureSpec extension to make it applicable to java.lang.Class instances. There is no reason why we can't make use of this for native types
author Peter Mehlitz <Peter.C.Mehlitz@nasa.gov>
date Sat, 24 Jan 2015 18:19:08 -0800
parents 61d41facf527
children
line wrap: on
line source

/*
 * Copyright (C) 2014, United States Government, as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All rights reserved.
 *
 * The Java Pathfinder core (jpf-core) platform is licensed under the
 * Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 *        http://www.apache.org/licenses/LICENSE-2.0. 
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package gov.nasa.jpf.vm;

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 create 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 int getIntValue (int index);

  // same as getIntValue(), just here to make intentions clear
  public abstract int getReferenceValue (int index);

  public abstract long getLongValue (int index);

  public abstract boolean getBooleanValue (int index);

  public abstract byte getByteValue (int index);

  public abstract char getCharValue (int index);

  public abstract short getShortValue (int index);

  public abstract float getFloatValue (int index);

  public abstract double getDoubleValue (int index);

  //--- the field modifier methods (both instance and static)

  public abstract void setReferenceValue (int index, int newValue);

  public abstract void setBooleanValue (int index, boolean newValue);

  public abstract void setByteValue (int index, byte newValue);

  public abstract void setCharValue (int index, char newValue);

  public abstract void setShortValue (int index, short newValue);

  public abstract void setFloatValue (int index, float newValue);

  public abstract void setIntValue (int index, int newValue);

  public abstract void setLongValue (int index, long newValue);

  public abstract void setDoubleValue (int index, double newValue);

  @Override
  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;
    }
  }

  @Override
  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.equals(fieldAttrs, f.fieldAttrs)) {
        return false;
      }
    }

    if (!ObjectList.equals(objectAttr, f.objectAttr)){
      return false;
    }

    return true;
  }

  // serialization interface
  public abstract void appendTo(IntVector v);


  @Override
  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;
  }
}