view src/main/gov/nasa/jpf/vm/InfoObject.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 cb7500a46eab
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.ObjectList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * common root for ClassInfo, MethodInfo, FieldInfo (and maybe more to follow)
 * 
 * so far, it's used to factorize the annotation support, but we can also
 * move the attributes up here
 * 
 * Note this is used for both declaration- and type- annotations since there is
 * a cross-over (type annotations of classes/interfaces are visible through the
 * reflection API that is otherwise just reserved for declaration annotations)
 * 
 * 2do - there are 3 annotation positions that are valid for both type and declaration
 * annotations: class/interface, field and formal method parameters. Of these,
 * only class/interface type annotations can be queried at runtime, i.e. are
 * treated similarly to declaration annotations. It is not clear if this is a
 * Java 8 implementation artifact or intentional
 * 
 * Other than annotating classes/interfaces, type and declaration annotations
 * are kept separate and only the latter ones can be queried from Java, hence
 * we provide a query API that is only accessible from instructions,
 * native peers and listeners. Type annotations are used
 */
public abstract class InfoObject implements Cloneable {

  static AnnotationInfo[] NO_ANNOTATIONS = new AnnotationInfo[0];
  static AbstractTypeAnnotationInfo[] NO_TYPE_ANNOTATIONS = new AbstractTypeAnnotationInfo[0];
  
  // the number of annotations per class/method/field is usually
  // small enough so that simple arrays are more efficient than HashMaps
  protected AnnotationInfo[] annotations = NO_ANNOTATIONS;

  protected AbstractTypeAnnotationInfo[] typeAnnotations = NO_TYPE_ANNOTATIONS;
  
  /** 
   * user defined attribute objects.
   * Note - this is NOT automatically state restored upon backtracking,
   * subclasses have to do this on their own if required
   */
  protected Object attr;
  
  
  public void setAnnotations (AnnotationInfo[] annotations){
    this.annotations = annotations;
  }
  
  public void addAnnotations (AnnotationInfo[] annotations){
    if (annotations == null){
      this.annotations = annotations;
    } else {
      AnnotationInfo[] newAi = new AnnotationInfo[this.annotations.length + annotations.length];
      System.arraycopy(this.annotations,0,newAi, 0, this.annotations.length);
      System.arraycopy(annotations, 0, newAi, this.annotations.length, annotations.length);
      this.annotations = newAi;
    }
  }
  
  public void addAnnotation (AnnotationInfo newAnnotation){
    AnnotationInfo[] ai = annotations;
    if (ai == null){
      ai = new AnnotationInfo[1];
      ai[0] = newAnnotation;

    } else {
      int len = annotations.length;
      ai = new AnnotationInfo[len+1];
      System.arraycopy(annotations, 0, ai, 0, len);
      ai[len] = newAnnotation;
    }

    annotations = ai;
  }

  // to be overridden by ClassInfo because of superclass inhertited annotations
  public boolean hasAnnotations(){
    return (annotations != NO_ANNOTATIONS);
  }
  
  // to be overridden by ClassInfo because of superclass inhertited annotations
  public AnnotationInfo[] getAnnotations() {
    return annotations;
  }
      
  // to be overridden by ClassInfo because of superclass inhertited annotations
  public AnnotationInfo getAnnotation (String name){    
    AnnotationInfo[] ai = annotations;
    if (ai != NO_ANNOTATIONS){
      for (int i=0; i<ai.length; i++){
        if (ai[i].getName().equals(name)){
          return ai[i];
        }
      }
    }
    return null;
  }
  
  public boolean hasAnnotation (String name){
    return getAnnotation(name) != null;    
  }
  
  public AnnotationInfo[] getDeclaredAnnotations(){
    return annotations;
  }

  //--- type annotations
  
  public void setTypeAnnotations (AbstractTypeAnnotationInfo[] typeAnnotations){
    this.typeAnnotations = typeAnnotations;
  }

  public void addTypeAnnotations (AbstractTypeAnnotationInfo[] tas){
    if (typeAnnotations == NO_TYPE_ANNOTATIONS){
      typeAnnotations = tas;
      
    } else {
      int oldLen = typeAnnotations.length;
      AbstractTypeAnnotationInfo[] newTA = new AbstractTypeAnnotationInfo[oldLen + tas.length];
      System.arraycopy(typeAnnotations, 0, newTA, 0, oldLen);
      System.arraycopy(tas, 0, newTA, oldLen, tas.length);
      typeAnnotations = newTA;
    }
  }
  
  public void addTypeAnnotation (AbstractTypeAnnotationInfo newAnnotation){
    AbstractTypeAnnotationInfo[] ai = typeAnnotations;
    if (ai == null){
      ai = new AbstractTypeAnnotationInfo[1];
      ai[0] = newAnnotation;

    } else {
      int len = annotations.length;
      ai = new AbstractTypeAnnotationInfo[len+1];
      System.arraycopy(annotations, 0, ai, 0, len);
      ai[len] = newAnnotation;
    }

    typeAnnotations = ai;
  }

  
  public AbstractTypeAnnotationInfo[] getTypeAnnotations() {
    return typeAnnotations;
  }
  
  public boolean hasTypeAnnotations(){
    return (typeAnnotations != NO_TYPE_ANNOTATIONS);    
  }
  
  public boolean hasTypeAnnotation (String name){
    return getTypeAnnotation(name) != null;    
  }
  
  public AbstractTypeAnnotationInfo getTypeAnnotation (String annoClsName){    
    AbstractTypeAnnotationInfo[] ai = typeAnnotations;
    if (ai != NO_TYPE_ANNOTATIONS){
      for (int i=0; i<ai.length; i++){
        if (ai[i].getName().equals(annoClsName)){
          return ai[i];
        }
      }
    }
    return null;
  }

  public <T extends AbstractTypeAnnotationInfo> List<T> getTargetTypeAnnotations (Class<T> targetType){
    List<T> list = null;
    
    AbstractTypeAnnotationInfo[] ais = typeAnnotations;
    if (ais != NO_TYPE_ANNOTATIONS){
      for (AbstractTypeAnnotationInfo ai : ais){
        if (targetType.isAssignableFrom(ai.getClass())){
          if (list == null){
            list = new ArrayList<>();
          }
          list.add((T)ai);
        }
      }
    }
    
    if (list != null){
      return list;
    } else {
      return Collections.emptyList();
    }
  }
  
  //--- the generic attribute API

  public boolean hasAttr () {
    return (attr != null);
  }

  public boolean hasAttr (Class<?> attrType){
    return ObjectList.containsType(attr, attrType);
  }

  public boolean hasAttrValue (Object a){
    return ObjectList.contains(attr, a);
  }
  
  /**
   * 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 getAttr(){
    return attr;
  }

  /**
   * 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 setAttr (Object a){
    attr = a;    
  }

  public void addAttr (Object a){
    attr = ObjectList.add(attr, a);
  }

  public void removeAttr (Object a){
    attr = ObjectList.remove(attr, a);
  }

  public void replaceAttr (Object oldAttr, Object newAttr){
    attr = ObjectList.replace(attr, 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 getAttr (Class<T> attrType) {
    return ObjectList.getFirst(attr, attrType);
  }

  public <T> T getNextAttr (Class<T> attrType, Object prev) {
    return ObjectList.getNext(attr, attrType, prev);
  }

  public ObjectList.Iterator attrIterator(){
    return ObjectList.iterator(attr);
  }
  
  public <T> ObjectList.TypedIterator<T> attrIterator(Class<T> attrType){
    return ObjectList.typedIterator(attr, attrType);
  }
}