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);
}
}
}
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);
}
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");
}
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;
}
}
}
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;
}
Aggregations