/*
* 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.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.trifort.rootbeer.generate.opencl.OpenCLClass;
import org.trifort.rootbeer.generate.opencl.OpenCLScene;
import org.trifort.rootbeer.generate.opencl.OpenCLType;
import soot.*;
import soot.jimple.IntConstant;
import soot.jimple.NullConstant;
import soot.rbclassload.NumberedType;
import soot.rbclassload.RootbeerClassLoader;
import soot.rbclassload.StringToType;
public class VisitorGen extends AbstractVisitorGen {
SootClass m_runtimeBasicBlock;
private String m_className;
private Set<Type> m_getSizeMethodsMade;
private Set<String> m_sentinalCtorsCreated;
//Locals from code generation
private Local m_param0;
public VisitorGen(SootClass runtime_basic_block){
m_runtimeBasicBlock = runtime_basic_block;
m_getSizeMethodsMade = new HashSet<Type>();
m_sentinalCtorsCreated = new HashSet<String>();
}
public void generate(){
m_bcl.push(new BytecodeLanguage());
makeSentinalCtors();
makeSerializer();
addGetSerializerMethod();
}
private void makeSerializer() {
makeGcObjectClass();
makeCtor();
makeWriteStaticsToHeapMethod();
makeReadStaticsFromHeapMethod();
makeGetSizeMethod();
makeGetLengthMethod();
makeWriteToHeapMethod();
makeReadFromHeapMethod();
}
private void makeGcObjectClass() {
String base_name = m_runtimeBasicBlock.getName();
m_className = base_name+"Serializer";
m_bcl.top().makeClass(m_className, "org.trifort.rootbeer.runtime.Serializer");
}
private void makeGetLengthMethod(){
SootClass object_soot_class = Scene.v().getSootClass("java.lang.Object");
m_bcl.top().startMethod("doGetSize", IntType.v(), object_soot_class.getType());
m_thisRef = m_bcl.top().refThis();
m_param0 = m_bcl.top().refParameter(0);
List<Type> types = RootbeerClassLoader.v().getDfsInfo().getOrderedRefLikeTypes();
for(Type type : types){
makeGetSizeMethodForType(type);
}
m_bcl.top().returnValue(IntConstant.v(0));
m_bcl.top().endMethod();
}
private void makeGetSizeMethod(){
SootClass object_soot_class = Scene.v().getSootClass("java.lang.Object");
m_bcl.top().startMethod("getArrayLength", IntType.v(), object_soot_class.getType());
m_thisRef = m_bcl.top().refThis();
m_param0 = m_bcl.top().refParameter(0);
List<Type> types = RootbeerClassLoader.v().getDfsInfo().getOrderedRefLikeTypes();
for(Type type : types){
makeGetLengthMethodForType(type);
}
m_bcl.top().returnValue(IntConstant.v(0));
m_bcl.top().endMethod();
}
private void makeGetLengthMethodForType(Type type){
if(type instanceof ArrayType == false)
return;
String label = getNextLabel();
m_bcl.top().ifInstanceOfStmt(m_param0, type, label);
Local object_to_write_from = m_bcl.top().cast(type, m_param0);
Local length = m_bcl.top().lengthof(object_to_write_from);
m_bcl.top().returnValue(length);
m_bcl.top().label(label);
}
private void makeGetSizeMethodForType(Type type) {
if(type instanceof ArrayType == false &&
type instanceof RefType == false){
return;
}
if(m_getSizeMethodsMade.contains(type))
return;
m_getSizeMethodsMade.add(type);
if(type instanceof RefType){
RefType ref_type = (RefType) type;
SootClass soot_class = ref_type.getSootClass();
if(soot_class.getName().equals("java.lang.Object"))
return;
if(soot_class.isInterface()){
return;
}
if(differentPackageAndPrivate(ref_type)){
return;
}
}
if(typeIsPublic(type) == false)
return;
String label = getNextLabel();
m_bcl.top().ifInstanceOfStmt(m_param0, type, label);
if(type instanceof ArrayType){
ArrayType atype = (ArrayType) type;
Local size = m_bcl.top().local(IntType.v());
m_bcl.top().assign(size, IntConstant.v(Constants.ArrayOffsetSize));
Local element_size = m_bcl.top().local(IntType.v());
OpenCLType ocl_type = new OpenCLType(atype.baseType);
if(atype.numDimensions == 1)
m_bcl.top().assign(element_size, IntConstant.v(ocl_type.getSize()));
else
m_bcl.top().assign(element_size, IntConstant.v(4));
Local object_to_write_from = m_bcl.top().cast(type, m_param0);
Local length = m_bcl.top().lengthof(object_to_write_from);
m_bcl.top().mult(element_size, length);
m_bcl.top().plus(size, element_size);
m_bcl.top().returnValue(size);
}else if(type instanceof RefType) {
RefType rtype = (RefType) type;
OpenCLClass ocl_class = OpenCLScene.v().getOpenCLClass(rtype.getSootClass());
int size = ocl_class.getSize();
m_bcl.top().returnValue(IntConstant.v(size));
}
m_bcl.top().label(label);
}
private void makeWriteToHeapMethod() {
List<Type> types = RootbeerClassLoader.v().getDfsInfo().getOrderedRefLikeTypes();
VisitorWriteGen write_gen = new VisitorWriteGen(types,
m_className, m_bcl.top());
write_gen.makeWriteToHeapMethod();
}
private void makeReadFromHeapMethod() {
List<Type> types = RootbeerClassLoader.v().getDfsInfo().getOrderedRefLikeTypes();
VisitorReadGen read_gen = new VisitorReadGen(types,
m_className, m_bcl.top());
read_gen.makeReadFromHeapMethod();
}
private void makeWriteStaticsToHeapMethod() {
VisitorWriteGenStatic static_write_gen = new VisitorWriteGenStatic(m_bcl.top());
static_write_gen.makeMethod();
}
private void makeReadStaticsFromHeapMethod() {
VisitorReadGenStatic static_read_gen = new VisitorReadGenStatic(m_bcl.top());
static_read_gen.makeMethod();
}
private void addGetSerializerMethod() {
m_bcl.top().openClass(m_runtimeBasicBlock);
SootClass gc_object_visitor_soot_class = Scene.v().getSootClass("org.trifort.rootbeer.runtime.Serializer");
SootClass mem_cls = Scene.v().getSootClass("org.trifort.rootbeer.runtime.Memory");
m_bcl.top().startMethod("getSerializer", gc_object_visitor_soot_class.getType(), mem_cls.getType(), mem_cls.getType());
Local thisref = m_bcl.top().refThis();
Local param0 = m_bcl.top().refParameter(0);
Local param1 = m_bcl.top().refParameter(1);
Local ret = m_bcl.top().newInstance(m_className, param0, param1);
m_bcl.top().returnValue(ret);
m_bcl.top().endMethod();
}
private void makeCtor() {
SootClass mem_cls = Scene.v().getSootClass("org.trifort.rootbeer.runtime.Memory");
m_bcl.top().startMethod("<init>", VoidType.v(), mem_cls.getType(), mem_cls.getType());
Local this_ref = m_bcl.top().refThis();
Local param0 = m_bcl.top().refParameter(0);
Local param1 = m_bcl.top().refParameter(1);
m_bcl.top().pushMethod("org.trifort.rootbeer.runtime.Serializer", "<init>", VoidType.v(), mem_cls.getType(), mem_cls.getType());
m_bcl.top().invokeMethodNoRet(this_ref, param0, param1);
m_bcl.top().returnVoid();
m_bcl.top().endMethod();
}
private void generateSentinalCtor(RefType ref_type) {
SootClass soot_class = ref_type.getSootClass();
if(m_sentinalCtorsCreated.contains(soot_class.getName()))
return;
m_sentinalCtorsCreated.add(soot_class.getName());
soot_class = Scene.v().getSootClass(soot_class.getName());
if(soot_class.isApplicationClass() == false)
return;
if(soot_class.declaresMethod("void <init>(org.trifort.rootbeer.runtime.Sentinal)")){
return;
}
SootClass parent_class = soot_class.getSuperclass();
parent_class = Scene.v().getSootClass(parent_class.getName());
BytecodeLanguage bcl = new BytecodeLanguage();
bcl.openClass(soot_class);
bcl.startMethod("<init>", VoidType.v(), RefType.v("org.trifort.rootbeer.runtime.Sentinal"));
Local thisref = bcl.refThis();
String parent_name = parent_class.getName();
if(parent_class.isApplicationClass() == false){
if(parent_class.declaresMethod("void <init>()")){
bcl.pushMethod(parent_name, "<init>", VoidType.v());
bcl.invokeMethodNoRet(thisref);
} else {
System.out.println("Library class "+parent_name+" on the GPU does not have a void constructor");
System.exit(-1);
}
} else {
bcl.pushMethod(parent_name, "<init>", VoidType.v(), RefType.v("org.trifort.rootbeer.runtime.Sentinal"));
bcl.invokeMethodNoRet(thisref, NullConstant.v());
}
bcl.returnVoid();
bcl.endMethod();
}
private void makeSentinalCtors() {
List<RefType> types = RootbeerClassLoader.v().getDfsInfo().getOrderedRefTypes();
//types are ordered from largest type number to smallest
//reverse the order for this computation because the sentinal ctors
//need the parent to first have the sential ctor made.
Collections.reverse(types);
for(RefType ref_type : types){
AcceptableGpuTypes accept = new AcceptableGpuTypes();
if(accept.shouldGenerateCtor(ref_type.getClassName())){
generateSentinalCtor(ref_type);
}
}
}
String getClassName() {
return m_className;
}
}