/* * Copyright 2012 Phil Pratt-Szeliga and other contributors * http://chirrup.org/ * * See the file LICENSE for copying permission. */ package org.trifort.rootbeer.generate.bytecode; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.trifort.rootbeer.generate.opencl.OpenCLScene; import org.trifort.rootbeer.generate.opencl.OpenCLType; import org.trifort.rootbeer.generate.opencl.fields.OpenCLField; import org.trifort.rootbeer.util.Stack; import soot.*; import soot.jimple.IntConstant; import soot.jimple.LongConstant; import soot.jimple.NullConstant; import soot.rbclassload.ClassHierarchy; import soot.rbclassload.RootbeerClassLoader; public class VisitorReadGen extends AbstractVisitorGen { private Stack<Local> m_currObj; private Local m_param0; private Local m_param1; private Local m_refParam; private Local m_mem; private Local m_textureMem; private Map<Type, Local> m_readFromHeapMethodsMade; private Map<Type, Local> m_ctorReadFromHeapMethodsMade; private List<Type> m_orderedHistory; private Set<String> m_visitedReader; public VisitorReadGen(List<Type> ordered_history, String class_name, BytecodeLanguage bcl){ m_readFromHeapMethodsMade = new HashMap<Type, Local>(); m_ctorReadFromHeapMethodsMade = new HashMap<Type, Local>(); m_orderedHistory = ordered_history; m_visitedReader = new HashSet<String>(); m_bcl = new Stack<BytecodeLanguage>(); m_bcl.push(bcl); m_gcObjVisitor = new Stack<Local>(); m_objSerializing = new Stack<Local>(); m_currMem = new Stack<Local>(); m_currObj = new Stack<Local>(); } public void makeReadFromHeapMethod() { BytecodeLanguage bcl = m_bcl.top(); SootClass obj_cls = Scene.v().getSootClass("java.lang.Object"); bcl.startMethod("doReadFromHeap", obj_cls.getType(), obj_cls.getType(), BooleanType.v(), LongType.v()); m_thisRef = bcl.refThis(); m_gcObjVisitor.push(m_thisRef); m_param0 = bcl.refParameter(0); m_objSerializing.push(m_param0); m_param1 = bcl.refParameter(1); m_refParam = bcl.refParameter(2); m_mem = bcl.refInstanceField(m_thisRef, "mMem"); m_textureMem = bcl.refInstanceField(m_thisRef, "mTextureMem"); String dont_return_null_label = getNextLabel(); bcl.ifStmt(m_refParam, "!=", LongConstant.v(-1), dont_return_null_label); bcl.println("returning null"); bcl.returnValue(NullConstant.v()); bcl.label(dont_return_null_label); Local mem = bcl.local(m_mem.getType()); bcl.assign(mem, m_mem); m_currMem.push(mem); BclMemory bcl_mem = new BclMemory(m_bcl.top(), mem); bcl_mem.setAddress(m_refParam); bcl_mem.incrementAddress(3); Local ctor_used = bcl_mem.readByte(); Local class_number = bcl_mem.readInt(); ClassHierarchy class_hierarchy = RootbeerClassLoader.v().getClassHierarchy(); long string_number = class_hierarchy.getNumberForType("java.lang.String"); //create readers for String and char[] Local ret; String after_ctors_label = getNextLabel(); String ctors_label = getNextLabel(); String string_label = getNextLabel(); String increment_addr_label = getNextLabel(); bcl.ifStmt(class_number, "==", IntConstant.v((int) string_number), string_label); bcl.ifStmt(ctor_used, "==", IntConstant.v(1), ctors_label); bcl.ifStmt(m_param0, "==", NullConstant.v(), ctors_label); bcl.gotoLabel(increment_addr_label); bcl.label(string_label); RefType string_type = RefType.v("java.lang.String"); ret = makeReadFromHeapBodyForString(string_type); m_readFromHeapMethodsMade.put(string_type, ret); bcl.returnValue(ret); bcl.label(ctors_label); for(Type type : m_orderedHistory){ makeCtorReadFromHeapMethodForType(type, false, class_number, ctor_used, after_ctors_label); } RefType obj = RefType.v("java.lang.Object"); makeCtorReadFromHeapMethodForType(obj, true, class_number, ctor_used, after_ctors_label); bcl.label(increment_addr_label); bcl_mem.incrementAddress(8); bcl.label(after_ctors_label); bcl_mem.incrementAddress(16); for(Type type : m_orderedHistory){ makeReadFromHeapMethodForType(type, false, ctor_used); } makeReadFromHeapMethodForType(obj, true, ctor_used); bcl.returnValue(NullConstant.v()); bcl.endMethod(); } private void makeReadFromHeapMethodForType(Type type, boolean doing_object, Local ctor_used) { if(type instanceof ArrayType == false && type instanceof RefType == false){ return; } if(m_readFromHeapMethodsMade.containsKey(type)) return; if(type instanceof RefType){ RefType ref_type = (RefType) type; if(ref_type.getClassName().equals("java.lang.Object")){ if(!doing_object){ return; } } SootClass soot_class = ref_type.getSootClass(); if(soot_class.isInterface()){ return; } if(differentPackageAndPrivate(ref_type)){ return; } } String label = getNextLabel(); BytecodeLanguage bcl = m_bcl.top(); bcl.ifInstanceOfStmt(m_param0, type, label); //bcl.println("reading: "+type.toString()); //BclMemory bcl_mem = new BclMemory(bcl, m_mem); //Local ptr = bcl_mem.getPointer(); //bcl.println(ptr); Local ret; if(type instanceof ArrayType){ ret = makeReadFromHeapBodyForArrayType((ArrayType) type); } else { ret = makeReadFromHeapBodyForSootClass((RefType) type); } m_readFromHeapMethodsMade.put(type, ret); bcl.returnValue(ret); bcl.label(label); } private void makeCtorReadFromHeapMethodForType(Type type, boolean doing_object, Local class_number, Local ctor_used, String after_ctors_label) { if(type instanceof ArrayType == false && type instanceof RefType == false){ return; } if(m_ctorReadFromHeapMethodsMade.containsKey(type)) return; if(type instanceof RefType){ RefType ref_type = (RefType) type; if(ref_type.getClassName().equals("java.lang.Object")){ if(!doing_object){ return; } } SootClass soot_class = ref_type.getSootClass(); if(soot_class.isInterface()){ return; } if(differentPackageAndPrivate(ref_type)){ return; } } String label = getNextLabel(); BytecodeLanguage bcl = m_bcl.top(); ClassHierarchy class_hierarchy = RootbeerClassLoader.v().getClassHierarchy(); long number = class_hierarchy.getNumberForType(type.toString()); bcl.ifStmt(class_number, "!=", IntConstant.v((int) number), label); Local ret; if(type instanceof ArrayType){ ret = makeCtorReadFromHeapBodyForArrayType((ArrayType) type, ctor_used); m_ctorReadFromHeapMethodsMade.put(type, ret); bcl.assign(m_param0, ret); bcl.gotoLabel(after_ctors_label); } else { ret = makeCtorReadFromHeapBodyForSootClass((RefType) type, ctor_used, class_number); m_ctorReadFromHeapMethodsMade.put(type, ret); bcl.assign(m_param0, ret); bcl.gotoLabel(after_ctors_label); } bcl.label(label); } private Local makeCtorReadFromHeapBodyForArrayType(ArrayType type, Local ctor_used) { BytecodeLanguage bcl = m_bcl.top(); BclMemory bcl_mem = new BclMemory(bcl, m_currMem.top()); bcl_mem.incrementAddress(4); Local array_length = bcl_mem.readInt(); //bcl.println("reading size: "); //bcl.println(size); Local ret = bcl.local(type); bcl.assign(ret, bcl.newArray(type, array_length)); return ret; } private Local makeReadFromHeapBodyForArrayType(ArrayType type) { BytecodeLanguage bcl = m_bcl.top(); BclMemory bcl_mem = new BclMemory(bcl, m_currMem.top()); Local ret = bcl.local(type); ret = bcl.cast(type, m_param0); Local size = bcl.lengthof(ret); //optimization for single-dimensional arrays of primitive types. //doesn't work for chars yet because they are still stored as ints on the gpu if(type.baseType instanceof PrimType && type.numDimensions == 1 && type.baseType.equals(CharType.v()) == false){ bcl.pushMethod(m_currMem.top(), "readArray", VoidType.v(), type); bcl.invokeMethodNoRet(m_currMem.top(), ret); OpenCLType ocl_type = new OpenCLType(type.baseType); Local element_size = bcl.local(IntType.v()); bcl.assign(element_size, IntConstant.v(ocl_type.getSize())); bcl.mult(element_size, size); bcl_mem.incrementAddress(element_size); return ret; } Local i = bcl.local(IntType.v()); bcl.assign(i, IntConstant.v(0)); String end_for_label = getNextLabel(); String before_if_label = getNextLabel(); bcl.label(before_if_label); bcl.ifStmt(i, "==", size, end_for_label); Local new_curr; if(type.numDimensions != 1){ new_curr = readFromHeapArray(ret, i, size); } else if(type.baseType instanceof RefType){ Local temp = readFromHeapArray(ret, i, size); new_curr = bcl.cast(type.baseType, temp); } else { new_curr = bcl_mem.readVar(type.baseType); } bcl.assignElementToArray(ret, new_curr, i); bcl.plus(i, 1); bcl.gotoLabel(before_if_label); bcl.label(end_for_label); bcl_mem.finishReading(); return ret; } private Local makeReadFromHeapBodyForString(RefType type){ BytecodeLanguage bcl = m_bcl.top(); BclMemory bcl_mem = new BclMemory(bcl, m_currMem.top()); bcl_mem.incrementAddress(4+4+16); Local ref = bcl_mem.readRef(); bcl_mem.setAddress(ref); bcl_mem.incrementAddress(12); Local array_length = bcl_mem.readInt(); bcl_mem.incrementAddress(16); ArrayType array_type = ArrayType.v(CharType.v(), 1); Local ret = bcl.local(array_type); bcl.assign(ret, bcl.newArray(array_type, array_length)); Local i = bcl.local(IntType.v()); bcl.assign(i, IntConstant.v(0)); String end_for_label = getNextLabel(); String before_if_label = getNextLabel(); bcl.label(before_if_label); bcl.ifStmt(i, "==", array_length, end_for_label); Local new_curr = bcl_mem.readChar(); bcl.assignElementToArray(ret, new_curr, i); bcl.plus(i, 1); bcl.gotoLabel(before_if_label); bcl.label(end_for_label); SootClass string_class = Scene.v().getSootClass("java.lang.String"); Local new_string = bcl.newInstance(string_class.getName(), ret); bcl_mem.finishReading(); m_ctorReadFromHeapMethodsMade.put(type, new_string); m_readFromHeapMethodsMade.put(type, new_string); return new_string; } private Local makeCtorReadFromHeapBodyForSootClass(RefType type, Local ctor_used, Local class_number) { BytecodeLanguage bcl = m_bcl.top(); BclMemory bcl_mem = new BclMemory(bcl, m_currMem.top()); bcl_mem.incrementAddress(8); SootClass soot_class = type.getSootClass(); String name = soot_class.getName(); if(soot_class.isApplicationClass() == false){ if(soot_class.declaresMethod("void <init>()")){ Local object_to_write_to = bcl.local(type); Local new_object = bcl.newInstance(name); bcl.assign(object_to_write_to, new_object); return object_to_write_to; } else { JavaNumberTypes number_types = new JavaNumberTypes(); String type_string = type.toString(); if(number_types.get().contains(type_string)){ bcl_mem.incrementAddress(Constants.MallocAlignBytes); Local value; if(type_string.equals("java.lang.Byte")){ value = bcl_mem.readByte(); } else if(type_string.equals("java.lang.Boolean")){ value = bcl_mem.readBoolean(); } else if(type_string.equals("java.lang.Character")){ value = bcl_mem.readChar(); } else if(type_string.equals("java.lang.Short")){ value = bcl_mem.readShort(); } else if(type_string.equals("java.lang.Integer")){ value = bcl_mem.readInt(); } else if(type_string.equals("java.lang.Long")){ value = bcl_mem.readLong(); } else if(type_string.equals("java.lang.Float")){ value = bcl_mem.readFloat(); } else if(type_string.equals("java.lang.Double")){ value = bcl_mem.readDouble(); } else { throw new UnsupportedOperationException("cannot create type: "+type_string); } Local object_to_write_to = bcl.local(type); Local new_object = bcl.newInstance(name, value); bcl.assign(object_to_write_to, new_object); bcl_mem.finishReading(); bcl.returnValue(object_to_write_to); return object_to_write_to; } else { Local object_to_write_to = bcl.local(type); bcl.assign(object_to_write_to, NullConstant.v()); return object_to_write_to; } } } else { Local object_to_write_to = bcl.local(type); Local sentinal = bcl.newInstance("org.trifort.rootbeer.runtime.Sentinal"); Local new_object = bcl.newInstance(name, sentinal); bcl.assign(object_to_write_to, new_object); return object_to_write_to; } } private Local makeReadFromHeapBodyForSootClass(RefType type){ BytecodeLanguage bcl = m_bcl.top(); SootClass soot_class = type.getSootClass(); Local object_to_write_to = bcl.cast(type, m_param0); BclMemory bcl_mem = new BclMemory(bcl, m_currMem.top()); SootClass obj_class = Scene.v().getSootClass("java.lang.Object"); bcl.pushMethod(m_thisRef, "checkCache",obj_class.getType(), LongType.v(), obj_class.getType()); object_to_write_to = bcl.invokeMethodRet(m_thisRef, m_refParam, object_to_write_to); object_to_write_to = bcl.cast(type, object_to_write_to); m_currObj.push(object_to_write_to); m_objSerializing.push(object_to_write_to); readFields(soot_class, true); readFields(soot_class, false); m_currObj.pop(); m_objSerializing.pop(); bcl_mem.finishReading(); return object_to_write_to; } private void readFields(SootClass curr_class, boolean ref_types){ if(curr_class.isApplicationClass()){ attachReader(curr_class.getName(), ref_types); callBaseClassReader(curr_class.getName(), ref_types); } else { insertReader(curr_class.getName(), ref_types); } } private Local readFromHeapArray(Local object_to_read_from, Local i, Local size) { BytecodeLanguage bcl = m_bcl.top(); BclMemory bcl_mem = new BclMemory(bcl, m_currMem.top()); Local curr; String after_read = getNextLabel(); String before_read_int = getNextLabel(); bcl.ifStmt(i, ">=", size, after_read); curr = bcl.indexArray(object_to_read_from, i); bcl.gotoLabel(before_read_int); bcl.label(after_read); if(object_to_read_from.getType() instanceof RefLikeType){ bcl.assign(curr, NullConstant.v()); } else { bcl.assign(curr, IntConstant.v(0)); } bcl.label(before_read_int); Local curr_phi = bcl.local(object_to_read_from.getType()); bcl.assign(curr_phi, curr); Local object_addr = bcl_mem.readRef(); bcl_mem.pushAddress(); SootClass obj_cls = Scene.v().getSootClass("java.lang.Object"); bcl.pushMethod(m_thisRef, "readFromHeap", obj_cls.getType(), obj_cls.getType(), BooleanType.v(), LongType.v()); Local ret = bcl.invokeMethodRet(m_thisRef, curr_phi, m_param1, object_addr); bcl_mem.popAddress(); return ret; } public void attachReader(String class_name, boolean ref_fields){ String specialization; if(ref_fields){ specialization = "RefFields"; } else { specialization = "NonRefFields"; } specialization += JavaNameToOpenCL.convert(class_name); specialization += OpenCLScene.v().getIdent(); String visited_name = class_name + specialization; if(m_visitedReader.contains(visited_name)) return; m_visitedReader.add(visited_name); SootClass curr_class = Scene.v().getSootClass(class_name); SootClass parent = curr_class.getSuperclass(); parent = Scene.v().getSootClass(parent.getName()); if(parent.isApplicationClass()){ attachReader(parent.getName(), ref_fields); } BytecodeLanguage bcl = new BytecodeLanguage(); Local gc_obj_visit = m_gcObjVisitor.top(); m_bcl.push(bcl); bcl.openClass(class_name); SootClass mem = Scene.v().getSootClass("org.trifort.rootbeer.runtime.Memory"); bcl.startMethod("org_trifort_readFromHeap"+specialization, VoidType.v(), mem.getType(), gc_obj_visit.getType()); m_objSerializing.push(bcl.refThis()); m_currMem.push(bcl.refParameter(0)); m_gcObjVisitor.push(bcl.refParameter(1)); doReader(class_name, ref_fields); if(parent.getName().equals("java.lang.Object") == false){ if(parent.isApplicationClass()){ callBaseClassReader(parent.getName(), ref_fields); } else { insertReader(parent.getName(), ref_fields); } } bcl.returnVoid(); bcl.endMethod(); m_objSerializing.pop(); m_currMem.pop(); m_gcObjVisitor.pop(); m_bcl.pop(); } public void insertReader(String class_name, boolean ref_fields){ doReader(class_name, ref_fields); SootClass curr_class = Scene.v().getSootClass(class_name); if(curr_class.hasSuperclass() == false) return; SootClass parent = curr_class.getSuperclass(); parent = Scene.v().getSootClass(parent.getName()); if(parent.getName().equals("java.lang.Object") == false){ if(parent.isApplicationClass()){ attachReader(parent.getName(), ref_fields); callBaseClassReader(parent.getName(), ref_fields); } else { insertReader(parent.getName(), ref_fields); } } } public void doReader(String class_name, boolean do_ref_fields){ BytecodeLanguage bcl = m_bcl.top(); BclMemory bcl_mem = new BclMemory(bcl, m_currMem.top()); SootClass soot_class = Scene.v().getSootClass(class_name); //read all the ref fields int inc_size = 0; if(do_ref_fields){ List<OpenCLField> ref_fields = getRefFields(soot_class); for(OpenCLField ref_field : ref_fields){ //increment the address to get to this location bcl_mem.incrementAddress(inc_size); inc_size = 0; //read the field readRefField(ref_field); } if(inc_size > 0){ bcl_mem.incrementAddress(inc_size); } } else { List<OpenCLField> non_ref_fields = getNonRefFields(soot_class); for(OpenCLField non_ref_field : non_ref_fields){ //increment the address to get to this location if(inc_size > 0){ bcl_mem.incrementAddress(inc_size); inc_size = 0; } //read the field readNonRefField(non_ref_field); } if(inc_size > 0){ bcl_mem.incrementAddress(inc_size); } } bcl_mem.align(); } public void callBaseClassReader(String class_name, boolean ref_types) { String specialization; if(ref_types){ specialization = "RefFields"; } else { specialization = "NonRefFields"; } specialization += JavaNameToOpenCL.convert(class_name); specialization += OpenCLScene.v().getIdent(); SootClass mem = Scene.v().getSootClass("org.trifort.rootbeer.runtime.Memory"); BytecodeLanguage bcl = m_bcl.top(); Local gc_obj_visit = m_gcObjVisitor.top(); bcl.pushMethod(class_name, "org_trifort_readFromHeap"+specialization, VoidType.v(), mem.getType(), gc_obj_visit.getType()); bcl.invokeMethodNoRet(m_objSerializing.top(), m_currMem.top(), gc_obj_visit); } }