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;
}
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;
}
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;
}
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;
}
Aggregations