Package org.trifort.rootbeer.generate.bytecode

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

/*
* 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.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import soot.*;
import soot.jimple.*;
import soot.rbclassload.ClassHierarchy;
import soot.rbclassload.HierarchyGraph;
import soot.rbclassload.MethodSignatureUtil;
import soot.rbclassload.RootbeerClassLoader;
import soot.rbclassload.TypeToString;

public class BytecodeLanguage {

  private Jimple m_jimple;
  private SootClass m_currClass;

  //method fields
  private SootMethod m_currMethod;
  private JimpleBody m_currBody;
  private List<Type> m_parameterTypes;
  private UnitAssembler m_assembler;

  private Stack<SootMethod> m_methodStack;

  public BytecodeLanguage(){
    m_jimple = Jimple.v();
    m_methodStack = new Stack<SootMethod>();
  }

  public SootClass makeClass(String name){
    SootClass ret = new SootClass(name, Modifier.PUBLIC);

    SootClass object_soot_class = Scene.v().getSootClass("java.lang.Object");
    ret.setSuperclass(object_soot_class);
    Scene.v().addClass(ret);
    ret.setApplicationClass();

    m_currClass = ret;
    return ret;
  }

  public SootClass makeClass(String name, String parent){
    SootClass ret = new SootClass(name, Modifier.PUBLIC);

    //set superclass
    SootClass parent_class = Scene.v().getSootClass(parent);
    ret.setSuperclass(parent_class);

    Scene.v().addClass(ret);
    ret.setApplicationClass();

    m_currClass = ret;
    return ret;
  }

  public void addFieldToClass(Local local){
    SootField field = new SootField(local.getName(), local.getType(), Modifier.PUBLIC);
    m_currClass.addField(field);
  }
 
  public void addFieldToClass(Local local, String name){
    SootField field = new SootField(name, local.getType(), Modifier.PUBLIC);
    m_currClass.addField(field);
  }


  public void openClass(String name){
    m_currClass = Scene.v().getSootClass(name);
  }

  public void openClass(SootClass soot_class){
    m_currClass = soot_class;
  }

  public void startMethod(String method_name, Type return_type, Type... arg_types){
    doStartMethod(method_name, return_type, Modifier.PUBLIC, arg_types);
  }
 
  private void doStartMethod(String method_name, Type return_type, int modifiers, Type... arg_types){
    m_assembler = new UnitAssembler();

    m_parameterTypes = convertTypeArrayToList(arg_types);
    m_currMethod = new SootMethod(method_name, m_parameterTypes, return_type, modifiers);
    m_currMethod.setDeclaringClass(m_currClass);

    m_currBody = m_jimple.newBody(m_currMethod);
    m_currMethod.setActiveBody(m_currBody);
    m_currClass.addMethod(m_currMethod);
   
    RootbeerClassLoader.v().addGeneratedMethod(m_currMethod.getSignature());
  }
 
  public void startStaticMethod(String method_name, Type return_type, Type... arg_types){
    doStartMethod(method_name, return_type, Modifier.PUBLIC | Modifier.STATIC, arg_types);
  }

  public void continueMethod(UnitAssembler assembler){
    m_assembler = assembler;
  }

  public Local refThis(){
    String name = "this0";
    RefType type = m_currClass.getType();
    Local thislocal = m_jimple.newLocal(name, type);
    Unit u = m_jimple.newIdentityStmt(thislocal, m_jimple.newThisRef(type));
    m_assembler.add(u);
    return thislocal;
  }

  public Local refParameter(int index){
    Type type = m_parameterTypes.get(index);
    String name = "parameter"+Integer.toString(index);
    Local parameterI = m_jimple.newLocal(name, type);
    Unit u = m_jimple.newIdentityStmt(parameterI, m_jimple.newParameterRef(type, index));
    m_assembler.add(u);
    return parameterI;
  }

  public Local binOp(Value lhs, String op, Value rhs){
    Value binop = null;
    if(op.equals("*")){
      binop = m_jimple.newMulExpr(lhs, rhs);
    }

    Local ret = m_jimple.newLocal(getLocalName(), lhs.getType());
    Unit u = m_jimple.newAssignStmt(ret, binop);
    m_assembler.add(u);
    return ret;
  }

  public void setInstanceField(SootField field, Local field_instance, Value value){
    Value lhs;
    if(field.isStatic() == false)
      lhs = m_jimple.newInstanceFieldRef(field_instance, field.makeRef());
    else
      lhs = m_jimple.newStaticFieldRef(field.makeRef());
    Unit u = m_jimple.newAssignStmt(lhs, value);
    m_assembler.add(u);
  }

  public void setInstanceField(String field_name, Local field_instance, Value value){
    Type type = field_instance.getType();
    if(type instanceof RefType == false)
      throw new RuntimeException("How do we handle this case?");
    RefType ref_type = (RefType) type;
    SootClass soot_class = ref_type.getSootClass();
    SootField soot_field = soot_class.getFieldByName(field_name);
    setInstanceField(soot_field, field_instance, value);
  }

  public void setStaticField(SootField field, Value value) {
    Value lhs;
    lhs = m_jimple.newStaticFieldRef(field.makeRef());
    Unit u = m_jimple.newAssignStmt(lhs, value);
    m_assembler.add(u);
  }

  public void endMethod(){
    //System.out.println("Ending method: "+m_currMethod.getName());
    m_assembler.assemble(m_currBody);
    //System.out.println(m_assembler.toString());
  }

  private List<Type> convertTypeArrayToList(Type[] type_array){
    List<Type> ret = new ArrayList<Type>();
    for(int i = 0; i < type_array.length; ++i){
      ret.add(type_array[i]);
    }
    return ret;
  }

  public void pushMethod(Local class_instance, String method_name, Type return_type, Type... arg_types){
    String class_name = getTypeString(class_instance);
    pushMethod(class_name, method_name, return_type, arg_types);
  }
 
  public void pushMethod(SootClass soot_class, String method_name, Type return_type, Type... arg_types){
    String class_name = soot_class.getName();
    pushMethod(class_name, method_name, return_type, arg_types);   
  }

  public void pushMethod(String class_name, String method_name, Type return_type, Type... arg_types){
    SootClass soot_class = Scene.v().getSootClass(class_name);
    SootClass org_class = soot_class;
   
    TypeToString converter = new TypeToString();
    MethodSignatureUtil util = new MethodSignatureUtil();
    util.setClassName(class_name);
    util.setMethodName(method_name);
    util.setReturnType(converter.convert(return_type));
    List<String> parameter_types = new ArrayList<String>();
    for(Type arg_type : arg_types){
      parameter_types.add(converter.convert(arg_type));
    }
    util.setParameterTypes(parameter_types);
    SootMethod soot_method = util.getSootMethod();
    m_methodStack.push(soot_method);
  }

  private List<Value> convertValueArrayToList(Value[] local_array){
    List<Value> ret = new ArrayList<Value>();
    new ArrayList<Type>();
    for(int i = 0; i < local_array.length; ++i){
      ret.add(local_array[i]);
    }
    return ret;
  }

  public void invokeMethodNoRet(Local base, Value... args){
    SootMethod method = m_methodStack.pop();
    List<Value> args_list = convertValueArrayToList(args);
    Value invoke_expr;
    if(method.getName().equals("<init>")){
      invoke_expr = m_jimple.newSpecialInvokeExpr(base, method.makeRef(), args_list);
    } else {
      //I can't find any way to distinguish between an interface and non-interface
      //method.  let's just try both and use whatever works.
      try {
        invoke_expr = m_jimple.newVirtualInvokeExpr(base, method.makeRef(), args_list);
      } catch(RuntimeException ex){
        invoke_expr = m_jimple.newInterfaceInvokeExpr(base, method.makeRef(), args_list);
      }
    }

    Unit u = m_jimple.newInvokeStmt(invoke_expr);
    m_assembler.add(u);
  }
 
  public void invokeStaticMethodNoRet(Value... args){
    SootMethod method = m_methodStack.pop();
    List<Value> args_list = convertValueArrayToList(args);
    Value invoke_expr;
   
    invoke_expr = m_jimple.newStaticInvokeExpr(method.makeRef(), args_list);
   
    Unit u = m_jimple.newInvokeStmt(invoke_expr);
    m_assembler.add(u);
  }
 
  public void invokeSpecialNoRet(Local base, Value... args){
    SootMethod method = m_methodStack.pop();
    List<Value> args_list = convertValueArrayToList(args);
    Value invoke_expr;
    invoke_expr = m_jimple.newSpecialInvokeExpr(base, method.makeRef(), args_list);

    Unit u = m_jimple.newInvokeStmt(invoke_expr);
    m_assembler.add(u);
  }

  public Local invokeMethodRet(Local base, Value... args){
    SootMethod method = m_methodStack.pop();
    List<Value> args_list = convertValueArrayToList(args);
    Value invoke_expr;
    if(method.getName().equals("<init>")){
      invoke_expr = m_jimple.newSpecialInvokeExpr(base, method.makeRef(), args_list);
    } else {
      //I can't find any way to distinguish between an interface and non-interface
      //method.  let's just try both and use whatever works.
      try {
        invoke_expr = m_jimple.newVirtualInvokeExpr(base, method.makeRef(), args_list);
      } catch(RuntimeException ex){
        invoke_expr = m_jimple.newInterfaceInvokeExpr(base, method.makeRef(), args_list);
      }
    }

    String name = getLocalName();
    Local ret = m_jimple.newLocal(name, method.getReturnType());
    Unit u = m_jimple.newAssignStmt(ret, invoke_expr);
    m_assembler.add(u);
    return ret;
  }

  private String getLocalName(){
    return RegisterNamer.v().getName();
  }

  public Local local(Type type){
    Local ret = m_jimple.newLocal(getLocalName(), type);
    return ret;
  }

  public void ifStmt(Value lhs, String op, Value rhs, String target_label){
    Value condition;
    if(op.equals("==")){
      condition = m_jimple.newEqExpr(lhs, rhs);
    } else if(op.equals("!=")){
      condition = m_jimple.newNeExpr(lhs, rhs);
    } else if(op.equals(">=")){
      condition = m_jimple.newGeExpr(lhs, rhs);   
    } else {
      throw new UnsupportedOperationException();
    }
    m_assembler.addIf(condition, target_label);
  }

  public void ifInstanceOfStmt(Value lhs, Type rhs, String target){
    //Local lhs_instanceof_rhs_local = lhs instanceof rhs;
    Value lhs_instanceof_rhs;
    lhs_instanceof_rhs = m_jimple.newInstanceOfExpr(lhs, rhs);
    Local lhs_instance_of_rhs_local = m_jimple.newLocal(getLocalName(), BooleanType.v());
    Unit u1 = m_jimple.newAssignStmt(lhs_instance_of_rhs_local, lhs_instanceof_rhs);
    m_assembler.add(u1);

    Value eq = m_jimple.newEqExpr(lhs_instance_of_rhs_local, IntConstant.v(0));
    m_assembler.addIf(eq, target);
  }

  public void label(String label_string){
    m_assembler.addLabel(label_string);
  }

  public void returnVoid() {
    m_assembler.add(m_jimple.newReturnVoidStmt());
  }

  public void returnValue(Value value){
    Unit u = m_jimple.newReturnStmt(value);
    m_assembler.add(u);
  }

  public Local refInstanceField(Local base, String field_name){
    Type base_type = base.getType();
    SootClass base_class = Scene.v().getSootClass(base_type.toString());
    SootField field = getFieldByName(base_class, field_name);
    Local ret = m_jimple.newLocal(getLocalName(), field.getType());

    Value rhs = m_jimple.newInstanceFieldRef(base, field.makeRef());
    Unit u = m_jimple.newAssignStmt(ret, rhs);
    m_assembler.add(u);
    return ret;
  }

  Local refStaticField(Local base, String field_name) {
    Type base_type = base.getType();
    return refStaticField(base_type, field_name);
  }

  Local refStaticField(Type base_type, String field_name) {
    SootClass base_class = Scene.v().getSootClass(base_type.toString());
    SootField field = getFieldByName(base_class, field_name);
    Local ret = m_jimple.newLocal(getLocalName(), field.getType());

    Value rhs = m_jimple.newStaticFieldRef(field.makeRef());
    Unit u = m_jimple.newAssignStmt(ret, rhs);
    m_assembler.add(u);
    return ret;
  }

  public void refInstanceFieldToInput(Local base, String field_name, Local input){
    Type base_type = base.getType();
    SootClass base_class = Scene.v().getSootClass(base_type.toString());
    SootField field = getFieldByName(base_class, field_name);

    Value rhs = m_jimple.newInstanceFieldRef(base, field.makeRef());
    Unit u = m_jimple.newAssignStmt(input, rhs);
    m_assembler.add(u);
  }
 
  public void refInstanceFieldFromInput(Local base, String field_name, Local input){
    Type base_type = base.getType();
    SootClass base_class = Scene.v().getSootClass(base_type.toString());
    SootField field = getFieldByName(base_class, field_name);

    Value rhs = m_jimple.newInstanceFieldRef(base, field.makeRef());
    Unit u = m_jimple.newAssignStmt(rhs, input);
    m_assembler.add(u);
  }

  public String getTypeString(Local local){
    Type type = local.getType();
    return type.toString();
  }

  public Local cast(Type type, Local rhs){
    Local ret = m_jimple.newLocal(getLocalName(), type);
    Value rhs_value = m_jimple.newCastExpr(rhs, type);
    Unit u = m_jimple.newAssignStmt(ret, rhs_value);
    m_assembler.add(u);
    return ret;
  }

  public Local newInstance(String mClassName, Value... params) {
    SootClass soot_class = Scene.v().getSootClass(mClassName);
    Local u1_lhs = m_jimple.newLocal(getLocalName(), soot_class.getType());
    Value u1_rhs = m_jimple.newNewExpr(soot_class.getType());
    Unit u1 = m_jimple.newAssignStmt(u1_lhs, u1_rhs);
    m_assembler.add(u1);

    Type[] arg_types = new Type[params.length];
    for(int i = 0; i < params.length; ++i){
      arg_types[i] = params[i].getType();
    }
    pushMethod(u1_lhs, "<init>", VoidType.v(), arg_types);
    invokeMethodNoRet(u1_lhs, params);

    Local u2_lhs = m_jimple.newLocal(getLocalName(), soot_class.getType());
    Unit u2 = m_jimple.newAssignStmt(u2_lhs, u1_lhs);
    m_assembler.add(u2);
    return u2_lhs;
  }

  public Local newInstanceValueOf(String mClassName, Value param) {
    // Generate mClassName.valueOf(param)
    SootClass soot_class = Scene.v().getSootClass(mClassName);
    Local l_res = m_jimple.newLocal(getLocalName(), soot_class.getType());
    SootMethodRef classForNameRef = soot.Scene.v().makeMethodRef(soot_class,
        "valueOf", Arrays.asList(param.getType()), soot_class.getType(), true);
    Unit u1 = m_jimple.newAssignStmt(l_res, m_jimple.newStaticInvokeExpr(classForNameRef, Arrays.asList(new Value[]{param})));
    m_assembler.add(u1);
    return l_res;
  }

  public Value newArray(Type type, Value size) {
    ArrayType atype = (ArrayType) type;
    if(atype.numDimensions == 1)
      return m_jimple.newNewArrayExpr(atype.baseType, size);
    else {
      ArrayType to_create = ArrayType.v(atype.baseType, atype.numDimensions-1);
      return m_jimple.newNewArrayExpr(to_create, size);
    }
  }

  public void assign(Value lhs, Value rhs) {
    Unit u = m_jimple.newAssignStmt(lhs, rhs);
    m_assembler.add(u);
  }

  public Unit getLastUnitCreated(){
    return m_assembler.getLastUnitCreated();
  }

  public void gotoLabel(String label2) {
    m_assembler.addGoto(label2);
  }

  public void makeVoidCtor() {
    startMethod("<init>", VoidType.v());
    SootClass super_soot_class = m_currClass.getSuperclass();
    Local thisref = refThis();
    pushMethod(super_soot_class.getName(), "<init>", VoidType.v());
    invokeMethodNoRet(thisref);
    returnVoid();
    endMethod();
  }

  public UnitAssembler getAssembler() {
    return m_assembler;
  }

  Local lengthof(Value array) {
    Value rhs = m_jimple.newLengthExpr(array);
    Local lhs = m_jimple.newLocal(getLocalName(), IntType.v());
    Unit u = m_jimple.newAssignStmt(lhs, rhs);
    m_assembler.add(u);
    return lhs;
  }

  Local indexArray(Local base, Value i) {
    Value rhs = m_jimple.newArrayRef(base, i);
    Type type = base.getType();
    if(type instanceof ArrayType == false)
      throw new RuntimeException("How do we handle this case?");
    ArrayType atype = (ArrayType) type;

    Local lhs;
    if(atype.numDimensions == 1){
      lhs = m_jimple.newLocal(getLocalName(), atype.baseType);
    } else {
      Type lhs_type = ArrayType.v(atype.baseType, atype.numDimensions-1);
      lhs = m_jimple.newLocal(getLocalName(), lhs_type);
    }
    Unit u = m_jimple.newAssignStmt(lhs, rhs);
    m_assembler.add(u);
    return lhs;
  }
 
  public void assignArray(Local base, Value i, Local value){
    Value lhs = m_jimple.newArrayRef(base, i);
    Unit u = m_jimple.newAssignStmt(lhs, value);
    m_assembler.add(u);
  }

  void plus(Local i, int add_value) {
    Value rhs = m_jimple.newAddExpr(i, IntConstant.v(add_value));
    Unit u = m_jimple.newAssignStmt(i, rhs);
    m_assembler.add(u);
  }

  void plus(Local i, Value add_value) {
    Value rhs = m_jimple.newAddExpr(i, add_value);
    Unit u = m_jimple.newAssignStmt(i, rhs);
    m_assembler.add(u);
  }

  void mult(Local lhs, Value mult_value){
    Value rhs = m_jimple.newMulExpr(lhs, mult_value);
    Unit u = m_jimple.newAssignStmt(lhs, rhs);
    m_assembler.add(u);
  }

  void noOp() {
    Unit u = m_jimple.newNopStmt();
    m_assembler.add(u);
  }
 
  void assignElementToArray(Local base, Value rhs, Value i) {
    Value lhs = m_jimple.newArrayRef(base, i);
    Unit u = m_jimple.newAssignStmt(lhs, rhs);
    m_assembler.add(u);
  }

  public void println(String message){
    Type system = RefType.v("java.lang.System");
    Local out = refStaticField(system, "out");
    Type string = RefType.v("java.lang.String");
    pushMethod(out, "println", VoidType.v(), string);
    invokeMethodNoRet(out, StringConstant.v(message));
  }

  void println(Value number) {
    Type system = RefType.v("java.lang.System");
    Local out = refStaticField(system, "out");
    pushMethod(out, "println", VoidType.v(), IntType.v());
    invokeMethodNoRet(out, number);
  }
 
  void printlnLong(Value number) {
    Type system = RefType.v("java.lang.System");
    Local out = refStaticField(system, "out");
    pushMethod(out, "println", VoidType.v(), LongType.v());
    invokeMethodNoRet(out, number);
  }

  SootClass getSootClass() {
    return m_currClass;
  }

  Local classConstant(Type type) {
    String class_name = convertToConstant(type);
    Value curr = ClassConstant.v(class_name);
    Local ret = m_jimple.newLocal(getLocalName(), curr.getType());
    Unit u = m_jimple.newAssignStmt(ret, curr);
    m_assembler.add(u);
    return ret;
  }

  private String convertToConstant(Type type) {
    if(type instanceof ArrayType){
      ArrayType array_type = (ArrayType) type;
      String prefix = "";
      int dims = array_type.numDimensions;
      for(int i = 0; i < dims; ++i){
        prefix += "[";
      }
      String base_string = convertToConstant(array_type.baseType);
      if(array_type.baseType instanceof RefType){
        return prefix + "L" + base_string + ";";
      } else {
        return prefix + base_string;
      }
    } else if(type instanceof RefType){
      RefType ref_type = (RefType) type;
      return ref_type.getSootClass().getName().replace(".", "/");
    } else if(type instanceof PrimType){
      if(type.equals(BooleanType.v())){
        return "Z";
      } else if(type.equals(ByteType.v())){
        return "B";
      } else if(type.equals(ShortType.v())){
        return "S";
      } else if(type.equals(CharType.v())){
        return "C";
      } else if(type.equals(IntType.v())){
        return "I";
      } else if(type.equals(LongType.v())){
        return "J";
      } else if(type.equals(FloatType.v())){
        return "F";
      } else if(type.equals(DoubleType.v())){
        return "D";
      }
    }
   
    throw new RuntimeException("please report bug in BytecodeLanguage.convertToConstant");
  }

  private SootField getFieldByName(SootClass base_class, String field_name) {
    List<String> queue = new LinkedList<String>();
    queue.add(base_class.getName());
    while(queue.isEmpty() == false){
      String curr_class = queue.get(0);
      queue.remove(0);
      SootClass soot_class = Scene.v().getSootClass(curr_class);
      if(soot_class.declaresFieldByName(field_name)){
        return soot_class.getFieldByName(field_name);
      }
      if(soot_class.hasSuperclass()){
        queue.add(soot_class.getSuperclass().getName());
      }
      if(soot_class.hasOuterClass()){
        queue.add(soot_class.getOuterClass().getName());
      }
    }
    throw new RuntimeException("cannot find field: "+field_name+" in "+base_class.getName());
  }
}
TOP

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

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.