Search in sources :

Example 1 with ForEachLoop

use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.

the class LoopRegionVisitor method checkArrayForEach.

private static LoopType checkArrayForEach(MethodNode mth, InsnNode initInsn, InsnNode incrInsn, IfCondition condition) {
    if (!(incrInsn instanceof ArithNode)) {
        return null;
    }
    ArithNode arithNode = (ArithNode) incrInsn;
    if (arithNode.getOp() != ArithOp.ADD) {
        return null;
    }
    InsnArg lit = incrInsn.getArg(1);
    if (!lit.isLiteral() || ((LiteralArg) lit).getLiteral() != 1) {
        return null;
    }
    if (initInsn.getType() != InsnType.CONST || !initInsn.getArg(0).isLiteral() || ((LiteralArg) initInsn.getArg(0)).getLiteral() != 0) {
        return null;
    }
    InsnArg condArg = incrInsn.getArg(0);
    if (!condArg.isRegister()) {
        return null;
    }
    SSAVar sVar = ((RegisterArg) condArg).getSVar();
    List<RegisterArg> args = sVar.getUseList();
    if (args.size() != 3 || args.get(2) != condArg) {
        return null;
    }
    condArg = args.get(0);
    RegisterArg arrIndex = args.get(1);
    InsnNode arrGetInsn = arrIndex.getParentInsn();
    if (arrGetInsn == null || arrGetInsn.getType() != InsnType.AGET) {
        return null;
    }
    if (!condition.isCompare()) {
        return null;
    }
    Compare compare = condition.getCompare();
    if (compare.getOp() != IfOp.LT || compare.getA() != condArg) {
        return null;
    }
    InsnNode len;
    InsnArg bCondArg = compare.getB();
    if (bCondArg.isInsnWrap()) {
        len = ((InsnWrapArg) bCondArg).getWrapInsn();
    } else if (bCondArg.isRegister()) {
        len = ((RegisterArg) bCondArg).getAssignInsn();
    } else {
        return null;
    }
    if (len == null || len.getType() != InsnType.ARRAY_LENGTH) {
        return null;
    }
    InsnArg arrayArg = len.getArg(0);
    if (!arrayArg.equals(arrGetInsn.getArg(0))) {
        return null;
    }
    RegisterArg iterVar = arrGetInsn.getResult();
    if (iterVar == null) {
        return null;
    }
    // array for each loop confirmed
    len.add(AFlag.SKIP);
    arrGetInsn.add(AFlag.SKIP);
    InstructionRemover.unbindInsn(mth, len);
    // inline array variable
    CodeShrinker.shrinkMethod(mth);
    if (arrGetInsn.contains(AFlag.WRAPPED)) {
        InsnArg wrapArg = BlockUtils.searchWrappedInsnParent(mth, arrGetInsn);
        if (wrapArg != null && wrapArg.getParentInsn() != null) {
            wrapArg.getParentInsn().replaceArg(wrapArg, iterVar);
        } else {
            LOG.debug(" checkArrayForEach: Wrapped insn not found: {}, mth: {}", arrGetInsn, mth);
        }
    }
    return new ForEachLoop(iterVar, len.getArg(0));
}
Also used : InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) SSAVar(jadx.core.dex.instructions.args.SSAVar) InsnArg(jadx.core.dex.instructions.args.InsnArg) LiteralArg(jadx.core.dex.instructions.args.LiteralArg) Compare(jadx.core.dex.regions.conditions.Compare) ArithNode(jadx.core.dex.instructions.ArithNode) ForEachLoop(jadx.core.dex.regions.loops.ForEachLoop)

Example 2 with ForEachLoop

use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.

the class RegionGen method makeLoop.

public void makeLoop(LoopRegion region, ICodeWriter code) throws CodegenException {
    code.startLineWithNum(region.getSourceLine());
    LoopLabelAttr labelAttr = region.getInfo().getStart().get(AType.LOOP_LABEL);
    if (labelAttr != null) {
        code.add(mgen.getNameGen().getLoopLabel(labelAttr)).add(": ");
    }
    IfCondition condition = region.getCondition();
    if (condition == null) {
        // infinite loop
        code.add("while (true) {");
        makeRegionIndent(code, region.getBody());
        code.startLine('}');
        return;
    }
    InsnNode condInsn = condition.getFirstInsn();
    InsnCodeOffset.attach(code, condInsn);
    ConditionGen conditionGen = new ConditionGen(this);
    LoopType type = region.getType();
    if (type != null) {
        if (type instanceof ForLoop) {
            ForLoop forLoop = (ForLoop) type;
            code.add("for (");
            makeInsn(forLoop.getInitInsn(), code, Flags.INLINE);
            code.add("; ");
            conditionGen.add(code, condition);
            code.add("; ");
            makeInsn(forLoop.getIncrInsn(), code, Flags.INLINE);
            code.add(") {");
            CodeGenUtils.addCodeComments(code, mth, condInsn);
            makeRegionIndent(code, region.getBody());
            code.startLine('}');
            return;
        }
        if (type instanceof ForEachLoop) {
            ForEachLoop forEachLoop = (ForEachLoop) type;
            code.add("for (");
            declareVar(code, forEachLoop.getVarArg());
            code.add(" : ");
            addArg(code, forEachLoop.getIterableArg(), false);
            code.add(") {");
            CodeGenUtils.addCodeComments(code, mth, condInsn);
            makeRegionIndent(code, region.getBody());
            code.startLine('}');
            return;
        }
        throw new JadxRuntimeException("Unknown loop type: " + type.getClass());
    }
    if (region.isConditionAtEnd()) {
        code.add("do {");
        CodeGenUtils.addCodeComments(code, mth, condInsn);
        makeRegionIndent(code, region.getBody());
        code.startLineWithNum(region.getSourceLine());
        code.add("} while (");
        conditionGen.add(code, condition);
        code.add(");");
    } else {
        code.add("while (");
        conditionGen.add(code, condition);
        code.add(") {");
        CodeGenUtils.addCodeComments(code, mth, condInsn);
        makeRegionIndent(code, region.getBody());
        code.startLine('}');
    }
}
Also used : InsnNode(jadx.core.dex.nodes.InsnNode) ForLoop(jadx.core.dex.regions.loops.ForLoop) LoopLabelAttr(jadx.core.dex.attributes.nodes.LoopLabelAttr) LoopType(jadx.core.dex.regions.loops.LoopType) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) IfCondition(jadx.core.dex.regions.conditions.IfCondition) ForEachLoop(jadx.core.dex.regions.loops.ForEachLoop)

Example 3 with ForEachLoop

use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.

the class LoopRegionVisitor method checkIterableForEach.

private static boolean checkIterableForEach(MethodNode mth, LoopRegion loopRegion, IfCondition condition) {
    List<RegisterArg> condArgs = condition.getRegisterArgs();
    if (condArgs.size() != 1) {
        return false;
    }
    RegisterArg iteratorArg = condArgs.get(0);
    SSAVar sVar = iteratorArg.getSVar();
    if (sVar == null || sVar.isUsedInPhi()) {
        return false;
    }
    List<RegisterArg> itUseList = sVar.getUseList();
    InsnNode assignInsn = iteratorArg.getAssignInsn();
    if (itUseList.size() != 2) {
        return false;
    }
    if (!checkInvoke(assignInsn, null, "iterator()Ljava/util/Iterator;")) {
        return false;
    }
    InsnArg iterableArg = assignInsn.getArg(0);
    InsnNode hasNextCall = itUseList.get(0).getParentInsn();
    InsnNode nextCall = itUseList.get(1).getParentInsn();
    if (!checkInvoke(hasNextCall, "java.util.Iterator", "hasNext()Z") || !checkInvoke(nextCall, "java.util.Iterator", "next()Ljava/lang/Object;")) {
        return false;
    }
    List<InsnNode> toSkip = new LinkedList<>();
    RegisterArg iterVar;
    if (nextCall.contains(AFlag.WRAPPED)) {
        InsnArg wrapArg = BlockUtils.searchWrappedInsnParent(mth, nextCall);
        if (wrapArg != null && wrapArg.getParentInsn() != null) {
            InsnNode parentInsn = wrapArg.getParentInsn();
            BlockNode block = BlockUtils.getBlockByInsn(mth, parentInsn);
            if (block == null) {
                return false;
            }
            if (!RegionUtils.isRegionContainsBlock(loopRegion, block)) {
                return false;
            }
            if (parentInsn.getType() == InsnType.CHECK_CAST) {
                iterVar = parentInsn.getResult();
                if (iterVar == null || !fixIterableType(mth, iterableArg, iterVar)) {
                    return false;
                }
                InsnArg castArg = BlockUtils.searchWrappedInsnParent(mth, parentInsn);
                if (castArg != null && castArg.getParentInsn() != null) {
                    castArg.getParentInsn().replaceArg(castArg, iterVar);
                } else {
                    // cast not inlined
                    toSkip.add(parentInsn);
                }
            } else {
                iterVar = nextCall.getResult();
                if (iterVar == null) {
                    return false;
                }
                // restore variable from inlined insn
                iterVar.remove(AFlag.REMOVE);
                nextCall.add(AFlag.DONT_GENERATE);
                if (!fixIterableType(mth, iterableArg, iterVar)) {
                    return false;
                }
                parentInsn.replaceArg(wrapArg, iterVar);
            }
        } else {
            LOG.warn(" checkIterableForEach: Wrapped insn not found: {}, mth: {}", nextCall, mth);
            return false;
        }
    } else {
        iterVar = nextCall.getResult();
        if (iterVar == null) {
            return false;
        }
        if (!usedOnlyInLoop(mth, loopRegion, iterVar)) {
            return false;
        }
        if (!assignOnlyInLoop(mth, loopRegion, iterVar)) {
            return false;
        }
        toSkip.add(nextCall);
    }
    assignInsn.add(AFlag.DONT_GENERATE);
    assignInsn.getResult().add(AFlag.DONT_GENERATE);
    for (InsnNode insnNode : toSkip) {
        insnNode.add(AFlag.DONT_GENERATE);
    }
    for (RegisterArg itArg : itUseList) {
        itArg.add(AFlag.DONT_GENERATE);
    }
    ForEachLoop forEachLoop = new ForEachLoop(iterVar, iterableArg);
    forEachLoop.injectFakeInsns(loopRegion);
    loopRegion.setType(forEachLoop);
    return true;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) SSAVar(jadx.core.dex.instructions.args.SSAVar) InsnArg(jadx.core.dex.instructions.args.InsnArg) ForEachLoop(jadx.core.dex.regions.loops.ForEachLoop) LinkedList(java.util.LinkedList)

Example 4 with ForEachLoop

use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.

the class RegionGen method makeLoop.

private CodeWriter makeLoop(LoopRegion region, CodeWriter code) throws CodegenException {
    BlockNode header = region.getHeader();
    if (header != null) {
        List<InsnNode> headerInsns = header.getInstructions();
        if (headerInsns.size() > 1) {
            ErrorsCounter.methodError(mth, "Found not inlined instructions from loop header");
            int last = headerInsns.size() - 1;
            for (int i = 0; i < last; i++) {
                InsnNode insn = headerInsns.get(i);
                makeInsn(insn, code);
            }
        }
    }
    LoopLabelAttr labelAttr = region.getInfo().getStart().get(AType.LOOP_LABEL);
    if (labelAttr != null) {
        code.startLine(mgen.getNameGen().getLoopLabel(labelAttr)).add(':');
    }
    IfCondition condition = region.getCondition();
    if (condition == null) {
        // infinite loop
        code.startLine("while (true) {");
        makeRegionIndent(code, region.getBody());
        code.startLine('}');
        return code;
    }
    ConditionGen conditionGen = new ConditionGen(this);
    LoopType type = region.getType();
    if (type != null) {
        if (type instanceof ForLoop) {
            ForLoop forLoop = (ForLoop) type;
            code.startLine("for (");
            makeInsn(forLoop.getInitInsn(), code, Flags.INLINE);
            code.add("; ");
            conditionGen.add(code, condition);
            code.add("; ");
            makeInsn(forLoop.getIncrInsn(), code, Flags.INLINE);
            code.add(") {");
            makeRegionIndent(code, region.getBody());
            code.startLine('}');
            return code;
        }
        if (type instanceof ForEachLoop) {
            ForEachLoop forEachLoop = (ForEachLoop) type;
            code.startLine("for (");
            declareVar(code, forEachLoop.getVarArg());
            code.add(" : ");
            addArg(code, forEachLoop.getIterableArg(), false);
            code.add(") {");
            makeRegionIndent(code, region.getBody());
            code.startLine('}');
            return code;
        }
        throw new JadxRuntimeException("Unknown loop type: " + type.getClass());
    }
    if (region.isConditionAtEnd()) {
        code.startLine("do {");
        makeRegionIndent(code, region.getBody());
        code.startLine("} while (");
        conditionGen.add(code, condition);
        code.add(");");
    } else {
        code.startLine("while (");
        conditionGen.add(code, condition);
        code.add(") {");
        makeRegionIndent(code, region.getBody());
        code.startLine('}');
    }
    return code;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) InsnNode(jadx.core.dex.nodes.InsnNode) ForLoop(jadx.core.dex.regions.loops.ForLoop) LoopLabelAttr(jadx.core.dex.attributes.nodes.LoopLabelAttr) LoopType(jadx.core.dex.regions.loops.LoopType) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) IfCondition(jadx.core.dex.regions.conditions.IfCondition) ForEachLoop(jadx.core.dex.regions.loops.ForEachLoop)

Example 5 with ForEachLoop

use of jadx.core.dex.regions.loops.ForEachLoop in project jadx by skylot.

the class LoopRegionVisitor method checkArrayForEach.

private static LoopType checkArrayForEach(MethodNode mth, LoopRegion loopRegion, InsnNode initInsn, InsnNode incrInsn, IfCondition condition) {
    if (!(incrInsn instanceof ArithNode)) {
        return null;
    }
    ArithNode arithNode = (ArithNode) incrInsn;
    if (arithNode.getOp() != ArithOp.ADD) {
        return null;
    }
    InsnArg lit = incrInsn.getArg(1);
    if (!lit.isLiteral() || ((LiteralArg) lit).getLiteral() != 1) {
        return null;
    }
    if (initInsn.getType() != InsnType.CONST || !initInsn.getArg(0).isLiteral() || ((LiteralArg) initInsn.getArg(0)).getLiteral() != 0) {
        return null;
    }
    InsnArg condArg = incrInsn.getArg(0);
    if (!condArg.isRegister()) {
        return null;
    }
    SSAVar sVar = ((RegisterArg) condArg).getSVar();
    List<RegisterArg> args = sVar.getUseList();
    if (args.size() != 3) {
        return null;
    }
    condArg = InsnUtils.getRegFromInsn(args, InsnType.IF);
    if (condArg == null) {
        return null;
    }
    RegisterArg arrIndex = InsnUtils.getRegFromInsn(args, InsnType.AGET);
    if (arrIndex == null) {
        return null;
    }
    InsnNode arrGetInsn = arrIndex.getParentInsn();
    if (arrGetInsn == null || arrGetInsn.containsWrappedInsn()) {
        return null;
    }
    if (!condition.isCompare()) {
        return null;
    }
    Compare compare = condition.getCompare();
    if (compare.getOp() != IfOp.LT || compare.getA() != condArg) {
        return null;
    }
    InsnNode len;
    InsnArg bCondArg = compare.getB();
    if (bCondArg.isInsnWrap()) {
        len = ((InsnWrapArg) bCondArg).getWrapInsn();
    } else if (bCondArg.isRegister()) {
        len = ((RegisterArg) bCondArg).getAssignInsn();
    } else {
        return null;
    }
    if (len == null || len.getType() != InsnType.ARRAY_LENGTH) {
        return null;
    }
    InsnArg arrayArg = len.getArg(0);
    if (!arrayArg.equals(arrGetInsn.getArg(0))) {
        return null;
    }
    RegisterArg iterVar = arrGetInsn.getResult();
    if (iterVar == null) {
        return null;
    }
    if (!usedOnlyInLoop(mth, loopRegion, iterVar)) {
        return null;
    }
    // array for each loop confirmed
    incrInsn.getResult().add(AFlag.DONT_GENERATE);
    condArg.add(AFlag.DONT_GENERATE);
    bCondArg.add(AFlag.DONT_GENERATE);
    arrGetInsn.add(AFlag.DONT_GENERATE);
    compare.getInsn().add(AFlag.DONT_GENERATE);
    if (arrGetInsn.contains(AFlag.WRAPPED)) {
        InsnArg wrapArg = BlockUtils.searchWrappedInsnParent(mth, arrGetInsn);
        if (wrapArg != null && wrapArg.getParentInsn() != null) {
            InsnNode parentInsn = wrapArg.getParentInsn();
            parentInsn.replaceArg(wrapArg, iterVar.duplicate());
            parentInsn.rebindArgs();
        } else {
            LOG.debug(" checkArrayForEach: Wrapped insn not found: {}, mth: {}", arrGetInsn, mth);
        }
    }
    ForEachLoop forEachLoop = new ForEachLoop(iterVar, len.getArg(0));
    forEachLoop.injectFakeInsns(loopRegion);
    if (InsnUtils.dontGenerateIfNotUsed(len)) {
        InsnRemover.remove(mth, len);
    }
    CodeShrinkVisitor.shrinkMethod(mth);
    return forEachLoop;
}
Also used : InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) SSAVar(jadx.core.dex.instructions.args.SSAVar) InsnArg(jadx.core.dex.instructions.args.InsnArg) LiteralArg(jadx.core.dex.instructions.args.LiteralArg) Compare(jadx.core.dex.regions.conditions.Compare) ArithNode(jadx.core.dex.instructions.ArithNode) ForEachLoop(jadx.core.dex.regions.loops.ForEachLoop)

Aggregations

InsnNode (jadx.core.dex.nodes.InsnNode)5 ForEachLoop (jadx.core.dex.regions.loops.ForEachLoop)5 InsnArg (jadx.core.dex.instructions.args.InsnArg)3 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)3 SSAVar (jadx.core.dex.instructions.args.SSAVar)3 LoopLabelAttr (jadx.core.dex.attributes.nodes.LoopLabelAttr)2 ArithNode (jadx.core.dex.instructions.ArithNode)2 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)2 BlockNode (jadx.core.dex.nodes.BlockNode)2 Compare (jadx.core.dex.regions.conditions.Compare)2 IfCondition (jadx.core.dex.regions.conditions.IfCondition)2 ForLoop (jadx.core.dex.regions.loops.ForLoop)2 LoopType (jadx.core.dex.regions.loops.LoopType)2 JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)2 LinkedList (java.util.LinkedList)1