package nhandler.conversion.jpf2jvm; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import cmu.conditional.Conditional; import cmu.conditional.One; import cmu.utils.RuntimeConstants; 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.StaticElementInfo; import nhandler.conversion.ConversionException; import nhandler.conversion.ConverterBase; /** * This class is used to convert objects and classes from JPF to JVM. This is only * applicable on types which are compatible between JPF and JVM, meaning that the same * classes are used to represent them in both environments. * * @author Nastaran Shafiei */ public class JPF2JVMGenericConverter extends JPF2JVMConverter { @Override protected void setStaticFields(Class<?> JVMCls, StaticElementInfo sei, MJIEnv env, FeatureExpr ctx) throws ConversionException { ClassInfo ci = sei.getClassInfo(); while (JVMCls != null) { Field fld[] = JVMCls.getDeclaredFields(); for (int i = 0; i < fld.length; i++) { boolean isStatic = ((Modifier.toString(fld[i].getModifiers())).indexOf("static") != -1); boolean isFinal = ((Modifier.toString(fld[i].getModifiers())).indexOf("final") != -1); // Provide access to private and final fields fld[i].setAccessible(true); FieldInfo fi = sei.getFieldInfo(fld[i].getName()); // For class only set the values of static fields if (fi != null && isStatic) { /** * Why we check for !(isFinal)? * * We do not set the value for "static final" fields. But we take * care of "non-static final" fields. * * static final fields can be initialized at the declaration time, * OW it MUST be initialized inside the static block. By using * Class.forName() the class is initialized. Since when the class * is initialized the static blocks are executed, the static final * fields of object returned by Class.forName() have already have * the right values and we do not need to update their value. * * Non-static final fields can be initialized at the declaration * time. But if the non-static field is final blank, it MUST be * initialized in the constructor. By using Class.newInstance() * the class is instantiated as if by a new expression with an * empty argument list. If the object represented by JPFRef * created using different constructor, the value of final blank * fields might be different when using the constructor with an * empty argument list. Therefore the values of non-static final * fields have to be set. */ if (!isFinal) { // If the current field is of reference type if (fi.isReference()) { int fieldValueRef = sei.getFields().getReferenceValue(fi.getStorageOffset()).getValue(); Object JVMField = obtainJVMObj(fieldValueRef, env, ctx); // Temporary solution cpwTODO if (JVMField != null && JVMField.getClass() == cmu.conditional.One.class) { JVMField = ((cmu.conditional.One<?>) JVMField).getValue(); } try { fld[i].set(null, JVMField); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } // If the current field is of primitive type else { try { Utilities.setJVMPrimitiveField(fld[i], JVMCls, sei, fi, ctx); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } JVMCls = JVMCls.getSuperclass(); ci = ci.getSuperClass(); if (ci != null) { sei = ci.getStaticElementInfo(); } } } /** * Updates the values in the JVM object */ @Override public void setInstanceFields(Object JVMObj, DynamicElementInfo dei, MJIEnv env, FeatureExpr ctx) throws ConversionException { Class<?> cls = JVMObj.getClass(); ClassInfo JPFCl = dei.getClassInfo(); if (!cls.getName().equals(JPFCl.getName())) { System.out.println(cls.getName() + " != " + JPFCl.getName()); } while (cls != null) { if (JPFCl == null) { System.out.println("no classinfo for: " + dei.getObjectRef() + " " + cls); } Field fld[] = cls.getDeclaredFields(); for (int i = 0; i < fld.length; i++) { // It is true if the field is declared as static. boolean isNonStaticField = ((Modifier.toString(fld[i].getModifiers())).indexOf("static") == -1); // Provide access to private and final fields fld[i].setAccessible(true); if (JPFCl == null) { System.out.println(cls); } FieldInfo fi = JPFCl.getInstanceField(fld[i].getName()); if (fi != null && isNonStaticField) { // Field is of reference type if (fi.isReference()) { int fieldValueRef = dei.getFields().getReferenceValue(fi.getStorageOffset()).simplify(ctx).getValue(); Object JVMField = obtainJVMObj(fieldValueRef, env, ctx); if (JVMField instanceof Conditional) { JVMField = ((One<?>) JVMField).getValue(); } if (JVMField instanceof Conditional[]) { @SuppressWarnings("rawtypes") final Conditional[] conditionals = (Conditional[]) JVMField; long[] array = new long[conditionals.length]; for (int index = 0; index < conditionals.length; index++) { array[index] = (long)conditionals[index].getValue(); } JVMField = array; } try { if (fld[i].getType().equals(char[].class) && JVMField instanceof String) { fld[i].set(JVMObj, ((String)JVMField).toCharArray()); } else { fld[i].set(JVMObj, JVMField); } } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } // Field is of primitive type else { try { Utilities.setJVMPrimitiveField(fld[i], JVMObj, dei, fi, ctx); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } cls = cls.getSuperclass(); JPFCl = JPFCl.getSuperClass(); } } @Override public void updateInstanceFields(Object JVMObj, DynamicElementInfo dei, MJIEnv env, FeatureExpr ctx) throws ConversionException { Class<?> cls = JVMObj.getClass(); ClassInfo JPFCl = dei.getClassInfo(); while (cls != null) { Field fld[] = cls.getDeclaredFields(); for (int i = 0; i < fld.length; i++) { // It is true if the field is NOT declared as static. boolean isNonStaticField = ((Modifier.toString(fld[i].getModifiers())).indexOf("static") == -1); // Provide access to private and final fields fld[i].setAccessible(true); FieldInfo fi = JPFCl.getInstanceField(fld[i].getName()); if (fi != null && isNonStaticField) { // Field is of reference type if (fi.isReference()) { // Warning: getValue() here could be dangerous int fieldValueRef = dei.getFields().getReferenceValue(fi.getStorageOffset()).getValue(); // If the field object is already in sync, skip. // Otherwise, updateInstanceFields() gets called again and again if (ConverterBase.updatedJPFObj.containsKey(fieldValueRef)) { // TODO: Say that this field belongs to a class which contains a public field x // TODO: if x is changed somewhere in the code, current impl could not reflect // TODO: those changes to the corresponding JVMObject continue; } Object JVMField = obtainJVMObj(fieldValueRef, env, ctx); ConverterBase.updatedJPFObj.put(fieldValueRef, JVMField); try { fld[i].set(JVMObj, JVMField); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } // Field is of primitive type else { try { Utilities.setJVMPrimitiveField(fld[i], JVMObj, dei, fi, ctx); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } cls = cls.getSuperclass(); JPFCl = JPFCl.getSuperClass(); } } /** * Returns a new JVM object instantiated from the given class * * @param cl a JVM class * @return a new JVM object instantiated from the given class, cl */ @Override protected Object instantiateFrom(Class<?> cl) { if (Modifier.isAbstract(cl.getModifiers()) ) { System.out.println("cannot instanciate abstract class: " + cl); } Object JVMObj = null; if (cl == Class.class) { return cl; } if (RuntimeConstants.debug) { System.out.println("create JVM object " + cl); } if (cl.getName().equals(ClassLoader.class.getName())) { JVMObj = getClass().getClassLoader(); System.out.println(cl + " -> " + JVMObj); return JVMObj; } Constructor<?> constructor = getNoArgCtor(cl); try { constructor.setAccessible(true); JVMObj = constructor.newInstance(); } catch (Exception e) { System.out.println("Cannot instantiate from " + cl + " using no-arg constructor: " + constructor); e.printStackTrace(); } return JVMObj; } /** * Returns a constructor with no arguments. * * @param cl a JVM class * @return a constructor with no arguments */ protected Constructor<?> getNoArgCtor(Class<?> cl) { Constructor<?>[] ctors = cl.getDeclaredConstructors(); Constructor<?> ctor = null; // Check if the given class has a constructor with no arguments for (Constructor<?> c : ctors) { if (c.getParameterTypes().length == 0) { ctor = c; } } if (ctor == null) { try { ctor = sun.reflect.ReflectionFactory.getReflectionFactory().newConstructorForSerialization(cl, Object.class.getConstructor()); } catch (Exception e1) { System.out.println("Cannot create a default constructor to instantiate from"); e1.printStackTrace(); } } return ctor; } }