| Index: src/x64/codegen-x64.cc
 | 
| diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
 | 
| index dd8015f14d10f78933afad97aa1e94c1aa5429ce..27e12afdae67bce0646f52b8c770052fc4e1068d 100644
 | 
| --- a/src/x64/codegen-x64.cc
 | 
| +++ b/src/x64/codegen-x64.cc
 | 
| @@ -3129,14 +3129,16 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -// The value in dst was optimistically incremented or decremented.  The
 | 
| -// result overflowed or was not smi tagged.  Undo the operation, call
 | 
| -// into the runtime to convert the argument to a number, and call the
 | 
| -// specialized add or subtract stub.  The result is left in dst.
 | 
| +// The value in dst was optimistically incremented or decremented.
 | 
| +// The result overflowed or was not smi tagged.  Call into the runtime
 | 
| +// to convert the argument to a number, and call the specialized add
 | 
| +// or subtract stub.  The result is left in dst.
 | 
|  class DeferredPrefixCountOperation: public DeferredCode {
 | 
|   public:
 | 
| -  DeferredPrefixCountOperation(Register dst, bool is_increment)
 | 
| -      : dst_(dst), is_increment_(is_increment) {
 | 
| +  DeferredPrefixCountOperation(Register dst,
 | 
| +                               bool is_increment,
 | 
| +                               TypeInfo input_type)
 | 
| +      : dst_(dst), is_increment_(is_increment), input_type_(input_type) {
 | 
|      set_comment("[ DeferredCountOperation");
 | 
|    }
 | 
|  
 | 
| @@ -3145,13 +3147,16 @@ class DeferredPrefixCountOperation: public DeferredCode {
 | 
|   private:
 | 
|    Register dst_;
 | 
|    bool is_increment_;
 | 
| +  TypeInfo input_type_;
 | 
|  };
 | 
|  
 | 
|  
 | 
|  void DeferredPrefixCountOperation::Generate() {
 | 
|    __ push(dst_);
 | 
| -  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
 | 
| -  __ push(rax);
 | 
| +  if (!input_type_.IsNumber()) {
 | 
| +    __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
 | 
| +    __ push(rax);
 | 
| +  }
 | 
|    __ Push(Smi::FromInt(1));
 | 
|    if (is_increment_) {
 | 
|      __ CallRuntime(Runtime::kNumberAdd, 2);
 | 
| @@ -3162,15 +3167,21 @@ void DeferredPrefixCountOperation::Generate() {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -// The value in dst was optimistically incremented or decremented.  The
 | 
| -// result overflowed or was not smi tagged.  Undo the operation and call
 | 
| -// into the runtime to convert the argument to a number.  Update the
 | 
| -// original value in old.  Call the specialized add or subtract stub.
 | 
| -// The result is left in dst.
 | 
| +// The value in dst was optimistically incremented or decremented.
 | 
| +// The result overflowed or was not smi tagged.  Call into the runtime
 | 
| +// to convert the argument to a number.  Update the original value in
 | 
| +// old.  Call the specialized add or subtract stub.  The result is
 | 
| +// left in dst.
 | 
|  class DeferredPostfixCountOperation: public DeferredCode {
 | 
|   public:
 | 
| -  DeferredPostfixCountOperation(Register dst, Register old, bool is_increment)
 | 
| -      : dst_(dst), old_(old), is_increment_(is_increment) {
 | 
| +  DeferredPostfixCountOperation(Register dst,
 | 
| +                                Register old,
 | 
| +                                bool is_increment,
 | 
| +                                TypeInfo input_type)
 | 
| +      : dst_(dst),
 | 
| +        old_(old),
 | 
| +        is_increment_(is_increment),
 | 
| +        input_type_(input_type) {
 | 
|      set_comment("[ DeferredCountOperation");
 | 
|    }
 | 
|  
 | 
| @@ -3180,18 +3191,22 @@ class DeferredPostfixCountOperation: public DeferredCode {
 | 
|    Register dst_;
 | 
|    Register old_;
 | 
|    bool is_increment_;
 | 
| +  TypeInfo input_type_;
 | 
|  };
 | 
|  
 | 
|  
 | 
|  void DeferredPostfixCountOperation::Generate() {
 | 
| -  __ push(dst_);
 | 
| -  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
 | 
| -
 | 
| -  // Save the result of ToNumber to use as the old value.
 | 
| -  __ push(rax);
 | 
| +  if (input_type_.IsNumber()) {
 | 
| +    __ push(dst_);  // Save the input to use as the old value.
 | 
| +    __ push(dst_);
 | 
| +  } else {
 | 
| +    __ push(dst_);
 | 
| +    __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
 | 
| +    __ push(rax);  // Save the result of ToNumber to use as the old value.
 | 
| +    __ push(rax);
 | 
| +  }
 | 
|  
 | 
|    // Call the runtime for the addition or subtraction.
 | 
| -  __ push(rax);
 | 
|    __ Push(Smi::FromInt(1));
 | 
|    if (is_increment_) {
 | 
|      __ CallRuntime(Runtime::kNumberAdd, 2);
 | 
| @@ -3238,6 +3253,14 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
 | 
|        old_value = allocator_->Allocate();
 | 
|        ASSERT(old_value.is_valid());
 | 
|        __ movq(old_value.reg(), new_value.reg());
 | 
| +
 | 
| +      // The return value for postfix operations is ToNumber(input).
 | 
| +      // Keep more precise type info if the input is some kind of
 | 
| +      // number already. If the input is not a number we have to wait
 | 
| +      // for the deferred code to convert it.
 | 
| +      if (new_value.type_info().IsNumber()) {
 | 
| +        old_value.set_type_info(new_value.type_info());
 | 
| +      }
 | 
|      }
 | 
|      // Ensure the new value is writable.
 | 
|      frame_->Spill(new_value.reg());
 | 
| @@ -3246,10 +3269,12 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
 | 
|      if (is_postfix) {
 | 
|        deferred = new DeferredPostfixCountOperation(new_value.reg(),
 | 
|                                                     old_value.reg(),
 | 
| -                                                   is_increment);
 | 
| +                                                   is_increment,
 | 
| +                                                   new_value.type_info());
 | 
|      } else {
 | 
|        deferred = new DeferredPrefixCountOperation(new_value.reg(),
 | 
| -                                                  is_increment);
 | 
| +                                                  is_increment,
 | 
| +                                                  new_value.type_info());
 | 
|      }
 | 
|  
 | 
|      __ JumpIfNotSmi(new_value.reg(), deferred->entry_label());
 | 
| @@ -3267,6 +3292,15 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
 | 
|      __ movq(new_value.reg(), kScratchRegister);
 | 
|      deferred->BindExit();
 | 
|  
 | 
| +    // Postfix count operations return their input converted to
 | 
| +    // number. The case when the input is already a number is covered
 | 
| +    // above in the allocation code for old_value.
 | 
| +    if (is_postfix && !new_value.type_info().IsNumber()) {
 | 
| +      old_value.set_type_info(TypeInfo::Number());
 | 
| +    }
 | 
| +
 | 
| +    new_value.set_type_info(TypeInfo::Number());
 | 
| +
 | 
|      // Postfix: store the old value in the allocated slot under the
 | 
|      // reference.
 | 
|      if (is_postfix) frame_->SetElementAt(target.size(), &old_value);
 | 
| @@ -5254,8 +5288,13 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
 | 
|    Result left = frame_->Pop();
 | 
|  
 | 
|    if (op == Token::ADD) {
 | 
| -    bool left_is_string = left.is_constant() && left.handle()->IsString();
 | 
| -    bool right_is_string = right.is_constant() && right.handle()->IsString();
 | 
| +    const bool left_is_string = left.type_info().IsString();
 | 
| +    const bool right_is_string = right.type_info().IsString();
 | 
| +    // Make sure constant strings have string type info.
 | 
| +    ASSERT(!(left.is_constant() && left.handle()->IsString()) ||
 | 
| +           left_is_string);
 | 
| +    ASSERT(!(right.is_constant() && right.handle()->IsString()) ||
 | 
| +           right_is_string);
 | 
|      if (left_is_string || right_is_string) {
 | 
|        frame_->Push(&left);
 | 
|        frame_->Push(&right);
 | 
| @@ -5264,7 +5303,8 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
 | 
|          if (right_is_string) {
 | 
|            // TODO(lrn): if both are constant strings
 | 
|            // -- do a compile time cons, if allocation during codegen is allowed.
 | 
| -          answer = frame_->CallRuntime(Runtime::kStringAdd, 2);
 | 
| +          StringAddStub stub(NO_STRING_CHECK_IN_STUB);
 | 
| +          answer = frame_->CallStub(&stub, 2);
 | 
|          } else {
 | 
|            answer =
 | 
|              frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2);
 | 
| @@ -5273,6 +5313,7 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
 | 
|          answer =
 | 
|            frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
 | 
|        }
 | 
| +      answer.set_type_info(TypeInfo::String());
 | 
|        frame_->Push(&answer);
 | 
|        return;
 | 
|      }
 | 
| @@ -5358,10 +5399,13 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op,
 | 
|            : TypeInfo::Number();
 | 
|        break;
 | 
|      case Token::ADD:
 | 
| -      // Result could be a string or a number. Check types of inputs.
 | 
| -      result_type = operands_type.IsNumber()
 | 
| -          ? TypeInfo::Number()
 | 
| -          : TypeInfo::Unknown();
 | 
| +      if (operands_type.IsNumber()) {
 | 
| +        result_type = TypeInfo::Number();
 | 
| +      } else if (operands_type.IsString()) {
 | 
| +        result_type = TypeInfo::String();
 | 
| +      } else {
 | 
| +        result_type = TypeInfo::Unknown();
 | 
| +      }
 | 
|        break;
 | 
|      case Token::SUB:
 | 
|      case Token::MUL:
 | 
| 
 |