/*
* Copyright 2012 Phil Pratt-Szeliga and other contributors
* http://chirrup.org/
*
* See the file LICENSE for copying permission.
*/
package org.trifort.rootbeer.runtime;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
public abstract class Serializer {
public Memory mMem;
public Memory mTextureMem;
private static final Map<Object, Long> mWriteToGpuCache;
private static final Map<Long, Object> mReverseWriteToGpuCache;
private static final Map<Long, Object> mReadFromGpuCache;
private static Map<Long, Integer> m_classRefToTypeNumber;
static {
mWriteToGpuCache = new IdentityHashMap<Object, Long>();
mReverseWriteToGpuCache = new HashMap<Long, Object>();
mReadFromGpuCache = new HashMap<Long, Object>();
m_classRefToTypeNumber = new HashMap<Long, Integer>();
}
public Serializer(Memory mem, Memory texture_mem){
mMem = mem;
mTextureMem = texture_mem;
mReadFromGpuCache.clear();
mWriteToGpuCache.clear();
mReverseWriteToGpuCache.clear();
m_classRefToTypeNumber.clear();
}
public void writeStaticsToHeap(){
doWriteStaticsToHeap();
}
public long writeToHeap(Object o){
return writeToHeap(o, true);
}
private static class WriteCacheResult {
public long m_Ref;
public boolean m_NeedToWrite;
public WriteCacheResult(long ref, boolean need_to_write){
m_Ref = ref;
m_NeedToWrite = need_to_write;
}
}
public void addClassRef(long ref, int class_number){
m_classRefToTypeNumber.put(ref, class_number);
}
public int[] getClassRefArray(){
int max_type = 0;
for(int num : m_classRefToTypeNumber.values()){
if(num > max_type){
max_type = num;
}
}
int[] ret = new int[max_type+1];
for(long value : m_classRefToTypeNumber.keySet()){
int pos = m_classRefToTypeNumber.get(value);
ret[pos] = (int) (value >> 4);
}
return ret;
}
private static synchronized WriteCacheResult checkWriteCache(Object o, int size, boolean read_only, Memory mem){
//strings are cached in Java 1.6, we need to make strings individual units
//for rootbeer so concurrent modifications change different objects
if(o instanceof String){
long ref = mem.mallocWithSize(size);
return new WriteCacheResult(ref, true);
} else {
if(mWriteToGpuCache.containsKey(o)){
long ref = mWriteToGpuCache.get(o);
return new WriteCacheResult(ref, false);
}
long ref = mem.mallocWithSize(size);
mWriteToGpuCache.put(o, ref);
mReverseWriteToGpuCache.put(ref, o);
return new WriteCacheResult(ref, true);
}
}
public Object writeCacheFetch(long ref){
synchronized(mWriteToGpuCache){
if(mReverseWriteToGpuCache.containsKey(ref)){
return mReverseWriteToGpuCache.get(ref);
}
return null;
}
}
public long writeToHeap(Object o, boolean write_data){
if(o == null)
return -1;
int size = doGetSize(o);
boolean read_only = false;
WriteCacheResult result;
result = checkWriteCache(o, size, read_only, mMem);
if(result.m_NeedToWrite == false){
return result.m_Ref;
}
//if(o == null){
// System.out.println("writeToHeap: null at addr: "+result.m_Ref);
//} else {
// System.out.println("writeToHeap: "+o.toString()+" at addr: "+result.m_Ref);
//}
doWriteToHeap(o, write_data, result.m_Ref, read_only);
//BufferPrinter printer = new BufferPrinter();
//printer.print(mMem, result.m_Ref, 128);
return result.m_Ref;
}
protected Object checkCache(long address, Object item){
synchronized(mReadFromGpuCache){
if(mReadFromGpuCache.containsKey(address)){
return mReadFromGpuCache.get(address);
} else {
mReadFromGpuCache.put(address, item);
return item;
}
}
}
public Object readFromHeap(Object o, boolean read_data, long address){
synchronized(mReadFromGpuCache){
if(mReadFromGpuCache.containsKey(address)){
Object ret = mReadFromGpuCache.get(address);
return ret;
}
}
long null_ptr_check = address >> 4;
if(null_ptr_check == -1){
return null;
}
//if(o == null){
// System.out.println("readFromHeap: null. addr: "+address);
//} else {
// System.out.println("readFromHeap: "+o.toString()+". addr: "+address+" class: "+o.getClass());
//}
//BufferPrinter printer = new BufferPrinter();
//printer.print(mMem, address-128, 256);
Object ret = doReadFromHeap(o, read_data, address);
//if(ret == null){
// System.out.println("doReadFromHeap: null. addr: "+address);
//} else {
// if(ret instanceof char[]){
// char[] char_array = (char[]) ret;
// String str = new String(char_array);
// System.out.println("doReadFromHeap char[]: "+str+".["+char_array.length+"] addr: "+address);
// } else {
// System.out.println("doReadFromHeap: "+ret.toString()+". addr: "+address);
// }
//}
return ret;
}
public void readStaticsFromHeap(){
doReadStaticsFromHeap();
}
public Object readField(Object base, String name){
Class cls = base.getClass();
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
Object ret = f.get(base);
return ret;
} catch(Exception ex){
cls = cls.getSuperclass();
//java.lang.Throwable.backtrace cannot be found this way, I don't know why.
if(cls == null){
return null;
}
}
}
}
public Object readStaticField(Class cls, String name){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
Object ret = f.get(null);
return ret;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeField(Object base, String name, Object value){
Class cls = base.getClass();
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.set(base, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticField(Class cls, String name, Object value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.set(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticByteField(Class cls, String name, byte value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.setByte(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticBooleanField(Class cls, String name, boolean value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.setBoolean(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticCharField(Class cls, String name, char value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.setChar(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticShortField(Class cls, String name, short value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.setShort(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticIntField(Class cls, String name, int value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.setInt(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticLongField(Class cls, String name, long value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.setLong(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticFloatField(Class cls, String name, float value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.setFloat(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public void writeStaticDoubleField(Class cls, String name, double value){
while(true){
try {
Field f = cls.getDeclaredField(name);
f.setAccessible(true);
f.setDouble(null, value);
return;
} catch(Exception ex){
cls = cls.getSuperclass();
}
}
}
public abstract void doWriteToHeap(Object o, boolean write_data, long ref, boolean read_only);
public abstract void doWriteStaticsToHeap();
public abstract Object doReadFromHeap(Object o, boolean read_data, long ref);
public abstract void doReadStaticsFromHeap();
public abstract int doGetSize(Object o);
}