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