Package org.trifort.rootbeer.generate.bytecode

Source Code of org.trifort.rootbeer.generate.bytecode.GenerateForKernel

/*
* 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.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import org.trifort.rootbeer.configuration.Configuration;
import org.trifort.rootbeer.configuration.RootbeerPaths;
import org.trifort.rootbeer.deadmethods.DeadMethods;
import org.trifort.rootbeer.generate.opencl.OpenCLScene;
import org.trifort.rootbeer.generate.opencl.tweaks.CompileResult;

import soot.*;
import soot.jimple.IntConstant;
import soot.jimple.Jimple;
import soot.jimple.JimpleBody;
import soot.jimple.StringConstant;
import soot.options.Options;
import soot.rbclassload.RootbeerClassLoader;

public class GenerateForKernel {
  private MethodCodeSegment m_codeSegment;
  private SootClass m_sootClass;
  private List<Local> m_firstIterationLocals;
  private Jimple m_jimple;
  private String m_runtimeBasicBlockClassName;
  private String m_serializerClassName;

  public GenerateForKernel(SootMethod method, String uuid){
    m_jimple = Jimple.v();
    m_firstIterationLocals = new ArrayList<Local>();
    m_sootClass = method.getDeclaringClass();
    m_codeSegment = new MethodCodeSegment(method);
  }

  public Type getType(){
    return m_sootClass.getType();
  }

  public void makeClass() throws Exception {
    m_serializerClassName = m_codeSegment.getSootClass().getName()+"Serializer";
   
    makeCpuBody();
    makeGpuBody();
    makeIsUsingGarbageCollectorBody();
    makeIsReadOnly();   
    makeExceptionNumbers();
                           
    SerializerAdder adder = new SerializerAdder();
    adder.add(m_codeSegment);
  }

  private void makeCpuBody() {
    m_codeSegment.makeCpuBody(m_sootClass);
 
 
  private void makeGetCodeMethodThatReturnsBytes(boolean m32, String filename) {
    BytecodeLanguage bcl = new BytecodeLanguage();
    bcl.openClass(m_sootClass);
    SootClass string = Scene.v().getSootClass("java.lang.String");
    bcl.startMethod("getCubin"  + (m32 ? "32" : "64"), string.getType());
    Local thisref = bcl.refThis();
    bcl.returnValue(StringConstant.v(filename));
    bcl.endMethod();
  }
 
  private void makeGetCubinSizeMethod(boolean m32, int length){
    BytecodeLanguage bcl = new BytecodeLanguage();
    bcl.openClass(m_sootClass);
    bcl.startMethod("getCubin"+(m32 ? "32" : "64")+"Size", IntType.v());
    Local thisref = bcl.refThis();
    bcl.returnValue(IntConstant.v(length));
    bcl.endMethod();
  }

  private void makeGetCubinErrorMethod(boolean m32, boolean error){
    BytecodeLanguage bcl = new BytecodeLanguage();
    bcl.openClass(m_sootClass);
    bcl.startMethod("getCubin"+(m32 ? "32" : "64")+"Error", BooleanType.v());
    Local thisref = bcl.refThis();
    int intError = 0;
    if(error == true){
      intError = 1;
    }
    bcl.returnValue(IntConstant.v(intError));
    bcl.endMethod();
  }
 
  private void makeGetCodeMethodThatReturnsString(String gpu_code, boolean unix){   
    //make the getCode method with the results of the opencl code generation
    String name = "getCode";
    if(unix){
      name += "Unix";
    } else {
      name += "Windows";
    }
    SootMethod getCode = new SootMethod(name, new ArrayList(), RefType.v("java.lang.String"), Modifier.PUBLIC);
    getCode.setDeclaringClass(m_sootClass);
    m_sootClass.addMethod(getCode);
   
    RootbeerClassLoader.v().addGeneratedMethod(getCode.getSignature());

    JimpleBody body = m_jimple.newBody(getCode);
    UnitAssembler assembler = new UnitAssembler();

    //create an instance of self
    Local thislocal = m_jimple.newLocal("this0", m_sootClass.getType());
    Unit thisid = m_jimple.newIdentityStmt(thislocal, m_jimple.newThisRef(m_sootClass.getType()));
    assembler.add(thisid);

    //java string constants encoded in a class file have a maximum size of 65535...
    //$r1 = new java.lang.StringBuilder;
    SootClass string_builder_soot_class = Scene.v().getSootClass("java.lang.StringBuilder");
    Local r1 = m_jimple.newLocal("r1", string_builder_soot_class.getType());
    Value r1_assign_rhs = m_jimple.newNewExpr(string_builder_soot_class.getType());
    Unit r1_assign = m_jimple.newAssignStmt(r1, r1_assign_rhs);
    assembler.add(r1_assign);

    //specialinvoke $r1.<java.lang.StringBuilder: void <init>()>();
    SootMethod string_builder_ctor = string_builder_soot_class.getMethod("void <init>()");
    Value r1_ctor = m_jimple.newSpecialInvokeExpr(r1, string_builder_ctor.makeRef(), new ArrayList());
    Unit r1_ctor_unit = m_jimple.newInvokeStmt(r1_ctor);
    assembler.add(r1_ctor_unit);
   
    //r2 = $r1;
    Local r2 = m_jimple.newLocal("r2", string_builder_soot_class.getType());
    Unit r2_assign_r1 = m_jimple.newAssignStmt(r2, r1);
    assembler.add(r2_assign_r1);
   
    SootClass string_class = Scene.v().getSootClass("java.lang.String");
    SootMethod string_builder_append = string_builder_soot_class.getMethod("java.lang.StringBuilder append(java.lang.String)");

    GpuCodeSplitter splitter = new GpuCodeSplitter();
    List<String> blocks = splitter.split(gpu_code);

    for(String block : blocks){
      Value curr_string_constant = StringConstant.v(block);
       
      //virtualinvoke r2.<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>("gpu code");
      List args = new ArrayList();
      args.add(curr_string_constant);
      Value invoke_expr = m_jimple.newVirtualInvokeExpr(r2, string_builder_append.makeRef(), args);
      Unit invoke_stmt = m_jimple.newInvokeStmt(invoke_expr);
      assembler.add(invoke_stmt);
    }

    //$r5 = virtualinvoke r2.<java.lang.StringBuilder: java.lang.String toString()>();
    Local r5 = m_jimple.newLocal("r5", string_class.getType());
    SootMethod to_string = string_builder_soot_class.getMethod("java.lang.String toString()");
    Value r5_rhs = m_jimple.newVirtualInvokeExpr(r2, to_string.makeRef());
    Unit r5_assign = m_jimple.newAssignStmt(r5, r5_rhs);
    assembler.add(r5_assign);

    assembler.add(m_jimple.newReturnStmt(r5));

    assembler.assemble(body);
    getCode.setActiveBody(body);
  }

  private void makeGpuBody() throws Exception {
    OpenCLScene.v().addCodeSegment(m_codeSegment);
    if(Configuration.compilerInstance().getMode() == Configuration.MODE_GPU){
      CompileResult[] result = OpenCLScene.v().getCudaCode();
      for (CompileResult res : result) {
        String suffix = res.is32Bit() ? "-32" : "-64";
        if (res.getBinary() == null) {
          makeGetCodeMethodThatReturnsBytes(res.is32Bit(), cubinFilename(false, suffix) + ".error");
          makeGetCubinSizeMethod(res.is32Bit(), 0);
          makeGetCubinErrorMethod(res.is32Bit(), true);
        } else {
          byte[] bytes = res.getBinary();
          writeBytesToFile(bytes, cubinFilename(true, suffix));
          makeGetCodeMethodThatReturnsBytes(res.is32Bit(), cubinFilename(false, suffix));
          makeGetCubinSizeMethod(res.is32Bit(), bytes.length);
          makeGetCubinErrorMethod(res.is32Bit(), false);
        }
      }
      makeGetCodeMethodThatReturnsString("", true);
      makeGetCodeMethodThatReturnsString("", false);
    } else {
      String[] code = OpenCLScene.v().getOpenCLCode();
      //code[0] is unix
      //code[1] is windows
     
      PrintWriter writer = new PrintWriter(RootbeerPaths.v().getRootbeerHome()+"pre_dead_unix.c");
      writer.println(code[0]);
      writer.flush();
      writer.close();
     
      writer = new PrintWriter(RootbeerPaths.v().getRootbeerHome()+"pre_dead_windows.c");
      writer.println(code[1]);
      writer.flush();
      writer.close();
     
      System.out.println("removing dead methods...");
      DeadMethods dead_methods = new DeadMethods();
      dead_methods.parseString(code[0]);
      code[0] = dead_methods.getResult();
      dead_methods.parseString(code[1]);
      code[1] = dead_methods.getResult();
     
      //jpp can't handle declspec very well
      code[1] = code[1].replace("void entry(char * gc_info_space,", "__declspec(dllexport)\nvoid entry(char * gc_info_space,");
     
      makeGetCodeMethodThatReturnsString(code[0], true);
      makeGetCodeMethodThatReturnsString(code[1], false);
      makeGetCodeMethodThatReturnsBytes(true, "");
      makeGetCodeMethodThatReturnsBytes(false, "");
    }
  }
 
  private String cubinFilename(boolean use_class_folder, String suffix){
    String class_name = File.separator +
            m_serializerClassName.replace(".", File.separator) +
            suffix + ".cubin";
    if(use_class_folder)
      return RootbeerPaths.v().getOutputClassFolder() + class_name;
    else
      return class_name;
  }
 
  private void writeBytesToFile(byte[] bytes, String filename) {
    try {
      File file = new File(filename);
      File parent = file.getParentFile();
      parent.mkdirs();
      OutputStream os = new FileOutputStream(filename);
      os.write(bytes);
      os.flush();
      os.close();
    } catch(Exception ex){
      ex.printStackTrace();
    }
  }
 
  public SootField getField(String name, Type type){
    return m_sootClass.getField(name, type);
  }

  public void addFirstIterationLocal(Local local) {
    m_firstIterationLocals.add(local);
  }

  private void makeIsUsingGarbageCollectorBody() {
    BytecodeLanguage bcl = new BytecodeLanguage();
    bcl.openClass(m_sootClass);
    bcl.startMethod("isUsingGarbageCollector", BooleanType.v());
    bcl.refThis();
    if(OpenCLScene.v().getUsingGarbageCollector())
      bcl.returnValue(IntConstant.v(1));
    else
      bcl.returnValue(IntConstant.v(0));
    bcl.endMethod();
  }

  public String getRuntimeBasicBlockName() {
    return m_runtimeBasicBlockClassName;
  }

  public String getSerializerName() {
    return m_serializerClassName;
  }

  private void makeIsReadOnly() {
    BytecodeLanguage bcl = new BytecodeLanguage();
    bcl.openClass(m_sootClass);
    bcl.startMethod("isReadOnly", BooleanType.v());
    bcl.refThis();
    if(OpenCLScene.v().getReadOnlyTypes().isRootReadOnly())
      bcl.returnValue(IntConstant.v(1));
    else
      bcl.returnValue(IntConstant.v(0));
    bcl.endMethod();
  }

  private void makeExceptionNumbers() {
    String prefix = Options.v().rbcl_remap_prefix();
    if(Options.v().rbcl_remap_all() == false){
      prefix = "";
    }
    makeExceptionMethod("getNullPointerNumber", prefix+"java.lang.NullPointerException");
    makeExceptionMethod("getOutOfMemoryNumber", prefix+"java.lang.OutOfMemoryError");
  }
 
  private void makeExceptionMethod(String method_name, String cls_name) {
    SootClass soot_class = Scene.v().getSootClass(cls_name);
    int number = RootbeerClassLoader.v().getClassNumber(soot_class);
   
    BytecodeLanguage bcl = new BytecodeLanguage();
    bcl.openClass(m_sootClass);
    bcl.startMethod(method_name, IntType.v());
    bcl.refThis();
    bcl.returnValue(IntConstant.v(number));
    bcl.endMethod();
  }

}
TOP

Related Classes of org.trifort.rootbeer.generate.bytecode.GenerateForKernel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.