/*
* Copyright 2012 Phil Pratt-Szeliga and other contributors
* http://chirrup.org/
*
* See the file LICENSE for copying permission.
*/
package org.trifort.rootbeer.generate.opencl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.trifort.rootbeer.generate.opencl.tweaks.Tweaks;
import soot.*;
import soot.rbclassload.ClassHierarchy;
import soot.rbclassload.HierarchyGraph;
import soot.rbclassload.MethodSignatureUtil;
import soot.rbclassload.RootbeerClassLoader;
/**
* Represents an OpenCL function that dispatches to the real OpenCL function
* implementing the behavior of a certain classes version of a virtual method.
* @author pcpratts
*/
public class OpenCLPolymorphicMethod {
private final SootMethod m_sootMethod;
private MethodSignatureUtil m_util;
private Set<String> m_extraMethods;
public OpenCLPolymorphicMethod(SootMethod soot_method){
m_sootMethod = soot_method;
m_util = new MethodSignatureUtil();
m_extraMethods = new HashSet<String>();
m_extraMethods.add("<java.lang.Object: int hashCode()>");
}
public String getMethodPrototypes(){
if(m_sootMethod.getName().equals("<init>"))
return "";
List<String> decls = getMethodDecls();
StringBuilder ret = new StringBuilder();
for(String decl : decls){
decl += ";\n";
ret.append(decl);
}
return ret.toString();
}
private List<String> getMethodDecls(){
if(shouldOutput() == false){
return new ArrayList<String>();
}
List<SootMethod> virtual_methods = getVirtualMethods();
List<String> ret = new ArrayList<String>();
for(SootMethod virtual_method : virtual_methods){
SootClass soot_class = virtual_method.getDeclaringClass();
OpenCLMethod ocl_method = new OpenCLMethod(m_sootMethod, soot_class);
StringBuilder builder = new StringBuilder();
builder.append(Tweaks.v().getDeviceFunctionQualifier()+" ");
builder.append(ocl_method.getReturnString());
builder.append(" invoke_"+ocl_method.getPolymorphicName());
builder.append(ocl_method.getArgumentListStringPolymorphic());
ret.add(builder.toString());
}
return ret;
}
public Set<String> getMethodBodies(){
if(shouldOutput() == false){
return new HashSet<String>();
}
if(m_sootMethod.getName().equals("<init>"))
return new HashSet<String>();
List<String> decls = getMethodDecls();
Set<String> ret = new HashSet<String>();
for(String decl : decls){
String method = getMethodBody(decl);
ret.add(method);
}
return ret;
}
private List<SootMethod> getVirtualMethods(){
ClassHierarchy class_hierarchy = RootbeerClassLoader.v().getClassHierarchy();
List<String> virtual_methods = class_hierarchy.getVirtualMethods(m_sootMethod.getSignature());
List<SootMethod> ret = new ArrayList<SootMethod>();
for(String virtual_method : virtual_methods){
m_util.parse(virtual_method);
SootMethod soot_method = m_util.getSootMethod();
if(soot_method.isConcrete()){
ret.add(soot_method);
}
}
if(ret.contains(m_sootMethod) == false){
ret.add(m_sootMethod);
}
return ret;
}
public String getMethodBody(String decl){
StringBuilder ret = new StringBuilder();
String address_qual = Tweaks.v().getGlobalAddressSpaceQualifier();
//write function signature
ret.append(decl);
ret.append("{\n");
List<SootMethod> virtual_methods = getVirtualMethods();
if(m_sootMethod.isStatic()){
if(m_sootMethod.getReturnType() instanceof VoidType == false){
ret.append("return ");
}
Type first_type = m_sootMethod.getDeclaringClass().getType();
RefType ref_type = (RefType) first_type;
SootClass first_class = ref_type.getSootClass();
String invoke_string = getStaticInvokeString(first_class);
ret.append(invoke_string+"\n");
} else {
ret.append(address_qual+" char * thisref_deref;\n");
ret.append("GC_OBJ_TYPE_TYPE derived_type;\n");
ret.append("if(thisref == -1){\n");
ret.append(" *exception = %%java_lang_NullPointerException_TypeNumber%%;\n");
ret.append("return ");
if(m_sootMethod.getReturnType() instanceof VoidType == false)
ret.append("-1");
ret.append(";\n");
ret.append("}\n");
ret.append("thisref_deref = org_trifort_gc_deref(thisref);\n");
if(virtual_methods.size() == 1){
SootClass sclass = virtual_methods.get(0).getDeclaringClass();
String invoke_string = getInvokeString(sclass);
if(m_sootMethod.getReturnType() instanceof VoidType == false){
ret.append("return ");
}
ret.append(invoke_string+"\n");
} else {
ret.append("derived_type = org_trifort_gc_get_type(thisref_deref);\n");
ret.append("if(0){}\n");
int count = 0;
List<SootMethod> used_methods = new ArrayList<SootMethod>();
for(SootMethod method : virtual_methods){
SootClass sclass = method.getDeclaringClass();
if(sclass.isInterface()){
continue;
}
String invoke_string = getInvokeString(sclass);
if(invoke_string == ""){
continue;
}
used_methods.add(method);
}
Collections.sort(used_methods, new VirtualMethodComparator());
for(SootMethod method : used_methods){
SootClass sclass = method.getDeclaringClass();
String invoke_string = getInvokeString(sclass);
ret.append("else if(derived_type == "+RootbeerClassLoader.v().getClassNumber(sclass)+"){\n");
if(m_sootMethod.getReturnType() instanceof VoidType == false){
ret.append("return ");
}
ret.append(invoke_string+"\n");
ret.append("}\n");
count++;
}
}
}
ret.append("return ");
if(m_sootMethod.getReturnType() instanceof VoidType == false)
ret.append("-1");
ret.append(";\n");
ret.append("}\n");
return ret.toString();
}
//used to invoke polymorphic method inside this function
private String getInvokeString(SootClass start_class){
if(m_sootMethod.getName().equals("<init>"))
return "";
SootClass soot_class = start_class;
OpenCLMethod ocl_method = new OpenCLMethod(m_sootMethod, soot_class);
String ret = ocl_method.getPolymorphicName() + "(";
//write the thisref
ret += "thisref, ";
List args = m_sootMethod.getParameterTypes();
for(int i = 0; i < args.size(); ++i){
ret += "parameter" + Integer.toString(i);
ret += ", ";
}
ret += "exception);";
return ret;
}
private String getStaticInvokeString(SootClass soot_class) {
if(m_sootMethod.getName().equals("<init>"))
return "";
OpenCLMethod ocl_method = new OpenCLMethod(m_sootMethod, soot_class);
String ret = ocl_method.getPolymorphicName() + "(";
List args = m_sootMethod.getParameterTypes();
for(int i = 0; i < args.size(); ++i){
ret += "parameter" + Integer.toString(i);
ret += ", ";
}
ret += "exception);";
return ret;
}
public class VirtualMethodComparator implements
Comparator<SootMethod> {
@Override
public int compare(SootMethod lhs, SootMethod rhs) {
SootClass lhs_class = lhs.getDeclaringClass();
SootClass rhs_class = rhs.getDeclaringClass();
Integer lhs_number = RootbeerClassLoader.v().getClassNumber(lhs_class);
Integer rhs_number = RootbeerClassLoader.v().getClassNumber(rhs_class);
return lhs_number.compareTo(rhs_number);
}
}
private boolean shouldOutput(){
if(m_extraMethods.contains(m_sootMethod.getSignature())){
return true;
}
return m_sootMethod.isConcrete();
}
}