Skip to content

Commit

Permalink
Skip unchanged functions in DeadAssignmentsElimination
Browse files Browse the repository at this point in the history
Also, do the early bailout bookkeeping as part of the intial crawl
so that we don't need to do an extra crawl for it.

For large compiles, these can make the pass take about half the time as it did
previously.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=132491657
  • Loading branch information
blickly committed Sep 7, 2016
1 parent 8051053 commit 7bfa992
Showing 1 changed file with 47 additions and 35 deletions.
82 changes: 47 additions & 35 deletions src/com/google/javascript/jscomp/DeadAssignmentsElimination.java
Expand Up @@ -17,14 +17,15 @@
package com.google.javascript.jscomp; package com.google.javascript.jscomp;


import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.javascript.jscomp.ControlFlowGraph.Branch; import com.google.javascript.jscomp.ControlFlowGraph.Branch;
import com.google.javascript.jscomp.DataFlowAnalysis.FlowState; import com.google.javascript.jscomp.DataFlowAnalysis.FlowState;
import com.google.javascript.jscomp.LiveVariablesAnalysis.LiveVariableLattice; import com.google.javascript.jscomp.LiveVariablesAnalysis.LiveVariableLattice;
import com.google.javascript.jscomp.NodeTraversal.AbstractScopedCallback; import com.google.javascript.jscomp.NodeTraversal.AbstractScopedCallback;
import com.google.javascript.jscomp.graph.DiGraph.DiGraphNode; import com.google.javascript.jscomp.graph.DiGraph.DiGraphNode;
import com.google.javascript.rhino.IR; import com.google.javascript.rhino.IR;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import java.util.ArrayDeque;
import java.util.Deque;


/** /**
* Removes local variable assignments that are useless based on information from {@link * Removes local variable assignments that are useless based on information from {@link
Expand All @@ -37,37 +38,16 @@ class DeadAssignmentsElimination extends AbstractScopedCallback implements Compi


private final AbstractCompiler compiler; private final AbstractCompiler compiler;
private LiveVariablesAnalysis liveness; private LiveVariablesAnalysis liveness;
private final Deque<BailoutInformation> functionStack;


private static final class BailoutDetector implements NodeUtil.Visitor, Predicate<Node> { private static final class BailoutInformation {
boolean containsFunction; boolean containsFunction;
boolean containsRemovableAssign; boolean containsRemovableAssign;

}
// shouldTraverse
@Override
public boolean apply(Node n) {
// Skip traversing inside functions, since we already know we will bailout for those.
return !containsFunction;
}

@Override
public void visit(Node n) {
if (n.isFunction()) {
containsFunction = true;
} else if (isRemovableAssign(n)) {
containsRemovableAssign = true;
}
}

// Matches all assignment operators and increment/decrement operators.
// Does *not* match VAR initialization, since RemoveUnusedVariables
// will already remove variables that are initialized but unused.
boolean isRemovableAssign(Node n) {
return (NodeUtil.isAssignmentOp(n) && n.getFirstChild().isName()) || n.isInc() || n.isDec();
}
};


public DeadAssignmentsElimination(AbstractCompiler compiler) { public DeadAssignmentsElimination(AbstractCompiler compiler) {
this.compiler = compiler; this.compiler = compiler;
this.functionStack = new ArrayDeque<>();
} }


@Override @Override
Expand All @@ -78,25 +58,52 @@ public void process(Node externs, Node root) {
} }


@Override @Override
public void enterScope(NodeTraversal t) { public void visit(NodeTraversal t, Node n, Node parent) {
// Only do dead assignment elimination in function block scopes. if (functionStack.isEmpty()) {
if (!t.inFunctionBlockScope()) {
return; return;
} }
if (n.isFunction()) {
functionStack.peekFirst().containsFunction = true;
} else if (isRemovableAssign(n)) {
functionStack.peekFirst().containsRemovableAssign = true;
}
}

@Override
public void enterScope(NodeTraversal t) {
if (t.inFunctionBlockScope()) {
functionStack.addFirst(new BailoutInformation());
}
}

@Override
public void exitScope(NodeTraversal t) {
if (t.inFunctionBlockScope()) {
eliminateDeadAssignments(t);
functionStack.removeFirst();
}
}


BailoutDetector bailoutDetector = new BailoutDetector(); private void eliminateDeadAssignments(NodeTraversal t) {
NodeUtil.visitPreOrder(t.getScopeRoot(), bailoutDetector, bailoutDetector); Preconditions.checkArgument(t.inFunctionBlockScope());
Preconditions.checkState(!functionStack.isEmpty());


// Skip unchanged functions (note that the scope root is the function block, not the function).
if (!compiler.hasScopeChanged(t.getScopeRoot().getParent())) {
return;
}

BailoutInformation currentFunction = functionStack.peekFirst();
// We are not going to do any dead assignment elimination in when there is // We are not going to do any dead assignment elimination in when there is
// at least one inner function because in most browsers, when there is a // at least one inner function because in most browsers, when there is a
// closure, ALL the variables are saved (escaped). // closure, ALL the variables are saved (escaped).
if (bailoutDetector.containsFunction) { if (currentFunction.containsFunction) {
return; return;
} }


// We don't do any dead assignment elimination if there are no assigns // We don't do any dead assignment elimination if there are no assigns
// to eliminate. :) // to eliminate. :)
if (!bailoutDetector.containsRemovableAssign) { if (!currentFunction.containsRemovableAssign) {
return; return;
} }


Expand All @@ -121,8 +128,13 @@ public void enterScope(NodeTraversal t) {
tryRemoveDeadAssignments(t, cfg); tryRemoveDeadAssignments(t, cfg);
} }


@Override
public void visit(NodeTraversal t, Node n, Node parent) {
// Matches all assignment operators and increment/decrement operators.
// Does *not* match VAR initialization, since RemoveUnusedVariables
// will already remove variables that are initialized but unused.
boolean isRemovableAssign(Node n) {
return (NodeUtil.isAssignmentOp(n) && n.getFirstChild().isName()) || n.isInc() || n.isDec();
} }


/** /**
Expand Down

0 comments on commit 7bfa992

Please sign in to comment.