@Override protected CompilerPass create(AbstractCompiler compiler) { return new MinimizeExitPoints(compiler); } };
void tryMinimizeSwitchExits(Node n, Token exitType, @Nullable String labelName) { checkState(n.isSwitch()); // Skipping the switch condition, visit all the children. for (Node c = n.getSecondChild(); c != null; c = c.getNext()) { if (c != n.getLastChild()) { tryMinimizeSwitchCaseExits(c, exitType, labelName); } else { // Last case, the last case block can be optimized more aggressively. tryMinimizeExits(c.getLastChild(), exitType, labelName); } } }
if (matchingExitNode(n, exitType, labelName)) { reportChangeToEnclosingScope(n); NodeUtil.removeChild(n.getParent(), n); return; tryMinimizeExits(ifBlock, exitType, labelName); Node elseBlock = ifBlock.getNext(); if (elseBlock != null) { tryMinimizeExits(elseBlock, exitType, labelName); tryMinimizeExits(tryBlock, exitType, labelName); Node allCatchNodes = NodeUtil.getCatchBlock(n); if (NodeUtil.hasCatchHandler(allCatchNodes)) { Node catchNode = allCatchNodes.getFirstChild(); Node catchCodeBlock = catchNode.getLastChild(); tryMinimizeExits(catchCodeBlock, exitType, labelName); tryMinimizeExits(labelBlock, exitType, labelName); tryMinimizeSwitchExits(n, exitType, labelName); return; tryMinimizeIfBlockExits(trueBlock, falseBlock, ifTree, exitType, labelName); falseBlock = trueBlock.getNext(); if (falseBlock != null) { tryMinimizeIfBlockExits(falseBlock, trueBlock,
if (!matchingExitNode(exitNode, exitType, labelName)) { return; if (!tryConvertAllBlockScopedFollowing(ifNode)) { return; moveAllFollowing(ifNode, ifNode.getParent(), newDestBlock); reportChangeToEnclosingScope(ifNode);
switch (n.getType()) { case Token.LABEL: tryMinimizeExits( n.getLastChild(), Token.BREAK, n.getFirstChild().getString()); break; tryMinimizeExits(NodeUtil.getLoopCodeBlock(n), Token.CONTINUE, null); break; tryMinimizeExits(NodeUtil.getLoopCodeBlock(n), Token.CONTINUE, null); tryMinimizeExits(n.getFirstChild(), Token.BREAK, null); tryMinimizeExits(n.getLastChild(), Token.RETURN, null); break; tryMinimizeSwitchExits(n, Token.BREAK, null); break;
if (!matchingExitNode(exitNode, exitType, labelName)) { return; moveAllFollowing(ifNode, ifNode.getParent(), newDestBlock); compiler.reportChangeToEnclosingScope(ifNode);
/** * Attempt to remove explicit exits from switch cases that also occur implicitly * after the switch. */ void tryMinimizeSwitchCaseExits(Node n, Token exitType, @Nullable String labelName) { checkState(NodeUtil.isSwitchCase(n)); checkState(n != n.getParent().getLastChild()); Node block = n.getLastChild(); Node maybeBreak = block.getLastChild(); if (maybeBreak == null || !maybeBreak.isBreak() || maybeBreak.hasChildren()) { // Can not minimize exits from a case without an explicit break from the switch. return; } // Now try to minimize the exits of the last child before the break, if it is removed // look at what has become the child before the break. Node childBeforeBreak = maybeBreak.getPrevious(); while (childBeforeBreak != null) { Node c = childBeforeBreak; tryMinimizeExits(c, exitType, labelName); // If the node is still the last child, we are done. childBeforeBreak = maybeBreak.getPrevious(); if (c == childBeforeBreak) { break; } } }
/** * Convert all let/const declarations following the start node to var declarations if possible. * * <p>See the unit tests for examples of why this is necessary before moving code into an inner * block, and why this is unsafe to do to declarations inside a loop. * * @param start The start point * @return Whether all block-scoped declarations have been converted. */ private static boolean tryConvertAllBlockScopedFollowing(Node start) { if (NodeUtil.isWithinLoop(start)) { // If in a loop, don't convert anything to a var. Return true only if there are no let/consts. return !hasBlockScopedVarsFollowing(start); } for (Node n = start.getNext(); n != null; n = n.getNext()) { if (n.isLet() || n.isConst()) { n.setToken(Token.VAR); } } return true; }
if (matchingExitNode(n, exitType, labelName)) { compiler.reportChangeToEnclosingScope(n); NodeUtil.removeChild(n.getParent(), n); tryMinimizeExits(ifBlock, exitType, labelName); Node elseBlock = ifBlock.getNext(); if (elseBlock != null) { tryMinimizeExits(elseBlock, exitType, labelName); tryMinimizeExits(tryBlock, exitType, labelName); Node allCatchNodes = NodeUtil.getCatchBlock(n); if (NodeUtil.hasCatchHandler(allCatchNodes)) { Node catchNode = allCatchNodes.getFirstChild(); Node catchCodeBlock = catchNode.getLastChild(); tryMinimizeExits(catchCodeBlock, exitType, labelName); tryMinimizeExits(labelBlock, exitType, labelName); tryMinimizeSwitchExits(n, exitType, labelName); return; tryMinimizeIfBlockExits(trueBlock, falseBlock, ifTree, exitType, labelName); falseBlock = trueBlock.getNext(); if (falseBlock != null) { tryMinimizeIfBlockExits(falseBlock, trueBlock, ifTree, exitType, labelName);
switch (n.getToken()) { case LABEL: tryMinimizeExits( n.getLastChild(), Token.BREAK, n.getFirstChild().getString()); break; case FOR_AWAIT_OF: case WHILE: tryMinimizeExits(NodeUtil.getLoopCodeBlock(n), Token.CONTINUE, null); break; tryMinimizeExits(NodeUtil.getLoopCodeBlock(n), Token.CONTINUE, null); tryMinimizeExits(n.getFirstChild(), Token.BREAK, null); tryMinimizeExits(n, Token.RETURN, null); tryMinimizeSwitchExits(n, Token.BREAK, null); break;
/** * Attempt to remove explicit exits from switch cases that also occur implicitly * after the switch. */ void tryMinimizeSwitchCaseExits(Node n, int exitType, @Nullable String labelName) { Preconditions.checkState(NodeUtil.isSwitchCase(n)); Preconditions.checkState(n != n.getParent().getLastChild()); Node block = n.getLastChild(); Node maybeBreak = block.getLastChild(); if (maybeBreak == null || !maybeBreak.isBreak() || maybeBreak.hasChildren()) { // Can not minimize exits from a case without an explicit break from the switch. return; } // Now try to minimize the exits of the last child before the break, if it is removed // look at what has become the child before the break. Node childBeforeBreak = block.getChildBefore(maybeBreak); while (childBeforeBreak != null) { Node c = childBeforeBreak; tryMinimizeExits(c, exitType, labelName); // If the node is still the last child, we are done. childBeforeBreak = block.getChildBefore(maybeBreak); if (c == childBeforeBreak) { break; } } }
void tryMinimizeSwitchExits(Node n, int exitType, @Nullable String labelName) { Preconditions.checkState(n.isSwitch()); // Skipping the switch condition, visit all the children. for (Node c = n.getSecondChild(); c != null; c = c.getNext()) { if (c != n.getLastChild()) { tryMinimizeSwitchCaseExits(c, exitType, labelName); } else { // Last case, the last case block can be optimized more aggressively. tryMinimizeExits(c.getLastChild(), exitType, labelName); } } }
/** Various peephole optimizations. */ private static CompilerPass createPeepholeOptimizationsPass( AbstractCompiler compiler, String passName) { final boolean late = false; final boolean useTypesForOptimization = compiler.getOptions().useTypesForLocalOptimization; List<AbstractPeepholeOptimization> optimizations = new ArrayList<>(); optimizations.add(new MinimizeExitPoints()); optimizations.add(new PeepholeMinimizeConditions(late)); optimizations.add(new PeepholeSubstituteAlternateSyntax(late)); optimizations.add(new PeepholeReplaceKnownMethods(late, useTypesForOptimization)); optimizations.add(new PeepholeRemoveDeadCode()); if (compiler.getOptions().j2clPassMode.shouldAddJ2clPasses()) { optimizations.add(new J2clEqualitySameRewriterPass(useTypesForOptimization)); optimizations.add(new J2clStringValueOfRewriterPass()); } optimizations.add(new PeepholeFoldConstants(late, useTypesForOptimization)); optimizations.add(new PeepholeCollectPropertyAssignments()); return new PeepholeOptimizationsPass(compiler, passName, optimizations); }