Search in sources :

Example 6 with Branch

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

the class TypeInference method branchedFlowThrough.

@Override
@SuppressWarnings({ "fallthrough", "incomplete-switch" })
List<FlowScope> branchedFlowThrough(Node source, FlowScope input) {
    // NOTE(nicksantos): Right now, we just treat ON_EX edges like UNCOND
    // edges. If we wanted to be perfect, we'd actually JOIN all the out
    // lattices of this flow with the in lattice, and then make that the out
    // lattice for the ON_EX edge. But it's probably too expensive to be
    // worthwhile.
    FlowScope output = flowThrough(source, input);
    Node condition = null;
    FlowScope conditionFlowScope = null;
    BooleanOutcomePair conditionOutcomes = null;
    List<DiGraphEdge<Node, Branch>> branchEdges = getCfg().getOutEdges(source);
    List<FlowScope> result = new ArrayList<>(branchEdges.size());
    for (DiGraphEdge<Node, Branch> branchEdge : branchEdges) {
        Branch branch = branchEdge.getValue();
        FlowScope newScope = output;
        switch(branch) {
            case ON_TRUE:
                if (source.isForIn() || source.isForOf()) {
                    Node item = source.getFirstChild();
                    Node obj = item.getNext();
                    FlowScope informed = traverse(obj, output.createChildFlowScope());
                    if (item.isVar()) {
                        item = item.getFirstChild();
                    }
                    if (source.isForIn()) {
                        // item is assigned a property name, so its type should be string.
                        if (item.isName()) {
                            JSType iterKeyType = getNativeType(STRING_TYPE);
                            ObjectType objType = getJSType(obj).dereference();
                            JSType objIndexType = objType == null ? null : objType.getTemplateTypeMap().getResolvedTemplateType(registry.getObjectIndexKey());
                            if (objIndexType != null && !objIndexType.isUnknownType()) {
                                JSType narrowedKeyType = iterKeyType.getGreatestSubtype(objIndexType);
                                if (!narrowedKeyType.isEmptyType()) {
                                    iterKeyType = narrowedKeyType;
                                }
                            }
                            redeclareSimpleVar(informed, item, iterKeyType);
                        }
                    } else {
                        // for/of. The type of `item` is the type parameter of the Iterable type.
                        ObjectType objType = getJSType(obj).dereference();
                        if (objType.isSubtypeOf(getNativeType(JSTypeNative.ITERABLE_TYPE))) {
                            if (objType.isTemplatizedType()) {
                                JSType newType = objType.getTemplateTypeMap().getResolvedTemplateType(registry.getIterableTemplate());
                                redeclareSimpleVar(informed, item, newType);
                            }
                        }
                    }
                    newScope = informed;
                    break;
                }
            case ON_FALSE:
                if (condition == null) {
                    condition = NodeUtil.getConditionExpression(source);
                    if (condition == null && source.isCase()) {
                        condition = source;
                        // of the loop.
                        if (conditionFlowScope == null) {
                            conditionFlowScope = traverse(condition.getFirstChild(), output.createChildFlowScope());
                        }
                    }
                }
                if (condition != null) {
                    if (condition.isAnd() || condition.isOr()) {
                        // of the loop.
                        if (conditionOutcomes == null) {
                            conditionOutcomes = condition.isAnd() ? traverseAnd(condition, output.createChildFlowScope()) : traverseOr(condition, output.createChildFlowScope());
                        }
                        newScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(condition, conditionOutcomes.getOutcomeFlowScope(condition.getToken(), branch == Branch.ON_TRUE), branch == Branch.ON_TRUE);
                    } else {
                        // of the loop.
                        if (conditionFlowScope == null) {
                            conditionFlowScope = traverse(condition, output.createChildFlowScope());
                        }
                        newScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(condition, conditionFlowScope, branch == Branch.ON_TRUE);
                    }
                }
                break;
            default:
                break;
        }
        result.add(newScope.optimize());
    }
    return result;
}
Also used : ObjectType(com.google.javascript.rhino.jstype.ObjectType) DiGraphEdge(com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge) JSType(com.google.javascript.rhino.jstype.JSType) Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) Node(com.google.javascript.rhino.Node) ArrayList(java.util.ArrayList) FlowScope(com.google.javascript.jscomp.type.FlowScope)

Example 7 with Branch

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

the class ControlFlowAnalysis method process.

@Override
public void process(Node externs, Node root) {
    Preconditions.checkArgument(NodeUtil.isValidCfgRoot(root), "Unexpected control flow graph root %s", root);
    this.root = root;
    astPositionCounter = 0;
    astPosition = new HashMap<>();
    nodePriorities = new HashMap<>();
    cfg = new AstControlFlowGraph(computeFallThrough(root), nodePriorities, edgeAnnotations);
    NodeTraversal.traverse(compiler, root, this);
    // the implicit return is last.
    astPosition.put(null, ++astPositionCounter);
    // Now, generate the priority of nodes by doing a depth-first
    // search on the CFG.
    priorityCounter = 0;
    DiGraphNode<Node, Branch> entry = cfg.getEntry();
    prioritizeFromEntryNode(entry);
    if (shouldTraverseFunctions) {
        // priority of them too.
        for (DiGraphNode<Node, Branch> candidate : cfg.getNodes()) {
            Node value = candidate.getValue();
            if (value != null && value.isFunction()) {
                prioritizeFromEntryNode(candidate);
            }
        }
    }
    // this shouldn't happen in real code.
    for (DiGraphNode<Node, Branch> candidate : cfg.getNodes()) {
        nodePriorities.computeIfAbsent(candidate, k -> ++priorityCounter);
    }
    // Again, the implicit return node is always last.
    nodePriorities.put(cfg.getImplicitReturn(), ++priorityCounter);
}
Also used : Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) Node(com.google.javascript.rhino.Node)

Example 8 with Branch

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

the class LiveVariablesAnalysis method flowThrough.

@Override
LiveVariableLattice flowThrough(Node node, LiveVariableLattice input) {
    final BitSet gen = new BitSet(input.liveSet.size());
    final BitSet kill = new BitSet(input.liveSet.size());
    // Make kills conditional if the node can end abruptly by an exception.
    boolean conditional = false;
    List<? extends DiGraphEdge<Node, Branch>> edgeList = getCfg().getOutEdges(node);
    for (DiGraphEdge<Node, Branch> edge : edgeList) {
        if (Branch.ON_EX.equals(edge.getValue())) {
            conditional = true;
        }
    }
    computeGenKill(node, gen, kill, conditional);
    LiveVariableLattice result = new LiveVariableLattice(input);
    // L_in = L_out - Kill + Gen
    result.liveSet.andNot(kill);
    result.liveSet.or(gen);
    return result;
}
Also used : Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) Node(com.google.javascript.rhino.Node) BitSet(java.util.BitSet)

Example 9 with Branch

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

the class DotFormatter method traverseNodes.

private void traverseNodes(Node parent) throws IOException {
    // key
    int keyParent = key(parent);
    // edges
    for (Node child = parent.getFirstChild(); child != null; child = child.getNext()) {
        int keyChild = key(child);
        builder.append(INDENT);
        builder.append(formatNodeName(keyParent));
        builder.append(ARROW);
        builder.append(formatNodeName(keyChild));
        builder.append(" [weight=1];\n");
        traverseNodes(child);
    }
    // Flow Edges
    if (cfg != null && cfg.hasNode(parent)) {
        List<? extends DiGraphEdge<Node, Branch>> outEdges = cfg.getOutEdges(parent);
        String[] edgeList = new String[outEdges.size()];
        for (int i = 0; i < edgeList.length; i++) {
            DiGraphEdge<Node, ControlFlowGraph.Branch> edge = outEdges.get(i);
            DiGraphNode<Node, Branch> succ = edge.getDestination();
            String toNode = null;
            if (succ == cfg.getImplicitReturn()) {
                toNode = "RETURN";
            } else {
                int keySucc = key(succ.getValue());
                toNode = formatNodeName(keySucc);
            }
            edgeList[i] = formatNodeName(keyParent) + ARROW + toNode + " [label=\"" + edge.getValue() + "\", " + "fontcolor=\"red\", " + "weight=0.01, color=\"red\"];\n";
        }
        Arrays.sort(edgeList);
        for (String element : edgeList) {
            builder.append(INDENT);
            builder.append(element);
        }
    }
}
Also used : Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) GraphvizNode(com.google.javascript.jscomp.graph.GraphvizGraph.GraphvizNode) Node(com.google.javascript.rhino.Node)

Example 10 with Branch

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

the class ControlFlowAnalysisTest method assertNodeOrder.

/**
 * Asserts the priority order of CFG nodes.
 *
 * Checks that the node type of the highest-priority node matches the
 * first element of the list, the type of the second node matches the
 * second element of the list, and so on.
 *
 * @param cfg The control flow graph.
 * @param nodeTypes The expected node types, in order.
 */
private void assertNodeOrder(ControlFlowGraph<Node> cfg, List<Token> nodeTypes) {
    List<? extends DiGraphNode<Node, Branch>> cfgNodes = Ordering.from(cfg.getOptionalNodeComparator(true)).sortedCopy(cfg.getNodes());
    // IMPLICIT RETURN must always be last.
    Node implicitReturn = cfgNodes.remove(cfgNodes.size() - 1).getValue();
    assertWithMessage(implicitReturn == null ? "null" : implicitReturn.toStringTree()).that(implicitReturn).isNull();
    assertThat(cfgNodes.stream().map(DiGraphNode::getValue).map(Node::getToken).collect(Collectors.toList())).isEqualTo(nodeTypes);
}
Also used : DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) 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