diff --git a/src/com/google/javascript/jscomp/DefaultPassConfig.java b/src/com/google/javascript/jscomp/DefaultPassConfig.java index 40e958f5b93..4d0eabf341d 100644 --- a/src/com/google/javascript/jscomp/DefaultPassConfig.java +++ b/src/com/google/javascript/jscomp/DefaultPassConfig.java @@ -1001,7 +1001,7 @@ private List getMainOptimizationLoop() { if (options.j2clPassMode.shouldAddJ2clPasses()) { passes.add(j2clConstantHoisterPass); - passes.add(j2clOptBundlePass); + passes.add(j2clClinitPass); } assertAllLoopablePasses(passes); @@ -1674,7 +1674,12 @@ protected FeatureSet featureSet() { new PassFactory("earlyPeepholeOptimizations", true) { @Override protected CompilerPass create(AbstractCompiler compiler) { - return new PeepholeOptimizationsPass(compiler, getName(), new PeepholeRemoveDeadCode()); + List peepholeOptimizations = new ArrayList<>(); + peepholeOptimizations.add(new PeepholeRemoveDeadCode()); + if (compiler.getOptions().j2clPassMode.shouldAddJ2clPasses()) { + peepholeOptimizations.add(new J2clEqualitySameRewriterPass()); + } + return new PeepholeOptimizationsPass(compiler, getName(), peepholeOptimizations); } @Override @@ -1709,16 +1714,18 @@ private static CompilerPass createPeepholeOptimizationsPass( AbstractCompiler compiler, String passName) { final boolean late = false; final boolean useTypesForOptimization = compiler.getOptions().useTypesForLocalOptimization; - return new PeepholeOptimizationsPass( - compiler, - passName, - new MinimizeExitPoints(compiler), - new PeepholeMinimizeConditions(late, useTypesForOptimization), - new PeepholeSubstituteAlternateSyntax(late), - new PeepholeReplaceKnownMethods(late, useTypesForOptimization), - new PeepholeRemoveDeadCode(), - new PeepholeFoldConstants(late, useTypesForOptimization), - new PeepholeCollectPropertyAssignments()); + List optimizations = new ArrayList<>(); + optimizations.add(new MinimizeExitPoints(compiler)); + optimizations.add(new PeepholeMinimizeConditions(late, useTypesForOptimization)); + optimizations.add(new PeepholeSubstituteAlternateSyntax(late)); + optimizations.add(new PeepholeReplaceKnownMethods(late, useTypesForOptimization)); + optimizations.add(new PeepholeRemoveDeadCode()); + if (compiler.getOptions().j2clPassMode.shouldAddJ2clPasses()) { + optimizations.add(new J2clEqualitySameRewriterPass()); + } + optimizations.add(new PeepholeFoldConstants(late, useTypesForOptimization)); + optimizations.add(new PeepholeCollectPropertyAssignments()); + return new PeepholeOptimizationsPass(compiler, passName, optimizations); } /** Various peephole optimizations. */ @@ -3283,24 +3290,13 @@ protected CompilerPass create(AbstractCompiler compiler) { } }; - /** Rewrites J2CL constructs to be more optimizable. */ - private final PassFactory j2clOptBundlePass = - new PassFactory("j2clOptBundlePass", false) { + /** Optimizes J2CL clinit methods. */ + private final PassFactory j2clClinitPass = + new PassFactory("j2clClinitPass", false) { @Override protected CompilerPass create(AbstractCompiler compiler) { List changedScopeNodes = compiler.getChangedScopeNodesForPass(getName()); - final J2clClinitPrunerPass j2clClinitPrunerPass = - new J2clClinitPrunerPass(compiler, changedScopeNodes); - final J2clEqualitySameRewriterPass j2clEqualitySameRewriterPass = - new J2clEqualitySameRewriterPass(compiler, changedScopeNodes); - return new CompilerPass() { - - @Override - public void process(Node externs, Node root) { - j2clClinitPrunerPass.process(externs, root); - j2clEqualitySameRewriterPass.process(externs, root); - } - }; + return new J2clClinitPrunerPass(compiler, changedScopeNodes); } }; diff --git a/src/com/google/javascript/jscomp/J2clEqualitySameRewriterPass.java b/src/com/google/javascript/jscomp/J2clEqualitySameRewriterPass.java index c37f5163096..456da53d66a 100644 --- a/src/com/google/javascript/jscomp/J2clEqualitySameRewriterPass.java +++ b/src/com/google/javascript/jscomp/J2clEqualitySameRewriterPass.java @@ -15,14 +15,11 @@ */ package com.google.javascript.jscomp; -import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; import com.google.javascript.rhino.IR; import com.google.javascript.rhino.Node; -import java.util.List; /** An optimization pass to re-write J2CL Equality.$same. */ -public class J2clEqualitySameRewriterPass extends AbstractPostOrderCallback - implements CompilerPass { +public class J2clEqualitySameRewriterPass extends AbstractPeepholeOptimization { /** Whether to use "==" or "===". */ private static enum Eq { @@ -30,56 +27,55 @@ private static enum Eq { TRIPLE } - private final AbstractCompiler compiler; - private final List changedScopeNodes; + private boolean shouldRunJ2clPasses = false; - J2clEqualitySameRewriterPass(AbstractCompiler compiler, List changedScopeNodes) { - this.compiler = compiler; - this.changedScopeNodes = changedScopeNodes; + @Override + void beginTraversal(AbstractCompiler compiler) { + super.beginTraversal(compiler); + shouldRunJ2clPasses = J2clSourceFileChecker.shouldRunJ2clPasses(compiler); } @Override - public void process(Node externs, Node root) { - if (!J2clSourceFileChecker.shouldRunJ2clPasses(compiler)) { - return; + Node optimizeSubtree(Node node) { + if (!shouldRunJ2clPasses) { + return node; } - NodeTraversal.traverseEs6ScopeRoots(compiler, root, changedScopeNodes, this, false); - } + if (!isEqualitySameCall(node)) { + return node; + } - @Override - public void visit(NodeTraversal t, Node node, Node parent) { - if (isEqualitySameCall(node)) { - trySubstituteEqualitySame(node); + Node replacement = trySubstituteEqualitySame(node); + if (replacement != node) { + replacement = replacement.useSourceInfoIfMissingFrom(node); + node.replaceWith(replacement); + reportCodeChange(); } + return replacement; } - private void trySubstituteEqualitySame(Node callNode) { + private Node trySubstituteEqualitySame(Node callNode) { Node firstExpr = callNode.getSecondChild(); Node secondExpr = callNode.getLastChild(); if (NodeUtil.isNullOrUndefined(firstExpr) || NodeUtil.isNullOrUndefined(secondExpr)) { // At least one side is null or undefined so no coercion danger. - rewriteToEq(callNode, firstExpr, secondExpr, Eq.DOUBLE); - return; + return rewriteToEq(firstExpr, secondExpr, Eq.DOUBLE); } if (NodeUtil.isLiteralValue(firstExpr, true) || NodeUtil.isLiteralValue(secondExpr, true)) { // There is a coercion danger but since at least one side is not null, we can use === that // will not trigger any coercion. - rewriteToEq(callNode, firstExpr, secondExpr, Eq.TRIPLE); - return; + return rewriteToEq(firstExpr, secondExpr, Eq.TRIPLE); } + + return callNode; } - private void rewriteToEq(Node callNode, Node firstExpr, Node secondExpr, Eq eq) { - Node parent = callNode.getParent(); + private Node rewriteToEq(Node firstExpr, Node secondExpr, Eq eq) { firstExpr.detach(); secondExpr.detach(); - Node replacement = - eq == Eq.DOUBLE ? IR.eq(firstExpr, secondExpr) : IR.sheq(firstExpr, secondExpr); - parent.replaceChild(callNode, replacement.useSourceInfoIfMissingFrom(callNode)); - compiler.reportChangeToEnclosingScope(parent); + return eq == Eq.DOUBLE ? IR.eq(firstExpr, secondExpr) : IR.sheq(firstExpr, secondExpr); } private static boolean isEqualitySameCall(Node node) { diff --git a/src/com/google/javascript/jscomp/PeepholeOptimizationsPass.java b/src/com/google/javascript/jscomp/PeepholeOptimizationsPass.java index 90f5c6e8ff0..10d3b716b92 100644 --- a/src/com/google/javascript/jscomp/PeepholeOptimizationsPass.java +++ b/src/com/google/javascript/jscomp/PeepholeOptimizationsPass.java @@ -19,6 +19,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; import com.google.javascript.rhino.Node; +import java.util.Arrays; import java.util.List; /** @@ -31,12 +32,19 @@ class PeepholeOptimizationsPass implements CompilerPass { private final AbstractCompiler compiler; private final String passName; - private final AbstractPeepholeOptimization[] peepholeOptimizations; + private final List peepholeOptimizations; private boolean retraverseOnChange; /** Creates a peephole optimization pass that runs the given optimizations. */ PeepholeOptimizationsPass( AbstractCompiler compiler, String passName, AbstractPeepholeOptimization... optimizations) { + this(compiler, passName, Arrays.asList(optimizations)); + } + + PeepholeOptimizationsPass( + AbstractCompiler compiler, + String passName, + List optimizations) { this.compiler = compiler; this.passName = passName; this.peepholeOptimizations = optimizations; diff --git a/test/com/google/javascript/jscomp/J2clEqualitySameRewriterPassTest.java b/test/com/google/javascript/jscomp/J2clEqualitySameRewriterPassTest.java index 67f3b715192..483e1ff3db7 100644 --- a/test/com/google/javascript/jscomp/J2clEqualitySameRewriterPassTest.java +++ b/test/com/google/javascript/jscomp/J2clEqualitySameRewriterPassTest.java @@ -29,18 +29,15 @@ protected void setUp() throws Exception { } @Override - protected CompilerPass getProcessor(Compiler compiler) { - return new J2clEqualitySameRewriterPass( - compiler, compiler.getChangedScopeNodesForPass("J2clEqualitySameRewriterPass")); + protected CompilerPass getProcessor(final Compiler compiler) { + return new PeepholeOptimizationsPass(compiler, getName(), new J2clEqualitySameRewriterPass()); } - @Override protected CompilerOptions getOptions() { CompilerOptions options = super.getOptions(); options.setJ2clPass(CompilerOptions.J2clPassMode.ON); return options; } - public void testRewriteEqualitySame() { test( LINE_JOINER.join(