package soot.sootify;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import soot.PatchingChain;
import soot.Unit;
import soot.UnitBox;
import soot.Value;
import soot.jimple.AssignStmt;
import soot.jimple.BreakpointStmt;
import soot.jimple.EnterMonitorStmt;
import soot.jimple.ExitMonitorStmt;
import soot.jimple.GotoStmt;
import soot.jimple.IdentityStmt;
import soot.jimple.IfStmt;
import soot.jimple.IntConstant;
import soot.jimple.InvokeStmt;
import soot.jimple.LookupSwitchStmt;
import soot.jimple.NopStmt;
import soot.jimple.RetStmt;
import soot.jimple.ReturnStmt;
import soot.jimple.ReturnVoidStmt;
import soot.jimple.Stmt;
import soot.jimple.StmtSwitch;
import soot.jimple.TableSwitchStmt;
import soot.jimple.ThrowStmt;
class StmtTemplatePrinter implements StmtSwitch {
private final TemplatePrinter p;
private final ValueTemplatePrinter vtp; //text for expression
private List<Unit> jumpTargets = new ArrayList<Unit>();
public StmtTemplatePrinter(TemplatePrinter templatePrinter, PatchingChain<Unit> units) {
this.p = templatePrinter;
this.vtp = new ValueTemplatePrinter(p);
for(Unit u: units) {
for(UnitBox ub: u.getUnitBoxes()) {
jumpTargets.add(ub.getUnit());
}
}
final List<Unit> unitsList = new ArrayList<Unit>(units);
Collections.sort(jumpTargets,new Comparator<Unit>() {
public int compare(Unit o1, Unit o2) {
return unitsList.indexOf(o1)-unitsList.indexOf(o2);
}
});
for(int i=0;i<jumpTargets.size();i++) {
p.println("NopStmt jumpTarget"+i+"= Jimple.v().newNopStmt();");
}
}
private String nameOfJumpTarget(Unit u) {
if(!isJumpTarget(u)) {
throw new InternalError("not a jumpt target! "+u);
}
return "jumpTarget"+jumpTargets.indexOf(u);
}
private boolean isJumpTarget(Unit u) {
return jumpTargets.contains(u);
}
private String printValueAssignment(Value value, String varName) {
return vtp.printValueAssignment(value, varName);
}
private void printStmt(Unit u, String... ops) {
String stmtClassName = u.getClass().getSimpleName();
if(stmtClassName.charAt(0)=='J') stmtClassName = stmtClassName.substring(1);
if(isJumpTarget(u)) {
String nameOfJumpTarget = nameOfJumpTarget(u);
p.println("units.add("+nameOfJumpTarget+");");
}
p.print("units.add(");
printFactoryMethodCall(stmtClassName, ops);
p.printlnNoIndent(");");
}
private void printFactoryMethodCall(String stmtClassName, String... ops) {
p.printNoIndent("Jimple.v().new");
p.printNoIndent(stmtClassName);
p.printNoIndent("(");
int i=1;
for(String op: ops) {
p.printNoIndent(op);
if(i<ops.length) {
p.printNoIndent(",");
}
i++;
}
p.printNoIndent(")");
}
public void caseThrowStmt(ThrowStmt stmt) {
String varName = printValueAssignment(stmt.getOp(),"op");
printStmt(stmt, varName);
}
@SuppressWarnings("unchecked")
public void caseTableSwitchStmt(TableSwitchStmt stmt) {
p.openBlock();
String varName = printValueAssignment(stmt.getKey(),"key");
int lowIndex= stmt.getLowIndex();
p.println("int lowIndex=" + lowIndex + ";");
int highIndex= stmt.getHighIndex();
p.println("int highIndex=" + highIndex + ";");
p.println("List<Unit> targets = new LinkedList<Unit>();");
for(Stmt s: (List<Stmt>)stmt.getTargets()) {
String nameOfJumpTarget = nameOfJumpTarget(s);
p.println("targets.add("+nameOfJumpTarget+")");
}
Unit defaultTarget = stmt.getDefaultTarget();
p.println("Unit defaultTarget = " + nameOfJumpTarget(defaultTarget) + ";");
printStmt(stmt, varName, "lowIndex", "highIndex", "targets", "defaultTarget");
p.closeBlock();
}
public void caseReturnVoidStmt(ReturnVoidStmt stmt) {
printStmt(stmt);
}
public void caseReturnStmt(ReturnStmt stmt) {
String varName = printValueAssignment(stmt.getOp(), "retVal");
printStmt(stmt,varName);
}
public void caseRetStmt(RetStmt stmt) {
String varName = printValueAssignment(stmt.getStmtAddress(), "stmtAddress");
printStmt(stmt,varName);
}
public void caseNopStmt(NopStmt stmt) {
printStmt(stmt);
}
@SuppressWarnings("unchecked")
public void caseLookupSwitchStmt(LookupSwitchStmt stmt) {
p.openBlock();
String keyVarName = printValueAssignment(stmt.getKey(), "key");
p.println("List<IntConstant> lookupValues = new LinkedList<IntConstant>();");
int i=0;
for(IntConstant c: (List<IntConstant>)stmt.getLookupValues()) {
vtp.suggestVariableName("lookupValue"+i);
c.apply(vtp);
i++;
p.println("lookupValues.add(lookupValue"+i+");");
}
p.println("List<Unit> targets = new LinkedList<Unit>();");
for(Stmt s: (List<Stmt>)stmt.getTargets()) {
String nameOfJumpTarget = nameOfJumpTarget(s);
p.println("targets.add("+nameOfJumpTarget+")");
}
Unit defaultTarget = stmt.getDefaultTarget();
p.println("Unit defaultTarget=" + defaultTarget.toString() + ";");
printStmt(stmt, keyVarName, "lookupValues", "targets", "defaultTarget");
p.closeBlock();
}
public void caseInvokeStmt(InvokeStmt stmt) {
String varName = printValueAssignment(stmt.getInvokeExpr(), "ie");
printStmt(stmt,varName);
}
public void caseIfStmt(IfStmt stmt) {
String varName = printValueAssignment(stmt.getCondition(), "condition");
Unit target = stmt.getTarget();
vtp.suggestVariableName("target");
String targetName = vtp.getLastAssignedVarName();
p.println("Unit "+targetName+"=" + nameOfJumpTarget(target) + ";");
printStmt(stmt,varName,targetName);
}
public void caseIdentityStmt(IdentityStmt stmt) {
String varName = printValueAssignment(stmt.getLeftOp(), "lhs");
String varName2 = printValueAssignment(stmt.getRightOp(), "idRef");
printStmt(stmt,varName,varName2);
}
public void caseGotoStmt(GotoStmt stmt) {
Unit target = stmt.getTarget();
vtp.suggestVariableName("target");
String targetName = vtp.getLastAssignedVarName();
p.println("Unit "+targetName+"=" + nameOfJumpTarget(target) + ";");
printStmt(stmt,targetName);
}
public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
String varName = printValueAssignment(stmt.getOp(), "monitor");
printStmt(stmt,varName);
}
public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
String varName = printValueAssignment(stmt.getOp(), "monitor");
printStmt(stmt,varName);
}
public void caseBreakpointStmt(BreakpointStmt stmt) {
printStmt(stmt);
}
public void caseAssignStmt(AssignStmt stmt) {
String varName = printValueAssignment(stmt.getLeftOp(), "lhs");
String varName2 = printValueAssignment(stmt.getRightOp(), "rhs");
printStmt(stmt,varName,varName2);
}
public void defaultCase(Object obj) {
throw new InternalError("should never be called");
}
}