/*
* 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.LinkedHashSet;
import java.util.List;
import java.util.Set;
import soot.Hierarchy;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.rbclassload.ClassHierarchy;
import soot.rbclassload.HierarchyGraph;
import soot.rbclassload.MethodSignatureUtil;
import soot.rbclassload.RootbeerClassLoader;
/**
* Represents all the versions of methods in a class Hierarchy
* @author pcpratts
*/
public class MethodHierarchies {
private Set<MethodHierarchy> m_hierarchies;
private MethodSignatureUtil m_util;
public MethodHierarchies(){
m_hierarchies = new LinkedHashSet<MethodHierarchy>();
m_util = new MethodSignatureUtil();
}
public void addMethod(SootMethod method){
MethodHierarchy new_hierarchy = new MethodHierarchy(method);
for(MethodHierarchy curr : m_hierarchies){
if(curr.contains(new_hierarchy)){
return;
}
}
m_hierarchies.add(new_hierarchy);
}
public List<OpenCLMethod> getMethods(){
List<OpenCLMethod> ret = new ArrayList<OpenCLMethod>();
//for each method
for(MethodHierarchy method_hierarchy : m_hierarchies){
//get the list of classes in the hierarchy
List<OpenCLMethod> methods = method_hierarchy.getMethods();
for(OpenCLMethod method : methods){
ret.add(method);
}
}
return ret;
}
public List<OpenCLPolymorphicMethod> getPolyMorphicMethods(){
List<OpenCLPolymorphicMethod> ret = new ArrayList<OpenCLPolymorphicMethod>();
for(MethodHierarchy method_hierarchy : m_hierarchies){
if(method_hierarchy.isPolyMorphic()){
ret.add(method_hierarchy.getOpenCLPolyMorphicMethod());
}
}
return ret;
}
private class MethodHierarchy {
private SootMethod m_method;
public MethodHierarchy(SootMethod method){
m_method = method;
}
public List<OpenCLMethod> getMethods(){
List<OpenCLMethod> ret = new ArrayList<OpenCLMethod>();
if(m_method.isConstructor()){
OpenCLMethod method = new OpenCLMethod(m_method, m_method.getDeclaringClass());
ret.add(method);
return ret;
}
List<String> methods = RootbeerClassLoader.v().getClassHierarchy().getVirtualMethods(m_method.getSignature());
for(String virt_method : methods){
m_util.parse(virt_method);
SootMethod soot_method = m_util.getSootMethod();
OpenCLMethod method = new OpenCLMethod(soot_method, soot_method.getDeclaringClass());
ret.add(method);
}
return ret;
}
public boolean isPolyMorphic(){
IsPolymorphic poly_checker = new IsPolymorphic();
if(poly_checker.test(m_method)){
return true;
}
return false;
}
public OpenCLPolymorphicMethod getOpenCLPolyMorphicMethod(){
SootClass soot_class = m_method.getDeclaringClass();
List<SootClass> interfaces = new ArrayList<SootClass>();
interfaces.addAll(soot_class.getInterfaces());
String sub_sig = m_method.getSubSignature();
for(SootClass iface : interfaces){
if(iface.declaresMethod(sub_sig)){
SootMethod iface_method = iface.getMethod(sub_sig);
return new OpenCLPolymorphicMethod(iface_method);
}
}
return new OpenCLPolymorphicMethod(m_method);
}
public boolean contains(MethodHierarchy other){
if(m_method.getSubSignature().equals(other.m_method.getSubSignature()) == false)
return false;
SootClass lhs_class = m_method.getDeclaringClass();
SootClass rhs_class = other.m_method.getDeclaringClass();
Integer lhs_number = RootbeerClassLoader.v().getClassNumber(lhs_class);
Integer rhs_number = RootbeerClassLoader.v().getClassNumber(rhs_class);
HierarchyGraph hgraph = RootbeerClassLoader.v().getClassHierarchy().getHierarchyGraph();
if(hgraph.sameHierarchy(lhs_number, rhs_number)){
return true;
}
return false;
}
}
}