| 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:
|
|
|