Search in sources :

Example 1 with Branch

use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.

the class DeadAssignmentsElimination method tryRemoveDeadAssignments.

/**
 * Try to remove useless assignments from a control flow graph that has been
 * annotated with liveness information.
 *
 * @param t The node traversal.
 * @param cfg The control flow graph of the program annotated with liveness
 *        information.
 */
private void tryRemoveDeadAssignments(NodeTraversal t, ControlFlowGraph<Node> cfg, Map<String, Var> allVarsInFn) {
    Iterable<? extends DiGraphNode<Node, Branch>> nodes = cfg.getNodes();
    for (DiGraphNode<Node, Branch> cfgNode : nodes) {
        LinearFlowState<LiveVariableLattice> state = cfgNode.getAnnotation();
        Node n = cfgNode.getValue();
        if (n == null) {
            continue;
        }
        switch(n.getToken()) {
            case IF:
            case WHILE:
            case DO:
                tryRemoveAssignment(t, NodeUtil.getConditionExpression(n), state, allVarsInFn);
                continue;
            case FOR:
            case FOR_IN:
            case FOR_OF:
            case FOR_AWAIT_OF:
                if (n.isVanillaFor()) {
                    tryRemoveAssignment(t, NodeUtil.getConditionExpression(n), state, allVarsInFn);
                }
                continue;
            case SWITCH:
            case CASE:
            case RETURN:
                if (n.hasChildren()) {
                    tryRemoveAssignment(t, n.getFirstChild(), state, allVarsInFn);
                }
                continue;
            // TODO(user): case VAR: Remove var a=1;a=2;.....
            default:
                break;
        }
        tryRemoveAssignment(t, n, state, allVarsInFn);
    }
}
Also used : LiveVariableLattice(com.google.javascript.jscomp.LiveVariablesAnalysis.LiveVariableLattice) Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) Node(com.google.javascript.rhino.Node)

Example 2 with Branch

use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.

the class CoalesceVariableNames method computeVariableNamesInterferenceGraph.

/**
 * In order to determine when it is appropriate to coalesce two variables, we use a live variables
 * analysis to make sure they are not alive at the same time. We take every CFG node and determine
 * which pairs of variables are alive at the same time. These pairs are set to true in a bit map.
 * We take every pairing of variables and use the bit map to check if the two variables are alive
 * at the same time. If two variables are alive at the same time, we create an edge between them
 * in the interference graph. The interference graph is the input to a graph coloring algorithm
 * that ensures any interfering variables are marked in different color groups, while variables
 * that can safely be coalesced are assigned the same color group.
 *
 * @param cfg
 * @param escaped we don't want to coalesce any escaped variables
 * @return graph with variable nodes and edges representing variable interference
 */
private UndiGraph<Var, Void> computeVariableNamesInterferenceGraph(ControlFlowGraph<Node> cfg, Set<? extends Var> escaped) {
    UndiGraph<Var, Void> interferenceGraph = LinkedUndirectedGraph.create();
    // First create a node for each non-escaped variable. We add these nodes in the order in which
    // they appear in the code because we want the names that appear earlier in the code to be used
    // when coalescing to variables that appear later in the code.
    Var[] orderedVariables = liveness.getAllVariablesInOrder().toArray(new Var[0]);
    // index i in interferenceGraphNodes is set to true when interferenceGraph
    // has node orderedVariables[i]
    BitSet interferenceGraphNodes = new BitSet();
    // interferenceBitSet[i] = indices of all variables that should have an edge with
    // orderedVariables[i]
    BitSet[] interferenceBitSet = new BitSet[orderedVariables.length];
    Arrays.setAll(interferenceBitSet, i -> new BitSet());
    int vIndex = -1;
    for (Var v : orderedVariables) {
        vIndex++;
        if (escaped.contains(v)) {
            continue;
        }
        // that is but, for now, we will respect the dead functions and not play around with it
        if (v.getParentNode().isFunction()) {
            continue;
        }
        // above) we assume that coalescing class names may cause a similar size regression.
        if (v.getParentNode().isClass()) {
            continue;
        }
        // bug for var redeclarations (https://github.com/google/closure-compiler/issues/3164)
        if (isInMultipleLvalueDecl(v)) {
            continue;
        }
        interferenceGraph.createNode(v);
        interferenceGraphNodes.set(vIndex);
    }
    // Set the pair of live variables in interferenceBitSet so we can add an edge between them.
    for (DiGraphNode<Node, Branch> cfgNode : cfg.getNodes()) {
        if (cfg.isImplicitReturn(cfgNode)) {
            continue;
        }
        LinearFlowState<LiveVariableLattice> state = cfgNode.getAnnotation();
        // Check the live states and add edge when possible. An edge between two variables
        // means that they are alive at overlapping times, which means that their
        // variable names cannot be coalesced.
        LiveVariableLattice livein = state.getIn();
        for (int i = livein.nextSetBit(0); i >= 0; i = livein.nextSetBit(i + 1)) {
            for (int j = livein.nextSetBit(i); j >= 0; j = livein.nextSetBit(j + 1)) {
                interferenceBitSet[i].set(j);
            }
        }
        LiveVariableLattice liveout = state.getOut();
        for (int i = liveout.nextSetBit(0); i >= 0; i = liveout.nextSetBit(i + 1)) {
            for (int j = liveout.nextSetBit(i); j >= 0; j = liveout.nextSetBit(j + 1)) {
                interferenceBitSet[i].set(j);
            }
        }
        LiveRangeChecker liveRangeChecker = new LiveRangeChecker(cfgNode.getValue(), orderedVariables, state);
        liveRangeChecker.check(cfgNode.getValue());
        liveRangeChecker.setCrossingVariables(interferenceBitSet);
    }
    // Go through each variable and try to connect them.
    int v1Index = -1;
    for (Var v1 : orderedVariables) {
        v1Index++;
        int v2Index = -1;
        for (Var v2 : orderedVariables) {
            v2Index++;
            // Skip duplicate pairs. Also avoid merging a variable with itself.
            if (v1Index > v2Index) {
                continue;
            }
            if (!interferenceGraphNodes.get(v1Index) || !interferenceGraphNodes.get(v2Index)) {
                // Skip nodes that were not added. They are globals and escaped locals.
                continue;
            }
            if ((v1.isParam() && v2.isParam()) || interferenceBitSet[v1Index].get(v2Index)) {
                // Add an edge between variable pairs that are both parameters
                // because we don't want parameters to share a name.
                interferenceGraph.connectIfNotFound(v1, null, v2);
            }
        }
    }
    return interferenceGraph;
}
Also used : LiveVariableLattice(com.google.javascript.jscomp.LiveVariablesAnalysis.LiveVariableLattice) GraphNode(com.google.javascript.jscomp.graph.GraphNode) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) BitSet(java.util.BitSet) Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch)

Example 3 with Branch

use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.

the class ControlFlowAnalysisTest method assertNoReturnEdge.

/**
 * Assert that there exists no control flow edge of the given type
 * from some node with the first token to the return node.
 */
private static void assertNoReturnEdge(ControlFlowGraph<Node> cfg, Token startToken) {
    List<DiGraphEdge<Node, Branch>> edges = getAllEdges(cfg);
    for (DiGraphEdge<Node, Branch> edge : edges) {
        Node source = edge.getSource().getValue();
        DiGraphNode<Node, Branch> dest = edge.getDestination();
        if (source.getToken() == startToken) {
            assertWithMessage("Token " + startToken + " should not have an out going" + " edge to the implicit return").that(cfg.isImplicitReturn(dest)).isFalse();
            return;
        }
    }
}
Also used : DiGraphEdge(com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge) Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) Node(com.google.javascript.rhino.Node)

Example 4 with Branch

use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.

the class ControlFlowAnalysisTest method assertReturnEdge.

/**
 * Assert that there exists a control flow edge of the given type
 * from some node with the first token to the return node.
 */
private static void assertReturnEdge(ControlFlowGraph<Node> cfg, Token startToken) {
    List<DiGraphEdge<Node, Branch>> edges = getAllEdges(cfg);
    for (DiGraphEdge<Node, Branch> edge : edges) {
        Node source = edge.getSource().getValue();
        DiGraphNode<Node, Branch> dest = edge.getDestination();
        if (source.getToken() == startToken && cfg.isImplicitReturn(dest)) {
            return;
        }
    }
    assertWithMessage("No return edge found").fail();
}
Also used : DiGraphEdge(com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge) Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) Node(com.google.javascript.rhino.Node)

Example 5 with Branch

use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.

the class ControlFlowAnalysisTest method getAllEdges.

/**
 * Gets all the control flow edges from some node with the first token to
 * some node with the second token.
 */
private static List<DiGraphEdge<Node, Branch>> getAllEdges(ControlFlowGraph<Node> cfg, Token startToken, Token endToken) {
    List<DiGraphEdge<Node, Branch>> edges = getAllEdges(cfg);
    Iterator<DiGraphEdge<Node, Branch>> it = edges.iterator();
    while (it.hasNext()) {
        DiGraphEdge<Node, Branch> edge = it.next();
        Node startNode = edge.getSource().getValue();
        Node endNode = edge.getDestination().getValue();
        if (startNode == null || endNode == null || startNode.getToken() != startToken || endNode.getToken() != endToken) {
            it.remove();
        }
    }
    return edges;
}
Also used : DiGraphEdge(com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge) Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) Node(com.google.javascript.rhino.Node)

Aggregations

Branch (com.google.javascript.jscomp.ControlFlowGraph.Branch)11 Node (com.google.javascript.rhino.Node)11 DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)9 DiGraphEdge (com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge)5 LiveVariableLattice (com.google.javascript.jscomp.LiveVariablesAnalysis.LiveVariableLattice)2 BitSet (java.util.BitSet)2 GraphNode (com.google.javascript.jscomp.graph.GraphNode)1 GraphvizNode (com.google.javascript.jscomp.graph.GraphvizGraph.GraphvizNode)1 FlowScope (com.google.javascript.jscomp.type.FlowScope)1 JSType (com.google.javascript.rhino.jstype.JSType)1 ObjectType (com.google.javascript.rhino.jstype.ObjectType)1 ArrayList (java.util.ArrayList)1