package nhandler.conversion.jpf2jvm;
import java.lang.reflect.Array;
import cmu.conditional.Conditional;
import de.fosd.typechef.featureexpr.FeatureExpr;
import gov.nasa.jpf.vm.ClassInfo;
import gov.nasa.jpf.vm.DynamicElementInfo;
import gov.nasa.jpf.vm.FieldInfo;
import gov.nasa.jpf.vm.MJIEnv;
import gov.nasa.jpf.vm.ReferenceArrayFields;
import gov.nasa.jpf.vm.StaticElementInfo;
import nhandler.conversion.ConversionException;
import nhandler.conversion.ConverterBase;
/**
* This class is used to converter objects and classes from JPF to JVM
*
* @author Nastaran Shafiei
* @author chupanw
*/
public abstract class JPF2JVMConverter extends ConverterBase {
public static Class<?> obtainJVMCls(int JPFRef, MJIEnv env, FeatureExpr ctx) throws ConversionException {
if (JPFRef == MJIEnv.NULL) {
return null;
}
ClassInfo ci = env.getReferredClassInfo(ctx, JPFRef);
JPF2JVMConverter converter = ConverterBase.converterFactory.getJPF2JVMConverter(ci.getName());
return converter.getJVMCls(JPFRef, env, ctx);
}
public static Object obtainJVMObj(int JPFRef, MJIEnv env, FeatureExpr ctx) throws ConversionException {
if (JPFRef == MJIEnv.NULL) {
return null;
}
if (ConverterBase.objMapJPF2JVM.containsKey(JPFRef)) {
Object object = ConverterBase.objMapJPF2JVM.get(JPFRef);
return object;
}
DynamicElementInfo dei = (DynamicElementInfo) env.getHeap().get(JPFRef);
ClassInfo ci = dei.getClassInfo();
JPF2JVMConverter converter = ConverterBase.converterFactory.getJPF2JVMConverter(ci.getName());
return converter.getJVMObj(JPFRef, env, ctx);
}
protected Class<?> loadClass(String cname, MJIEnv env, FeatureExpr ctx) throws ClassNotFoundException {
if (Utilities.isArray(cname)) {
return Class.forName(cname);
} else {
ClassLoader cl = env.getConfig().getClassLoader();
return cl.loadClass(cname);
}
}
/**
* Returns a new JVM Class object corresponding to the given JPF class. If
* such a Class object already exists, it is returned. Otherwise a new one is
* created.
*/
protected Class<?> getJVMCls(int JPFRef, MJIEnv env, FeatureExpr ctx) throws ConversionException {
Class<?> JVMCls = null;
if (JPFRef != MJIEnv.NULL) {
// First check if the class object has been already created.
JVMCls = ConverterBase.classMapJPF2JVM.get(JPFRef);
/**
* If the Class object has not been created & the given JPF class is not
* NULL, the corresponding JVM class object is created from JPFRef
*/
if (JVMCls == null) {
ClassInfo ci = env.getReferredClassInfo(ctx, JPFRef);
// Used to store static fields
StaticElementInfo sei = ci.getStaticElementInfo();
try {
JVMCls = loadClass(sei.getClassInfo().getName(), env, ctx);
ConverterBase.classMapJPF2JVM.put(JPFRef, JVMCls);
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError(sei.getClassInfo().getName());
}
assert (JVMCls.getName() != ci.getName());
setStaticFields(JVMCls, sei, env, ctx);
}
}
return JVMCls;
}
protected abstract void setStaticFields(Class<?> JVMCls, StaticElementInfo sei, MJIEnv env, FeatureExpr ctx) throws ConversionException;
/**
* Returns a JVM object corresponding to the given JPF object. If such an
* object already exists, it is returned. Otherwise a new one is created.
*/
protected Object getJVMObj(int JPFRef, MJIEnv env, FeatureExpr ctx) throws ConversionException {
if (env.isArray(JPFRef)) {
return this.getJVMArrObj(JPFRef, env, ctx);
} else {
return this.getJVMNonArrObj(JPFRef, env, ctx);
}
}
/**
* Returns a non-array JVM object corresponding to the given non-array JPF
* object. If such an object already exists, it is returned. Otherwise a new
* one is created.
*/
protected Object getJVMNonArrObj(int JPFRef, MJIEnv env, FeatureExpr ctx) throws ConversionException {
Object JVMObj = null;
if (JPFRef != MJIEnv.NULL) {
// First check if the object has been already created
JVMObj = ConverterBase.objMapJPF2JVM.get(JPFRef);
/**
* If the object has not been created & the given JPF object is not NULL,
* the corresponding JVM object is created from JPFRef
*/
if (JVMObj == null) {
// Used to store instance fields
DynamicElementInfo dei = (DynamicElementInfo) env.getHeap().get(JPFRef);
ClassInfo JPFCl = dei.getClassInfo();
if (!JPFCl.isRegistered()) {
JPFCl.registerClass(ctx, env.getThreadInfo());
}
// we treat Strings differently
if (JPFCl.isStringClassInfo()) {
JVMObj = createStringObject(JPFRef, env, ctx);
ConverterBase.objMapJPF2JVM.put(JPFRef, JVMObj);
} else {
int JPFClsRef = JPFCl.getStaticElementInfo().getClassObjectRef();
Class<?> JVMCl = this.getJVMCls(JPFClsRef, env, ctx);
// There is only one instance of every class. There is no need to update
// Class objects
if (JVMCl == Class.class) {
try {
String name = env.getReferredClassInfo(ctx, JPFRef).getName();
if (Utilities.isPrimitiveClass(name)) {
JVMObj = Utilities.getPrimitiveClass(name);
} else {
JVMObj = loadClass(name, env, ctx);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("JPF2JVMConverter.getJVMNonArrObj()");
}
return JVMObj;
} else {
// Creates a new instance of JVMCl
if (ConverterBase.objMapJPF2JVM.containsKey(JPFRef)) {
JVMObj = ConverterBase.objMapJPF2JVM.get(JPFRef);
System.out.println("JVM object " + JVMObj + " already exists!");
} else {
JVMObj = instantiateFrom(JVMCl);
ConverterBase.objMapJPF2JVM.put(JPFRef, JVMObj);
}
}
setInstanceFields(JVMObj, dei, env, ctx);
}
} else {
// Need to update the JVM object fields
DynamicElementInfo dei = (DynamicElementInfo) env.getHeap().get(JPFRef);
updateInstanceFields(JVMObj, dei, env, ctx);
}
}
return JVMObj;
}
public abstract void setInstanceFields(Object JVMObj, DynamicElementInfo dei, MJIEnv env, FeatureExpr ctx) throws ConversionException;
public abstract void updateInstanceFields(Object JVMObj, DynamicElementInfo dei, MJIEnv env, FeatureExpr ctx) throws ConversionException;
/**
* Returns a JVM array corresponding to the given JPF array. If such an array
* already exists, it is returned. Otherwise a new one is created.
*
* @param JPFRef an integer representing a JPF array
* @return a JVM array corresponding to the given JPF array, JPFRef
* @throws ConversionException if any incorrect input parameter is observed
*/
protected Object getJVMArrObj(int JPFRef, MJIEnv env, FeatureExpr ctx) throws ConversionException {
Object JVMArr = null;
if (JPFRef != MJIEnv.NULL) {
// First check if the array has been already created
JVMArr = ConverterBase.objMapJPF2JVM.get(JPFRef);
/**
* If the array has not been created & the given JPF array is not NULL,
* the corresponding JVM array is created from JPFRef
*/
if (JVMArr == null) {
// Used to store array elements
DynamicElementInfo dei = (DynamicElementInfo) env.getHeap().get(JPFRef);
// Array of primitive type
if (dei.getClassInfo().getComponentClassInfo().isPrimitive()) {
JVMArr = Utilities.createJVMPrimitiveArr(dei, ctx);
}
// Array of Non-primitives
else {
// int[] JPFArr = ((ReferenceArrayFields) dei.getFields()).asReferenceArray();
Conditional<Integer>[] JPFArrConditional = ((ReferenceArrayFields) dei.getFields()).asReferenceArray();
int[] JPFArr = new int[JPFArrConditional.length];
for (int i = 0; i < JPFArrConditional.length; i++) {
JPFArr[i] = JPFArrConditional[i].simplify(ctx).getValue();
}
int arrSize = JPFArr.length;
Class<?> compType = null;
try {
compType = loadClass(dei.getClassInfo().getComponentClassInfo().getName(), env, ctx);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Object[] arrObj = (Object[]) Array.newInstance(compType, arrSize);
for (int i = 0; i < arrSize; i++) {
arrObj[i] = obtainJVMObj(JPFArr[i], env, ctx);
}
JVMArr = arrObj;
}
ConverterBase.objMapJPF2JVM.put(JPFRef, JVMArr);
}
}
return JVMArr;
}
protected abstract Object instantiateFrom(Class<?> cl);
protected Object createStringObject(int JPFRef, MJIEnv env, FeatureExpr ctx) throws ConversionException {
DynamicElementInfo str = (DynamicElementInfo) env.getHeap().get(JPFRef);
if (!str.getClassInfo().isStringClassInfo()) {
throw new ConversionException();
}
FieldInfo fi = str.getFieldInfo("value");
int fieldValueRef = str.getFields().getReferenceValue(fi.getStorageOffset()).simplify(ctx).getValue();
// this is String.value which is of type of char[]
Object value = this.getJVMObj(fieldValueRef, env, ctx);
// In case that value is of the type One
Object JVMObj;
if (value instanceof Conditional) {
JVMObj = new String((char[]) ((Conditional<?>) value).simplify(ctx).getValue());
} else {
// TODO
// System.out.println("Warning from JPF2JVMConverter.java L244, JVMObj is not One:");
// System.out.println('\t' + Arrays.toString((char[]) value).replaceAll(",\\s", ""));
JVMObj = new String((char[]) value);
}
ConverterBase.objMapJPF2JVM.put(JPFRef, JVMObj);
return JVMObj;
}
}