Package com.strobel.assembler.flowanalysis

Examples of com.strobel.assembler.flowanalysis.ControlFlowNode


    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 List<Node> nodeBody = ((BasicBlock) node).getBody();
            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 || !nodeBody.isEmpty() && target == nodeBody.get(0))) {

                        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 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<>();

                //
                // It has to be just IfTrue; any preceding code would introduce a goto.
                //
                if (matchSingleAndBreak(basicBlock, AstCode.IfTrue, trueLabel, condition, falseLabel)) {
                    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)) {

                        removeOrThrow(loopContents, node);
                        removeOrThrow(scope, node);

                        //
                        // If false means enter the loop, negate the condition.
                        //
                        if (loopContents.contains(falseTarget) || falseTarget == node) {
                            final Label temp = trueLabel.get();

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

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

                        if (postLoopTarget != null) {
                            //
                            // Pull more nodes into the loop.
                            //
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 InstructionCollection instructions = methodBody.getInstructions();

        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> fallLabel = new StrongBox<>();
                final StrongBox<Label> tempTarget = new StrongBox<>();

                AstCode switchCode;

                if (matchLastAndBreak(block, switchCode = AstCode.TableSwitch, caseLabels, switchArgument, fallLabel) ||
                    matchLastAndBreak(block, switchCode = AstCode.LookupSwitch, caseLabels, switchArgument, fallLabel)) {

                    final Expression switchExpression = (Expression) blockBody.get(blockBody.size() - 2);
                    final Collection<Range> switchRanges = switchExpression.getArguments().get(0).getRanges();
                    final Instruction switchInstruction = instructions.atOffset(switchRanges.get(switchRanges.size() - 1).getStart());

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

                    final Switch switchNode = new Switch();

                    switchNode.setCondition(switchArgument.get());
                    removeTail(blockBody, switchCode, AstCode.Goto);
                    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 = switchInstruction.getOperand(0);
                    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];
                        //
                        // 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));

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

                            if (caseLabel == defaultLabel) {
                                continue;
                            }
                            else {
                                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));

                                    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));

                                caseBody.add(explicitBreak);
                            }
                        }

                        if (i != 0) {
                            if (switchCode == AstCode.TableSwitch) {
                                caseBlock.getValues().add(lowValue + i - 1);
                            }
                            else {
                                caseBlock.getValues().add(keys[i - 1]);
                            }
                        }
                    }

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

                        switchNode.getCaseBlocks().add(defaultBlock);

//                        defaultBlock.setEntryGoto(new Expression(AstCode.Goto, labels[0]));

                        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));

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

                    //
                    // TODO: Arrange the case blocks such that fall-throughs go to the right block.
                    //
                }

                //
                // 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())));

                    //
                    // 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()));
                    falseBlock.setEntryGoto(new Expression(AstCode.Goto, falseLabel.get()));

                    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

    private static ControlFlowNode findHandlerNode(final ControlFlowGraph cfg, final ExceptionHandler handler) {
        final List<ControlFlowNode> nodes = cfg.getNodes();

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

            if (node.getExceptionHandler() == handler) {
                return node;
            }
        }

        return null;
View Full Code Here

            //
            // Find all successors.
            //
            final ArrayList<ByteCode> branchTargets = new ArrayList<>();
            final ControlFlowNode node = nodeMap.get(byteCode.instruction);

            successors.clear();

            //
            // Add normal control first.
            //

            if (byteCode.instruction != node.getEnd()) {
                branchTargets.add(byteCode.next);
            }
            else {
                if (!byteCode.instruction.getOpCode().isUnconditionalBranch()) {
                    branchTargets.add(byteCode.next);
                }

                for (final ControlFlowNode successor : node.getSuccessors()) {
                    if (successor.getNodeType() == ControlFlowNodeType.Normal) {
                        successors.add(successor);
                    }
                    else if (successor.getNodeType() == ControlFlowNodeType.EndFinally) {
                        for (final ControlFlowNode s : successor.getSuccessors()) {
                            successors.add(s);
                        }
                    }
                }
            }

            //
            // Then add the exceptional control flow.
            //

            for (final ControlFlowNode successor : node.getSuccessors()) {
                if (successor.getExceptionHandler() != null) {
                    successors.add(
                        nodeMap.get(
                            successor.getExceptionHandler().getHandlerBlock().getFirstInstruction()
                        )
View Full Code Here

            final Set<ControlFlowNode> terminals = new HashSet<>();

            for (int i = 0; i < handlers.size(); i++) {
                final ExceptionHandler handler = handlers.get(i);
                final InstructionBlock handlerBlock = handler.getHandlerBlock();
                final ControlFlowNode handlerNode = findHandlerNode(_cfg, handler);
                final ControlFlowNode head = _nodeMap.get(handlerBlock.getFirstInstruction());
                final ControlFlowNode tryHead = _nodeMap.get(handler.getTryBlock().getFirstInstruction());

                terminals.clear();

                for (int j = 0; j < handlers.size(); j++) {
                    final ExceptionHandler otherHandler = handlers.get(j);

                    if (otherHandler.getTryBlock().equals(handler.getTryBlock())) {
                        terminals.add(findHandlerNode(_cfg, otherHandler));
                    }
                }

                final List<ControlFlowNode> tryNodes = new ArrayList<>(
                    findDominatedNodes(
                        _cfg,
                        tryHead,
                        true,
                        terminals
                    )
                );

                terminals.remove(handlerNode);

                if (handler.isFinally()) {
                    terminals.add(handlerNode.getEndFinallyNode());
                }

                final List<ControlFlowNode> handlerNodes = new ArrayList<>(
                    findDominatedNodes(
                        _cfg,
                        head,
                        true,
                        terminals
                    )
                );

                Collections.sort(tryNodes);
                Collections.sort(handlerNodes);

                final ControlFlowNode tail = last(handlerNodes);

                final HandlerInfo handlerInfo = new HandlerInfo(
                    handler,
                    handlerNode,
                    head,
View Full Code Here

            final int instructionCount,
            final Set<ControlFlowNode> toProcess,
            final Set<ControlFlowNode> forbiddenNodes) {

            final ExceptionHandler handler = handlerInfo.handler;
            final ControlFlowNode tryHead = _nodeMap.get(handler.getTryBlock().getFirstInstruction());
            final ControlFlowNode finallyTail = _nodeMap.get(handler.getHandlerBlock().getLastInstruction());
            final List<Pair<Instruction, Instruction>> startingPoints = new ArrayList<>();

        nextNode:
            for (ControlFlowNode node : toProcess) {
                final ExceptionHandler nodeHandler = node.getExceptionHandler();

                if (node.getNodeType() == ControlFlowNodeType.EndFinally) {
                    continue;
                }

                if (nodeHandler != null) {
                    node = _nodeMap.get(nodeHandler.getHandlerBlock().getLastInstruction());
                }

                if (_processedNodes.contains(node) || forbiddenNodes.contains(node)) {
                    continue;
                }

                Instruction tail = node.getEnd();
                boolean isLeave = false;
                boolean tryNext = false;
                boolean tryPrevious = false;

                if (finallyTail.getEnd().getOpCode().isReturn() ||
                    finallyTail.getEnd().getOpCode().isThrow()) {

                    isLeave = true;
                }

                if (last.getOpCode() == OpCode.GOTO || last.getOpCode() == OpCode.GOTO_W) {
                    tryNext = true;
                }

                if (tail.getOpCode().isUnconditionalBranch()) {
                    switch (tail.getOpCode()) {
                        case GOTO:
                        case GOTO_W:
                            tryPrevious = true;
                            break;

                        case RETURN:
                            tail = previous(tail);
                            tryPrevious = true;
                            break;

                        case IRETURN:
                        case LRETURN:
                        case FRETURN:
                        case DRETURN:
                        case ARETURN:
                            if (finallyTail.getEnd().getOpCode().getFlowControl() != FlowControl.Return) {
                                tail = previous(tail);
                            }
                            tryPrevious = true;
                            break;
View Full Code Here

        @SuppressWarnings("ConstantConditions")
        private Set<ControlFlowNode> collectNodes(final HandlerInfo handlerInfo) {
            final ControlFlowGraph cfg = _cfg;
            final List<ControlFlowNode> successors = new ArrayList<>();
            final Set<ControlFlowNode> toProcess = new LinkedHashSet<>();
            final ControlFlowNode endFinallyNode = handlerInfo.handlerNode.getEndFinallyNode();
            final Set<ControlFlowNode> exitOnlySuccessors = new LinkedHashSet<>();
            final InstructionBlock tryBlock = handlerInfo.handler.getTryBlock();

            if (endFinallyNode != null) {
                successors.add(handlerInfo.handlerNode);
            }

            for (final ControlFlowNode exit : cfg.getRegularExit().getPredecessors()) {
                if (exit.getNodeType() == ControlFlowNodeType.Normal &&
                    tryBlock.contains(exit.getEnd())) {

                    toProcess.add(exit);
                }
            }

            for (final ControlFlowNode exit : cfg.getExceptionalExit().getPredecessors()) {
                if (exit.getNodeType() == ControlFlowNodeType.Normal &&
                    tryBlock.contains(exit.getEnd())) {

                    toProcess.add(exit);
                }
            }

            for (int i = 0; i < successors.size(); i++) {
                final ControlFlowNode successor = successors.get(i);

                for (final ControlFlowEdge edge : successor.getIncoming()) {
                    if (edge.getSource() == successor) {
                        continue;
                    }

                    if (edge.getType() == JumpType.Normal &&
                        edge.getSource().getNodeType() == ControlFlowNodeType.Normal &&
                        !exitOnlySuccessors.contains(successor)) {

                        toProcess.add(edge.getSource());
                    }
                    else if (edge.getType() == JumpType.JumpToExceptionHandler &&
                             edge.getSource().getNodeType() == ControlFlowNodeType.Normal &&
                             (edge.getSource().getEnd().getOpCode().isThrow() ||
                              edge.getSource().getEnd().getOpCode().isReturn())) {

                        toProcess.add(edge.getSource());

                        if (exitOnlySuccessors.contains(successor)) {
                            exitOnlySuccessors.add(edge.getSource());
                        }
                    }
                    else if (edge.getSource().getNodeType() == ControlFlowNodeType.CatchHandler) {
                        final ControlFlowNode endCatch = findNode(
                            cfg,
                            edge.getSource().getExceptionHandler().getHandlerBlock().getLastInstruction()
                        );

                        if (handlerInfo.handler.getTryBlock().contains(endCatch.getEnd())) {
                            toProcess.add(endCatch);
                        }
                    }
                    else if (edge.getSource().getNodeType() == ControlFlowNodeType.FinallyHandler) {
                        successors.add(edge.getSource());
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.