com.googlecode.dex2jar.ir.ts.RemoveConstantFromSSA Maven / Gradle / Ivy
The newest version!
package com.googlecode.dex2jar.ir.ts;
import java.util.*;
import com.googlecode.dex2jar.ir.IrMethod;
import com.googlecode.dex2jar.ir.expr.Constant;
import com.googlecode.dex2jar.ir.expr.Exprs;
import com.googlecode.dex2jar.ir.expr.Local;
import com.googlecode.dex2jar.ir.expr.Value;
import com.googlecode.dex2jar.ir.stmt.AssignStmt;
import com.googlecode.dex2jar.ir.stmt.LabelStmt;
import com.googlecode.dex2jar.ir.stmt.Stmt;
/**
* 1. Remove constant AssignStmt.
*
*
* a = "123";
* return a;
*
*
* to
*
*
* return "123";
*
*
* 2. Remove Phi if all value are equal
*
*
* a = "123";
* // ...
* b = "123";
* // ...
* c = PHI(a, b);
* return c;
*
*
* to
*
*
* // ...
* return "123";
*
*/
public class RemoveConstantFromSSA extends StatedTransformer {
public static final Comparator LOCAL_COMPARATOR = new Comparator() {
@Override
public int compare(Local local, Local t1) {
return Integer.compare(local._ls_index, t1._ls_index);
}
};
@Override
public boolean transformReportChanged(IrMethod method) {
boolean changed = false;
List assignStmtList = new ArrayList<>();
Map cstMap = new HashMap<>();
for (Stmt p = method.stmts.getFirst(); p != null; p = p.getNext()) {
if (p.st == Stmt.ST.ASSIGN) {
AssignStmt as = (AssignStmt) p;
if (as.getOp1().vt == Value.VT.LOCAL) {
if (as.getOp2().vt == Value.VT.CONSTANT) {
assignStmtList.add(as);
cstMap.put((Local) as.getOp1(), ((Constant) as.getOp2()).value);
} else if (as.getOp2().vt == Value.VT.LOCAL) {
cstMap.put((Local) as.getOp1(), as.getOp2());
}
}
}
}
if (assignStmtList.size() == 0) {
return false;
}
RemoveLocalFromSSA.fixReplace(cstMap);
final Map toReplace = new HashMap<>();
Set usedInPhi = new HashSet<>();
List phiLabels = method.phiLabels;
if (phiLabels != null) {
boolean loopAgain = true;
while (loopAgain) {
loopAgain = false;
usedInPhi.clear();
for (Iterator it = phiLabels.iterator(); it.hasNext();) {
LabelStmt labelStmt = it.next();
if (labelStmt.phis != null) {
for (Iterator it2 = labelStmt.phis.iterator(); it2.hasNext();) {
AssignStmt phi = it2.next();
Value[] vs = phi.getOp2().getOps();
Object sameCst = null;
boolean allEqual = true;
for (Value p : vs) {
Object cst = cstMap.get(p);
if (cst == null) {
allEqual = false;
break;
}
if (sameCst == null) {
sameCst = cst;
} else if (!sameCst.equals(cst)) {
allEqual = false;
break;
}
}
if (allEqual) { // all are same constant
cstMap.put((Local) phi.getOp1(), sameCst);
if (sameCst instanceof Local) {
phi.setOp2((Value) sameCst);
} else {
phi.setOp2(Exprs.nConstant(sameCst));
assignStmtList.add(phi);
}
it2.remove();
method.stmts.insertAfter(labelStmt, phi);
changed = true;
loopAgain = true; // loop again
} else {
usedInPhi.addAll(Arrays.asList(phi.getOp2().getOps()));
}
}
if (labelStmt.phis.size() == 0) {
it.remove();
}
}
}
}
}
for (Iterator it = assignStmtList.iterator(); it.hasNext();) {
AssignStmt as = it.next();
if (!usedInPhi.contains(as.getOp1())) {
it.remove();
method.stmts.remove(as);
method.locals.remove(as.getOp1());
changed = true;
}
toReplace.put((Local) as.getOp1(), as.getOp2());
}
Cfg.travelMod(method.stmts, new Cfg.TravelCallBack() {
@Override
public Value onAssign(Local v, AssignStmt as) {
return v;
}
@Override
public Value onUse(Local v) {
Value n = toReplace.get(v);
return n == null ? v : n.clone();
}
}, false);
return changed;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy