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

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

Go to download

The Checker Framework enhances Java's type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

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