Search in sources :

Example 1 with ConditionalBlockImpl

use of org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl in project checker-framework by typetools.

the class CFGTranslationPhaseTwo method process.

/**
 * Perform phase two of the translation.
 *
 * @param in the result of phase one
 * @return a control flow graph that might still contain degenerate basic block (such as empty
 *     regular basic blocks or conditional blocks with the same block as 'then' and 'else'
 *     successor)
 */
// AST node comparisons
@SuppressWarnings("interning:not.interned")
public static ControlFlowGraph process(PhaseOneResult in) {
    Map<Label, Integer> bindings = in.bindings;
    ArrayList<ExtendedNode> nodeList = in.nodeList;
    // A leader is an extended node which will give rise to a basic block in phase two.
    Set<Integer> 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<MissingEdge> missingEdges = new MostlySingleton<>();
    // missing exceptional edges
    Set<MissingEdge> 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).
    // block being processed/built
    @NonNull RegularBlockImpl block = new RegularBlockImpl();
    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;
                    final 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
                    final Label thenLabel = cj.getThenLabel();
                    final 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);
                    assert target != null;
                    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();
                // sure).
                if (!node.getTerminatesExecution()) {
                    missingEdges.add(new MissingEdge(e, i + 1));
                }
                // exceptional edges
                for (Map.Entry<TypeMirror, Set<Label>> entry : en.getExceptions().entrySet()) {
                    TypeMirror cause = entry.getKey();
                    for (Label label : entry.getValue()) {
                        Integer target = bindings.get(label);
                        // TODO: This 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();
            source.addExceptionalSuccessor(target, cause);
        }
    }
    return new ControlFlowGraph(startBlock, regularExitBlock, exceptionalExitBlock, in.underlyingAST, in.treeLookupMap, in.convertedTreeLookupMap, in.unaryAssignNodeLookupMap, in.returnNodes, in.declaredClasses, in.declaredLambdas);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ExceptionBlockImpl(org.checkerframework.dataflow.cfg.block.ExceptionBlockImpl) BlockImpl(org.checkerframework.dataflow.cfg.block.BlockImpl) RegularBlockImpl(org.checkerframework.dataflow.cfg.block.RegularBlockImpl) ConditionalBlockImpl(org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl) SpecialBlockImpl(org.checkerframework.dataflow.cfg.block.SpecialBlockImpl) SingleSuccessorBlockImpl(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlockImpl) Set(java.util.Set) LinkedHashSet(java.util.LinkedHashSet) Node(org.checkerframework.dataflow.cfg.node.Node) ExceptionBlockImpl(org.checkerframework.dataflow.cfg.block.ExceptionBlockImpl) SingleSuccessorBlockImpl(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlockImpl) RegularBlockImpl(org.checkerframework.dataflow.cfg.block.RegularBlockImpl) TypeMirror(javax.lang.model.type.TypeMirror) SpecialBlockImpl(org.checkerframework.dataflow.cfg.block.SpecialBlockImpl) NonNull(org.checkerframework.checker.nullness.qual.NonNull) MostlySingleton(org.checkerframework.dataflow.util.MostlySingleton) ConditionalBlockImpl(org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl) ControlFlowGraph(org.checkerframework.dataflow.cfg.ControlFlowGraph) Map(java.util.Map)

Example 2 with ConditionalBlockImpl

use of org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl in project checker-framework by typetools.

the class CFGTranslationPhaseThree method getPredecessorHolder.

/**
 * Return a predecessor holder that can be used to set the successor of {@code pred} in the place
 * where previously the edge pointed to {@code cur}. Additionally, the predecessor holder also
 * takes care of unlinking (i.e., removing the {@code pred} from {@code cur's} predecessors).
 *
 * @param pred a block whose successor should be set
 * @param cur the previous successor of {@code pred}
 * @return a predecessor holder to set the successor of {@code pred}
 */
// AST node comparisons
@SuppressWarnings("interning:not.interned")
protected static PredecessorHolder getPredecessorHolder(final BlockImpl pred, final BlockImpl cur) {
    switch(pred.getType()) {
        case SPECIAL_BLOCK:
            SingleSuccessorBlockImpl s = (SingleSuccessorBlockImpl) pred;
            return singleSuccessorHolder(s, cur);
        case CONDITIONAL_BLOCK:
            // add pred correctly to predecessor list
            final ConditionalBlockImpl c = (ConditionalBlockImpl) pred;
            if (c.getThenSuccessor() == cur) {
                return new PredecessorHolder() {

                    @Override
                    public void setSuccessor(BlockImpl b) {
                        c.setThenSuccessor(b);
                        cur.removePredecessor(pred);
                    }

                    @Override
                    public BlockImpl getBlock() {
                        return c;
                    }
                };
            } else {
                assert c.getElseSuccessor() == cur;
                return new PredecessorHolder() {

                    @Override
                    public void setSuccessor(BlockImpl b) {
                        c.setElseSuccessor(b);
                        cur.removePredecessor(pred);
                    }

                    @Override
                    public BlockImpl getBlock() {
                        return c;
                    }
                };
            }
        case EXCEPTION_BLOCK:
            // add pred correctly to predecessor list
            final ExceptionBlockImpl e = (ExceptionBlockImpl) pred;
            if (e.getSuccessor() == cur) {
                return singleSuccessorHolder(e, cur);
            } else {
                // ignore keyfor type
                @SuppressWarnings("keyfor:assignment") Set<Map.Entry<TypeMirror, Set<Block>>> entrySet = e.getExceptionalSuccessors().entrySet();
                for (final Map.Entry<TypeMirror, Set<Block>> entry : entrySet) {
                    if (entry.getValue().contains(cur)) {
                        return new PredecessorHolder() {

                            @Override
                            public void setSuccessor(BlockImpl b) {
                                e.addExceptionalSuccessor(b, entry.getKey());
                                cur.removePredecessor(pred);
                            }

                            @Override
                            public BlockImpl getBlock() {
                                return e;
                            }
                        };
                    }
                }
            }
            throw new BugInCF("Unreachable");
        case REGULAR_BLOCK:
            RegularBlockImpl r = (RegularBlockImpl) pred;
            return singleSuccessorHolder(r, cur);
        default:
            throw new BugInCF("Unexpected block type " + pred.getType());
    }
}
Also used : ExceptionBlockImpl(org.checkerframework.dataflow.cfg.block.ExceptionBlockImpl) BlockImpl(org.checkerframework.dataflow.cfg.block.BlockImpl) RegularBlockImpl(org.checkerframework.dataflow.cfg.block.RegularBlockImpl) ConditionalBlockImpl(org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl) SingleSuccessorBlockImpl(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlockImpl) Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) ExceptionBlockImpl(org.checkerframework.dataflow.cfg.block.ExceptionBlockImpl) BugInCF(org.checkerframework.javacutil.BugInCF) SingleSuccessorBlockImpl(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlockImpl) RegularBlockImpl(org.checkerframework.dataflow.cfg.block.RegularBlockImpl) ConditionalBlockImpl(org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl) TypeMirror(javax.lang.model.type.TypeMirror) Block(org.checkerframework.dataflow.cfg.block.Block) Map(java.util.Map)

Example 3 with ConditionalBlockImpl

use of org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl in project checker-framework by typetools.

the class CFGTranslationPhaseThree method process.

/**
 * Perform phase three on the control flow graph {@code cfg}.
 *
 * @param cfg the control flow graph. Ownership is transfered to this method and the caller is not
 *     allowed to read or modify {@code cfg} after the call to {@code process} any more.
 * @return the resulting control flow graph
 */
// TODO: successors
@SuppressWarnings("nullness")
public static ControlFlowGraph process(ControlFlowGraph cfg) {
    Set<Block> worklist = cfg.getAllBlocks();
    Set<Block> dontVisit = new HashSet<>();
    // fix predecessor lists by removing any unreachable predecessors
    for (Block c : worklist) {
        BlockImpl cur = (BlockImpl) c;
        for (Block pred : new HashSet<>(cur.getPredecessors())) {
            if (!worklist.contains(pred)) {
                cur.removePredecessor((BlockImpl) pred);
            }
        }
    }
    // remove empty blocks
    for (Block cur : worklist) {
        if (dontVisit.contains(cur)) {
            continue;
        }
        if (cur.getType() == BlockType.REGULAR_BLOCK) {
            RegularBlockImpl b = (RegularBlockImpl) cur;
            if (b.isEmpty()) {
                Set<RegularBlockImpl> emptyBlocks = new HashSet<>();
                Set<PredecessorHolder> predecessors = new LinkedHashSet<>();
                BlockImpl succ = computeNeighborhoodOfEmptyBlock(b, emptyBlocks, predecessors);
                for (RegularBlockImpl e : emptyBlocks) {
                    succ.removePredecessor(e);
                    dontVisit.add(e);
                }
                for (PredecessorHolder p : predecessors) {
                    BlockImpl block = p.getBlock();
                    dontVisit.add(block);
                    succ.removePredecessor(block);
                    p.setSuccessor(succ);
                }
            }
        }
    }
    // remove useless conditional blocks
    /* Issue 3267 revealed that this is a dangerous optimization:
       it merges a block that evaluates one condition onto an unrelated following block,
       which can also be a condition. The then/else stores from the first block are still
       set, leading to incorrect results for the then/else stores in the following block.
       The correct result would be to merge the then/else stores from the previous block.
       However, as this is late in the CFG construction, I didn't see how to add e.g. a
       dummy variable declaration node in a dummy regular block, which would cause a merge.
       So for now, let's not perform this optimization.
       It would be interesting to know how large the impact of this optimization is.

    worklist = cfg.getAllBlocks();
    for (Block c : worklist) {
        BlockImpl cur = (BlockImpl) c;

        if (cur.getType() == BlockType.CONDITIONAL_BLOCK) {
            ConditionalBlockImpl cb = (ConditionalBlockImpl) cur;
            assert cb.getPredecessors().size() == 1;
            if (cb.getThenSuccessor() == cb.getElseSuccessor()) {
                BlockImpl pred = cb.getPredecessors().iterator().next();
                PredecessorHolder predecessorHolder = getPredecessorHolder(pred, cb);
                BlockImpl succ = (BlockImpl) cb.getThenSuccessor();
                succ.removePredecessor(cb);
                predecessorHolder.setSuccessor(succ);
            }
        }
    }
    */
    // merge consecutive basic blocks if possible
    worklist = cfg.getAllBlocks();
    for (Block cur : worklist) {
        if (cur.getType() == BlockType.REGULAR_BLOCK) {
            RegularBlockImpl b = (RegularBlockImpl) cur;
            Block succ = b.getRegularSuccessor();
            if (succ.getType() == BlockType.REGULAR_BLOCK) {
                RegularBlockImpl rs = (RegularBlockImpl) succ;
                if (rs.getPredecessors().size() == 1) {
                    b.setSuccessor(rs.getRegularSuccessor());
                    b.addNodes(rs.getNodes());
                    rs.getRegularSuccessor().removePredecessor(rs);
                }
            }
        }
    }
    return cfg;
}
Also used : ExceptionBlockImpl(org.checkerframework.dataflow.cfg.block.ExceptionBlockImpl) BlockImpl(org.checkerframework.dataflow.cfg.block.BlockImpl) RegularBlockImpl(org.checkerframework.dataflow.cfg.block.RegularBlockImpl) ConditionalBlockImpl(org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl) SingleSuccessorBlockImpl(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlockImpl) LinkedHashSet(java.util.LinkedHashSet) RegularBlockImpl(org.checkerframework.dataflow.cfg.block.RegularBlockImpl) Block(org.checkerframework.dataflow.cfg.block.Block) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Aggregations

LinkedHashSet (java.util.LinkedHashSet)3 BlockImpl (org.checkerframework.dataflow.cfg.block.BlockImpl)3 ConditionalBlockImpl (org.checkerframework.dataflow.cfg.block.ConditionalBlockImpl)3 ExceptionBlockImpl (org.checkerframework.dataflow.cfg.block.ExceptionBlockImpl)3 RegularBlockImpl (org.checkerframework.dataflow.cfg.block.RegularBlockImpl)3 SingleSuccessorBlockImpl (org.checkerframework.dataflow.cfg.block.SingleSuccessorBlockImpl)3 HashSet (java.util.HashSet)2 Map (java.util.Map)2 Set (java.util.Set)2 TypeMirror (javax.lang.model.type.TypeMirror)2 Block (org.checkerframework.dataflow.cfg.block.Block)2 NonNull (org.checkerframework.checker.nullness.qual.NonNull)1 ControlFlowGraph (org.checkerframework.dataflow.cfg.ControlFlowGraph)1 SpecialBlockImpl (org.checkerframework.dataflow.cfg.block.SpecialBlockImpl)1 Node (org.checkerframework.dataflow.cfg.node.Node)1 MostlySingleton (org.checkerframework.dataflow.util.MostlySingleton)1 BugInCF (org.checkerframework.javacutil.BugInCF)1