All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.checkerframework.dataflow.cfg.builder.CFGTranslationPhaseTwo Maven / Gradle / Ivy

There is a newer version: 3.42.0-eisop4
Show newest version
package org.checkerframework.dataflow.cfg.builder;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.dataflow.cfg.ControlFlowGraph;
import org.checkerframework.dataflow.cfg.block.BlockImpl;
import org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl;
import org.checkerframework.dataflow.cfg.block.ExceptionBlockImpl;
import org.checkerframework.dataflow.cfg.block.RegularBlockImpl;
import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlockImpl;
import org.checkerframework.dataflow.cfg.block.SpecialBlock.SpecialBlockType;
import org.checkerframework.dataflow.cfg.block.SpecialBlockImpl;
import org.checkerframework.dataflow.cfg.node.CatchMarkerNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.javacutil.BugInCF;
import org.plumelib.util.ArraySet;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.lang.model.type.TypeMirror;

/** Class that performs phase two of the translation process. */
@SuppressWarnings("nullness") // TODO
public class CFGTranslationPhaseTwo {

    private CFGTranslationPhaseTwo() {}

    /**
     * Perform phase two of the translation.
     *
     * @param in the result of phase one
     * @return a control flow graph that might still contain degenerate basic blocks (such as empty
     *     regular basic blocks or conditional blocks with the same block as 'then' and 'else'
     *     successor)
     */
    @SuppressWarnings("interning:not.interned") // AST node comparisons
    public static ControlFlowGraph process(PhaseOneResult in) {

        Map bindings = in.bindings;
        List nodeList = in.nodeList;
        // A leader is an extended node which will give rise to a basic block in phase two.
        Set leaders = in.leaders;

        assert !in.nodeList.isEmpty();

        // exit blocks
        SpecialBlockImpl regularExitBlock = new SpecialBlockImpl(SpecialBlockType.EXIT);
        SpecialBlockImpl exceptionalExitBlock =
                new SpecialBlockImpl(SpecialBlockType.EXCEPTIONAL_EXIT);

        // record missing edges that will be added later
        Set missingEdges = new ArraySet<>(1);

        // missing exceptional edges
        Set missingExceptionalEdges = new LinkedHashSet<>();

        // create start block
        SpecialBlockImpl startBlock = new SpecialBlockImpl(SpecialBlockType.ENTRY);
        missingEdges.add(new MissingEdge(startBlock, 0));

        // Loop through all 'leaders' (while dynamically detecting the leaders).
        @NonNull RegularBlockImpl block = new RegularBlockImpl(); // block being processed/built
        int i = 0;
        for (ExtendedNode node : nodeList) {
            switch (node.getType()) {
                case NODE:
                    if (leaders.contains(i)) {
                        RegularBlockImpl b = new RegularBlockImpl();
                        block.setSuccessor(b);
                        block = b;
                    }
                    block.addNode(node.getNode());
                    node.setBlock(block);

                    // does this node end the execution (modeled as an edge to
                    // the exceptional exit block)
                    boolean terminatesExecution = node.getTerminatesExecution();
                    if (terminatesExecution) {
                        block.setSuccessor(exceptionalExitBlock);
                        block = new RegularBlockImpl();
                    }
                    break;
                case CONDITIONAL_JUMP:
                    {
                        ConditionalJump cj = (ConditionalJump) node;
                        // Exception nodes may fall through to conditional jumps, so we set the
                        // block which is required for the insertion of missing edges.
                        node.setBlock(block);
                        assert block != null;
                        ConditionalBlockImpl cb = new ConditionalBlockImpl();
                        if (cj.getTrueFlowRule() != null) {
                            cb.setThenFlowRule(cj.getTrueFlowRule());
                        }
                        if (cj.getFalseFlowRule() != null) {
                            cb.setElseFlowRule(cj.getFalseFlowRule());
                        }
                        block.setSuccessor(cb);
                        block = new RegularBlockImpl();

                        // use two anonymous SingleSuccessorBlockImpl that set the
                        // 'then' and 'else' successor of the conditional block
                        Label thenLabel = cj.getThenLabel();
                        Label elseLabel = cj.getElseLabel();
                        Integer target = bindings.get(thenLabel);
                        assert target != null;
                        missingEdges.add(
                                new MissingEdge(
                                        new RegularBlockImpl() {
                                            @Override
                                            public void setSuccessor(BlockImpl successor) {
                                                cb.setThenSuccessor(successor);
                                            }
                                        },
                                        target));
                        target = bindings.get(elseLabel);
                        if (target == null) {
                            throw new BugInCF(
                                    String.format(
                                            "in conditional jump %s, no binding for elseLabel %s: %s",
                                            cj, elseLabel, bindings));
                        }
                        missingEdges.add(
                                new MissingEdge(
                                        new RegularBlockImpl() {
                                            @Override
                                            public void setSuccessor(BlockImpl successor) {
                                                cb.setElseSuccessor(successor);
                                            }
                                        },
                                        target));
                        break;
                    }
                case UNCONDITIONAL_JUMP:
                    UnconditionalJump uj = (UnconditionalJump) node;
                    if (leaders.contains(i)) {
                        RegularBlockImpl b = new RegularBlockImpl();
                        block.setSuccessor(b);
                        block = b;
                    }
                    node.setBlock(block);
                    if (node.getLabel() == in.regularExitLabel) {
                        block.setSuccessor(regularExitBlock);
                        block.setFlowRule(uj.getFlowRule());
                    } else if (node.getLabel() == in.exceptionalExitLabel) {
                        block.setSuccessor(exceptionalExitBlock);
                        block.setFlowRule(uj.getFlowRule());
                    } else {
                        int target = bindings.get(node.getLabel());
                        missingEdges.add(new MissingEdge(block, target, uj.getFlowRule()));
                    }
                    block = new RegularBlockImpl();
                    break;
                case EXCEPTION_NODE:
                    NodeWithExceptionsHolder en = (NodeWithExceptionsHolder) node;
                    // create new exception block and link with previous block
                    ExceptionBlockImpl e = new ExceptionBlockImpl();
                    Node nn = en.getNode();
                    e.setNode(nn);
                    node.setBlock(e);
                    block.setSuccessor(e);
                    block = new RegularBlockImpl();

                    // Ensure linking between e and next block (normal edge).
                    // Note: do not link to the next block for throw statements (these throw
                    // exceptions for sure).
                    if (!node.getTerminatesExecution()) {
                        missingEdges.add(new MissingEdge(e, i + 1));
                    }

                    // exceptional edges
                    for (Map.Entry> entry : en.getExceptions().entrySet()) {
                        TypeMirror cause = entry.getKey();
                        for (Label label : entry.getValue()) {
                            Integer target = bindings.get(label);
                            // TODO: `target` is sometimes null; is this a problem?
                            // assert target != null;
                            missingExceptionalEdges.add(new MissingEdge(e, target, cause));
                        }
                    }
                    break;
            }
            i++;
        }

        // add missing edges
        for (MissingEdge p : missingEdges) {
            Integer index = p.index;
            assert index != null : "CFGBuilder: problem in CFG construction " + p.source;
            ExtendedNode extendedNode = nodeList.get(index);
            BlockImpl target = extendedNode.getBlock();
            SingleSuccessorBlockImpl source = p.source;
            source.setSuccessor(target);
            if (p.flowRule != null) {
                source.setFlowRule(p.flowRule);
            }
        }

        // add missing exceptional edges
        for (MissingEdge p : missingExceptionalEdges) {
            Integer index = p.index;
            TypeMirror cause = p.cause;
            ExceptionBlockImpl source = (ExceptionBlockImpl) p.source;
            if (index == null) {
                // edge to exceptional exit
                source.addExceptionalSuccessor(exceptionalExitBlock, cause);
            } else {
                // edge to specific target
                ExtendedNode extendedNode = nodeList.get(index);
                BlockImpl target = extendedNode.getBlock();
                List targetNodes = target.getNodes();
                Node firstNode = targetNodes.isEmpty() ? null : targetNodes.get(0);
                if (firstNode instanceof CatchMarkerNode) {
                    TypeMirror catchType = ((CatchMarkerNode) firstNode).getCatchType();
                    if (in.types.isSubtype(catchType, cause)) {
                        cause = catchType;
                    }
                }
                source.addExceptionalSuccessor(target, cause);
            }
        }

        return new ControlFlowGraph(
                startBlock,
                regularExitBlock,
                exceptionalExitBlock,
                in.underlyingAST,
                in.treeToCfgNodes,
                in.treeToConvertedCfgNodes,
                in.postfixTreeToCfgNodes,
                in.returnNodes,
                in.declaredClasses,
                in.declaredLambdas);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy