/*
* Copyright 2012 Phil Pratt-Szeliga and other contributors
* http://chirrup.org/
*
* See the file LICENSE for copying permission.
*/
package org.trifort.rootbeer.generate.opencl.fields;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.trifort.rootbeer.configuration.Configuration;
import org.trifort.rootbeer.generate.bytecode.StaticOffsets;
import org.trifort.rootbeer.generate.opencl.OpenCLClass;
import org.trifort.rootbeer.generate.opencl.OpenCLScene;
import org.trifort.rootbeer.generate.opencl.OpenCLType;
import org.trifort.rootbeer.generate.opencl.fields.CompositeField;
import org.trifort.rootbeer.generate.opencl.fields.OffsetCalculator;
import org.trifort.rootbeer.generate.opencl.tweaks.Tweaks;
import soot.Local;
import soot.Modifier;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.Type;
import soot.Value;
import soot.jimple.toolkits.typing.fast.Integer127Type;
import soot.options.Options;
import soot.rbclassload.FieldSignatureUtil;
import soot.rbclassload.RootbeerClassLoader;
public class OpenCLField {
private final SootField m_sootField;
private final SootClass m_sootClass;
private boolean m_cloned;
private OpenCLField m_cloneSource;
private Map<Integer, List<SootClass>> m_offsets;
public OpenCLField(SootField soot_field, SootClass soot_class) {
m_sootField = soot_field;
m_sootClass = soot_class;
m_cloned = false;
}
public void setClone(OpenCLField source){
m_cloned = true;
m_cloneSource = source;
}
public boolean isCloned(){
return m_cloned;
}
public OpenCLField getCloneSource(){
return m_cloneSource;
}
public String getName(){
return m_sootField.getName();
}
public SootField getSootField(){
return m_sootField;
}
private String getFullName(){
FieldSignatureUtil util = new FieldSignatureUtil();
util.parse(m_sootField.getSignature());
SootField real_field = util.getSootField();
OpenCLClass ocl_class = OpenCLScene.v().getOpenCLClass(real_field.getDeclaringClass());
return ocl_class.getName()+"_"+getName();
}
public OpenCLType getClassType(){
Type soot_type = m_sootClass.getType();
return new OpenCLType(soot_type);
}
public OpenCLType getType(){
Type soot_type = m_sootField.getType();
return new OpenCLType(soot_type);
}
private List<String> getDecls(){
List<String> ret = new ArrayList<String>();
String type_string = getType().getCudaTypeString();
String device_function_qual = Tweaks.v().getDeviceFunctionQualifier();
String address_qual = Tweaks.v().getGlobalAddressSpaceQualifier();
if(m_sootField.isStatic() == false){
//instance getter
ret.add(device_function_qual+" "+type_string+" instance_getter_"+getFullName()+"(int thisref, int * exception)");
//instance setter
ret.add(device_function_qual+" void instance_setter_"+getFullName()+"(int thisref, "+type_string+" parameter0, int * exception)");
} else {
//static getter
ret.add(device_function_qual+" "+type_string+" static_getter_"+getFullName()+"(int * exception)");
//static setter
ret.add(device_function_qual+" void static_setter_"+getFullName()+"("+type_string+" parameter0, int * expcetion)");
}
return ret;
}
public String getGetterSetterPrototypes(){
StringBuilder ret = new StringBuilder();
List<String> decls = getDecls();
for(String decl : decls){
ret.append(decl+";\n");
}
return ret.toString();
}
public int getSize(){
return getType().getSize();
}
private void calculateOffsets(CompositeField composite){
OffsetCalculator calc = new OffsetCalculator(composite);
m_offsets = new TreeMap<Integer, List<SootClass>>();
for(SootClass sclass : composite.getClasses()){
int field_offset = calc.getOffset(this, sclass);
List<SootClass> classes;
if(m_offsets.containsKey(field_offset)){
classes = m_offsets.get(field_offset);
} else {
classes = new ArrayList<SootClass>();
m_offsets.put(field_offset, classes);
}
classes.add(sclass);
}
}
private int getOnlyOffset(){
Iterator<Integer> iter = m_offsets.keySet().iterator();
while(iter.hasNext()){
int ret = iter.next();
return ret;
}
return -1;
}
private String getGetterSetterBodiesInstance(CompositeField composite, boolean writable,
FieldTypeSwitch type_switch){
StringBuilder ret = new StringBuilder();
List<String> decls = getDecls();
String address_qual = Tweaks.v().getGlobalAddressSpaceQualifier();
String cast_string = getCastString();
calculateOffsets(composite);
String prefix = Options.v().rbcl_remap_prefix();
if(Options.v().rbcl_remap_all() == false){
prefix = "";
}
SootClass null_cls = Scene.v().getSootClass(prefix+"java.lang.NullPointerException");
int null_num = RootbeerClassLoader.v().getClassNumber(null_cls);
//instance getter
ret.append(decls.get(0)+"{\n");
int field_offset = getOnlyOffset();
//ret.append("if("+thisref+" & 0x1000000000000000L){\n");
//ret.append(" thisref &= 0x0fffffffffffffffL;\n");
//ret.append(" thisref += "+field_offset+";\n");
//ret.append(" return org_trifort_cache_get_"+type+"(thisref);\n");
//ret.append("} else {\n");
if(composite.getClasses().size() != 1){
ret.append("GC_OBJ_TYPE_TYPE derived_type;\n");
ret.append("int offset;\n");
}
ret.append(address_qual+" char * thisref_deref;\n");
if(Configuration.compilerInstance().getExceptions()){
ret.append("if(thisref == -1){\n");
ret.append(" *exception = "+null_num+";\n");
ret.append(" return 0;\n");
ret.append("}\n");
}
ret.append("thisref_deref = org_trifort_gc_deref(thisref);\n");
if(composite.getClasses().size() == 1){
SootClass sclass = composite.getClasses().get(0);
ret.append("return *(("+address_qual+" "+cast_string+" *) &thisref_deref["+Integer.toString(field_offset)+"]);\n");
} else {
ret.append("derived_type = org_trifort_gc_get_type(thisref_deref);\n");
ret.append("offset = "+type_switch.typeSwitchName(m_offsets)+"(derived_type);\n");
ret.append("return *(("+address_qual+" "+cast_string+" *) &thisref_deref[offset]);\n");
}
//ret.append("}\n");
ret.append("}\n");
//instance setter
ret.append(decls.get(1)+"{\n");
if(composite.getClasses().size() != 1){
ret.append("GC_OBJ_TYPE_TYPE derived_type;\n");
ret.append("int offset;\n");
}
ret.append(address_qual+" char * thisref_deref;\n");
if(Configuration.compilerInstance().getExceptions()){
ret.append("if(thisref == -1){\n");
ret.append(" *exception = "+null_num+";\n");
ret.append(" return;\n");
ret.append("}\n");
}
ret.append("thisref_deref = org_trifort_gc_deref(thisref);\n");
if(composite.getClasses().size() == 1){
ret.append("*(("+address_qual+" "+cast_string+" *) &thisref_deref["+Integer.toString(field_offset)+"]) = parameter0;\n");
} else {
ret.append("derived_type = org_trifort_gc_get_type(thisref_deref);\n");
ret.append("offset = "+type_switch.typeSwitchName(m_offsets)+"(derived_type);\n");
ret.append("*(("+address_qual+" "+cast_string+" *) &thisref_deref[offset]) = parameter0;\n");
}
ret.append("}\n");
return ret.toString();
}
private String getGetterSetterBodiesStatic() {
StringBuilder ret = new StringBuilder();
List<String> decls = getDecls();
String address_qual = Tweaks.v().getGlobalAddressSpaceQualifier();
StaticOffsets static_offsets = new StaticOffsets();
int offset = static_offsets.getIndex(this);
String cast_string = getCastString();
ret.append(decls.get(0)+"{\n");
ret.append(address_qual+" char * thisref_deref = org_trifort_gc_deref(0);\n");
ret.append("return *(("+address_qual+" "+cast_string+" *) &thisref_deref["+offset+"]);\n");
ret.append("}\n");
ret.append(decls.get(1)+"{\n");
ret.append(address_qual+" char * thisref_deref = org_trifort_gc_deref(0);\n");
ret.append("*(("+address_qual+" "+cast_string+" *) &thisref_deref["+offset+"]) = parameter0;\n");
ret.append("}\n");
return ret.toString();
}
public String getGetterSetterBodies(CompositeField composite, boolean writable,
FieldTypeSwitch type_switch){
if(m_sootField.isStatic()){
return getGetterSetterBodiesStatic();
} else {
return getGetterSetterBodiesInstance(composite, writable, type_switch);
}
}
private String checkAlignmentString(int field_offset){
String ret = "";
ret += "int addr = thisref_deref + "+field_offset+";\n";
ret += "if(addr % "+getSize()+" != 0){\n";
ret += " printf(\"misaligned field: "+m_sootField.toString()+"\\n\");\n";
ret += "}\n";
return ret;
}
public String getStaticGetterInvoke(){
return "static_getter_"+getFullName()+"(exception)";
}
public String getStaticSetterInvoke(){
return "static_setter_"+getFullName()+"(";
}
public String getInstanceGetterInvoke(Value base){
if(base instanceof Local == false)
throw new UnsupportedOperationException("how do we handle when a base is not a loca?");
Local local = (Local) base;
return "instance_getter_"+getFullName()+"("+local.getName()+", exception)";
}
public String getInstanceSetterInvoke(Value base){
if(base instanceof Local == false)
throw new UnsupportedOperationException("how do we handle when a base is not a loca?");
Local local = (Local) base;
return "instance_setter_"+getFullName()+"("+local.getName()+", ";
}
public String getInstanceSetterInvokeWithoutThisref(){
return "instance_setter_"+getFullName()+"(";
}
@Override
public String toString(){
return getType().getDerefString()+" "+getName();
}
@Override
public boolean equals(Object o){
if(o instanceof OpenCLField == false)
return false;
OpenCLField other = (OpenCLField) o;
if(m_sootField.equals(other.m_sootField) && m_sootClass.equals(other.m_sootClass))
return true;
return false;
}
@Override
public int hashCode() {
int hash = 7;
hash = 37 * hash + (this.m_sootField != null ? this.m_sootField.hashCode() : 0);
hash = 37 * hash + (this.m_sootClass != null ? this.m_sootClass.hashCode() : 0);
return hash;
}
public boolean isInstance() {
if(m_sootField.isStatic())
return false;
return true;
}
private String getCastString() {
String ret = getType().getCudaTypeString();
return ret;
}
public boolean isFinal() {
return m_sootField.isFinal();
}
}