Skip to content

Commit

Permalink
Live variables analysis Es6 modified to work for let/const/block scop…
Browse files Browse the repository at this point in the history
…e. DataFlowAnalysisTests - added tests for compute variables in ES6 and ES5

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=159312277
  • Loading branch information
simran-arora authored and blickly committed Jun 19, 2017
1 parent 92e8188 commit f0cfbde
Show file tree
Hide file tree
Showing 4 changed files with 380 additions and 37 deletions.
39 changes: 26 additions & 13 deletions src/com/google/javascript/jscomp/DataFlowAnalysis.java
Expand Up @@ -32,6 +32,7 @@
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import javax.annotation.Nullable;


/** /**
* A framework to help writing static program analysis. A subclass of * A framework to help writing static program analysis. A subclass of
Expand Down Expand Up @@ -589,13 +590,15 @@ public void visit(NodeTraversal t, Node n, Node parent) {
} }


/** /**
* ******************************************************************** Alternate implementation * Alternate implementation of compute escaped that accepts the child scope and the current
* of compute escaped that accepts the child scope and the current jsScope to help us access both * jsScope to help us access both the function and function body scopes.
* the function and function body scopes. *
* @param jsScopeChild If jsScope is a function scope, jsScopeChild is the scope for the body of
* that function. If not, jsScopeChild is null.
*/ */
static void computeEscaped( static void computeEscaped(
final Scope jsScope, final Scope jsScope,
final Scope jsScopeChild, @Nullable final Scope jsScopeChild,
final Set<Var> escaped, final Set<Var> escaped,
AbstractCompiler compiler, AbstractCompiler compiler,
Es6SyntacticScopeCreator scopeCreator) { Es6SyntacticScopeCreator scopeCreator) {
Expand All @@ -605,16 +608,24 @@ static void computeEscaped(
@Override @Override
public void visit(NodeTraversal t, Node n, Node parent) { public void visit(NodeTraversal t, Node n, Node parent) {


if (jsScope.getRootNode() == NodeUtil.getEnclosingFunction(n) Node enclosingBlock = NodeUtil.getEnclosingScopeRoot(n);
|| !n.isName() if (jsScope.isFunctionScope()) {
|| parent.isFunction()) { enclosingBlock = NodeUtil.getEnclosingFunction(n);
}
if (jsScope.getRootNode() == enclosingBlock || !n.isName() || parent.isFunction()) {
return; return;
} }

String name = n.getString(); String name = n.getString();
Var var = t.getScope().getVar(name); Var var = t.getScope().getVar(name);
Node enclosing = NodeUtil.getEnclosingFunction(var.getNode()); if (var != null) {
if (var != null && enclosing == jsScope.getRootNode()) { Node enclosingScopeNode = NodeUtil.getEnclosingScopeRoot(var.getNode());
escaped.add(var); if (jsScope.isFunctionScope()) {
enclosingScopeNode = NodeUtil.getEnclosingFunction(var.getNode());
}
if (enclosingScopeNode == jsScope.getRootNode()) {
escaped.add(var);
}
} }
} }
}; };
Expand All @@ -628,9 +639,11 @@ public void visit(NodeTraversal t, Node n, Node parent) {
} }
} }


for (Var var : jsScopeChild.getVarIterable()) { if (jsScopeChild != null) {
if (compiler.getCodingConvention().isExported(var.getName())) { for (Var var : jsScopeChild.getVarIterable()) {
escaped.add(var); if (compiler.getCodingConvention().isExported(var.getName())) {
escaped.add(var);
}
} }
} }
} }
Expand Down
84 changes: 60 additions & 24 deletions src/com/google/javascript/jscomp/LiveVariablesAnalysisEs6.java
Expand Up @@ -26,6 +26,7 @@
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable;


/** /**
* Compute the "liveness" of all local variables. A variable is "live" at a point of a program if * Compute the "liveness" of all local variables. A variable is "live" at a point of a program if
Expand Down Expand Up @@ -135,8 +136,8 @@ public int hashCode() {
LiveVariablesAnalysisEs6( LiveVariablesAnalysisEs6(
ControlFlowGraph<Node> cfg, ControlFlowGraph<Node> cfg,
Scope jsScope, Scope jsScope,
Scope jsScopeChild, @Nullable Scope jsScopeChild,
Compiler compiler, AbstractCompiler compiler,
Es6SyntacticScopeCreator scopeCreator) { Es6SyntacticScopeCreator scopeCreator) {
super(cfg, new LiveVariableJoinOp()); super(cfg, new LiveVariableJoinOp());
this.jsScope = jsScope; this.jsScope = jsScope;
Expand All @@ -154,14 +155,37 @@ public int hashCode() {
*/ */
private void addScopeVariables() { private void addScopeVariables() {
int num = 0; int num = 0;
for (Var v : jsScope.getVarIterable()) { if (jsScope.isFunctionScope()) {
scopeVariables.put(v.getName(), num); for (Var v : jsScope.getVarIterable()) {
num++; scopeVariables.put(v.getName(), num);
} num++;
}

if (jsScopeChild != null) {
for (Var v : jsScopeChild.getVarIterable()) {
// add the hoisted variables from this child scope
if ((v.isLet() || v.isConst()) && !jsScope.isFunctionScope()) {
continue;
}
scopeVariables.put(v.getName(), num);
num++;
}
}
} else if (jsScope.isFunctionBlockScope()) {
for (Var v : jsScope.getParent().getVarIterable()) {
scopeVariables.put(v.getName(), num);
num++;
}


for (Var v : jsScopeChild.getVarIterable()) { for (Var v : jsScope.getVarIterable()) {
scopeVariables.put(v.getName(), num); scopeVariables.put(v.getName(), num);
num++; num++;
}
} else {
for (Var v : jsScope.getVarIterable()) {
scopeVariables.put(v.getName(), num);
num++;
}
} }
} }


Expand Down Expand Up @@ -224,9 +248,9 @@ private void computeGenKill(Node n, BitSet gen, BitSet kill, boolean conditional


switch (n.getToken()) { switch (n.getToken()) {
case SCRIPT: case SCRIPT:
case BLOCK:
case ROOT: case ROOT:
case FUNCTION: case FUNCTION:
case BLOCK:
return; return;


case WHILE: case WHILE:
Expand All @@ -236,12 +260,13 @@ private void computeGenKill(Node n, BitSet gen, BitSet kill, boolean conditional
computeGenKill(NodeUtil.getConditionExpression(n), gen, kill, conditional); computeGenKill(NodeUtil.getConditionExpression(n), gen, kill, conditional);
return; return;


case FOR_OF:
case FOR_IN: case FOR_IN:
{ {
// for(x in y) {...} // for (x in y) {...}
Node lhs = n.getFirstChild(); Node lhs = n.getFirstChild();
if (lhs.isVar()) { if (NodeUtil.isNameDeclaration(lhs)) {
// for(var x in y) {...} // for (var x in y) {...}
lhs = lhs.getLastChild(); lhs = lhs.getLastChild();
} }


Expand All @@ -256,6 +281,8 @@ private void computeGenKill(Node n, BitSet gen, BitSet kill, boolean conditional
return; return;
} }


case LET:
case CONST:
case VAR: case VAR:
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (c.hasChildren()) { if (c.hasChildren()) {
Expand Down Expand Up @@ -320,13 +347,15 @@ private void addToSetIfLocal(Node node, BitSet set) {
if (!escaped.contains(var)) { if (!escaped.contains(var)) {
set.set(getVarIndex(var.getName())); set.set(getVarIndex(var.getName()));
} }
} else if (!jsScopeChild.isDeclaredSloppy(name, false)) { } else if (jsScopeChild != null && jsScope.isFunctionScope()) {
return; if (!jsScopeChild.isDeclared(name, false)) {
} else { return;
Var var = jsScopeChild.getVar(name); } else {
Var var = jsScopeChild.getVar(name);


if (!escaped.contains(var)) { if (!escaped.contains(var)) {
set.set(getVarIndex(var.getName())); set.set(getVarIndex(var.getName()));
}
} }
} }
} }
Expand All @@ -336,16 +365,23 @@ private void addToSetIfLocal(Node node, BitSet set) {
* escaped set. * escaped set.
*/ */
void markAllParametersEscaped() { void markAllParametersEscaped() {
Node lp = jsScope.getRootNode().getSecondChild(); if (jsScope.isFunctionScope()) {
for (Node arg = lp.getFirstChild(); arg != null; arg = arg.getNext()) { Node lp = jsScope.getRootNode().getSecondChild();
escaped.add(jsScope.getVar(arg.getString())); for (Node arg = lp.getFirstChild(); arg != null; arg = arg.getNext()) {
escaped.add(jsScope.getVar(arg.getString()));
}
} }
} }


private boolean isArgumentsName(Node n) { private boolean isArgumentsName(Node n) {
boolean childDeclared;
if (jsScopeChild != null) {
childDeclared = jsScopeChild.isDeclared(ARGUMENT_ARRAY_ALIAS, false);
} else {
childDeclared = true;
}
return n.isName() return n.isName()
&& n.getString().equals(ARGUMENT_ARRAY_ALIAS) && n.getString().equals(ARGUMENT_ARRAY_ALIAS)
&& (!jsScope.isDeclaredSloppy(ARGUMENT_ARRAY_ALIAS, false) && (!jsScope.isDeclaredSloppy(ARGUMENT_ARRAY_ALIAS, false) || !childDeclared);
|| !jsScopeChild.isDeclaredSloppy(ARGUMENT_ARRAY_ALIAS, false));
} }
} }

0 comments on commit f0cfbde

Please sign in to comment.