Package nhandler.conversion.jvm2jpf

Source Code of nhandler.conversion.jvm2jpf.JVM2JPFConverter

package nhandler.conversion.jvm2jpf;

import gov.nasa.jpf.vm.ArrayFields;
import gov.nasa.jpf.vm.ClassInfo;
import gov.nasa.jpf.vm.ClassInfoException;
import gov.nasa.jpf.vm.ClassLoaderInfo;
import gov.nasa.jpf.vm.DynamicElementInfo;
import gov.nasa.jpf.vm.ElementInfo;
import gov.nasa.jpf.vm.MJIEnv;
import gov.nasa.jpf.vm.StaticElementInfo;

import java.util.Iterator;

import nhandler.conversion.ConversionException;
import nhandler.conversion.ConverterBase;

/**
* This class is used to converter objects and classes from JVM to JPF
*
* @author Nastaran Shafiei
*/

public abstract class JVM2JPFConverter extends ConverterBase {

  public static ClassInfo obtainJPFCls (Class<?> JVMCls, MJIEnv env) throws ConversionException{
    if(JVMCls == null) {
      return null;
    }

    JVM2JPFConverter converter = ConverterBase.converterFactory.getJVM2JPFConverter(JVMCls.getName());
    return converter.getJPFCls(JVMCls, env);
  }

  public static int obtainJPFObj (Object JVMObj, MJIEnv env) throws ConversionException {
    if (JVMObj == null){
      return MJIEnv.NULL;
    }

    JVM2JPFConverter converter = ConverterBase.converterFactory.getJVM2JPFConverter(JVMObj.getClass().getName());
    return converter.getJPFObj(JVMObj, env);
  }

  public static void updateJPFObj (Object JVMObj, int JPFObj, MJIEnv env) throws ConversionException {
    if (JVMObj == null){
      return;
    }

    JVM2JPFConverter converter = ConverterBase.converterFactory.getJVM2JPFConverter(JVMObj.getClass().getName());
    converter.getUpdatedJPFObj(JVMObj, JPFObj, env);
  }

  /**
   * Returns a JPF class corresponding to the given JVM Class object. If such an
   * class exists, it is updated (if it has not been updated) corresponding to
   * the given JVMObj. Otherwise a new JPF class corresponding to the given JVM
   * class object is created and added to the list of the JPF loaded classes.
   *
   * @param JVMCls
   *          a JVM Class object
   *
   * @return a JPF class corresponding to the given JVM class, JVMCls
   *
   * @throws ConversionException
   *           if any incorrect input parameter is observed
   */
  protected ClassInfo getJPFCls (Class<?> JVMCls, MJIEnv env) throws ConversionException{
    ClassInfo JPFCls = null;
    int JPFClsRef = Integer.MIN_VALUE;

    if (JVMCls != null){
      // retrieving the integer representing the Class in JPF
      JPFCls = ClassLoaderInfo.getCurrentResolvedClassInfo(JVMCls.getName());

      // First check if the class has been already updated
      if (!ConverterBase.updatedJPFCls.contains(JPFClsRef)){
        StaticElementInfo sei = null;
       
        /**
         * If the corresponding ClassInfo does not exist, a new ClassInfo object
         * is created and will be added to the loadedClasses.
         */
        if (!JPFCls.isRegistered()){
          JPFCls.registerClass(env.getThreadInfo());
          sei = JPFCls.getStaticElementInfo();
          JPFClsRef = sei.getObjectRef();
        } else {
          sei = JPFCls.getModifiableStaticElementInfo();
        }

        // This is to avoid JPF to initialized the class
        JPFCls.setInitialized();

        ConverterBase.updatedJPFCls.add(JPFClsRef);

        setStaticFields(JVMCls, sei, env);
      }
    }
    return JPFCls;
  }

  /**
   * Sets the static fields of a JPF class corresponding to the given JVM class
   * @param JVMCls a class object in JVM
   * @param sei captures the value of static fields
   * @throws ConversionException
   */
  protected abstract void setStaticFields(Class<?> JVMCls, StaticElementInfo sei, MJIEnv env) throws ConversionException;

  /**
   * Returns a JPF object corresponding to the given JVM object. If such an
   * object exists, it is updated (if it has not been updated) corresponding to
   * the given JVMObj. Otherwise a new JPF object corresponding to the given JVM
   * object is created.
   *
   * @param JVMObj
   *          a JVM object
   *
   * @return a JPF object corresponding to the given JVM object, JVMObj
   *
   * @throws ConversionException
   *           if any incorrect input parameter is observed
   */
  protected int getJPFObj (Object JVMObj, MJIEnv env) throws ConversionException {
    int JPFRef = MJIEnv.NULL;
    if (JVMObj != null){
      if (JVMObj.getClass() == Class.class){
        JPFRef = (this.getJPFCls((Class<?>) JVMObj, env)).getClassObjectRef();
      } else{
        JPFRef = this.getExistingJPFRef(JVMObj, true, env);
        if (JPFRef == MJIEnv.NULL){
          JPFRef = this.getNewJPFRef(JVMObj, env);
        }
      }
    }
    return JPFRef;
  }

  /**
   * Updates the given JPF object, according to the given JVM object. For the
   * case of the non-array object, its JPF class is also updated according to
   * the class of the given JVM object.
   *
   * @param JVMObj
   *          a JVM object
   * @param JPFObj
   *          a JPF object
   *
   * @throws ConversionException
   *           if any incorrect input parameter is observed
   */
  protected void getUpdatedJPFObj (Object JVMObj, int JPFObj, MJIEnv env) throws ConversionException{
    //if (this.isValidJPFRef(JVMObj, JPFObj)){
      // Both JVM and JPF objects are null, No need for updating
      if (JVMObj == null){
        return;
      }

      if (JVMObj.getClass().isArray()){
        this.updateJPFArrObj(JVMObj, JPFObj, env);
      } else{
        this.updateJPFNonArrObj(JVMObj, JPFObj, env);
      }
   // } else{
   //   throw new ConversionException("The given JPFObj is not valid!");
   // }
  }

  /**
   * Checks if the given JPF reference is valid, meaning that either the JPF
   * reference represents the same object as the given JVM object. This method
   * should be always invoked before updating the given JPF object corresponding
   * to the given JVM object.
   *
   * @param JVMObj
   *          a JVM object
   * @param JPFObj
   *          a JPF object
   * @return true if the given JPFObj represents the same object as JPFObj, OW
   *         false is returned.
   *
   * @throws ConversionException
   *           if any incorrect input parameter is observed
   */
  // todo - investigate this using Socket.jpf example
  protected boolean isValidJPFRef (Object JVMObj, int JPFObj, MJIEnv env) throws ConversionException{
    boolean isValid;

    if(!ConverterBase.isResetState()) {
      return true;
    }

    if (JPFObj == MJIEnv.NULL || JVMObj == null){
      isValid = (JPFObj == MJIEnv.NULL && JVMObj == null);
    } else if (JVMObj.getClass() == Class.class){
      isValid = true;
    } else{
      int existingJPFObj = this.getExistingJPFRef(JVMObj, false, env);
      isValid = (existingJPFObj == JPFObj);// || existingJPFObj == MJIEnv.NULL);
    }
    return isValid;
  }

  /**
   * Updates the given non-array JPF object according to the given non-array JVM
   * object. The class of the object is also updated according to the class of
   * the given JVM object.
   *
   * @param JVMObj
   *          a non-array JVM object
   * @param JPFObj
   *          a non-array JPF object
   *
   * @throws ConversionException
   *           if any incorrect input parameter is observed
   */
  protected void updateJPFNonArrObj (Object JVMObj, int JPFObj, MJIEnv env) throws ConversionException{
    if (JVMObj != null){
      // First check if the JPF object has been already updated
      if (!ConverterBase.updatedJPFObj.containsKey(JPFObj)){
        ConverterBase.updatedJPFObj.put(JPFObj, JVMObj);
        ConverterBase.objMapJPF2JVM.put(JPFObj, JVMObj);

        // Why do we need that? Because JPF might have not leaded the class
        // before! JPF classloader does not recognize them!
        // I don't now why exactly!
        // INVESTIGATE: Why not arrays?
        if (JVMObj.getClass() == Class.class){
          try{
            Class<?> temp = (Class<?>) JVMObj;
            if (!temp.isArray() && !temp.isPrimitive())
              env.getConfig().getClassLoader().loadClass(temp.getName());
          } catch (ClassNotFoundException e1){
            e1.printStackTrace();
          }
        }
       
        DynamicElementInfo dei = (DynamicElementInfo) env.getHeap().getModifiable(JPFObj);

        setInstanceFields(JVMObj, dei, env);
      }
    }
  }

  protected abstract void setInstanceFields(Object JVMObj, DynamicElementInfo dei, MJIEnv env) throws ConversionException;

  /**
   * Updates the given JPF array according to the given JVM array.
   *
   * @param JVMArr
   *          a JVM array
   * @param JPFArr
   *          a JPF array
   *
   * @throws ConversionException
   *           if any incorrect input parameter is observed
   */
  protected void updateJPFArrObj (Object JVMArr, int JPFArr, MJIEnv env) throws ConversionException{
    if (JVMArr != null){
      // First check if the JPF array has been already updated
      if (!ConverterBase.updatedJPFObj.containsKey(JPFArr)){
        ConverterBase.updatedJPFObj.put(JPFArr, JVMArr);
        ConverterBase.objMapJPF2JVM.put(JPFArr, JVMArr);

        DynamicElementInfo dei = (DynamicElementInfo) env.getHeap().getModifiable(JPFArr);

        ArrayFields fields = (ArrayFields) dei.getFields();

        // Array of primitive type
        if (dei.getClassInfo().getComponentClassInfo().isPrimitive()){
          Utilities.setJPFPrimitiveArr(dei, JVMArr, env);
        }
        // Array of Non-primitives
        else{
          int arrSize = fields.arrayLength();
          Object[] arrObj = (Object[]) JVMArr;

          for (int i = 0; i < arrSize; i++){
            int elementValueRef = dei.getReferenceElement(i);

            if (arrObj[i] == null){
              elementValueRef = MJIEnv.NULL;
            } else if (elementValueRef == MJIEnv.NULL || ConverterBase.objMapJPF2JVM.get(elementValueRef) != arrObj[i]){
              elementValueRef = obtainJPFObj(arrObj[i], env);
            } else if (ConverterBase.objMapJPF2JVM.get(elementValueRef) == arrObj[i]){
              updateJPFObj(arrObj[i], elementValueRef, env);
            } else{
              throw new ConversionException("Unconsidered case observed! - JVM2JPF.updateArr()");
            }
            dei.setReferenceElement(i, elementValueRef);
          }
        }
      }
    }
  }

  /**
   * Looks info the existing hash tables, declared in Converter, to see if the
   * JPF object corresponding to the given JVM object has been already created.
   *
   * @param JVMObj
   *          a JVM object
   *
   * @return a non-null JPF object if there already exists a JPF object
   *         corresponding to the given JVM object. OW null JPF object is
   *         returned.
   *
   * @throws ConversionException
   *           if any incorrect input parameter is observed
   */
  protected int getExistingJPFRef (Object JVMObj, boolean update, MJIEnv env) throws ConversionException{
    int JPFRef = MJIEnv.NULL;
    boolean found = false;
    if (ConverterBase.updatedJPFObj.containsValue(JVMObj)){
      Iterator<Integer> iterator = (ConverterBase.updatedJPFObj.keySet()).iterator();
      Integer key;
      while (!found && iterator.hasNext()){
        key = iterator.next();
        Object value = ConverterBase.updatedJPFObj.get(key);
        if (value == JVMObj){
          found = true;
          JPFRef = key;
        }
      }
    }

    if (!found && ConverterBase.objMapJPF2JVM.containsValue(JVMObj)){
      Iterator<Integer> iterator = (ConverterBase.objMapJPF2JVM.keySet()).iterator();
      Integer key;
      while (!found && iterator.hasNext()){
        key = iterator.next();
        Object value = ConverterBase.objMapJPF2JVM.get(key);
        if (value == JVMObj){
          found = true;
          JPFRef = key;
          if (update == true){
            getUpdatedJPFObj(JVMObj, JPFRef, env);
          }
        }
      }
    }
    return JPFRef;
  }

  /**
   * Creates a new JPF object corresponding to the given JVM object. It also
   * updates the class of the JPF object according to the class of the given JVM
   * object.
   *
   * @param JVMObj
   *          a JVM object
   * @return a new JPF object corresponding to the given JVM object.
   *
   * @throws ConversionException
   *           if any incorrect input parameter is observed
   *
   */
  protected int getNewJPFRef (Object JVMObj, MJIEnv env) throws ConversionException{
    int JPFRef = MJIEnv.NULL;
    Class<?> JVMCls = JVMObj.getClass();
    if (!JVMCls.isArray()){
      // we treat Strings differently, until we immigrate to JDK7
      if(JVMObj.getClass()==String.class) {
        JPFRef = env.newString(JVMObj.toString());
      } else {
        ClassInfo fci = null;
        try{
          fci = this.getJPFCls(JVMCls, env);
        } catch (ClassInfoException e){
          System.out.println("WARNING: the class " + JVMCls + " is ignored!");
          return MJIEnv.NULL;
        }

        ElementInfo ei = env.getHeap().newObject(fci, env.getThreadInfo());
        JPFRef = ei.getObjectRef();
       
        this.updateJPFNonArrObj(JVMObj, JPFRef, env);
      }
    } else{
      JPFRef = Utilities.createNewJPFArray(JVMObj, env);
      this.updateJPFArrObj(JVMObj, JPFRef, env);
    }

    return JPFRef;
  }
}
TOP

Related Classes of nhandler.conversion.jvm2jpf.JVM2JPFConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.