| Index: src/ia32/codegen-ia32.cc
 | 
| ===================================================================
 | 
| --- src/ia32/codegen-ia32.cc	(revision 4129)
 | 
| +++ src/ia32/codegen-ia32.cc	(working copy)
 | 
| @@ -1102,7 +1102,8 @@
 | 
|  
 | 
|  void CodeGenerator::GenericBinaryOperation(Token::Value op,
 | 
|                                             StaticType* type,
 | 
| -                                           OverwriteMode overwrite_mode) {
 | 
| +                                           OverwriteMode overwrite_mode,
 | 
| +                                           bool no_negative_zero) {
 | 
|    Comment cmnt(masm_, "[ BinaryOperation");
 | 
|    Comment cmnt_token(masm_, Token::String(op));
 | 
|  
 | 
| @@ -1170,10 +1171,12 @@
 | 
|      answer = stub.GenerateCall(masm_, frame_, &left, &right);
 | 
|    } else if (right_is_smi_constant) {
 | 
|      answer = ConstantSmiBinaryOperation(op, &left, right.handle(),
 | 
| -                                        type, false, overwrite_mode);
 | 
| +                                        type, false, overwrite_mode,
 | 
| +                                        no_negative_zero);
 | 
|    } else if (left_is_smi_constant) {
 | 
|      answer = ConstantSmiBinaryOperation(op, &right, left.handle(),
 | 
| -                                        type, true, overwrite_mode);
 | 
| +                                        type, true, overwrite_mode,
 | 
| +                                        no_negative_zero);
 | 
|    } else {
 | 
|      // Set the flags based on the operation, type and loop nesting level.
 | 
|      // Bit operations always assume they likely operate on Smis. Still only
 | 
| @@ -1184,7 +1187,8 @@
 | 
|          (Token::IsBitOp(op) ||
 | 
|           operands_type.IsInteger32() ||
 | 
|           type->IsLikelySmi())) {
 | 
| -      answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode);
 | 
| +      answer = LikelySmiBinaryOperation(op, &left, &right,
 | 
| +                                        overwrite_mode, no_negative_zero);
 | 
|      } else {
 | 
|        GenericBinaryOpStub stub(op,
 | 
|                                 overwrite_mode,
 | 
| @@ -1291,7 +1295,8 @@
 | 
|  Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
 | 
|                                                 Result* left,
 | 
|                                                 Result* right,
 | 
| -                                               OverwriteMode overwrite_mode) {
 | 
| +                                               OverwriteMode overwrite_mode,
 | 
| +                                               bool no_negative_zero) {
 | 
|    Result answer;
 | 
|    // Special handling of div and mod because they use fixed registers.
 | 
|    if (op == Token::DIV || op == Token::MOD) {
 | 
| @@ -1395,13 +1400,16 @@
 | 
|        // Check for negative zero result.  If result is zero, and divisor
 | 
|        // is negative, return a floating point negative zero.  The
 | 
|        // virtual frame is unchanged in this block, so local control flow
 | 
| -      // can use a Label rather than a JumpTarget.
 | 
| -      Label non_zero_result;
 | 
| -      __ test(left->reg(), Operand(left->reg()));
 | 
| -      __ j(not_zero, &non_zero_result);
 | 
| -      __ test(right->reg(), Operand(right->reg()));
 | 
| -      deferred->Branch(negative);
 | 
| -      __ bind(&non_zero_result);
 | 
| +      // can use a Label rather than a JumpTarget.  If the context of this
 | 
| +      // expression will treat -0 like 0, do not do this test.
 | 
| +      if (!no_negative_zero) {
 | 
| +        Label non_zero_result;
 | 
| +        __ test(left->reg(), Operand(left->reg()));
 | 
| +        __ j(not_zero, &non_zero_result);
 | 
| +        __ test(right->reg(), Operand(right->reg()));
 | 
| +        deferred->Branch(negative);
 | 
| +        __ bind(&non_zero_result);
 | 
| +      }
 | 
|        // Check for the corner case of dividing the most negative smi by
 | 
|        // -1. We cannot use the overflow flag, since it is not set by
 | 
|        // idiv instruction.
 | 
| @@ -1423,12 +1431,14 @@
 | 
|        // the dividend is negative, return a floating point negative
 | 
|        // zero.  The frame is unchanged in this block, so local control
 | 
|        // flow can use a Label rather than a JumpTarget.
 | 
| -      Label non_zero_result;
 | 
| -      __ test(edx, Operand(edx));
 | 
| -      __ j(not_zero, &non_zero_result, taken);
 | 
| -      __ test(left->reg(), Operand(left->reg()));
 | 
| -      deferred->Branch(negative);
 | 
| -      __ bind(&non_zero_result);
 | 
| +      if (!no_negative_zero) {
 | 
| +        Label non_zero_result;
 | 
| +        __ test(edx, Operand(edx));
 | 
| +        __ j(not_zero, &non_zero_result, taken);
 | 
| +        __ test(left->reg(), Operand(left->reg()));
 | 
| +        deferred->Branch(negative);
 | 
| +        __ bind(&non_zero_result);
 | 
| +      }
 | 
|        deferred->BindExit();
 | 
|        left->Unuse();
 | 
|        right->Unuse();
 | 
| @@ -1571,14 +1581,16 @@
 | 
|        // argument is negative, go to slow case.  The frame is unchanged
 | 
|        // in this block, so local control flow can use a Label rather
 | 
|        // than a JumpTarget.
 | 
| -      Label non_zero_result;
 | 
| -      __ test(answer.reg(), Operand(answer.reg()));
 | 
| -      __ j(not_zero, &non_zero_result, taken);
 | 
| -      __ mov(answer.reg(), left->reg());
 | 
| -      __ or_(answer.reg(), Operand(right->reg()));
 | 
| -      deferred->Branch(negative);
 | 
| -      __ xor_(answer.reg(), Operand(answer.reg()));  // Positive 0 is correct.
 | 
| -      __ bind(&non_zero_result);
 | 
| +      if (!no_negative_zero) {
 | 
| +        Label non_zero_result;
 | 
| +        __ test(answer.reg(), Operand(answer.reg()));
 | 
| +        __ j(not_zero, &non_zero_result, taken);
 | 
| +        __ mov(answer.reg(), left->reg());
 | 
| +        __ or_(answer.reg(), Operand(right->reg()));
 | 
| +        deferred->Branch(negative);
 | 
| +        __ xor_(answer.reg(), Operand(answer.reg()));  // Positive 0 is correct.
 | 
| +        __ bind(&non_zero_result);
 | 
| +      }
 | 
|        break;
 | 
|      }
 | 
|  
 | 
| @@ -1817,7 +1829,8 @@
 | 
|                                                   Handle<Object> value,
 | 
|                                                   StaticType* type,
 | 
|                                                   bool reversed,
 | 
| -                                                 OverwriteMode overwrite_mode) {
 | 
| +                                                 OverwriteMode overwrite_mode,
 | 
| +                                                 bool no_negative_zero) {
 | 
|    // NOTE: This is an attempt to inline (a bit) more of the code for
 | 
|    // some possible smi operations (like + and -) when (at least) one
 | 
|    // of the operands is a constant smi.
 | 
| @@ -1828,10 +1841,10 @@
 | 
|      Result unsafe_operand(value);
 | 
|      if (reversed) {
 | 
|        return LikelySmiBinaryOperation(op, &unsafe_operand, operand,
 | 
| -                                      overwrite_mode);
 | 
| +                                      overwrite_mode, no_negative_zero);
 | 
|      } else {
 | 
|        return LikelySmiBinaryOperation(op, operand, &unsafe_operand,
 | 
| -                                      overwrite_mode);
 | 
| +                                      overwrite_mode, no_negative_zero);
 | 
|      }
 | 
|    }
 | 
|  
 | 
| @@ -1911,7 +1924,7 @@
 | 
|        if (reversed) {
 | 
|          Result constant_operand(value);
 | 
|          answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
 | 
| -                                          overwrite_mode);
 | 
| +                                          overwrite_mode, no_negative_zero);
 | 
|        } else {
 | 
|          // Only the least significant 5 bits of the shift value are used.
 | 
|          // In the slow case, this masking is done inside the runtime call.
 | 
| @@ -1947,7 +1960,7 @@
 | 
|        if (reversed) {
 | 
|          Result constant_operand(value);
 | 
|          answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
 | 
| -                                          overwrite_mode);
 | 
| +                                          overwrite_mode, no_negative_zero);
 | 
|        } else {
 | 
|          // Only the least significant 5 bits of the shift value are used.
 | 
|          // In the slow case, this masking is done inside the runtime call.
 | 
| @@ -2140,10 +2153,10 @@
 | 
|          Result constant_operand(value);
 | 
|          if (reversed) {
 | 
|            answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
 | 
| -                                            overwrite_mode);
 | 
| +                                            overwrite_mode, no_negative_zero);
 | 
|          } else {
 | 
|            answer = LikelySmiBinaryOperation(op, operand, &constant_operand,
 | 
| -                                            overwrite_mode);
 | 
| +                                            overwrite_mode, no_negative_zero);
 | 
|          }
 | 
|        }
 | 
|        break;
 | 
| @@ -2180,10 +2193,10 @@
 | 
|        Result constant_operand(value);
 | 
|        if (reversed) {
 | 
|          answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
 | 
| -                                          overwrite_mode);
 | 
| +                                          overwrite_mode, no_negative_zero);
 | 
|        } else {
 | 
|          answer = LikelySmiBinaryOperation(op, operand, &constant_operand,
 | 
| -                                          overwrite_mode);
 | 
| +                                          overwrite_mode, no_negative_zero);
 | 
|        }
 | 
|        break;
 | 
|      }
 | 
| @@ -4950,7 +4963,8 @@
 | 
|           node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
 | 
|      GenericBinaryOperation(node->binary_op(),
 | 
|                             node->type(),
 | 
| -                           overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
 | 
| +                           overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE,
 | 
| +                           node->no_negative_zero());
 | 
|    } else {
 | 
|      Load(node->value());
 | 
|    }
 | 
| @@ -5027,7 +5041,8 @@
 | 
|           node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
 | 
|      GenericBinaryOperation(node->binary_op(),
 | 
|                             node->type(),
 | 
| -                           overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
 | 
| +                           overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE,
 | 
| +                           node->no_negative_zero());
 | 
|    } else {
 | 
|      Load(node->value());
 | 
|    }
 | 
| @@ -5106,7 +5121,8 @@
 | 
|           node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
 | 
|      GenericBinaryOperation(node->binary_op(),
 | 
|                             node->type(),
 | 
| -                           overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
 | 
| +                           overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE,
 | 
| +                           node->no_negative_zero());
 | 
|    } else {
 | 
|      Load(node->value());
 | 
|    }
 | 
| @@ -6868,7 +6884,8 @@
 | 
|        Load(node->left());
 | 
|        Load(node->right());
 | 
|      }
 | 
| -    GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
 | 
| +    GenericBinaryOperation(node->op(), node->type(),
 | 
| +                           overwrite_mode, node->no_negative_zero());
 | 
|    }
 | 
|  }
 | 
|  
 | 
| 
 |