package nhandler.conversion;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import cmu.utils.RuntimeConstants;
import gov.nasa.jpf.JPF;
import gov.nasa.jpf.Resetable;
import gov.nasa.jpf.vm.MJIEnv;
import nhandler.util.ValueIdentityHashMap;
/**
* This is just a common root of all Converters and keeps key elements used by
* Converter classes
*
* @author Nastaran Shafiei
*/
public class ConverterBase {
public static ArrayList<Object> socketObjArray = new ArrayList<>();
public static ConverterFactory converterFactory;
/**
* Keeps track of the JVM objects that have been already created from their
* corresponding JPF objects, while performing conversion from JPF to JVM
*/
@SuppressWarnings("serial")
public static Map<Integer, Object> objMapJPF2JVM = new HashMap<Integer, Object>() {
@Override
public Object put(Integer key, Object value) {
if (containsKey(key)) {
Object currentObject = get(key);
if (currentObject == value) {
return null;
}
System.out.println("--- object for id " + key + " already created, but newly created " + value);
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
System.out.println(element);
}
System.out.println("-----------------------------------");
}
return super.put(key, value);
};
@SuppressWarnings("unused")
@Override
public Object remove(Object key) {
Object object = super.remove(key);
if (RuntimeConstants.debugGC && object != null) {
System.out.println("GC JVM Heap(" + objMapJPF2JVM.size() + ") " + printSize(object) + object.getClass().getName() + " @ " + key);
}
return object;
}
private String printSize(final Object object) {
int size = 0;
if (object.getClass().isArray()) {
final String componentType = object.getClass().getComponentType().getSimpleName();
switch (componentType) {
case "char":
size = Character.SIZE * ((char[]) object).length;
break;
case "byte":
size = Byte.SIZE * ((byte[]) object).length;
break;
default:
System.out.println("to string for " + componentType + " not supported");
break;
}
} else if (object instanceof String) {
size = (Character.SIZE * ((String)object).toCharArray().length) >> 3;
}
if (size == 0) {
return "";
}
size = (size >> 3);
if (size >= 1024) {
size = size >> 10;
if (size >= 1024) {
size = size >> 10;
return size + " MB ";
}
return size + " KB ";
}
return size + " Byte ";
};
};
/**
* Keeps track of the JVM classes that have been already created from their
* corresponding JPF classes, while performing conversion from JPF to JVM
*/
public static ValueIdentityHashMap<Integer, Class<?>> classMapJPF2JVM = new ValueIdentityHashMap<Integer, Class<?>>();
/**
* Keeps track of the JPF objects that have been already updated from their
* corresponding JVM objects, while performing conversion from JVM to JPF
*/
public static HashMap<Integer, Object> updatedJPFObj = new ValueIdentityHashMap<Integer, Object>();
/**
* Keeps track of the JPF classes that have been already updated from their
* corresponding JVM classes, while performing conversion from JVM to JPF
*/
public static Set<Integer> updatedJPFCls = new HashSet<Integer>();
static boolean resetState;
static {
JPF.resetable.add(new Resetable() {
@Override
public void reset() {
updatedJPFObj.clear();
classMapJPF2JVM.clear();
objMapJPF2JVM.clear();
updatedJPFCls.clear();
resetState = false;
}
});
JPF.JVMheap = objMapJPF2JVM;
}
public static void init() {
converterFactory = new DefaultConverterFactory();
}
public static boolean isResetState() {
return resetState;
}
/**
* This needs to be invoked at the beginning of every method created
* on-the-fly
*/
public static void reset(MJIEnv env) {
ConverterBase.resetState = env.getConfig().getBoolean("nhandler.resetVMState");
if (ConverterBase.resetState) {
// these are reset on-demond by setting the nhandler.resetVMState
// property in the properties file
ConverterBase.objMapJPF2JVM.clear();
ConverterBase.classMapJPF2JVM.clear();
// clearObj(ConverterBase.objMapJPF2JVM);
// clearCls(ConverterBase.classMapJPF2JVM);
// checkSocket();
}
// these always need to be reset
ConverterBase.updatedJPFObj.clear();
ConverterBase.updatedJPFCls.clear();
}
public static void clearObj(ValueIdentityHashMap<Integer, Object> map) {
boolean changed = true;
while (changed) {
changed = false;
for (Map.Entry<Integer, Object> entry : map.entrySet()) {
Object obj = entry.getValue();
if (obj.getClass().getName().equals("java.net.Socket")
|| obj.getClass().getName().equals("java.net.SocksSocketImpl")
|| obj.getClass().getName().equals("java.net.SocketInputStream")
|| obj.getClass().getName().equals("java.net.SocketOutputStream")
|| obj.getClass().getName().startsWith("java.util.zip.ZipFile")
|| obj.getClass().getName().equals("java.util.jar.JarFile")
|| obj.getClass().getName().equals("sun.net.www.protocol.jar.URLJarFile")
|| obj.getClass().getName().equals("sun.net.www.protocol.jar.JarURLConnection")
|| obj.getClass().getName().equals("java.util.ResourceBundle")
|| obj.getClass().getName().equals("java.util.zip.CRC32")
|| obj.getClass().getName().equals("sun.nio.ch.IOUtil")
|| obj.getClass().getName().equals("sun.nio.ch.KQueueArrayWrapper")
|| obj.getClass().getName().equals("java.util.zip.Deflater")
) {
continue;
} else {
changed = true;
map.remove(entry.getKey());
break;
}
}
}
}
public static void clearCls(ValueIdentityHashMap<Integer, Class<?>> map) {
boolean changed = true;
while (changed) {
changed = false;
for (Map.Entry<Integer, Class<?>> entry : map.entrySet()) {
Class<?> cls = entry.getValue();
if (cls.getName().equals("java.net.Socket")
|| cls.getName().equals("java.net.SocksSocketImpl") // this one is not in the jpf.properties file, but we need this
|| cls.getName().equals("java.net.SocketInputStream")
|| cls.getName().equals("java.net.SocketOutputStream")
|| cls.getName().startsWith("java.util.zip.ZipFile")
|| cls.getName().equals("java.util.jar.JarFile")
|| cls.getName().equals("sun.net.www.protocol.jar.URLJarFile")
|| cls.getName().equals("sun.net.www.protocol.jar.JarURLConnection")
|| cls.getName().equals("java.util.ResourceBundle")
|| cls.getName().equals("java.util.zip.CRC32")
|| cls.getName().equals("sun.nio.ch.IOUtil")
|| cls.getName().equals("sun.nio.ch.KQueueArrayWrapper")
|| cls.getName().equals("java.util.zip.Deflater")
) {
continue;
} else {
changed = true;
map.remove(entry.getKey());
break;
}
}
}
}
public static void checkSocket() {
if (socketObjArray.size() >= 4) {
System.out.println("clearing!!!");
socketObjArray.clear();
objMapJPF2JVM.clear();
}
}
}