com.googlecode.dex2jar.ir.ts.array.ArrayElementTransformer Maven / Gradle / Ivy
The newest version!
package com.googlecode.dex2jar.ir.ts.array;
import com.googlecode.dex2jar.ir.IrMethod;
import com.googlecode.dex2jar.ir.StmtTraveler;
import com.googlecode.dex2jar.ir.expr.*;
import com.googlecode.dex2jar.ir.stmt.AssignStmt;
import com.googlecode.dex2jar.ir.stmt.LabelStmt;
import com.googlecode.dex2jar.ir.stmt.Stmt;
import com.googlecode.dex2jar.ir.stmt.Stmts;
import com.googlecode.dex2jar.ir.ts.Cfg;
import com.googlecode.dex2jar.ir.ts.StatedTransformer;
import java.lang.reflect.Array;
import java.util.*;
/**
* require SSA, element index are const
*
* transformer
*
* ...
* a[4]="abc"
* return a[4]
*
* to
*
* ...
* a[4]="abc"
* return "abc"
*
*/
public class ArrayElementTransformer extends StatedTransformer {
@Override
public boolean transformReportChanged(IrMethod method) {
Set arrays = searchForArrayObject(method);
if (arrays.size() == 0) {
return false;
}
for (Local local : method.locals) {
local._ls_index = -1;
}
int i = 0;
for (Local local : arrays) {
local._ls_index = i++;
}
final int size = i;
Cfg.createCFG(method);
final List values = new ArrayList<>();
final List used = new ArrayList<>();
Cfg.dfs(method.stmts, new Cfg.FrameVisitor() {
Set phis = new HashSet<>();
@Override
public ArrayValue[] merge(ArrayValue[] srcFrame, ArrayValue[] distFrame, Stmt src, Stmt dist) {
if (dist.st == Stmt.ST.LABEL) {
LabelStmt labelStmt = (LabelStmt) dist;
if (labelStmt.phis != null) {
for (AssignStmt phi : labelStmt.phis) {
int idx = ((Local) phi.getOp1())._ls_index;
if (idx >= 0) {
phis.add(idx);
}
}
}
}
if (distFrame == null) {
distFrame = new ArrayValue[size];
for (int i = 0; i < size; i++) {
if (phis.contains(i)) {
ArrayValue aov = new ArrayValue();
values.add(aov);
aov.s = ArrayValue.S.UNKNOWN;
aov.indexType = ArrayValue.IndexType.NONE;
aov.stmt = dist;
distFrame[i] = aov;
} else {
ArrayValue arc = srcFrame[i];
if (arc != null) {
ArrayValue aov = new ArrayValue();
values.add(aov);
aov.s = ArrayValue.S.INHERIT;
aov.indexType = ArrayValue.IndexType.NONE;
aov.stmt = dist;
aov.parent = arc;
distFrame[i] = aov;
}
}
}
} else {
for (int i = 0; i < size; i++) {
if (phis.contains(i)) {
continue;
}
ArrayValue arc = srcFrame[i];
ArrayValue aov = distFrame[i];
if (arc != null && aov != null) {
if (aov.parent == null) {
aov.parent = arc;
} else if (!aov.parent.equals(arc)) {
if (aov.otherParents == null) {
aov.otherParents = new HashSet<>();
}
aov.otherParents.add(arc);
}
}
}
}
phis.clear();
return distFrame;
}
@Override
public ArrayValue[] initFirstFrame(Stmt first) {
return new ArrayValue[size];
}
ArrayValue[] tmp = new ArrayValue[size];
Stmt currentStmt;
@Override
public ArrayValue[] exec(ArrayValue[] frame, Stmt stmt) {
currentStmt = stmt;
System.arraycopy(frame, 0, tmp, 0, size);
if (stmt.st == Stmt.ST.ASSIGN) {
// create an array
if (stmt.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) stmt.getOp1();
use(stmt.getOp2());
if (local._ls_index >= 0) {
Value op2 = stmt.getOp2();
if (op2.vt == Value.VT.NEW_ARRAY) {
ArrayValue av = new ArrayValue();
av.s = ArrayValue.S.DEFAULT;
av.size = op2.getOp();
values.add(av);
tmp[local._ls_index] = av;
} else if (op2.vt == Value.VT.FILLED_ARRAY) {
ArrayValue av = new ArrayValue();
av.s = ArrayValue.S.DEFAULT;
av.indexType = ArrayValue.IndexType.CONST;
av.stmt = stmt;
FilledArrayExpr fae = (FilledArrayExpr) stmt.getOp2();
av.size = Exprs.nInt(fae.getOps().length);
Value[] ops = fae.getOps();
for (int i = 0; i < ops.length; i++) {
av.elements1.put(i, ops[i]);
}
values.add(av);
tmp[local._ls_index] = av;
} else if (op2.vt == Value.VT.CONSTANT) {
Object cst = ((Constant) op2).value;
if (cst != null && !cst.equals(Constant.Null) && cst.getClass().isArray()) {
ArrayValue av = new ArrayValue();
av.s = ArrayValue.S.DEFAULT;
av.indexType = ArrayValue.IndexType.CONST;
av.stmt = stmt;
int size = Array.getLength(cst);
av.size = Exprs.nInt(size);
for (int i = 0; i < size; i++) {
av.elements1.put(i, Exprs.nConstant(Array.get(cst, size)));
}
values.add(av);
tmp[local._ls_index] = av;
} else {
ArrayValue av = new ArrayValue();
values.add(av);
av.s = ArrayValue.S.UNKNOWN;
av.indexType = ArrayValue.IndexType.NONE;
av.stmt = stmt;
tmp[local._ls_index] = av;
}
} else {
ArrayValue av = new ArrayValue();
values.add(av);
av.s = ArrayValue.S.UNKNOWN;
av.indexType = ArrayValue.IndexType.NONE;
av.stmt = stmt;
tmp[local._ls_index] = av;
}
}
// assign index1
} else if (stmt.getOp1().vt == Value.VT.ARRAY) {
use(stmt.getOp2());
ArrayExpr ae = (ArrayExpr) stmt.getOp1();
if (ae.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) ae.getOp1();
Value index = ae.getOp2();
if (local._ls_index >= 0) {
if (index.vt == Value.VT.CONSTANT) {
ArrayValue parent = tmp[local._ls_index];
ArrayValue av = new ArrayValue();
values.add(av);
av.parent = parent;
av.elements1.put(((Number) (((Constant) index).value)).intValue(), stmt.getOp2());
av.indexType = ArrayValue.IndexType.CONST;
av.s = ArrayValue.S.INHERIT;
av.stmt = stmt;
tmp[local._ls_index] = av;
} else if (index.vt == Value.VT.LOCAL) {
ArrayValue parent = tmp[local._ls_index];
ArrayValue av = new ArrayValue();
values.add(av);
av.parent = parent;
av.elements1.put(index, stmt.getOp2());
av.indexType = ArrayValue.IndexType.LOCAL;
av.s = ArrayValue.S.INHERIT;
av.stmt = stmt;
tmp[local._ls_index] = av;
} else {
ArrayValue av = new ArrayValue();
values.add(av);
av.s = ArrayValue.S.UNKNOWN;
av.indexType = ArrayValue.IndexType.NONE;
av.stmt = stmt;
tmp[local._ls_index] = av;
}
} else {
use(stmt.getOp1());
}
} else {
use(stmt.getOp1());
}
} else {
use(stmt.getOp1());
use(stmt.getOp2());
}
// assign index2
} else if (stmt.st == Stmt.ST.FILL_ARRAY_DATA) {
if (stmt.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) stmt.getOp1();
if (local._ls_index >= 0) {
Object array = ((Constant) stmt.getOp2()).value;
ArrayValue parent = tmp[local._ls_index];
ArrayValue av = new ArrayValue();
values.add(av);
av.parent = parent;
int size = Array.getLength(array);
av.size = Exprs.nInt(size);
for (int i = 0; i < size; i++) {
av.elements1.put(i, Exprs.nConstant(Array.get(array, i)));
}
av.indexType = ArrayValue.IndexType.CONST;
av.s = ArrayValue.S.INHERIT;
av.stmt = stmt;
tmp[local._ls_index] = av;
}
} else {
use(stmt.getOp1());
}
} else {
switch (stmt.et) {
case E0:
break;
case E1:
use(stmt.getOp());
break;
case E2:
use(stmt.getOp1());
use(stmt.getOp2());
break;
case En:
throw new RuntimeException();
}
}
return tmp;
}
private void use(Value v) {
switch (v.et) {
case E0:
break;
case E1:
use(v.getOp());
break;
case E2:
Value op1 = v.getOp1();
Value op2 = v.getOp2();
use(op1);
use(op2);
if (v.vt == Value.VT.ARRAY) {
if (op1.vt == Value.VT.LOCAL && (op2.vt == Value.VT.LOCAL || op2.vt == Value.VT.CONSTANT)) {
Local local = (Local) op1;
if (local._ls_index > 0) {
used.add(currentStmt);
}
}
}
break;
case En:
for (Value op : v.getOps()) {
use(op);
}
break;
}
}
});
// TODO travel stmt to find must-be array element
for (Stmt p : method.stmts) {
}
new StmtTraveler() {
@Override
public Value travel(Value op) {
op = super.travel(op);
if (op.vt == Value.VT.ARRAY) {
}
return op;
}
}.travel(method.stmts);
return false;
}
public static void main(String... args) {
IrMethod m = new IrMethod();
m.isStatic = true;
m.name = "a";
m.args = new String[0];
m.ret = "[Ljava/lang/String;";
m.owner = "La;";
Local array = Exprs.nLocal(1);
m.locals.add(array);
m.stmts.add(Stmts.nAssign(array, Exprs.nNewArray("Ljava/lang/String;", Exprs.nInt(2))));
m.stmts.add(Stmts.nAssign(Exprs.nArray(array, Exprs.nInt(1), "Ljava/lang/String;"), Exprs.nString("123")));
m.stmts.add(Stmts.nAssign(Exprs.nArray(array, Exprs.nInt(0), "Ljava/lang/String;"), Exprs.nString("456")));
m.stmts.add(Stmts.nReturn(array));
new ArrayElementTransformer().transform(m);
}
private Set searchForArrayObject(IrMethod method) {
final Set arrays = new HashSet<>();
for (Stmt stmt : method.stmts) {
if (stmt.st == Stmt.ST.ASSIGN) {
// create an array
if (stmt.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) stmt.getOp1();
if (stmt.getOp2().vt == Value.VT.NEW_ARRAY || stmt.getOp2().vt == Value.VT.FILLED_ARRAY) {
arrays.add(local);
}
// assign index1
} else if (stmt.getOp1().vt == Value.VT.ARRAY) {
ArrayExpr ae = (ArrayExpr) stmt.getOp1();
if (ae.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) ae.getOp1();
arrays.add(local);
}
}
// assign index2
} else if (stmt.st == Stmt.ST.FILL_ARRAY_DATA) {
if (stmt.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) stmt.getOp1();
arrays.add(local);
}
}
}
return arrays;
}
static class ArrayValue {
enum S {
/**
* all element are default value. that is null for object and 0 for primitive
*/
DEFAULT,
/**
* all element are unknown value
*/
UNKNOWN,
/**
* the element value is based on its parent
*/
INHERIT
}
enum IndexType {
CONST, LOCAL, NONE
}
IndexType indexType = IndexType.NONE;
S s = S.INHERIT;
ArrayValue parent;
Value size;
Set otherParents;
Map
© 2015 - 2024 Weber Informatics LLC | Privacy Policy