Package backend

Source Code of backend.ExprCodeGenerator

package backend;

import java.util.ArrayList;

import soot.Local;
import soot.Scene;
import soot.SootClass;
import soot.SootMethodRef;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.jimple.Constant;
import soot.jimple.IntConstant;
import soot.jimple.Jimple;
import soot.jimple.NopStmt;
import soot.jimple.StaticInvokeExpr;
import soot.jimple.StringConstant;
import soot.util.Chain;
import ast.AddExpr;
import ast.ArrayIndex;
import ast.ArrayLiteral;
import ast.Assignment;
import ast.BinaryExpr;
import ast.BooleanLiteral;
import ast.Call;
import ast.CompExpr;
import ast.DivExpr;
import ast.EqExpr;
import ast.Expr;
import ast.FunctionDeclaration;
import ast.GeqExpr;
import ast.GtExpr;
import ast.IntLiteral;
import ast.LeqExpr;
import ast.LtExpr;
import ast.ModExpr;
import ast.Module;
import ast.MulExpr;
import ast.NegExpr;
import ast.NeqExpr;
import ast.Parameter;
import ast.StringLiteral;
import ast.SubExpr;
import ast.VarDecl;
import ast.VarName;
import ast.Visitor;

/**
* This class is in charge of creating Jimple code for a given expression (and its nested
* expressions, if applicable).
*/
/**
* TOOD
* @author Danyang
* Finally, the expression code generator ExprCodeGenerator is again a visitor class, with different methods
performing code generation for different kinds of expressions, each returning a Soot Value. It defines a utility
method wrap that checks whether some value can be used as an operand (i.e., it is a literal or a variable); if not, it
generates a new assignment statement storing the argument value into a fresh temporary variable, and returns that
temporary variable. Hence, whenever you need to use the value returned by a recursive invocation of the
expression code generator as an operand to another operator, you should use wrap to ensure that the result is a
valid Jimple expression. Several visitor methods have already been defined, study them carefully. The TODO
comments show you which ones you need to implement yourself. 
*/
public class ExprCodeGenerator extends Visitor<Value> {
  /** The {@link FunctionCodeGenerator} that instantiated this object. */
  private final FunctionCodeGenerator fcg;
 
  /** We cache the statement list of the enclosing function for convenience. */
  private final Chain<Unit> units;
 
  private ExprCodeGenerator(FunctionCodeGenerator fcg) {
    this.fcg = fcg;
    this.units = fcg.getBody().getUnits();
  }
 
  /**
   * Ensures that the given value can be used as an operand; that is, if the
   * value is not a {@link Local} or a {@link Constant}, this method allocates
   * a new temporary variable and stores the value into that temporary.
   */
  private Value wrap(Value v) {
    if(v == null || v instanceof Local || v instanceof Constant) {
      return v;
    } else {
      Local temp = fcg.mkTemp(v.getType());
      units.add(Jimple.v().newAssignStmt(temp, v));
      return temp;
    }
  }

  /**
   * Convenience method to generate code for an expression and wrap it.
   * FOR OUTSIDE USAGE
   */
  public static Value generate(Expr expr, FunctionCodeGenerator fcg) {
    ExprCodeGenerator gen = new ExprCodeGenerator(fcg);
    return gen.wrap(expr.accept(gen));
  }
 
  /** Generate code for an assignment. */
  @Override
  public Value visitAssignment(Assignment nd) {
    // note that the left hand side should _not_ be wrapped!
    Value lhs = nd.getLHS().accept(this),
        rhs = wrap(nd.getRHS().accept(this));
    units.add(Jimple.v().newAssignStmt(lhs, rhs));
    return rhs;
  }
 
  /** Generate code for an integer literal. */
  @Override
  public Value visitIntLiteral(IntLiteral nd) {
    /* DONE: return something meaningful here */
    //Value value = ExprCodeGenerator.generate(nd, this.fcg); // recursive, stack overflow
    Value value = IntConstant.v( // no need wrap
            nd.getValue().intValue()
          );
    // why not units.add(...)? because only add statement, not expression
    return value;
  }
 
  /** Generate code for a string literal. */
  @Override
  public Value visitStringLiteral(StringLiteral nd) {
    /* DONE: return something meaningful here */
    Value value = StringConstant.v( // no need wrap
            nd.getValue()
          );
    return value;
  }
 
  /** Generate code for a Boolean literal. */
  @Override
  public Value visitBooleanLiteral(BooleanLiteral nd) {
    /* DONE: return something meaningful here (hint: translate 'true' to integer
     *       constant 1, 'false' to integer constant 0) */
    Boolean truthBoolean = nd.getValue();
    Value value;
    if(truthBoolean) {
      value = IntConstant.v(1); // no need wrap
    }
    else {
      value = IntConstant.v(0); // no need wrap
    }
    return value;
  }
 
  /** Generate code for an array literal. */
  @Override
  public Value visitArrayLiteral(ArrayLiteral nd) {
    Type elttp = SootTypeUtil.getSootType(nd.getElement(0).type());
    // create a new array with the appropriate number of elements
    Value array = wrap(Jimple.v().newNewArrayExpr(elttp, IntConstant.v(nd.getNumElement())));
    for(int i=0;i<nd.getNumElement();++i) {
      // generate code to store the individual expressions into the elements of the array
      Value elt = wrap(nd.getElement(i).accept(this));
      units.add(Jimple.v().newAssignStmt(Jimple.v().newArrayRef(array, IntConstant.v(i)), elt));
    }
    return array;
  }
 
  /** Generate code for an array index expression. */
  /**
   * Index (the element)
   */
  @Override
  public Value visitArrayIndex(ArrayIndex nd) {
    /* DONE: generate code for array index */
    Value index = this.wrap(nd.getIndex().accept(this));
    Value base = this.wrap(nd.getBase().accept(this)); // need wrap due to int [][] a;
    return Jimple.v().newArrayRef(base, index);
  }
 
  /** Generate code for a variable name. */
  @Override
  public Value visitVarName(VarName nd) {
    VarDecl decl = nd.decl();
    // determine whether this name refers to a local or to a field
    if(decl.isLocal()) {
      return fcg.getSootLocal(decl);
    } else {
      SootClass declaringClass = fcg.getModuleCodeGenerator().getProgramCodeGenerator().getSootClass(decl.getModule());
      Type fieldType = SootTypeUtil.getSootType(decl.getTypeName().getDescriptor());
      return Jimple.v().newStaticFieldRef(Scene.v().makeFieldRef(declaringClass, decl.getName(), fieldType, true));
    }
  }
 
  /** Generate code for a binary expression. */
  @Override
  public Value visitBinaryExpr(BinaryExpr nd) {
    /* DONE: generate code for binary expression here; you can either use a visitor
     *       to determine the type of binary expression you are dealing with, or
     *       generate code in the more specialized visitor methods visitAddExpr,
     *       visitSubExpr, etc., instead
     */
    final Value lhsValue = this.wrap(nd.getLeft().accept(this));
    final Value rhsValue = this.wrap(nd.getRight().accept(this));
    Value binValue = this.wrap(nd.accept(new Visitor<Value>() {
      @Override
      public Value visitAddExpr(AddExpr nd) {
        return Jimple.v().newAddExpr(lhsValue, rhsValue);
      }
      @Override
      public Value visitSubExpr(SubExpr nd) {
        return Jimple.v().newSubExpr(lhsValue, rhsValue);
      }
      @Override
      public Value visitMulExpr(MulExpr nd) {
        return Jimple.v().newMulExpr(lhsValue, rhsValue);
      }
      @Override
      public Value visitDivExpr(DivExpr nd) {
        return Jimple.v().newDivExpr(lhsValue, rhsValue);
      }
      @Override
      public Value visitModExpr(ModExpr nd) {
        // difference between Mod and Rem
        return Jimple.v().newRemExpr(lhsValue, rhsValue);
      }
   
    }));
   
    return binValue;
  }
 
  /** Generate code for a comparison expression. */
  @Override
  public Value visitCompExpr(CompExpr nd) {
    final Value left = wrap(nd.getLeft().accept(this)),
          right = wrap(nd.getRight().accept(this));
    Value res = nd.accept(new Visitor<Value>() {
      @Override
      public Value visitEqExpr(EqExpr nd) {
        return Jimple.v().newEqExpr(left, right);
      }
      @Override
      public Value visitNeqExpr(NeqExpr nd) {
        return Jimple.v().newNeExpr(left, right);
      }
      @Override
      public Value visitLtExpr(LtExpr nd) {
        return Jimple.v().newLtExpr(left, right);
      }
      @Override
      public Value visitGtExpr(GtExpr nd) {
        return Jimple.v().newGtExpr(left, right);
      }
      @Override
      public Value visitLeqExpr(LeqExpr nd) {
        return Jimple.v().newLeExpr(left, right);
      }
      @Override
      public Value visitGeqExpr(GeqExpr nd) {
        return Jimple.v().newGeExpr(left, right);
      }
    });
    // compute a result of 0 or 1 depending on the truth value of the expression
    Local resvar = fcg.mkTemp(SootTypeUtil.getSootType(nd.type()));
    units.add(Jimple.v().newAssignStmt(resvar, IntConstant.v(1)));
    NopStmt join = Jimple.v().newNopStmt();
    units.add(Jimple.v().newIfStmt(res, join));
    units.add(Jimple.v().newAssignStmt(resvar, IntConstant.v(0)));
    units.add(join);
    return resvar;
  }
 
  /** Generate code for a negation expression. */
  @Override
  public Value visitNegExpr(NegExpr nd) {
    /* DONE: generate code for negation expression */
    Value value = this.wrap(nd.getOperand().accept(this));
    return Jimple.v().newNegExpr(value);
  }
 
  /** Generate code for a function call. */
  @Override
  public Value visitCall(Call nd) {
    String calleeName = nd.getCallee().getName();
    FunctionDeclaration calleeDecl = nd.getCallTarget();
    Module calleeModule = calleeDecl.getModule();
    ArrayList<Type> parmTypes = new ArrayList<Type>(calleeDecl.getNumParameter());
    for(Parameter parm : calleeDecl.getParameters())
      parmTypes.add(SootTypeUtil.getSootType(parm.type()));
    Type rettp = SootTypeUtil.getSootType(calleeDecl.getReturnType().getDescriptor());
   
    // compute reference to callee
    SootClass calleeSootClass = fcg.getModuleCodeGenerator().getProgramCodeGenerator().getSootClass(calleeModule);
    SootMethodRef callee = Scene.v().makeMethodRef(calleeSootClass, calleeName, parmTypes, rettp, true);
   
    // prepare arguments
    Value[] args = new Value[nd.getNumArgument()];
    for(int i=0;i<args.length;++i)
      args[i] = wrap(nd.getArgument(i).accept(this));
   
    // assemble invoke expression
    StaticInvokeExpr invk = Jimple.v().newStaticInvokeExpr(callee, args);
   
    // decide what to do with the result
    if(rettp == soot.VoidType.v()) {
      units.add(Jimple.v().newInvokeStmt(invk));
      return null;
    } else {
      Local res = fcg.mkTemp(rettp);
      units.add(Jimple.v().newAssignStmt(res, invk));
      return res;
    }   
  }
}
TOP

Related Classes of backend.ExprCodeGenerator

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.