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.43.0
Show newest version
package org.checkerframework.dataflow.cfg.builder;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.lang.model.type.TypeMirror;
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.Node;
import org.checkerframework.dataflow.util.MostlySingleton;

/** 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 block (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;
    ArrayList 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 MostlySingleton<>();

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

          // 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: 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.postfixLookupMap,
        in.returnNodes,
        in.declaredClasses,
        in.declaredLambdas);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy