Search in sources :

Example 1 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode in project closure-compiler by google.

the class NewTypeInference method analyzeFunctionBwd.

private void analyzeFunctionBwd(NTIWorkset workset) {
    for (DiGraphNode<Node, ControlFlowGraph.Branch> dn : workset.backward()) {
        Node n = dn.getValue();
        TypeEnv outEnv = checkNotNull(getOutEnv(dn));
        TypeEnv inEnv;
        println("\tBWD Statment: ", n);
        println("\t\toutEnv: ", outEnv);
        switch(n.getToken()) {
            case EXPR_RESULT:
                inEnv = analyzeExprBwd(n.getFirstChild(), outEnv, UNKNOWN).env;
                break;
            case RETURN:
                {
                    Node retExp = n.getFirstChild();
                    if (retExp == null) {
                        inEnv = outEnv;
                    } else {
                        JSType declRetType = this.currentScope.getDeclaredTypeForOwnBody().getReturnType();
                        declRetType = firstNonNull(declRetType, UNKNOWN);
                        inEnv = analyzeExprBwd(retExp, outEnv, declRetType).env;
                    }
                    break;
                }
            case VAR:
                {
                    if (NodeUtil.isTypedefDecl(n)) {
                        inEnv = outEnv;
                        break;
                    }
                    inEnv = outEnv;
                    for (Node nameNode = n.getFirstChild(); nameNode != null; nameNode = nameNode.getNext()) {
                        String varName = nameNode.getString();
                        Node rhs = nameNode.getFirstChild();
                        JSType declType = this.currentScope.getDeclaredTypeOf(varName);
                        inEnv = envPutType(inEnv, varName, UNKNOWN);
                        if (rhs == null || this.currentScope.isLocalFunDef(varName)) {
                            continue;
                        }
                        JSType inferredType = envGetType(outEnv, varName);
                        JSType requiredType;
                        if (declType == null) {
                            requiredType = inferredType;
                        } else {
                            // TODO(dimvar): look if the meet is needed
                            requiredType = JSType.meet(declType, inferredType);
                            requiredType = firstNonBottom(requiredType, UNKNOWN);
                        }
                        inEnv = analyzeExprBwd(rhs, inEnv, requiredType).env;
                    }
                    break;
                }
            case BLOCK:
            case ROOT:
            case BREAK:
            case CATCH:
            case CONTINUE:
            case DEFAULT_CASE:
            case DEBUGGER:
            case EMPTY:
            case SCRIPT:
            case TRY:
            case WITH:
                inEnv = outEnv;
                break;
            case DO:
            case FOR:
            case FOR_IN:
            case FOR_OF:
            case IF:
            case WHILE:
                Node expr = (n.isForIn() || n.isForOf()) ? n.getFirstChild() : NodeUtil.getConditionExpression(n);
                inEnv = analyzeExprBwd(expr, outEnv).env;
                break;
            case THROW:
            case CASE:
            case SWITCH:
                inEnv = analyzeExprBwd(n.getFirstChild(), outEnv).env;
                break;
            default:
                if (NodeUtil.isStatement(n)) {
                    throw new RuntimeException("Unhandled statement type: " + n.getToken());
                } else {
                    inEnv = analyzeExprBwd(n, outEnv).env;
                    break;
                }
        }
        println("\t\tinEnv: ", inEnv);
        for (DiGraphEdge<Node, ControlFlowGraph.Branch> de : dn.getInEdges()) {
            envs.put(de, inEnv);
        }
    }
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 2 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode in project closure-compiler by google.

the class NewTypeInference method getOutEnv.

private TypeEnv getOutEnv(DiGraphNode<Node, ControlFlowGraph.Branch> dn) {
    List<DiGraphEdge<Node, ControlFlowGraph.Branch>> outEdges = dn.getOutEdges();
    if (outEdges.isEmpty()) {
        // This occurs when visiting a throw in the backward direction.
        checkArgument(dn.getValue().isThrow());
        return this.typeEnvFromDeclaredTypes;
    }
    if (outEdges.size() == 1) {
        return envs.get(outEdges.get(0));
    }
    Set<TypeEnv> envSet = new LinkedHashSet<>();
    for (DiGraphEdge<Node, ControlFlowGraph.Branch> de : outEdges) {
        TypeEnv env = envs.get(de);
        if (env != null) {
            envSet.add(env);
        }
    }
    checkState(!envSet.isEmpty());
    return TypeEnv.join(envSet);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) DiGraphEdge(com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 3 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode 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;
        }
    }
    fail("No return edge found");
}
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 DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode 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) {
            assertFalse("Token " + startToken + " should not have an out going" + " edge to the implicit return", cfg.isImplicitReturn(dest));
            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 5 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode 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 pairing of variables
 * and for every CFG node, determine whether 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.
    List<Var> orderedVariables = liveness.getAllVariablesInOrder();
    for (Var v : orderedVariables) {
        if (escaped.contains(v)) {
            continue;
        }
        // around with it.
        if (v.getParentNode().isFunction()) {
            continue;
        }
        // incorrect semantics. See test case "testCapture".
        if (v.isLet() || v.isConst()) {
            Node nameDecl = NodeUtil.getEnclosingNode(v.getNode(), NodeUtil::isNameDeclaration);
            if (NodeUtil.findLhsNodesInNode(nameDecl).size() > 1) {
                continue;
            }
        }
        interferenceGraph.createNode(v);
    }
    // Go through each variable and try to connect them.
    int v1Index = -1;
    for (Var v1 : orderedVariables) {
        v1Index++;
        int v2Index = -1;
        NEXT_VAR_PAIR: for (Var v2 : orderedVariables) {
            v2Index++;
            // Skip duplicate pairs.
            if (v1Index > v2Index) {
                continue;
            }
            if (!interferenceGraph.hasNode(v1) || !interferenceGraph.hasNode(v2)) {
                // locals. Also avoid merging a variable with itself.
                continue NEXT_VAR_PAIR;
            }
            if (v1.isParam() && v2.isParam()) {
                interferenceGraph.connectIfNotFound(v1, null, v2);
                continue NEXT_VAR_PAIR;
            }
            // time, add an edge between them and continue to the next pair.
            NEXT_CROSS_CFG_NODE: for (DiGraphNode<Node, Branch> cfgNode : cfg.getDirectedGraphNodes()) {
                if (cfg.isImplicitReturn(cfgNode)) {
                    continue NEXT_CROSS_CFG_NODE;
                }
                FlowState<LiveVariableLattice> state = cfgNode.getAnnotation();
                if ((state.getIn().isLive(v1Index) && state.getIn().isLive(v2Index)) || (state.getOut().isLive(v1Index) && state.getOut().isLive(v2Index))) {
                    interferenceGraph.connectIfNotFound(v1, null, v2);
                    continue NEXT_VAR_PAIR;
                }
            }
            // if there's a collision *within* the cfg node.
            NEXT_INTRA_CFG_NODE: for (DiGraphNode<Node, Branch> cfgNode : cfg.getDirectedGraphNodes()) {
                if (cfg.isImplicitReturn(cfgNode)) {
                    continue NEXT_INTRA_CFG_NODE;
                }
                FlowState<LiveVariableLattice> state = cfgNode.getAnnotation();
                boolean v1OutLive = state.getOut().isLive(v1Index);
                boolean v2OutLive = state.getOut().isLive(v2Index);
                CombinedLiveRangeChecker checker = new CombinedLiveRangeChecker(cfgNode.getValue(), new LiveRangeChecker(v1, v2OutLive ? null : v2), new LiveRangeChecker(v2, v1OutLive ? null : v1));
                checker.check(cfgNode.getValue());
                if (checker.connectIfCrossed(interferenceGraph)) {
                    continue NEXT_VAR_PAIR;
                }
            }
        }
    }
    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) Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch)

Aggregations

DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)12 Node (com.google.javascript.rhino.Node)12 Branch (com.google.javascript.jscomp.ControlFlowGraph.Branch)6 DiGraphEdge (com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge)5 TypeEnv (com.google.javascript.jscomp.newtypes.TypeEnv)4 LiveVariableLattice (com.google.javascript.jscomp.LiveVariablesAnalysis.LiveVariableLattice)2 JSType (com.google.javascript.jscomp.newtypes.JSType)2 LinkedHashSet (java.util.LinkedHashSet)2 GraphNode (com.google.javascript.jscomp.graph.GraphNode)1 GraphvizNode (com.google.javascript.jscomp.graph.GraphvizGraph.GraphvizNode)1 Token (com.google.javascript.rhino.Token)1