Skip to content

Commit

Permalink
Migrates PeepholeOptimizationsPass to the new changed scopes system.
Browse files Browse the repository at this point in the history
Reduces peephole pass time by ~32%, from ~4300ms to ~2900ms
(averaged across 30 compiles, in [], performed locally).

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161715016
  • Loading branch information
stalcup authored and Tyler Breisacher committed Jul 13, 2017
1 parent 67606b0 commit 89d5711
Show file tree
Hide file tree
Showing 19 changed files with 154 additions and 176 deletions.
23 changes: 4 additions & 19 deletions src/com/google/javascript/jscomp/AbstractPeepholeOptimization.java
Expand Up @@ -29,7 +29,6 @@
*/ */
abstract class AbstractPeepholeOptimization { abstract class AbstractPeepholeOptimization {


private NodeTraversal traversal;
protected AbstractCompiler compiler; protected AbstractCompiler compiler;


/** /**
Expand Down Expand Up @@ -60,7 +59,7 @@ protected void report(DiagnosticType diagnostic, Node n) {
* Subclasses must call these if they have changed the AST. * Subclasses must call these if they have changed the AST.
*/ */
protected void reportCodeChange() { protected void reportCodeChange() {
traversal.reportCodeChange(); compiler.reportCodeChange();
} }


/** /**
Expand All @@ -85,25 +84,11 @@ protected boolean isASTNormalized() {
return compiler.getLifeCycleStage().isNormalized(); return compiler.getLifeCycleStage().isNormalized();
} }


/** /** Informs the optimization that a traversal will begin. */
* Informs the optimization that a traversal will begin. void beginTraversal(AbstractCompiler compiler) {
*/ this.compiler = compiler;
void beginTraversal(NodeTraversal traversal) {
this.traversal = traversal;
this.compiler = traversal.getCompiler();
} }


/**
* Informs the optimization that a traversal has completed.
*/
void endTraversal() {
this.traversal = null;
this.compiler = null;
}

// NodeUtil's mayEffectMutableState and mayHaveSideEffects need access to the
// compiler object, route them through here to give them access.

/** /**
* @return Whether the node may create new mutable state, or change existing * @return Whether the node may create new mutable state, or change existing
* state. * state.
Expand Down
101 changes: 51 additions & 50 deletions src/com/google/javascript/jscomp/DefaultPassConfig.java
Expand Up @@ -1640,12 +1640,11 @@ protected FeatureSet featureSet() {


private final PassFactory earlyPeepholeOptimizations = private final PassFactory earlyPeepholeOptimizations =
new PassFactory("earlyPeepholeOptimizations", true) { new PassFactory("earlyPeepholeOptimizations", true) {
@Override @Override
protected CompilerPass create(AbstractCompiler compiler) { protected CompilerPass create(AbstractCompiler compiler) {
return new PeepholeOptimizationsPass(compiler, return new PeepholeOptimizationsPass(compiler, getName(), new PeepholeRemoveDeadCode());
new PeepholeRemoveDeadCode()); }
} };
};


private final PassFactory earlyInlineVariables = private final PassFactory earlyInlineVariables =
new PassFactory("earlyInlineVariables", true) { new PassFactory("earlyInlineVariables", true) {
Expand All @@ -1669,54 +1668,59 @@ protected FeatureSet featureSet() {
}; };


/** Various peephole optimizations. */ /** Various peephole optimizations. */
private static CompilerPass createPeepholeOptimizationsPass(AbstractCompiler compiler) { private static CompilerPass createPeepholeOptimizationsPass(
AbstractCompiler compiler, String passName) {
final boolean late = false; final boolean late = false;
final boolean useTypesForOptimization = compiler.getOptions().useTypesForLocalOptimization; final boolean useTypesForOptimization = compiler.getOptions().useTypesForLocalOptimization;
return new PeepholeOptimizationsPass(compiler, return new PeepholeOptimizationsPass(
new MinimizeExitPoints(compiler), compiler,
new PeepholeMinimizeConditions(late, useTypesForOptimization), passName,
new PeepholeSubstituteAlternateSyntax(late), new MinimizeExitPoints(compiler),
new PeepholeReplaceKnownMethods(late, useTypesForOptimization), new PeepholeMinimizeConditions(late, useTypesForOptimization),
new PeepholeRemoveDeadCode(), new PeepholeSubstituteAlternateSyntax(late),
new PeepholeFoldConstants(late, useTypesForOptimization), new PeepholeReplaceKnownMethods(late, useTypesForOptimization),
new PeepholeCollectPropertyAssignments()); new PeepholeRemoveDeadCode(),
new PeepholeFoldConstants(late, useTypesForOptimization),
new PeepholeCollectPropertyAssignments());
} }


/** Various peephole optimizations. */ /** Various peephole optimizations. */
private final PassFactory peepholeOptimizations = private final PassFactory peepholeOptimizations =
new PassFactory(Compiler.PEEPHOLE_PASS_NAME, false /* oneTimePass */) { new PassFactory(Compiler.PEEPHOLE_PASS_NAME, false /* oneTimePass */) {
@Override @Override
protected CompilerPass create(AbstractCompiler compiler) { protected CompilerPass create(AbstractCompiler compiler) {
return createPeepholeOptimizationsPass(compiler); return createPeepholeOptimizationsPass(compiler, getName());
} }
}; };


/** Various peephole optimizations. */ /** Various peephole optimizations. */
private final PassFactory peepholeOptimizationsOnce = private final PassFactory peepholeOptimizationsOnce =
new PassFactory(Compiler.PEEPHOLE_PASS_NAME, true /* oneTimePass */) { new PassFactory(Compiler.PEEPHOLE_PASS_NAME, true /* oneTimePass */) {
@Override @Override
protected CompilerPass create(AbstractCompiler compiler) { protected CompilerPass create(AbstractCompiler compiler) {
return createPeepholeOptimizationsPass(compiler); return createPeepholeOptimizationsPass(compiler, getName());
} }
}; };


/** Same as peepholeOptimizations but aggressively merges code together */ /** Same as peepholeOptimizations but aggressively merges code together */
private final PassFactory latePeepholeOptimizations = private final PassFactory latePeepholeOptimizations =
new PassFactory("latePeepholeOptimizations", true) { new PassFactory("latePeepholeOptimizations", true) {
@Override @Override
protected CompilerPass create(AbstractCompiler compiler) { protected CompilerPass create(AbstractCompiler compiler) {
final boolean late = true; final boolean late = true;
final boolean useTypesForOptimization = options.useTypesForLocalOptimization; final boolean useTypesForOptimization = options.useTypesForLocalOptimization;
return new PeepholeOptimizationsPass(compiler, return new PeepholeOptimizationsPass(
new StatementFusion(options.aggressiveFusion), compiler,
new PeepholeRemoveDeadCode(), getName(),
new PeepholeMinimizeConditions(late, useTypesForOptimization), new StatementFusion(options.aggressiveFusion),
new PeepholeSubstituteAlternateSyntax(late), new PeepholeRemoveDeadCode(),
new PeepholeReplaceKnownMethods(late, useTypesForOptimization), new PeepholeMinimizeConditions(late, useTypesForOptimization),
new PeepholeFoldConstants(late, useTypesForOptimization), new PeepholeSubstituteAlternateSyntax(late),
new ReorderConstantExpression()); new PeepholeReplaceKnownMethods(late, useTypesForOptimization),
} new PeepholeFoldConstants(late, useTypesForOptimization),
}; new ReorderConstantExpression());
}
};


/** Checks that all variables are defined. */ /** Checks that all variables are defined. */
private final HotSwapPassFactory checkVars = private final HotSwapPassFactory checkVars =
Expand Down Expand Up @@ -2689,17 +2693,14 @@ protected CompilerPass create(AbstractCompiler compiler) {
} }
}; };


/** /** Some simple, local collapses (e.g., {@code var x; var y;} becomes {@code var x,y;}. */
* Some simple, local collapses (e.g., {@code var x; var y;} becomes private final PassFactory exploitAssign =
* {@code var x,y;}. new PassFactory("exploitAssign", true) {
*/ @Override
private final PassFactory exploitAssign = new PassFactory("exploitAssign", true) { protected CompilerPass create(AbstractCompiler compiler) {
@Override return new PeepholeOptimizationsPass(compiler, getName(), new ExploitAssigns());
protected CompilerPass create(AbstractCompiler compiler) { }
return new PeepholeOptimizationsPass(compiler, };
new ExploitAssigns());
}
};


/** /**
* Some simple, local collapses (e.g., {@code var x; var y;} becomes * Some simple, local collapses (e.g., {@code var x; var y;} becomes
Expand Down
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/MinimizeExitPoints.java
Expand Up @@ -40,7 +40,7 @@ class MinimizeExitPoints extends AbstractPeepholeOptimization {


@VisibleForTesting @VisibleForTesting
final CompilerPass asCompilerPass() { final CompilerPass asCompilerPass() {
return new PeepholeOptimizationsPass(compiler, this); return new PeepholeOptimizationsPass(compiler, this.getClass().getSimpleName(), this);
} }


@Override @Override
Expand Down
93 changes: 31 additions & 62 deletions src/com/google/javascript/jscomp/PeepholeOptimizationsPass.java
Expand Up @@ -16,9 +16,10 @@


package com.google.javascript.jscomp; package com.google.javascript.jscomp;


import com.google.javascript.jscomp.NodeTraversal.AbstractShallowCallback; import com.google.common.annotations.VisibleForTesting;
import com.google.javascript.jscomp.NodeTraversal.FunctionCallback; import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Node;
import java.util.List;


/** /**
* A compiler pass to run various peephole optimizations (e.g. constant folding, * A compiler pass to run various peephole optimizations (e.g. constant folding,
Expand All @@ -27,93 +28,61 @@
* @author dcc@google.com (Devin Coughlin) * @author dcc@google.com (Devin Coughlin)
*/ */
class PeepholeOptimizationsPass implements CompilerPass { class PeepholeOptimizationsPass implements CompilerPass {
private AbstractCompiler compiler;


// Use an array here for faster iteration compared to ImmutableSet private final AbstractCompiler compiler;
private final String passName;
private final AbstractPeepholeOptimization[] peepholeOptimizations; private final AbstractPeepholeOptimization[] peepholeOptimizations;

private boolean retraverseOnChange; private boolean retraverseOnChange;
private RecentChange handler;
private FunctionCallback fnCallback;
private PeepCallback peepCallback;
private NodeTraversal traversal;


/** /** Creates a peephole optimization pass that runs the given optimizations. */
* Creates a peephole optimization pass that runs the given PeepholeOptimizationsPass(
* optimizations. AbstractCompiler compiler, String passName, AbstractPeepholeOptimization... optimizations) {
*/
PeepholeOptimizationsPass(AbstractCompiler compiler,
AbstractPeepholeOptimization... optimizations) {
this.compiler = compiler; this.compiler = compiler;
this.passName = passName;
this.peepholeOptimizations = optimizations; this.peepholeOptimizations = optimizations;
this.retraverseOnChange = true; this.retraverseOnChange = true;
this.handler = new RecentChange();
this.peepCallback = new PeepCallback();
this.traversal = new NodeTraversal(
compiler, peepCallback, new Es6SyntacticScopeCreator(compiler));
this.fnCallback = new ChangedFunctionCallback();
} }


@VisibleForTesting
void setRetraverseOnChange(boolean retraverse) { void setRetraverseOnChange(boolean retraverse) {
this.retraverseOnChange = retraverse; this.retraverseOnChange = retraverse;
} }


@Override @Override
public void process(Node externs, Node root) { public void process(Node externs, Node root) {
compiler.addChangeHandler(handler); beginTraversal();
beginTraversal(traversal);
NodeTraversal.traverseChangedFunctions(compiler, fnCallback);
endTraversal();
compiler.removeChangeHandler(handler);
}


private class ChangedFunctionCallback implements FunctionCallback { // Repeat to an internal fixed point.
@Override for (List<Node> changedScopeNodes = compiler.getChangedScopeNodesForPass(passName);
public void enterFunction(AbstractCompiler compiler, Node root) { changedScopeNodes == null || !changedScopeNodes.isEmpty();
if (root.isFunction()) { changedScopeNodes = compiler.getChangedScopeNodesForPass(passName)) {
root = root.getLastChild(); NodeTraversal.traverseEs6ScopeRoots(
compiler, root, changedScopeNodes, new PeepCallback(), false);

// Cancel the fixed point if requested.
if (!retraverseOnChange) {
break;
} }
do {
handler.reset();
traversal.traverse(root);
} while (retraverseOnChange && handler.hasCodeChanged());
} }
} }


private class PeepCallback extends AbstractShallowCallback { private class PeepCallback extends AbstractPostOrderCallback {
@Override @Override
public void visit(NodeTraversal t, Node n, Node parent) { public void visit(NodeTraversal t, Node n, Node parent) {
Node currentNode = n, newNode; Node currentNode = n;
boolean codeChanged = false; for (AbstractPeepholeOptimization optim : peepholeOptimizations) {
do { currentNode = optim.optimizeSubtree(currentNode);
codeChanged = false; if (currentNode == null) {
for (AbstractPeepholeOptimization optim : peepholeOptimizations) { return;
newNode = optim.optimizeSubtree(currentNode);
if (newNode != currentNode) {
codeChanged = true;
currentNode = newNode;
}
if (currentNode == null) {
return;
}
} }
} while(codeChanged); }
}
}

/**
* Make sure that all the optimizations have the current traversal so they
* can report errors.
*/
private void beginTraversal(NodeTraversal traversal) {
for (AbstractPeepholeOptimization optimization : peepholeOptimizations) {
optimization.beginTraversal(traversal);
} }
} }


private void endTraversal() { /** Make sure that all the optimizations have the current compiler so they can report errors. */
private void beginTraversal() {
for (AbstractPeepholeOptimization optimization : peepholeOptimizations) { for (AbstractPeepholeOptimization optimization : peepholeOptimizations) {
optimization.endTraversal(); optimization.beginTraversal(compiler);
} }
} }
} }
Expand Up @@ -95,6 +95,7 @@ public Node optimizeSubtree(Node node) {
return tryReduceReturn(node); return tryReduceReturn(node);


case COMMA: case COMMA:
// TODO(b/63630312): should flatten an entire comma expression in a single pass.
return trySplitComma(node); return trySplitComma(node);


case NAME: case NAME:
Expand Down Expand Up @@ -313,8 +314,8 @@ private Node trySplitComma(Node n) {
Node newStatement = IR.exprResult(right); Node newStatement = IR.exprResult(right);
newStatement.useSourceInfoIfMissingFrom(n); newStatement.useSourceInfoIfMissingFrom(n);


//This modifies outside the subtree, which is not // This modifies outside the subtree, which is not
//desirable in a peephole optimization. // desirable in a peephole optimization.
parent.getParent().addChildAfter(newStatement, parent); parent.getParent().addChildAfter(newStatement, parent);
reportCodeChange(); reportCodeChange();
return left; return left;
Expand Down
13 changes: 7 additions & 6 deletions test/com/google/javascript/jscomp/CreateSyntheticBlocksTest.java
Expand Up @@ -41,13 +41,14 @@ protected CompilerPass getProcessor(final Compiler compiler) {
return new CompilerPass() { return new CompilerPass() {
@Override @Override
public void process(Node externs, Node js) { public void process(Node externs, Node js) {
new CreateSyntheticBlocks(compiler, START_MARKER, END_MARKER).process( new CreateSyntheticBlocks(compiler, START_MARKER, END_MARKER).process(externs, js);
externs, js);
new MinimizeExitPoints(compiler).asCompilerPass().process(externs, js); new MinimizeExitPoints(compiler).asCompilerPass().process(externs, js);
new PeepholeOptimizationsPass(compiler, new PeepholeOptimizationsPass(
new PeepholeRemoveDeadCode(), compiler,
new PeepholeMinimizeConditions(true /* late */, false /* useTypes */), getName(),
new PeepholeFoldConstants(true, false)) new PeepholeRemoveDeadCode(),
new PeepholeMinimizeConditions(true /* late */, false /* useTypes */),
new PeepholeFoldConstants(true, false))
.process(externs, js); .process(externs, js);
new MinimizeExitPoints(compiler).asCompilerPass().process(externs, js); new MinimizeExitPoints(compiler).asCompilerPass().process(externs, js);
new Denormalize(compiler).process(externs, js); new Denormalize(compiler).process(externs, js);
Expand Down
2 changes: 1 addition & 1 deletion test/com/google/javascript/jscomp/ExploitAssignsTest.java
Expand Up @@ -184,6 +184,6 @@ public void testIssue1017() {


@Override @Override
protected CompilerPass getProcessor(Compiler compiler) { protected CompilerPass getProcessor(Compiler compiler) {
return new PeepholeOptimizationsPass(compiler,new ExploitAssigns()); return new PeepholeOptimizationsPass(compiler, getName(), new ExploitAssigns());
} }
} }
4 changes: 3 additions & 1 deletion test/com/google/javascript/jscomp/MultiPassTest.java
Expand Up @@ -359,7 +359,9 @@ private void addPeephole() {
@Override @Override
protected CompilerPass create(AbstractCompiler compiler) { protected CompilerPass create(AbstractCompiler compiler) {
final boolean late = false; final boolean late = false;
return new PeepholeOptimizationsPass(compiler, return new PeepholeOptimizationsPass(
compiler,
getName(),
new PeepholeMinimizeConditions(late, false /* useTypes */), new PeepholeMinimizeConditions(late, false /* useTypes */),
new PeepholeSubstituteAlternateSyntax(late), new PeepholeSubstituteAlternateSyntax(late),
new PeepholeReplaceKnownMethods(late, false), new PeepholeReplaceKnownMethods(late, false),
Expand Down
Expand Up @@ -21,7 +21,7 @@ public final class PeepholeCollectPropertyAssignmentsTest extends CompilerTestCa
@Override @Override
protected CompilerPass getProcessor(final Compiler compiler) { protected CompilerPass getProcessor(final Compiler compiler) {
return new PeepholeOptimizationsPass( return new PeepholeOptimizationsPass(
compiler, new PeepholeCollectPropertyAssignments()); compiler, getName(), new PeepholeCollectPropertyAssignments());
} }


public void test36122565a() { public void test36122565a() {
Expand Down

0 comments on commit 89d5711

Please sign in to comment.