Search in sources :

Example 1 with MeasuredNode

use of com.google.javascript.jscomp.MinimizedCondition.MeasuredNode in project closure-compiler by google.

the class PeepholeMinimizeConditions method tryMinimizeHook.

/**
 * Try flipping HOOKs that have negated conditions.
 *
 * Returns the replacement for n or the original if no replacement was
 * necessary.
 */
private Node tryMinimizeHook(Node n) {
    Node originalCond = n.getFirstChild();
    MinimizedCondition minCond = MinimizedCondition.fromConditionNode(originalCond);
    MeasuredNode mNode = minCond.getMinimized(MinimizationStyle.ALLOW_LEADING_NOT);
    if (mNode.isNot()) {
        // Swap the HOOK
        Node thenBranch = n.getSecondChild();
        replaceNode(originalCond, mNode.withoutNot());
        thenBranch.detach();
        n.addChildToBack(thenBranch);
        reportChangeToEnclosingScope(n);
    } else {
        replaceNode(originalCond, mNode);
    }
    return n;
}
Also used : MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) Node(com.google.javascript.rhino.Node)

Example 2 with MeasuredNode

use of com.google.javascript.jscomp.MinimizedCondition.MeasuredNode in project closure-compiler by google.

the class PeepholeMinimizeConditions method tryMinimizeIf.

/**
 * Try turning IF nodes into smaller HOOKs
 *
 * Returns the replacement for n or the original if no replacement was
 * necessary.
 */
private Node tryMinimizeIf(Node n) {
    Node parent = n.getParent();
    Node originalCond = n.getFirstChild();
    /* If the condition is a literal, we'll let other
     * optimizations try to remove useless code.
     */
    if (NodeUtil.isLiteralValue(originalCond, true)) {
        return n;
    }
    Node thenBranch = originalCond.getNext();
    Node elseBranch = thenBranch.getNext();
    MinimizedCondition minCond = MinimizedCondition.fromConditionNode(originalCond);
    // Compute two minimized representations. The first representation counts
    // a leading NOT node, and the second ignores a leading NOT node.
    // If we can fold the if statement into a HOOK or boolean operation,
    // then the NOT node does not matter, and we prefer the second condition.
    // If we cannot fold the if statement, then we prefer the first condition.
    MeasuredNode unnegatedCond = minCond.getMinimized(MinimizationStyle.PREFER_UNNEGATED);
    MeasuredNode shortCond = minCond.getMinimized(MinimizationStyle.ALLOW_LEADING_NOT);
    if (elseBranch == null) {
        if (isFoldableExpressBlock(thenBranch)) {
            Node expr = getBlockExpression(thenBranch);
            if (!late && isPropertyAssignmentInExpression(expr)) {
                // Keep opportunities for CollapseProperties such as
                // a.longIdentifier || a.longIdentifier = ... -> var a = ...;
                // until CollapseProperties has been run.
                replaceNode(originalCond, unnegatedCond);
                return n;
            }
            if (shortCond.isNot()) {
                // if(!x)bar(); -> x||bar();
                Node replacementCond = replaceNode(originalCond, shortCond.withoutNot()).detach();
                Node or = IR.or(replacementCond, expr.removeFirstChild()).srcref(n);
                Node newExpr = NodeUtil.newExpr(or);
                n.replaceWith(newExpr);
                reportChangeToEnclosingScope(parent);
                return newExpr;
            }
            // if(x)foo(); -> x&&foo();
            if (shortCond.isLowerPrecedenceThan(AND_PRECEDENCE) && isLowerPrecedence(expr.getFirstChild(), AND_PRECEDENCE)) {
                // One additional set of parentheses is worth the change even if
                // there is no immediate code size win. However, two extra pair of
                // {}, we would have to think twice. (unless we know for sure the
                // we can further optimize its parent.
                replaceNode(originalCond, shortCond);
                return n;
            }
            Node replacementCond = replaceNode(originalCond, shortCond).detach();
            Node and = IR.and(replacementCond, expr.removeFirstChild()).srcref(n);
            Node newExpr = NodeUtil.newExpr(and);
            n.replaceWith(newExpr);
            reportChangeToEnclosingScope(parent);
            return newExpr;
        } else {
            // Try to combine two IF-ELSE
            if (NodeUtil.isStatementBlock(thenBranch) && thenBranch.hasOneChild()) {
                Node innerIf = thenBranch.getFirstChild();
                if (innerIf.isIf()) {
                    Node innerCond = innerIf.getFirstChild();
                    Node innerThenBranch = innerCond.getNext();
                    Node innerElseBranch = innerThenBranch.getNext();
                    if (innerElseBranch == null && !(unnegatedCond.isLowerPrecedenceThan(AND_PRECEDENCE) && isLowerPrecedence(innerCond, AND_PRECEDENCE))) {
                        Node replacementCond = replaceNode(originalCond, unnegatedCond).detach();
                        n.detachChildren();
                        n.addChildToBack(IR.and(replacementCond, innerCond.detach()).srcref(originalCond));
                        n.addChildToBack(innerThenBranch.detach());
                        reportChangeToEnclosingScope(n);
                        // the inner IF-ELSE wasn't able to be folded into && anyways.
                        return n;
                    }
                }
            }
        }
        replaceNode(originalCond, unnegatedCond);
        return n;
    }
    /* TODO(dcc) This modifies the siblings of n, which is undesirable for a
     * peephole optimization. This should probably get moved to another pass.
     */
    tryRemoveRepeatedStatements(n);
    // An additional set of curly braces isn't worth it.
    if (shortCond.isNot() && !consumesDanglingElse(elseBranch)) {
        replaceNode(originalCond, shortCond.withoutNot());
        thenBranch.detach();
        n.addChildToBack(thenBranch);
        reportChangeToEnclosingScope(n);
        return n;
    }
    // if(x)return 1;else return 2; -> return x?1:2;
    if (isReturnExpressBlock(thenBranch) && isReturnExpressBlock(elseBranch)) {
        Node thenExpr = getBlockReturnExpression(thenBranch);
        Node elseExpr = getBlockReturnExpression(elseBranch);
        Node replacementCond = replaceNode(originalCond, shortCond).detach();
        thenExpr.detach();
        elseExpr.detach();
        // note - we ignore any cases with "return;", technically this
        // can be converted to "return undefined;" or some variant, but
        // that does not help code size.
        Node returnNode = IR.returnNode(IR.hook(replacementCond, thenExpr, elseExpr).srcref(n));
        n.replaceWith(returnNode);
        reportChangeToEnclosingScope(returnNode);
        return returnNode;
    }
    boolean thenBranchIsExpressionBlock = isFoldableExpressBlock(thenBranch);
    boolean elseBranchIsExpressionBlock = isFoldableExpressBlock(elseBranch);
    if (thenBranchIsExpressionBlock && elseBranchIsExpressionBlock) {
        Node thenOp = getBlockExpression(thenBranch).getFirstChild();
        Node elseOp = getBlockExpression(elseBranch).getFirstChild();
        if (thenOp.getToken() == elseOp.getToken()) {
            // if(x)a=1;else a=2; -> a=x?1:2;
            if (NodeUtil.isAssignmentOp(thenOp)) {
                Node lhs = thenOp.getFirstChild();
                if (areNodesEqualForInlining(lhs, elseOp.getFirstChild()) && // proceed even if there are side effects...
                !mayEffectMutableState(lhs) && (!mayHaveSideEffects(originalCond) || (thenOp.isAssign() && thenOp.getFirstChild().isName()))) {
                    Node replacementCond = replaceNode(originalCond, shortCond).detach();
                    Node assignName = thenOp.removeFirstChild();
                    Node thenExpr = thenOp.removeFirstChild();
                    Node elseExpr = elseOp.getLastChild();
                    elseExpr.detach();
                    Node hookNode = IR.hook(replacementCond, thenExpr, elseExpr).srcref(n);
                    Node assign = new Node(thenOp.getToken(), assignName, hookNode).srcref(thenOp);
                    Node expr = NodeUtil.newExpr(assign);
                    n.replaceWith(expr);
                    reportChangeToEnclosingScope(parent);
                    return expr;
                }
            }
        }
        // if(x)foo();else bar(); -> x?foo():bar()
        Node replacementCond = replaceNode(originalCond, shortCond).detach();
        thenOp.detach();
        elseOp.detach();
        Node expr = IR.exprResult(IR.hook(replacementCond, thenOp, elseOp).srcref(n));
        n.replaceWith(expr);
        reportChangeToEnclosingScope(parent);
        return expr;
    }
    boolean thenBranchIsVar = isVarBlock(thenBranch);
    boolean elseBranchIsVar = isVarBlock(elseBranch);
    // if(x)var y=1;else y=2  ->  var y=x?1:2
    if (thenBranchIsVar && elseBranchIsExpressionBlock && getBlockExpression(elseBranch).getFirstChild().isAssign()) {
        Node var = getBlockVar(thenBranch);
        Node elseAssign = getBlockExpression(elseBranch).getFirstChild();
        Node name1 = var.getFirstChild();
        Node maybeName2 = elseAssign.getFirstChild();
        if (name1.hasChildren() && maybeName2.isName() && name1.getString().equals(maybeName2.getString())) {
            checkState(name1.hasOneChild());
            Node thenExpr = name1.removeFirstChild();
            Node elseExpr = elseAssign.getLastChild().detach();
            Node replacementCond = replaceNode(originalCond, shortCond).detach();
            Node hookNode = IR.hook(replacementCond, thenExpr, elseExpr).srcref(n);
            var.detach();
            name1.addChildToBack(hookNode);
            n.replaceWith(var);
            reportChangeToEnclosingScope(parent);
            return var;
        }
    // if(x)y=1;else var y=2  ->  var y=x?1:2
    } else if (elseBranchIsVar && thenBranchIsExpressionBlock && getBlockExpression(thenBranch).getFirstChild().isAssign()) {
        Node var = getBlockVar(elseBranch);
        Node thenAssign = getBlockExpression(thenBranch).getFirstChild();
        Node maybeName1 = thenAssign.getFirstChild();
        Node name2 = var.getFirstChild();
        if (name2.hasChildren() && maybeName1.isName() && maybeName1.getString().equals(name2.getString())) {
            Node thenExpr = thenAssign.getLastChild().detach();
            checkState(name2.hasOneChild());
            Node elseExpr = name2.removeFirstChild();
            Node replacementCond = replaceNode(originalCond, shortCond).detach();
            Node hookNode = IR.hook(replacementCond, thenExpr, elseExpr).srcref(n);
            var.detach();
            name2.addChildToBack(hookNode);
            n.replaceWith(var);
            reportChangeToEnclosingScope(parent);
            return var;
        }
    }
    replaceNode(originalCond, unnegatedCond);
    return n;
}
Also used : MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) Node(com.google.javascript.rhino.Node)

Example 3 with MeasuredNode

use of com.google.javascript.jscomp.MinimizedCondition.MeasuredNode in project closure-compiler by google.

the class PeepholeMinimizeConditions method tryMinimizeExprResult.

/**
 * Try to remove leading NOTs from EXPR_RESULTS.
 *
 * Returns the replacement for n or the original if no replacement was
 * necessary.
 */
private Node tryMinimizeExprResult(Node n) {
    Node originalExpr = n.getFirstChild();
    MinimizedCondition minCond = MinimizedCondition.fromConditionNode(originalExpr);
    MeasuredNode mNode = minCond.getMinimized(MinimizationStyle.ALLOW_LEADING_NOT);
    if (mNode.isNot()) {
        // Remove the leading NOT in the EXPR_RESULT.
        replaceNode(originalExpr, mNode.withoutNot());
    } else {
        replaceNode(originalExpr, mNode);
    }
    return n;
}
Also used : MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) Node(com.google.javascript.rhino.Node)

Example 4 with MeasuredNode

use of com.google.javascript.jscomp.MinimizedCondition.MeasuredNode in project closure-compiler by google.

the class PeepholeMinimizeConditions method replaceNode.

private Node replaceNode(Node original, MeasuredNode measuredNodeReplacement) {
    if (measuredNodeReplacement.willChange(original)) {
        Node replacement = measuredNodeReplacement.applyTo(original);
        reportChangeToEnclosingScope(replacement);
        return replacement;
    }
    return original;
}
Also used : MeasuredNode(com.google.javascript.jscomp.MinimizedCondition.MeasuredNode) Node(com.google.javascript.rhino.Node)

Aggregations

MeasuredNode (com.google.javascript.jscomp.MinimizedCondition.MeasuredNode)4 Node (com.google.javascript.rhino.Node)4