Index: src/rewriter.cc |
=================================================================== |
--- src/rewriter.cc (revision 4966) |
+++ src/rewriter.cc (working copy) |
@@ -87,11 +87,13 @@ |
void AstOptimizer::VisitExpressionStatement(ExpressionStatement* node) { |
+ node->expression()->set_no_negative_zero(true); |
Visit(node->expression()); |
} |
void AstOptimizer::VisitIfStatement(IfStatement* node) { |
+ node->condition()->set_no_negative_zero(true); |
Visit(node->condition()); |
Visit(node->then_statement()); |
if (node->HasElseStatement()) { |
@@ -101,6 +103,7 @@ |
void AstOptimizer::VisitDoWhileStatement(DoWhileStatement* node) { |
+ node->cond()->set_no_negative_zero(true); |
Visit(node->cond()); |
Visit(node->body()); |
} |
@@ -108,6 +111,7 @@ |
void AstOptimizer::VisitWhileStatement(WhileStatement* node) { |
has_function_literal_ = false; |
+ node->cond()->set_no_negative_zero(true); |
Visit(node->cond()); |
node->may_have_function_literal_ = has_function_literal_; |
Visit(node->body()); |
@@ -120,6 +124,7 @@ |
} |
if (node->cond() != NULL) { |
has_function_literal_ = false; |
+ node->cond()->set_no_negative_zero(true); |
Visit(node->cond()); |
node->may_have_function_literal_ = has_function_literal_; |
} |
@@ -151,6 +156,7 @@ |
void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) { |
+ node->tag()->set_no_negative_zero(true); |
Visit(node->tag()); |
for (int i = 0; i < node->cases()->length(); i++) { |
CaseClause* clause = node->cases()->at(i); |
@@ -444,6 +450,7 @@ |
if (FLAG_safe_int32_compiler) { |
switch (node->op()) { |
case Token::BIT_NOT: |
+ node->expression()->set_no_negative_zero(true); |
node->expression()->set_to_int32(true); |
// Fall through. |
case Token::ADD: |
@@ -476,10 +483,49 @@ |
} |
+static bool CouldBeNegativeZero(AstNode* node) { |
+ Literal* literal = node->AsLiteral(); |
+ if (literal != NULL) { |
+ Handle<Object> handle = literal->handle(); |
+ if (handle->IsString() || handle->IsSmi()) { |
+ return false; |
+ } else if (handle->IsHeapNumber()) { |
+ double double_value = HeapNumber::cast(*handle)->value(); |
+ if (double_value != 0) { |
+ return false; |
+ } |
+ } |
+ } |
+ BinaryOperation* binary = node->AsBinaryOperation(); |
+ if (binary != NULL && Token::IsBitOp(binary->op())) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+ |
+static bool CouldBePositiveZero(AstNode* node) { |
+ Literal* literal = node->AsLiteral(); |
+ if (literal != NULL) { |
+ Handle<Object> handle = literal->handle(); |
+ if (handle->IsSmi()) { |
+ if (Smi::cast(*handle) != Smi::FromInt(0)) { |
+ return false; |
+ } |
+ } else if (handle->IsHeapNumber()) { |
+ // Heap number literal can't be +0, because that's a Smi. |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
+ |
+ |
void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) { |
// Depending on the operation we can propagate this node's type down the |
// AST nodes. |
- switch (node->op()) { |
+ Token::Value op = node->op(); |
+ switch (op) { |
case Token::COMMA: |
case Token::OR: |
node->left()->set_no_negative_zero(true); |
@@ -503,23 +549,54 @@ |
node->left()->set_no_negative_zero(true); |
node->right()->set_no_negative_zero(true); |
break; |
+ case Token::MUL: { |
+ VariableProxy* lvar_proxy = node->left()->AsVariableProxy(); |
+ VariableProxy* rvar_proxy = node->right()->AsVariableProxy(); |
+ if (lvar_proxy != NULL && rvar_proxy != NULL) { |
+ Variable* lvar = lvar_proxy->AsVariable(); |
+ Variable* rvar = rvar_proxy->AsVariable(); |
+ if (lvar != NULL && rvar != NULL) { |
+ if (lvar->mode() == Variable::VAR && rvar->mode() == Variable::VAR) { |
+ Slot* lslot = lvar->slot(); |
+ Slot* rslot = rvar->slot(); |
+ if (lslot->type() == rslot->type() && |
+ (lslot->type() == Slot::PARAMETER || |
+ lslot->type() == Slot::LOCAL) && |
+ lslot->index() == rslot->index()) { |
+ // A number squared doesn't give negative zero. |
+ node->set_no_negative_zero(true); |
+ } |
+ } |
+ } |
+ } |
+ } |
case Token::ADD: |
case Token::SUB: |
- case Token::MUL: |
case Token::DIV: |
- case Token::MOD: |
+ case Token::MOD: { |
if (node->type()->IsLikelySmi()) { |
node->left()->type()->SetAsLikelySmiIfUnknown(); |
node->right()->type()->SetAsLikelySmiIfUnknown(); |
} |
- node->left()->set_no_negative_zero(node->no_negative_zero()); |
- node->right()->set_no_negative_zero(node->no_negative_zero()); |
+ if (op == Token::ADD && (!CouldBeNegativeZero(node->left()) || |
+ !CouldBeNegativeZero(node->right()))) { |
+ node->left()->set_no_negative_zero(true); |
+ node->right()->set_no_negative_zero(true); |
+ } else if (op == Token::SUB && (!CouldBeNegativeZero(node->left()) || |
+ !CouldBePositiveZero(node->right()))) { |
+ node->left()->set_no_negative_zero(true); |
+ node->right()->set_no_negative_zero(true); |
+ } else { |
+ node->left()->set_no_negative_zero(node->no_negative_zero()); |
+ node->right()->set_no_negative_zero(node->no_negative_zero()); |
+ } |
if (node->op() == Token::DIV) { |
node->right()->set_no_negative_zero(false); |
} else if (node->op() == Token::MOD) { |
node->right()->set_no_negative_zero(true); |
} |
break; |
+ } |
default: |
UNREACHABLE(); |
break; |
@@ -530,7 +607,7 @@ |
// After visiting the operand nodes we have to check if this node's type |
// can be updated. If it does, then we can push that information down |
- // towards the leafs again if the new information is an upgrade over the |
+ // towards the leaves again if the new information is an upgrade over the |
// previous type of the operand nodes. |
if (node->type()->IsUnknown()) { |
if (node->left()->type()->IsLikelySmi() || |
@@ -590,7 +667,7 @@ |
void AstOptimizer::VisitCompareOperation(CompareOperation* node) { |
if (node->type()->IsKnown()) { |
- // Propagate useful information down towards the leafs. |
+ // Propagate useful information down towards the leaves. |
node->left()->type()->SetAsLikelySmiIfUnknown(); |
node->right()->type()->SetAsLikelySmiIfUnknown(); |
} |
@@ -604,7 +681,7 @@ |
// After visiting the operand nodes we have to check if this node's type |
// can be updated. If it does, then we can push that information down |
- // towards the leafs again if the new information is an upgrade over the |
+ // towards the leaves again if the new information is an upgrade over the |
// previous type of the operand nodes. |
if (node->type()->IsUnknown()) { |
if (node->left()->type()->IsLikelySmi() || |