Search in sources :

Example 31 with Stmt

use of com.googlecode.dex2jar.ir.stmt.Stmt in project dex2jar by pxb1988.

the class FillArrayTransformer method makeSureArrayUsedAfterAllElementAssigned0.

private void makeSureArrayUsedAfterAllElementAssigned0(IrMethod method, final Map<Local, ArrayObject> arraySizes) {
    int i = 0;
    for (Local local : arraySizes.keySet()) {
        local._ls_index = i++;
    }
    final int size = i;
    final List<ArrayObjectValue> values = new ArrayList<>();
    Cfg.dfs(method.stmts, new Cfg.FrameVisitor<ArrayObjectValue[]>() {

        @Override
        public ArrayObjectValue[] merge(ArrayObjectValue[] srcFrame, ArrayObjectValue[] distFrame, Stmt src, Stmt dist) {
            if (distFrame == null) {
                distFrame = new ArrayObjectValue[size];
                for (int i = 0; i < size; i++) {
                    ArrayObjectValue arc = srcFrame[i];
                    if (arc != null) {
                        ArrayObjectValue aov = new ArrayObjectValue(arc.local);
                        values.add(aov);
                        aov.array = arc.array;
                        aov.parent = arc;
                        aov.pos = (BitSet) arc.pos.clone();
                        distFrame[i] = aov;
                    }
                }
            } else {
                for (int i = 0; i < size; i++) {
                    ArrayObjectValue arc = srcFrame[i];
                    ArrayObjectValue aov = distFrame[i];
                    if (arc != null && aov != null) {
                        if (aov.otherParent == null) {
                            aov.otherParent = new HashSet<>();
                        }
                        aov.otherParent.add(arc);
                    }
                }
            }
            return distFrame;
        }

        @Override
        public ArrayObjectValue[] initFirstFrame(Stmt first) {
            return new ArrayObjectValue[size];
        }

        ArrayObjectValue[] tmp = initFirstFrame(null);

        Stmt currentStmt;

        @Override
        public ArrayObjectValue[] exec(ArrayObjectValue[] frame, Stmt stmt) {
            currentStmt = stmt;
            System.arraycopy(frame, 0, tmp, 0, size);
            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) {
                        ArrayObjectValue av = tmp[local._ls_index];
                        Constant cst = (Constant) stmt.getOp2();
                        int endPos = Array.getLength(cst.value);
                        av.pos.set(0, endPos);
                    }
                } else {
                    use(stmt.getOp1());
                }
            } else if (stmt.st == Stmt.ST.ASSIGN && 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();
                    if (local._ls_index >= 0) {
                        int index = ((Number) ((Constant) ae.getOp2()).value).intValue();
                        ArrayObjectValue av = tmp[local._ls_index];
                        av.pos.set(index);
                    } else {
                        use(ae);
                    }
                } else {
                    use(ae);
                }
            } else if (stmt.st == Stmt.ST.ASSIGN && stmt.getOp1().vt == Value.VT.LOCAL) {
                Local local = (Local) stmt.getOp1();
                use(stmt.getOp2());
                if (local._ls_index >= 0) {
                    ArrayObjectValue aov = new ArrayObjectValue(local);
                    aov.array = arraySizes.get(local);
                    aov.pos = new BitSet();
                    values.add(aov);
                    tmp[local._ls_index] = aov;
                }
            } 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:
                    if (v.vt == Value.VT.LOCAL) {
                        Local local = (Local) v;
                        if (local._ls_index >= 0) {
                            ArrayObjectValue aov = tmp[local._ls_index];
                            aov.array.used.add(currentStmt);
                            aov.used = true;
                        }
                    }
                    break;
                case E1:
                    use(v.getOp());
                    break;
                case E2:
                    use(v.getOp1());
                    use(v.getOp2());
                    break;
                case En:
                    for (Value op : v.getOps()) {
                        use(op);
                    }
                    break;
            }
        }
    });
    Set<ArrayObjectValue> used = markUsed(values);
    // check if ArrayObjectValue have different parent assignment
    for (ArrayObjectValue avo : used) {
        if (avo.array.used.size() > 1) {
            arraySizes.remove(avo.local);
        } else {
            if (avo.parent != null && avo.otherParent != null) {
                // BitSet bs = avo.pos;
                BitSet p = avo.parent.pos;
                for (ArrayObjectValue ps : avo.otherParent) {
                    if (!p.equals(ps.pos)) {
                        arraySizes.remove(avo.local);
                        break;
                    }
                }
            }
        }
    }
    // check for un full init array
    for (Iterator<Map.Entry<Local, ArrayObject>> it = arraySizes.entrySet().iterator(); it.hasNext(); ) {
        Map.Entry<Local, ArrayObject> e = it.next();
        Local local = e.getKey();
        ArrayObject arrayObject = e.getValue();
        for (Stmt use : arrayObject.used) {
            ArrayObjectValue[] frame = (ArrayObjectValue[]) use.frame;
            ArrayObjectValue aov = frame[local._ls_index];
            BitSet pos = aov.pos;
            if (pos.nextClearBit(0) < arrayObject.size || pos.nextSetBit(arrayObject.size) >= 0) {
                it.remove();
                break;
            }
        }
    }
    // clean up
    for (Stmt stmt : method.stmts) {
        stmt.frame = null;
    }
}
Also used : Cfg(com.googlecode.dex2jar.ir.ts.Cfg) LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) AssignStmt(com.googlecode.dex2jar.ir.stmt.AssignStmt) Stmt(com.googlecode.dex2jar.ir.stmt.Stmt)

Example 32 with Stmt

use of com.googlecode.dex2jar.ir.stmt.Stmt in project dex2jar by pxb1988.

the class FillArrayTransformer method searchForArrayObject.

private Map<Local, ArrayObject> searchForArrayObject(IrMethod method) {
    final Map<Local, ArrayObject> arraySizes = new HashMap<>();
    if (method.locals.size() == 0) {
        return arraySizes;
    }
    Cfg.createCFG(method);
    Cfg.dfsVisit(method, new Cfg.DfsVisitor() {

        @Override
        public void onVisit(Stmt p) {
            if (p.st == Stmt.ST.ASSIGN) {
                if (p.getOp2().vt == Value.VT.NEW_ARRAY && p.getOp1().vt == Value.VT.LOCAL) {
                    TypeExpr ae = (TypeExpr) p.getOp2();
                    if (ae.getOp().vt == Value.VT.CONSTANT) {
                        int size = ((Number) ((Constant) ae.getOp()).value).intValue();
                        // }
                        if (size >= 0) {
                            arraySizes.put((Local) p.getOp1(), new ArrayObject(size, ae.type, (AssignStmt) p));
                        }
                    }
                } else if (p.getOp1().vt == Value.VT.ARRAY) {
                    ArrayExpr ae = (ArrayExpr) p.getOp1();
                    if (ae.getOp1().vt == Value.VT.LOCAL) {
                        Local local = (Local) ae.getOp1();
                        ArrayObject arrayObject = arraySizes.get(local);
                        if (arrayObject != null) {
                            if (ae.getOp2().vt == Value.VT.CONSTANT) {
                                arrayObject.putItem.add(p);
                            } else {
                                arraySizes.remove(local);
                            }
                        }
                    }
                }
            } else if (p.st == Stmt.ST.FILL_ARRAY_DATA) {
                if (p.getOp1().vt == Value.VT.LOCAL) {
                    Local local = (Local) p.getOp1();
                    ArrayObject arrayObject = arraySizes.get(local);
                    if (arrayObject != null) {
                        arrayObject.putItem.add(p);
                    }
                }
            }
        }
    });
    if (arraySizes.size() > 0) {
        Set<Local> set = new HashSet<Local>();
        if (method.phiLabels != null) {
            for (LabelStmt labelStmt : method.phiLabels) {
                if (labelStmt.phis != null) {
                    for (AssignStmt as : labelStmt.phis) {
                        set.add((Local) as.getOp1());
                        for (Value v : as.getOp2().getOps()) {
                            set.add((Local) v);
                        }
                    }
                }
            }
        }
        if (set.size() > 0) {
            for (Local local : set) {
                arraySizes.remove(local);
            }
        }
    }
    return arraySizes;
}
Also used : LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) Cfg(com.googlecode.dex2jar.ir.ts.Cfg) AssignStmt(com.googlecode.dex2jar.ir.stmt.AssignStmt) LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) AssignStmt(com.googlecode.dex2jar.ir.stmt.AssignStmt) Stmt(com.googlecode.dex2jar.ir.stmt.Stmt)

Example 33 with Stmt

use of com.googlecode.dex2jar.ir.stmt.Stmt in project dex2jar by pxb1988.

the class UnSSATransformer method transform.

@Override
public void transform(IrMethod method) {
    if (method.phiLabels == null || method.phiLabels.size() == 0) {
        return;
    }
    // 1. Live analyze the method,
    // a. remove Phi,
    // b. record parameter reference
    LiveA liveA = new LiveA(method);
    liveA.analyze();
    genRegGraph(method, liveA);
    // 2. insert x=y
    fixPhi(method, method.phiLabels);
    insertAssignPath(method, method.phiLabels);
    // 4. clean up
    for (Local local : method.locals) {
        local.tag = null;
    }
    for (Stmt stmt : method.stmts) {
        stmt.frame = null;
    }
    for (LabelStmt labelStmt : method.phiLabels) {
        labelStmt.phis = null;
    }
    method.phiLabels = null;
}
Also used : LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) Local(com.googlecode.dex2jar.ir.expr.Local) LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) JumpStmt(com.googlecode.dex2jar.ir.stmt.JumpStmt) AssignStmt(com.googlecode.dex2jar.ir.stmt.AssignStmt) Stmt(com.googlecode.dex2jar.ir.stmt.Stmt)

Example 34 with Stmt

use of com.googlecode.dex2jar.ir.stmt.Stmt in project dex2jar by pxb1988.

the class UnSSATransformer method fixPhi.

/**
     * there is somewhere both a and its possible x is both live, insert a=x, will change the meaning for example
     * 
     * <pre>
     *                      L0:
     *                      a = phi(b, ... )
     *                      b = 234;
     *                      if a>0 goto L0: // a, b both live here
     *                      ...
     * </pre>
     * 
     * after insert a=b before the if stmt, the programe change to
     * 
     * <pre>
     *                      L0:
     *                      // a = phi(b, ... )
     *                      b = 234;
     *                      a = b
     *                      if a>0 goto L0:
     *                      ...
     * </pre>
     * 
     * the solution is by introduce a new local x
     * 
     * <pre>
     *                      L0:
     *                      x = phi(b, ... )
     *                      a = x
     *                      b = 234;
     *                      if a>0 goto L0: // a, b both live here
     *                      ...
     * </pre>
     * 
     * insert x = b is ok now
     * 
     * <pre>
     *                      L0:
     *                      // x = phi(b, ... )
     *                      a = x
     *                      b = 234;
     *                      x = b
     *                      if a>0 goto L0: // a, b both live here
     *                      ...
     * </pre>
     * 
     * @param phiLabels
     */
private void fixPhi(IrMethod method, Collection<LabelStmt> phiLabels) {
    for (LabelStmt labelStmt : phiLabels) {
        List<AssignStmt> phis = (List<AssignStmt>) labelStmt.phis;
        for (AssignStmt phi : phis) {
            Local a = (Local) phi.getOp1();
            PhiExpr b = (PhiExpr) phi.getOp2();
            boolean introduceNewLocal = false;
            RegAssign aReg = (RegAssign) a.tag;
            for (Value op : b.getOps()) {
                RegAssign bReg = (RegAssign) ((Local) op).tag;
                if (aReg.excludes.contains(bReg)) {
                    introduceNewLocal = true;
                    break;
                }
            }
            if (introduceNewLocal) {
                Local newLocal = (Local) a.clone();
                if (DEBUG) {
                    newLocal.debugName = "x" + method.locals.size();
                }
                phi.op1 = newLocal;
                RegAssign newRegAssign = new RegAssign();
                newLocal.tag = newRegAssign;
                method.locals.add(newLocal);
                Stmt newAssigStmt = Stmts.nAssign(a, newLocal);
                Stmt next = labelStmt.getNext();
                if (next != null && next.st == ST.IDENTITY && next.getOp2().vt == VT.EXCEPTION_REF) {
                    // it's a handler, insert after the exception ref
                    method.stmts.insertAfter(next, newAssigStmt);
                } else {
                    method.stmts.insertAfter(labelStmt, newAssigStmt);
                }
                LiveV[] frame = (LiveV[]) labelStmt.frame;
                if (DEBUG) {
                    LiveV[] copy = frame.clone();
                    LiveV n = new LiveV();
                    n.local = a;
                    n.used = true;
                    copy[a._ls_index] = new LiveV();
                    newAssigStmt.frame = copy;
                }
                LiveV thePhi = frame[a._ls_index];
                thePhi.local = newLocal;
                for (LiveV v : frame) {
                    if (v != null && v.used) {
                        RegAssign s = (RegAssign) v.local.tag;
                        s.excludes.add(newRegAssign);
                        newRegAssign.excludes.add(s);
                    }
                }
            }
        }
    }
}
Also used : LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) PhiExpr(com.googlecode.dex2jar.ir.expr.PhiExpr) AssignStmt(com.googlecode.dex2jar.ir.stmt.AssignStmt) Value(com.googlecode.dex2jar.ir.expr.Value) AnalyzeValue(com.googlecode.dex2jar.ir.ts.an.AnalyzeValue) Local(com.googlecode.dex2jar.ir.expr.Local) StmtList(com.googlecode.dex2jar.ir.stmt.StmtList) ArrayList(java.util.ArrayList) List(java.util.List) LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) JumpStmt(com.googlecode.dex2jar.ir.stmt.JumpStmt) AssignStmt(com.googlecode.dex2jar.ir.stmt.AssignStmt) Stmt(com.googlecode.dex2jar.ir.stmt.Stmt)

Example 35 with Stmt

use of com.googlecode.dex2jar.ir.stmt.Stmt in project dex2jar by pxb1988.

the class UnSSATransformer method genRegGraph.

private void genRegGraph(IrMethod method, LiveA liveA) {
    for (Local local : method.locals) {
        local.tag = new RegAssign();
    }
    Set<Stmt> tos = new HashSet<>();
    for (Stmt stmt : method.stmts) {
        if ((stmt.st == ST.ASSIGN || stmt.st == ST.IDENTITY) && stmt.getOp1().vt == VT.LOCAL) {
            Local localAssignTo = (Local) stmt.getOp1();
            RegAssign regAssignTo = (RegAssign) localAssignTo.tag;
            Set<Integer> excludeIdx = new HashSet<>();
            Cfg.collectTos(stmt, tos);
            for (Stmt target : tos) {
                LiveV[] frame = (LiveV[]) target.frame;
                if (frame == null) {
                    continue;
                }
                // exclude thisReg and phiReg
                excludeIdx.clear();
                excludeIdx.add(localAssignTo._ls_index);
                if (target.st == ST.LABEL) {
                    LabelStmt label = (LabelStmt) target;
                    if (label.phis != null) {
                        for (AssignStmt phiAssignStmt : (List<AssignStmt>) label.phis) {
                            Local phiLocal = (Local) phiAssignStmt.getOp1();
                            excludeIdx.add(phiLocal._ls_index);
                        }
                    }
                }
                for (int i = 0; i < frame.length; i++) {
                    if (excludeIdx.contains(i)) {
                        continue;
                    }
                    LiveV v = frame[i];
                    if (v != null && v.used) {
                        RegAssign b = (RegAssign) v.local.tag;
                        regAssignTo.excludes.add(b);
                        b.excludes.add(regAssignTo);
                    }
                }
            }
            tos.clear();
        } else if (stmt.st == ST.LABEL) {
            //
            LabelStmt label = (LabelStmt) stmt;
            if (label.phis != null) {
                for (AssignStmt phiAssignStmt : (List<AssignStmt>) label.phis) {
                    Local phiLocal = (Local) phiAssignStmt.getOp1();
                    RegAssign a = (RegAssign) phiLocal.tag;
                    LiveV[] frame = (LiveV[]) stmt.frame;
                    for (LiveV v : frame) {
                        if (v != null && v.used) {
                            RegAssign b = (RegAssign) v.local.tag;
                            a.excludes.add(b);
                            b.excludes.add(a);
                        }
                    }
                }
            }
        }
    }
    if (DEBUG) {
        System.out.println(liveA.toString());
    }
}
Also used : LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) AssignStmt(com.googlecode.dex2jar.ir.stmt.AssignStmt) Local(com.googlecode.dex2jar.ir.expr.Local) LabelStmt(com.googlecode.dex2jar.ir.stmt.LabelStmt) JumpStmt(com.googlecode.dex2jar.ir.stmt.JumpStmt) AssignStmt(com.googlecode.dex2jar.ir.stmt.AssignStmt) Stmt(com.googlecode.dex2jar.ir.stmt.Stmt) StmtList(com.googlecode.dex2jar.ir.stmt.StmtList) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet)

Aggregations

Stmt (com.googlecode.dex2jar.ir.stmt.Stmt)41 LabelStmt (com.googlecode.dex2jar.ir.stmt.LabelStmt)31 Local (com.googlecode.dex2jar.ir.expr.Local)23 AssignStmt (com.googlecode.dex2jar.ir.stmt.AssignStmt)22 Test (org.junit.Test)10 Value (com.googlecode.dex2jar.ir.expr.Value)8 ArrayList (java.util.ArrayList)7 JumpStmt (com.googlecode.dex2jar.ir.stmt.JumpStmt)4 Cfg (com.googlecode.dex2jar.ir.ts.Cfg)4 Trap (com.googlecode.dex2jar.ir.Trap)3 StmtList (com.googlecode.dex2jar.ir.stmt.StmtList)3 List (java.util.List)3 StmtTraveler (com.googlecode.dex2jar.ir.StmtTraveler)2 Constant (com.googlecode.dex2jar.ir.expr.Constant)2 PhiExpr (com.googlecode.dex2jar.ir.expr.PhiExpr)2 E2Stmt (com.googlecode.dex2jar.ir.stmt.Stmt.E2Stmt)2 HashSet (java.util.HashSet)2 IR2JConverter (com.googlecode.d2j.converter.IR2JConverter)1 DexFileNode (com.googlecode.d2j.node.DexFileNode)1 DexMethodNode (com.googlecode.d2j.node.DexMethodNode)1