Search in sources :

Example 86 with BlockNode

use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.

the class RegionMaker method canInsertBreak.

private boolean canInsertBreak(BlockNode exit) {
    if (BlockUtils.containsExitInsn(exit)) {
        return false;
    }
    List<BlockNode> simplePath = BlockUtils.buildSimplePath(exit);
    if (!simplePath.isEmpty()) {
        BlockNode lastBlock = simplePath.get(simplePath.size() - 1);
        if (lastBlock.contains(AFlag.RETURN) || lastBlock.getSuccessors().isEmpty()) {
            return false;
        }
    }
    // check if there no outer switch (TODO: very expensive check)
    Set<BlockNode> paths = BlockUtils.getAllPathsBlocks(mth.getEnterBlock(), exit);
    for (BlockNode block : paths) {
        if (BlockUtils.checkLastInsnType(block, InsnType.SWITCH)) {
            return false;
        }
    }
    return true;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode)

Example 87 with BlockNode

use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.

the class RegionMaker method processSwitch.

private BlockNode processSwitch(IRegion currentRegion, BlockNode block, SwitchInsn insn, RegionStack stack) {
    // map case blocks to keys
    int len = insn.getTargets().length;
    Map<BlockNode, List<Object>> blocksMap = new LinkedHashMap<>(len);
    BlockNode[] targetBlocksArr = insn.getTargetBlocks();
    for (int i = 0; i < len; i++) {
        List<Object> keys = blocksMap.computeIfAbsent(targetBlocksArr[i], k -> new ArrayList<>(2));
        keys.add(insn.getKey(i));
    }
    BlockNode defCase = insn.getDefTargetBlock();
    if (defCase != null) {
        List<Object> keys = blocksMap.computeIfAbsent(defCase, k -> new ArrayList<>(1));
        keys.add(SwitchRegion.DEFAULT_CASE_KEY);
    }
    // search 'out' block - 'next' block after whole switch statement
    BlockNode out;
    LoopInfo loop = mth.getLoopForBlock(block);
    if (loop == null) {
        out = calcPostDomOut(mth, block, mth.getPreExitBlocks());
    } else {
        BlockNode loopEnd = loop.getEnd();
        stack.addExit(loop.getStart());
        if (stack.containsExit(block) || block == loopEnd || loopEnd.getPredecessors().contains(block)) {
            // in exits or last insn in loop => no 'out' block
            out = null;
        } else {
            // treat 'continue' as exit
            out = calcPostDomOut(mth, block, loopEnd.getPredecessors());
            if (out != null) {
                insertContinueInSwitch(block, out, loopEnd);
            } else {
                // no 'continue'
                out = calcPostDomOut(mth, block, Collections.singletonList(loopEnd));
            }
        }
        if (out == loop.getStart()) {
            // no other outs instead back edge to loop start
            out = null;
        }
    }
    if (out != null && processedBlocks.get(out.getId())) {
        // out block already processed, prevent endless loop
        throw new JadxRuntimeException("Failed to find switch 'out' block");
    }
    SwitchRegion sw = new SwitchRegion(currentRegion, block);
    currentRegion.getSubBlocks().add(sw);
    stack.push(sw);
    stack.addExit(out);
    // detect fallthrough cases
    Map<BlockNode, BlockNode> fallThroughCases = new LinkedHashMap<>();
    if (out != null) {
        BitSet caseBlocks = BlockUtils.blocksToBitSet(mth, blocksMap.keySet());
        caseBlocks.clear(out.getId());
        for (BlockNode successor : block.getCleanSuccessors()) {
            BlockNode fallThroughBlock = searchFallThroughCase(successor, out, caseBlocks);
            if (fallThroughBlock != null) {
                fallThroughCases.put(successor, fallThroughBlock);
            }
        }
        // check fallthrough cases order
        if (!fallThroughCases.isEmpty() && isBadCasesOrder(blocksMap, fallThroughCases)) {
            Map<BlockNode, List<Object>> newBlocksMap = reOrderSwitchCases(blocksMap, fallThroughCases);
            if (isBadCasesOrder(newBlocksMap, fallThroughCases)) {
                mth.addWarnComment("Can't fix incorrect switch cases order, some code will duplicate");
                fallThroughCases.clear();
            } else {
                blocksMap = newBlocksMap;
            }
        }
    }
    for (Entry<BlockNode, List<Object>> entry : blocksMap.entrySet()) {
        List<Object> keysList = entry.getValue();
        BlockNode caseBlock = entry.getKey();
        if (stack.containsExit(caseBlock)) {
            sw.addCase(keysList, new Region(stack.peekRegion()));
        } else {
            BlockNode next = fallThroughCases.get(caseBlock);
            stack.addExit(next);
            Region caseRegion = makeRegion(caseBlock, stack);
            stack.removeExit(next);
            if (next != null) {
                next.add(AFlag.FALL_THROUGH);
                caseRegion.add(AFlag.FALL_THROUGH);
            }
            sw.addCase(keysList, caseRegion);
        // 'break' instruction will be inserted in RegionMakerVisitor.PostRegionVisitor
        }
    }
    removeEmptyCases(insn, sw, defCase);
    stack.pop();
    return out;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) BitSet(java.util.BitSet) LinkedHashMap(java.util.LinkedHashMap) LoopInfo(jadx.core.dex.attributes.nodes.LoopInfo) Region(jadx.core.dex.regions.Region) IRegion(jadx.core.dex.nodes.IRegion) SwitchRegion(jadx.core.dex.regions.SwitchRegion) SynchronizedRegion(jadx.core.dex.regions.SynchronizedRegion) LoopRegion(jadx.core.dex.regions.loops.LoopRegion) IfRegion(jadx.core.dex.regions.conditions.IfRegion) List(java.util.List) ArrayList(java.util.ArrayList) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException) SwitchRegion(jadx.core.dex.regions.SwitchRegion)

Example 88 with BlockNode

use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.

the class CodeShrinkVisitor method canMoveBetweenBlocks.

private static boolean canMoveBetweenBlocks(MethodNode mth, InsnNode assignInsn, BlockNode assignBlock, BlockNode useBlock, InsnNode useInsn) {
    if (!BlockUtils.isPathExists(assignBlock, useBlock)) {
        return false;
    }
    List<RegisterArg> argsList = ArgsInfo.getArgs(assignInsn);
    BitSet args = new BitSet();
    for (RegisterArg arg : argsList) {
        args.set(arg.getRegNum());
    }
    boolean startCheck = false;
    for (InsnNode insn : assignBlock.getInstructions()) {
        if (startCheck && (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args))) {
            return false;
        }
        if (insn == assignInsn) {
            startCheck = true;
        }
    }
    Set<BlockNode> pathsBlocks = BlockUtils.getAllPathsBlocks(assignBlock, useBlock);
    pathsBlocks.remove(assignBlock);
    pathsBlocks.remove(useBlock);
    for (BlockNode block : pathsBlocks) {
        if (block.contains(AFlag.DONT_GENERATE)) {
            if (BlockUtils.checkLastInsnType(block, InsnType.MONITOR_EXIT)) {
                if (RegionUtils.isBlocksInSameRegion(mth, assignBlock, useBlock)) {
                // allow move inside same synchronized region
                } else {
                    // don't move from synchronized block
                    return false;
                }
            }
            // skip checks for not generated blocks
            continue;
        }
        for (InsnNode insn : block.getInstructions()) {
            if (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args)) {
                return false;
            }
        }
    }
    for (InsnNode insn : useBlock.getInstructions()) {
        if (insn == useInsn) {
            return true;
        }
        if (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args)) {
            return false;
        }
    }
    throw new JadxRuntimeException("Can't process instruction move : " + assignBlock);
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) BitSet(java.util.BitSet) JadxRuntimeException(jadx.core.utils.exceptions.JadxRuntimeException)

Example 89 with BlockNode

use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.

the class SSATransform method resetSSAVars.

private static void resetSSAVars(MethodNode mth) {
    for (SSAVar ssaVar : mth.getSVars()) {
        ssaVar.getAssign().resetSSAVar();
        ssaVar.getUseList().forEach(RegisterArg::resetSSAVar);
    }
    for (BlockNode block : mth.getBasicBlocks()) {
        block.remove(AType.PHI_LIST);
    }
    mth.getSVars().clear();
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) SSAVar(jadx.core.dex.instructions.args.SSAVar)

Example 90 with BlockNode

use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.

the class SSATransform method fixUselessPhi.

private static boolean fixUselessPhi(MethodNode mth) {
    boolean changed = false;
    List<PhiInsn> insnToRemove = new ArrayList<>();
    for (SSAVar var : mth.getSVars()) {
        // phi result not used
        if (var.getUseCount() == 0) {
            InsnNode assignInsn = var.getAssign().getParentInsn();
            if (assignInsn != null && assignInsn.getType() == InsnType.PHI) {
                insnToRemove.add((PhiInsn) assignInsn);
                changed = true;
            }
        }
    }
    for (BlockNode block : mth.getBasicBlocks()) {
        PhiListAttr phiList = block.get(AType.PHI_LIST);
        if (phiList == null) {
            continue;
        }
        Iterator<PhiInsn> it = phiList.getList().iterator();
        while (it.hasNext()) {
            PhiInsn phi = it.next();
            if (fixPhiWithSameArgs(mth, block, phi)) {
                it.remove();
                changed = true;
            }
        }
    }
    removePhiList(mth, insnToRemove);
    return changed;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) InsnNode(jadx.core.dex.nodes.InsnNode) PhiInsn(jadx.core.dex.instructions.PhiInsn) SSAVar(jadx.core.dex.instructions.args.SSAVar) PhiListAttr(jadx.core.dex.attributes.nodes.PhiListAttr) ArrayList(java.util.ArrayList)

Aggregations

BlockNode (jadx.core.dex.nodes.BlockNode)220 InsnNode (jadx.core.dex.nodes.InsnNode)91 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)43 ArrayList (java.util.ArrayList)41 BitSet (java.util.BitSet)31 JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)29 InsnArg (jadx.core.dex.instructions.args.InsnArg)25 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)21 ExceptionHandler (jadx.core.dex.trycatch.ExceptionHandler)19 PhiInsn (jadx.core.dex.instructions.PhiInsn)14 SSAVar (jadx.core.dex.instructions.args.SSAVar)14 Nullable (org.jetbrains.annotations.Nullable)14 LoopInfo (jadx.core.dex.attributes.nodes.LoopInfo)13 IRegion (jadx.core.dex.nodes.IRegion)13 HashSet (java.util.HashSet)13 MethodNode (jadx.core.dex.nodes.MethodNode)12 Region (jadx.core.dex.regions.Region)12 LoopRegion (jadx.core.dex.regions.loops.LoopRegion)12 InsnType (jadx.core.dex.instructions.InsnType)11 SynchronizedRegion (jadx.core.dex.regions.SynchronizedRegion)11