Package com.strobel.assembler.flowanalysis

Examples of com.strobel.assembler.flowanalysis.ControlFlowNode


            }

            SubroutineInfo info = subroutineMap.get(target);

            if (info == null) {
                final ControlFlowNode start = findNode(cfg, target);

                final List<ControlFlowNode> contents = toList(
                    findDominatedNodes(
                        cfg,
                        start,
View Full Code Here


        agenda.add(head);
        visited.add(head);

        while (!agenda.isEmpty()) {
            ControlFlowNode addNode = agenda.removeFirst();

            if (terminals.contains(addNode)) {
                continue;
            }

            if (diveIntoHandlers && addNode.getExceptionHandler() != null) {
                addNode = findNode(cfg, addNode.getExceptionHandler().getHandlerBlock().getFirstInstruction());
            }
            else if (diveIntoHandlers && addNode.getNodeType() == ControlFlowNodeType.EndFinally) {
                agenda.addAll(addNode.getDominatorTreeChildren());
                continue;
            }

            if (addNode == null || addNode.getNodeType() != ControlFlowNodeType.Normal) {
                continue;
            }

            if (!head.dominates(addNode) &&
                !shouldIncludeExceptionalExit(cfg, head, addNode)) {

                continue;
            }

            if (!result.add(addNode)) {
                continue;
            }

            for (final ControlFlowNode successor : addNode.getSuccessors()) {
                if (visited.add(successor)) {
                    agenda.add(successor);
                }
            }
        }
View Full Code Here

        }

        if (!node.getDominanceFrontier().contains(cfg.getExceptionalExit()) &&
            !node.dominates(cfg.getExceptionalExit())) {

            final ControlFlowNode innermostHandlerNode = findInnermostExceptionHandlerNode(cfg, node.getEnd().getOffset(), false);

            if (innermostHandlerNode == null || !node.getDominanceFrontier().contains(innermostHandlerNode)) {
                return false;
            }
        }
View Full Code Here

    private static ControlFlowNode findInnermostExceptionHandlerNode(
        final ControlFlowGraph cfg,
        final int offsetInTryBlock,
        final boolean finallyOnly) {
        ExceptionHandler result = null;
        ControlFlowNode resultNode = null;

        final List<ControlFlowNode> nodes = cfg.getNodes();

        for (int i = nodes.size() - 1; i >= 0; i--) {
            final ControlFlowNode node = nodes.get(i);
            final ExceptionHandler handler = node.getExceptionHandler();

            if (handler == null) {
                break;
            }
View Full Code Here

    private ControlFlowGraph buildGraph(final List<Node> nodes, final Label entryLabel) {
        int index = 0;

        final List<ControlFlowNode> cfNodes = new ArrayList<>();

        final ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);
        final ControlFlowNode regularExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.RegularExit);
        final ControlFlowNode exceptionalExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.ExceptionalExit);

        cfNodes.add(entryPoint);
        cfNodes.add(regularExit);
        cfNodes.add(exceptionalExit);

        //
        // Create graph nodes.
        //

        labelsToNodes.clear();

        final Map<Node, ControlFlowNode> astNodesToControlFlowNodes = new IdentityHashMap<>();

        for (final Node node : nodes) {
            final ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal);

            cfNodes.add(cfNode);
            astNodesToControlFlowNodes.put(node, cfNode);
            cfNode.setUserData(node);

            //
            // Find all contained labels.
            //
            for (final Label label : node.getSelfAndChildrenRecursive(Label.class)) {
                labelsToNodes.put(label, cfNode);
            }
        }

        final ControlFlowNode entryNode = labelsToNodes.get(entryLabel);
        final ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);

        entryPoint.getOutgoing().add(entryEdge);
        entryNode.getIncoming().add(entryEdge);

        //
        // Create edges.
        //

        for (final Node node : nodes) {
            final ControlFlowNode source = astNodesToControlFlowNodes.get(node);

            //
            // Find all branches.
            //

            for (final Expression e : node.getSelfAndChildrenRecursive(Expression.class)) {
                if (!e.isBranch()) {
                    continue;
                }

                for (final Label target : e.getBranchTargets()) {
                    final ControlFlowNode destination = labelsToNodes.get(target);

                    if (destination != null &&
                        (destination != source || canBeSelfContainedLoop((BasicBlock) node, e, target))) {

                        final ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);

                        if (!source.getOutgoing().contains(edge)) {
                            source.getOutgoing().add(edge);
                        }

                        if (!destination.getIncoming().contains(edge)) {
                            destination.getIncoming().add(edge);
                        }
                    }
                }
            }
        }
View Full Code Here

        final ArrayDeque<ControlFlowNode> agenda = new ArrayDeque<>();

        agenda.addLast(entryPoint);

        while (!agenda.isEmpty()) {
            final ControlFlowNode node = agenda.pollFirst();

            //
            // If the node is a loop header...
            //
            if (scope.contains(node) &&
                node.getDominanceFrontier().contains(node) &&
                (node != entryPoint || !excludeEntryPoint)) {

                final Set<ControlFlowNode> loopContents = findLoopContents(scope, node);

                //
                // If the first or last expression is a loop condition...
                //
                final BasicBlock basicBlock = (BasicBlock) node.getUserData();
                final StrongBox<Expression> condition = new StrongBox<>();
                final StrongBox<Label> trueLabel = new StrongBox<>();
                final StrongBox<Label> falseLabel = new StrongBox<>();

                final ControlFlowNode lastInLoop = lastOrDefault(loopContents);
                final BasicBlock lastBlock = (BasicBlock) lastInLoop.getUserData();

                //
                // Check for an infinite loop.
                //

                if (loopContents.size() == 1 &&
                    matchSimpleBreak(basicBlock, trueLabel) &&
                    trueLabel.get() == first(basicBlock.getBody())) {

                    final Loop emptyLoop = new Loop();

                    emptyLoop.setBody(new Block());

                    final BasicBlock block = new BasicBlock();
                    final List<Node> blockBody = block.getBody();

                    blockBody.add(basicBlock.getBody().get(0));
                    blockBody.add(emptyLoop);

                    result.add(block);
                    scope.remove(lastInLoop);
                    continue;
                }

                //
                // Check for a conditional loop.
                //

                for (int pass = 0; pass < 2; pass++) {
                    final boolean isPostCondition = pass == 1;

                    final boolean foundCondition = isPostCondition ? matchLastAndBreak(lastBlock, AstCode.IfTrue, trueLabel, condition, falseLabel)
                                                                   : matchSingleAndBreak(basicBlock, AstCode.IfTrue, trueLabel, condition, falseLabel);

                    //
                    // It has to be just IfTrue; any preceding code would introduce a goto.
                    //
                    if (!foundCondition) {
                        continue;
                    }

                    final ControlFlowNode trueTarget = labelsToNodes.get(trueLabel.get());
                    final ControlFlowNode falseTarget = labelsToNodes.get(falseLabel.get());

                    //
                    // If one point inside the loop and the other outside...
                    //

                    if ((!loopContents.contains(falseTarget) || loopContents.contains(trueTarget)) &&
                        (!loopContents.contains(trueTarget) || loopContents.contains(falseTarget))) {

                        continue;
                    }

                    final boolean flipped = loopContents.contains(falseTarget) || falseTarget == node;

                    //
                    // If false means enter the loop, negate the condition.
                    //
                    if (flipped) {
                        final Label temp = trueLabel.get();

                        trueLabel.set(falseLabel.get());
                        falseLabel.set(temp);
                        condition.set(AstOptimizer.simplifyLogicalNot(new Expression(AstCode.LogicalNot, null, condition.get().getOffset(), condition.get())));
                    }

                    final boolean canWriteConditionalLoop;

                    if (isPostCondition) {
                        final Expression continueGoto;

                        if (flipped) {
                            continueGoto = (Expression) last(lastBlock.getBody());
                        }
                        else {
                            continueGoto = (Expression) lastBlock.getBody().get(lastBlock.getBody().size() - 2);
                        }

                        canWriteConditionalLoop = countJumps(loopContents, trueLabel.get(), continueGoto) == 0;
                    }
                    else {
                        canWriteConditionalLoop = true;
                    }

                    if (canWriteConditionalLoop) {
                        removeOrThrow(loopContents, node);
                        removeOrThrow(scope, node);

                        final ControlFlowNode postLoopTarget = labelsToNodes.get(falseLabel.get());

                        if (postLoopTarget != null) {
                            //
                            // Pull more nodes into the loop.
                            //
                            final Set<ControlFlowNode> postLoopContents = findDominatedNodes(scope, postLoopTarget);
                            final LinkedHashSet<ControlFlowNode> pullIn = new LinkedHashSet<>(scope);

                            pullIn.removeAll(postLoopContents);

                            for (final ControlFlowNode n : pullIn) {
                                if (node.dominates(n)) {
                                    loopContents.add(n);
                                }
                            }
                        }

                        //
                        // Use loop to implement the IfTrue.
                        //
                        final BasicBlock block;
                        final List<Node> basicBlockBody;
                        final Label loopLabel;

                        if (isPostCondition) {
                            block = new BasicBlock();
                            basicBlockBody = block.getBody();

                            removeTail(lastBlock.getBody(), AstCode.IfTrue, AstCode.Goto);

                            if (lastBlock.getBody().size() > 1) {
                                lastBlock.getBody().add(new Expression(AstCode.Goto, trueLabel.get(), Expression.MYSTERY_OFFSET));
                                loopLabel = new Label("Loop_" + _nextLabelIndex++);
                            }
                            else {
                                scope.remove(lastInLoop);
                                loopContents.remove(lastInLoop);
                                loopLabel = (Label) lastBlock.getBody().get(0);
                            }

                            basicBlockBody.add(loopLabel);
                        }
                        else {
                            block = basicBlock;
                            basicBlockBody = block.getBody();
                            removeTail(basicBlockBody, AstCode.IfTrue, AstCode.Goto);
                        }

                        final Loop loop = new Loop();
                        final Block bodyBlock = new Block();

                        loop.setCondition(condition.get());
                        loop.setBody(bodyBlock);

                        if (isPostCondition) {
                            loop.setLoopType(LoopType.PostCondition);
                            bodyBlock.getBody().add(basicBlock);
                        }

                        bodyBlock.setEntryGoto(new Expression(AstCode.Goto, trueLabel.get(), Expression.MYSTERY_OFFSET));
                        bodyBlock.getBody().addAll(findLoops(loopContents, node, isPostCondition));

                        basicBlockBody.add(loop);

                        if (isPostCondition) {
                            basicBlockBody.add(new Expression(AstCode.Goto, falseLabel.get(), Expression.MYSTERY_OFFSET));
                        }
                        else {
                            basicBlockBody.add(new Expression(AstCode.Goto, falseLabel.get(), Expression.MYSTERY_OFFSET));
                        }

                        result.add(block);
                        scope.removeAll(loopContents);

                        break;
                    }
                }

                //
                // Fallback method: while (true) { ... }
                //
                if (scope.contains(node)) {
                    final BasicBlock block = new BasicBlock();
                    final List<Node> blockBody = block.getBody();
                    final Loop loop = new Loop();
                    final Block bodyBlock = new Block();

                    loop.setBody(bodyBlock);

                    final LoopExitInfo exitInfo = findLoopExitInfo(loopContents);

                    if (exitInfo.exitLabel != null) {
                        final ControlFlowNode postLoopTarget = labelsToNodes.get(exitInfo.exitLabel);

                        if (postLoopTarget.getIncoming().size() == 1) {
                            //
                            // See if our only exit comes from an inner switch's default label.  If so, pull it in
                            // to the loop if there are no other references.
                            //

                            final ControlFlowNode predecessor = firstOrDefault(postLoopTarget.getPredecessors());

                            if (predecessor != null && loopContents.contains(predecessor)) {
                                final BasicBlock b = (BasicBlock) predecessor.getUserData();

                                if (matchLast(b, AstCode.Switch, switchLabels, condition) &&
                                    !ArrayUtilities.isNullOrEmpty(switchLabels.get()) &&
                                    exitInfo.exitLabel == switchLabels.get()[0]) {

                                    final Set<ControlFlowNode> defaultContents = findDominatedNodes(scope, postLoopTarget);

                                    for (final ControlFlowNode n : defaultContents) {
                                        if (scope.contains(n) && node.dominates(n)) {
                                            loopContents.add(n);
                                        }
                                    }
                                }
                            }
                        }

                        if (!loopContents.contains(postLoopTarget)) {
                            //
                            // Pull more nodes into the loop.
                            //
                            final Set<ControlFlowNode> postLoopContents = findDominatedNodes(scope, postLoopTarget);
                            final LinkedHashSet<ControlFlowNode> pullIn = new LinkedHashSet<>(scope);

                            pullIn.removeAll(postLoopContents);

                            for (final ControlFlowNode n : pullIn) {
                                if (n.getBlockIndex() < postLoopTarget.getBlockIndex() && scope.contains(n) && node.dominates(n)) {
                                    loopContents.add(n);
                                }
                            }
                        }
                    }
                    else if (exitInfo.additionalNodes.size() == 1) {
                        final ControlFlowNode postLoopTarget = first(exitInfo.additionalNodes);
                        final BasicBlock postLoopBlock = (BasicBlock) postLoopTarget.getUserData();
                        final Node postLoopBlockHead = firstOrDefault(postLoopBlock.getBody());

                        //
                        // See if our only exit comes from an inner switch's default label.  If so, pull it in
                        // to the loop if there are no other references.
                        //

                        final ControlFlowNode predecessor = single(postLoopTarget.getPredecessors());

                        if (postLoopBlockHead instanceof Label &&
                            loopContents.contains(predecessor)) {

                            final BasicBlock b = (BasicBlock) predecessor.getUserData();

                            if (matchLast(b, AstCode.Switch, switchLabels, condition) &&
                                !ArrayUtilities.isNullOrEmpty(switchLabels.get()) &&
                                postLoopBlockHead == switchLabels.get()[0]) {
View Full Code Here

        for (final ControlFlowNode node : contents) {
            final BasicBlock basicBlock = (BasicBlock) node.getUserData();

            for (final Expression e : basicBlock.getSelfAndChildrenRecursive(Expression.class)) {
                for (final Label target : e.getBranchTargets()) {
                    final ControlFlowNode targetNode = labelsToNodes.get(target);

                    if (targetNode == null || contents.contains(targetNode)) {
                        continue;
                    }

                    if (targetNode.getIncoming().size() == 1) {
                        exitInfo.additionalNodes.add(targetNode);
                    }
                    else if (exitInfo.exitLabel == null) {
                        exitInfo.exitLabel = target;
                    }
View Full Code Here

        final Set<ControlFlowNode> agenda = new LinkedHashSet<>(viaBackEdges);
        final Set<ControlFlowNode> result = new LinkedHashSet<>();

        while (!agenda.isEmpty()) {
            final ControlFlowNode addNode = agenda.iterator().next();

            agenda.remove(addNode);

            if (scope.contains(addNode) && head.dominates(addNode) && result.add(addNode)) {
                for (final ControlFlowNode predecessor : addNode.getPredecessors()) {
                    agenda.add(predecessor);
                }
            }
        }
View Full Code Here

        final Stack<ControlFlowNode> agenda = new Stack<>();

        agenda.push(entryNode);

        while (!agenda.isEmpty()) {
            final ControlFlowNode node = agenda.pop();

            if (node == null) {
                continue;
            }

            //
            // Find a block that represents a simple condition.
            //

            if (scope.contains(node)) {
                final BasicBlock block = (BasicBlock) node.getUserData();
                final List<Node> blockBody = block.getBody();

                final StrongBox<Label[]> caseLabels = new StrongBox<>();
                final StrongBox<Expression> switchArgument = new StrongBox<>();
                final StrongBox<Label> tempTarget = new StrongBox<>();

                if (matchLast(block, AstCode.Switch, caseLabels, switchArgument)) {
                    final Expression switchExpression = (Expression) blockBody.get(blockBody.size() - 1);

                    //
                    // Replace the switch code with a Switch node.
                    //

                    final Switch switchNode = new Switch();

                    switchNode.setCondition(switchArgument.get());
                    removeTail(blockBody, AstCode.Switch);
                    blockBody.add(switchNode);
                    result.add(block);

                    //
                    // Replace the item so it isn't picked up as content.
                    //

                    removeOrThrow(scope, node);

                    //
                    // Pull in code of cases.
                    //

                    final Label[] labels = caseLabels.get();
                    final SwitchInfo switchInfo = switchExpression.getUserData(AstKeys.SWITCH_INFO);
                    final int lowValue = switchInfo.getLowValue();
                    final int[] keys = switchInfo.getKeys();
                    final Label defaultLabel = labels[0];
                    final ControlFlowNode defaultTarget = labelsToNodes.get(defaultLabel);

                    boolean defaultFollowsSwitch = false;

                    for (int i = 1; i < labels.length; i++) {
                        final Label caseLabel = labels[i];

                        if (caseLabel == defaultLabel) {
                            continue;
                        }

                        //
                        // Find or create a new case block.
                        //

                        CaseBlock caseBlock = null;

                        for (final CaseBlock cb : switchNode.getCaseBlocks()) {
                            if (cb.getEntryGoto().getOperand() == caseLabel) {
                                caseBlock = cb;
                                break;
                            }
                        }

                        if (caseBlock == null) {
                            caseBlock = new CaseBlock();

                            caseBlock.setEntryGoto(new Expression(AstCode.Goto, caseLabel, Expression.MYSTERY_OFFSET));

                            final ControlFlowNode caseTarget = labelsToNodes.get(caseLabel);
                            final List<Node> caseBody = caseBlock.getBody();

                            switchNode.getCaseBlocks().add(caseBlock);

                            if (caseTarget != null) {
                                if (caseTarget.getDominanceFrontier().contains(defaultTarget)) {
                                    defaultFollowsSwitch = true;
                                }

                                final Set<ControlFlowNode> content = findDominatedNodes(scope, caseTarget);

                                scope.removeAll(content);
                                caseBody.addAll(findConditions(content, caseTarget));
                            }
                            else {
                                final BasicBlock explicitGoto = new BasicBlock();

                                explicitGoto.getBody().add(new Label("SwitchGoto_" + _nextLabelIndex++));
                                explicitGoto.getBody().add(new Expression(AstCode.Goto, caseLabel, Expression.MYSTERY_OFFSET));

                                caseBody.add(explicitGoto);
                            }

                            if (caseBody.isEmpty() ||
                                !matchLast((BasicBlock) caseBody.get(caseBody.size() - 1), AstCode.Goto, tempTarget) ||
                                !ArrayUtilities.contains(labels, tempTarget.get())) {

                                //
                                // Add explicit break that should not be used by default, but which might be used
                                // by goto removal.
                                //

                                final BasicBlock explicitBreak = new BasicBlock();

                                explicitBreak.getBody().add(new Label("SwitchBreak_" + _nextLabelIndex++));
                                explicitBreak.getBody().add(new Expression(AstCode.LoopOrSwitchBreak, null, Expression.MYSTERY_OFFSET));

                                caseBody.add(explicitBreak);
                            }
                        }

                        if (switchInfo.hasKeys()) {
                            caseBlock.getValues().add(keys[i - 1]);
                        }
                        else {
                            caseBlock.getValues().add(lowValue + i - 1);
                        }
                    }

                    if (!defaultFollowsSwitch) {
                        final CaseBlock defaultBlock = new CaseBlock();

                        defaultBlock.setEntryGoto(new Expression(AstCode.Goto, defaultLabel, Expression.MYSTERY_OFFSET));

                        switchNode.getCaseBlocks().add(defaultBlock);

                        final Set<ControlFlowNode> content = findDominatedNodes(scope, defaultTarget);

                        scope.removeAll(content);
                        defaultBlock.getBody().addAll(findConditions(content, defaultTarget));

                        //
                        // Add explicit break that should not be used by default, but which might be used
                        // by goto removal.
                        //

                        final BasicBlock explicitBreak = new BasicBlock();

                        explicitBreak.getBody().add(new Label("SwitchBreak_" + _nextLabelIndex++));
                        explicitBreak.getBody().add(new Expression(AstCode.LoopOrSwitchBreak, null, Expression.MYSTERY_OFFSET));

                        defaultBlock.getBody().add(explicitBreak);
                    }

                    reorderCaseBlocks(switchNode);
                }

                //
                // Two-way branch...
                //
                final StrongBox<Expression> condition = new StrongBox<>();
                final StrongBox<Label> trueLabel = new StrongBox<>();
                final StrongBox<Label> falseLabel = new StrongBox<>();

                if (matchLastAndBreak(block, AstCode.IfTrue, trueLabel, condition, falseLabel)) {
                    //
                    // Flip bodies since that seems to be the Java compiler tradition.
                    //

                    final Label temp = trueLabel.get();

                    trueLabel.set(falseLabel.get());
                    falseLabel.set(temp);
                    condition.set(AstOptimizer.simplifyLogicalNot(new Expression(AstCode.LogicalNot, null, condition.get().getOffset(), condition.get())));

                    //
                    // Convert IfTrue expression to Condition.
                    //

                    final Condition conditionNode = new Condition();
                    final Block trueBlock = new Block();
                    final Block falseBlock = new Block();

                    trueBlock.setEntryGoto(new Expression(AstCode.Goto, trueLabel.get(), Expression.MYSTERY_OFFSET));
                    falseBlock.setEntryGoto(new Expression(AstCode.Goto, falseLabel.get(), Expression.MYSTERY_OFFSET));

                    conditionNode.setCondition(condition.get());
                    conditionNode.setTrueBlock(trueBlock);
                    conditionNode.setFalseBlock(falseBlock);

                    removeTail(blockBody, AstCode.IfTrue, AstCode.Goto);
                    blockBody.add(conditionNode);
                    result.add(block);

                    //
                    // Remove the item immediately so it isn't picked up as content.
                    //
                    removeOrThrow(scope, node);

                    final ControlFlowNode trueTarget = labelsToNodes.get(trueLabel.get());
                    final ControlFlowNode falseTarget = labelsToNodes.get(falseLabel.get());

                    //
                    // Pull in the conditional code.
                    //
View Full Code Here

        final Set<ControlFlowNode> result = new LinkedHashSet<>();

        agenda.add(head);

        while (!agenda.isEmpty()) {
            final ControlFlowNode addNode = agenda.iterator().next();

            agenda.remove(addNode);

            if (scope.contains(addNode) && head.dominates(addNode) && result.add(addNode)) {
                for (final ControlFlowNode successor : addNode.getSuccessors()) {
                    agenda.add(successor);
                }
            }
        }
View Full Code Here

TOP

Related Classes of com.strobel.assembler.flowanalysis.ControlFlowNode

Copyright © 2018 www.massapicom. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.