OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 5497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5508 // Omit evaluating the value of the primitive literal. | 5508 // Omit evaluating the value of the primitive literal. |
5509 // It will be discarded anyway, and can have no side effect. | 5509 // It will be discarded anyway, and can have no side effect. |
5510 frame_->Push(Factory::undefined_value()); | 5510 frame_->Push(Factory::undefined_value()); |
5511 } else { | 5511 } else { |
5512 Load(node->expression()); | 5512 Load(node->expression()); |
5513 frame_->SetElementAt(0, Factory::undefined_value()); | 5513 frame_->SetElementAt(0, Factory::undefined_value()); |
5514 } | 5514 } |
5515 | 5515 |
5516 } else { | 5516 } else { |
5517 Load(node->expression()); | 5517 Load(node->expression()); |
| 5518 bool overwrite = |
| 5519 (node->expression()->AsBinaryOperation() != NULL && |
| 5520 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); |
5518 switch (op) { | 5521 switch (op) { |
5519 case Token::SUB: { | 5522 case Token::SUB: { |
5520 bool overwrite = | 5523 GenericUnaryOpStub stub(Token::SUB, overwrite); |
5521 (node->expression()->AsBinaryOperation() != NULL && | |
5522 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); | |
5523 UnarySubStub stub(overwrite); | |
5524 // TODO(1222589): remove dependency of TOS being cached inside stub | 5524 // TODO(1222589): remove dependency of TOS being cached inside stub |
5525 Result operand = frame_->Pop(); | 5525 Result operand = frame_->Pop(); |
5526 Result answer = frame_->CallStub(&stub, &operand); | 5526 Result answer = frame_->CallStub(&stub, &operand); |
5527 frame_->Push(&answer); | 5527 frame_->Push(&answer); |
5528 break; | 5528 break; |
5529 } | 5529 } |
5530 | 5530 |
5531 case Token::BIT_NOT: { | 5531 case Token::BIT_NOT: { |
5532 // Smi check. | 5532 // Smi check. |
5533 JumpTarget smi_label; | 5533 JumpTarget smi_label; |
5534 JumpTarget continue_label; | 5534 JumpTarget continue_label; |
5535 Result operand = frame_->Pop(); | 5535 Result operand = frame_->Pop(); |
5536 operand.ToRegister(); | 5536 operand.ToRegister(); |
5537 __ test(operand.reg(), Immediate(kSmiTagMask)); | 5537 __ test(operand.reg(), Immediate(kSmiTagMask)); |
5538 smi_label.Branch(zero, &operand, taken); | 5538 smi_label.Branch(zero, &operand, taken); |
5539 | 5539 |
5540 frame_->Push(&operand); // undo popping of TOS | 5540 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); |
5541 Result answer = frame_->InvokeBuiltin(Builtins::BIT_NOT, | 5541 Result answer = frame_->CallStub(&stub, &operand); |
5542 CALL_FUNCTION, 1); | 5542 continue_label.Jump(&answer); |
5543 | 5543 |
5544 continue_label.Jump(&answer); | |
5545 smi_label.Bind(&answer); | 5544 smi_label.Bind(&answer); |
5546 answer.ToRegister(); | 5545 answer.ToRegister(); |
5547 frame_->Spill(answer.reg()); | 5546 frame_->Spill(answer.reg()); |
5548 __ not_(answer.reg()); | 5547 __ not_(answer.reg()); |
5549 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag. | 5548 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag. |
| 5549 |
5550 continue_label.Bind(&answer); | 5550 continue_label.Bind(&answer); |
5551 frame_->Push(&answer); | 5551 frame_->Push(&answer); |
5552 break; | 5552 break; |
5553 } | 5553 } |
5554 | 5554 |
5555 case Token::ADD: { | 5555 case Token::ADD: { |
5556 // Smi check. | 5556 // Smi check. |
5557 JumpTarget continue_label; | 5557 JumpTarget continue_label; |
5558 Result operand = frame_->Pop(); | 5558 Result operand = frame_->Pop(); |
5559 operand.ToRegister(); | 5559 operand.ToRegister(); |
(...skipping 1715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7275 __ test(eax, Immediate(kSmiTagMask)); | 7275 __ test(eax, Immediate(kSmiTagMask)); |
7276 __ j(not_zero, &skip_allocation, not_taken); | 7276 __ j(not_zero, &skip_allocation, not_taken); |
7277 // Fall through! | 7277 // Fall through! |
7278 case NO_OVERWRITE: | 7278 case NO_OVERWRITE: |
7279 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 7279 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
7280 __ bind(&skip_allocation); | 7280 __ bind(&skip_allocation); |
7281 break; | 7281 break; |
7282 default: UNREACHABLE(); | 7282 default: UNREACHABLE(); |
7283 } | 7283 } |
7284 // Store the result in the HeapNumber and return. | 7284 // Store the result in the HeapNumber and return. |
7285 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 7285 if (CpuFeatures::IsSupported(SSE2)) { |
7286 __ fild_s(Operand(esp, 1 * kPointerSize)); | 7286 CpuFeatures::Scope use_sse2(SSE2); |
7287 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 7287 __ cvtsi2sd(xmm0, Operand(ebx)); |
| 7288 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 7289 } else { |
| 7290 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 7291 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 7292 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 7293 } |
7288 GenerateReturn(masm); | 7294 GenerateReturn(masm); |
7289 } | 7295 } |
7290 | 7296 |
7291 // Go to runtime for non-number inputs. | 7297 // Go to runtime for non-number inputs. |
7292 __ bind(&operand_conversion_failure); | 7298 __ bind(&operand_conversion_failure); |
7293 // SHR should return uint32 - go to runtime for non-smi/negative result. | 7299 // SHR should return uint32 - go to runtime for non-smi/negative result. |
7294 if (op_ == Token::SHR) { | 7300 if (op_ == Token::SHR) { |
7295 __ bind(&non_smi_result); | 7301 __ bind(&non_smi_result); |
7296 } | 7302 } |
7297 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 7303 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7689 __ j(zero, &done); // argument in eax is OK | 7695 __ j(zero, &done); // argument in eax is OK |
7690 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); | 7696 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); |
7691 __ cmp(scratch, Factory::heap_number_map()); | 7697 __ cmp(scratch, Factory::heap_number_map()); |
7692 __ j(not_equal, non_float); // argument in eax is not a number -> NaN | 7698 __ j(not_equal, non_float); // argument in eax is not a number -> NaN |
7693 | 7699 |
7694 // Fall-through: Both operands are numbers. | 7700 // Fall-through: Both operands are numbers. |
7695 __ bind(&done); | 7701 __ bind(&done); |
7696 } | 7702 } |
7697 | 7703 |
7698 | 7704 |
7699 void UnarySubStub::Generate(MacroAssembler* masm) { | 7705 void GenericUnaryOpStub::Generate(MacroAssembler* masm) { |
7700 Label undo; | 7706 Label slow, done; |
7701 Label slow; | |
7702 Label done; | |
7703 Label try_float; | |
7704 | 7707 |
7705 // Check whether the value is a smi. | 7708 if (op_ == Token::SUB) { |
7706 __ test(eax, Immediate(kSmiTagMask)); | 7709 // Check whether the value is a smi. |
7707 __ j(not_zero, &try_float, not_taken); | 7710 Label try_float; |
| 7711 __ test(eax, Immediate(kSmiTagMask)); |
| 7712 __ j(not_zero, &try_float, not_taken); |
7708 | 7713 |
7709 // Enter runtime system if the value of the expression is zero | 7714 // Go slow case if the value of the expression is zero |
7710 // to make sure that we switch between 0 and -0. | 7715 // to make sure that we switch between 0 and -0. |
7711 __ test(eax, Operand(eax)); | 7716 __ test(eax, Operand(eax)); |
7712 __ j(zero, &slow, not_taken); | 7717 __ j(zero, &slow, not_taken); |
7713 | 7718 |
7714 // The value of the expression is a smi that is not zero. Try | 7719 // The value of the expression is a smi that is not zero. Try |
7715 // optimistic subtraction '0 - value'. | 7720 // optimistic subtraction '0 - value'. |
7716 __ mov(edx, Operand(eax)); | 7721 Label undo; |
7717 __ Set(eax, Immediate(0)); | 7722 __ mov(edx, Operand(eax)); |
7718 __ sub(eax, Operand(edx)); | 7723 __ Set(eax, Immediate(0)); |
7719 __ j(overflow, &undo, not_taken); | 7724 __ sub(eax, Operand(edx)); |
| 7725 __ j(overflow, &undo, not_taken); |
7720 | 7726 |
7721 // If result is a smi we are done. | 7727 // If result is a smi we are done. |
7722 __ test(eax, Immediate(kSmiTagMask)); | 7728 __ test(eax, Immediate(kSmiTagMask)); |
7723 __ j(zero, &done, taken); | 7729 __ j(zero, &done, taken); |
7724 | 7730 |
7725 // Restore eax and enter runtime system. | 7731 // Restore eax and go slow case. |
7726 __ bind(&undo); | 7732 __ bind(&undo); |
7727 __ mov(eax, Operand(edx)); | 7733 __ mov(eax, Operand(edx)); |
| 7734 __ jmp(&slow); |
7728 | 7735 |
7729 // Enter runtime system. | 7736 // Try floating point case. |
| 7737 __ bind(&try_float); |
| 7738 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 7739 __ cmp(edx, Factory::heap_number_map()); |
| 7740 __ j(not_equal, &slow); |
| 7741 if (overwrite_) { |
| 7742 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); |
| 7743 __ xor_(edx, HeapNumber::kSignMask); // Flip sign. |
| 7744 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx); |
| 7745 } else { |
| 7746 __ mov(edx, Operand(eax)); |
| 7747 // edx: operand |
| 7748 __ AllocateHeapNumber(eax, ebx, ecx, &undo); |
| 7749 // eax: allocated 'empty' number |
| 7750 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); |
| 7751 __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. |
| 7752 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); |
| 7753 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); |
| 7754 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); |
| 7755 } |
| 7756 } else if (op_ == Token::BIT_NOT) { |
| 7757 // Check if the operand is a heap number. |
| 7758 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 7759 __ cmp(edx, Factory::heap_number_map()); |
| 7760 __ j(not_equal, &slow, not_taken); |
| 7761 |
| 7762 // Convert the heap number in eax to an untagged integer in ecx. |
| 7763 IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), &slow); |
| 7764 |
| 7765 // Do the bitwise operation and check if the result fits in a smi. |
| 7766 Label try_float; |
| 7767 __ not_(ecx); |
| 7768 __ cmp(ecx, 0xc0000000); |
| 7769 __ j(sign, &try_float, not_taken); |
| 7770 |
| 7771 // Tag the result as a smi and we're done. |
| 7772 ASSERT(kSmiTagSize == 1); |
| 7773 __ lea(eax, Operand(ecx, times_2, kSmiTag)); |
| 7774 __ jmp(&done); |
| 7775 |
| 7776 // Try to store the result in a heap number. |
| 7777 __ bind(&try_float); |
| 7778 if (!overwrite_) { |
| 7779 // Allocate a fresh heap number, but don't overwrite eax until |
| 7780 // we're sure we can do it without going through the slow case |
| 7781 // that needs the value in eax. |
| 7782 __ AllocateHeapNumber(ebx, edx, edi, &slow); |
| 7783 __ mov(eax, Operand(ebx)); |
| 7784 } |
| 7785 if (CpuFeatures::IsSupported(SSE2)) { |
| 7786 CpuFeatures::Scope use_sse2(SSE2); |
| 7787 __ cvtsi2sd(xmm0, Operand(ecx)); |
| 7788 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 7789 } else { |
| 7790 __ push(ecx); |
| 7791 __ fild_s(Operand(esp, 0)); |
| 7792 __ pop(ecx); |
| 7793 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 7794 } |
| 7795 } else { |
| 7796 UNIMPLEMENTED(); |
| 7797 } |
| 7798 |
| 7799 // Return from the stub. |
| 7800 __ bind(&done); |
| 7801 __ StubReturn(1); |
| 7802 |
| 7803 // Handle the slow case by jumping to the JavaScript builtin. |
7730 __ bind(&slow); | 7804 __ bind(&slow); |
7731 __ pop(ecx); // pop return address | 7805 __ pop(ecx); // pop return address. |
7732 __ push(eax); | 7806 __ push(eax); |
7733 __ push(ecx); // push return address | 7807 __ push(ecx); // push return address |
7734 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); | 7808 switch (op_) { |
7735 | 7809 case Token::SUB: |
7736 // Try floating point case. | 7810 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); |
7737 __ bind(&try_float); | 7811 break; |
7738 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 7812 case Token::BIT_NOT: |
7739 __ cmp(edx, Factory::heap_number_map()); | 7813 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); |
7740 __ j(not_equal, &slow); | 7814 break; |
7741 if (overwrite_) { | 7815 default: |
7742 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); | 7816 UNREACHABLE(); |
7743 __ xor_(edx, HeapNumber::kSignMask); // Flip sign. | |
7744 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx); | |
7745 } else { | |
7746 __ mov(edx, Operand(eax)); | |
7747 // edx: operand | |
7748 __ AllocateHeapNumber(eax, ebx, ecx, &undo); | |
7749 // eax: allocated 'empty' number | |
7750 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); | |
7751 __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. | |
7752 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); | |
7753 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); | |
7754 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); | |
7755 } | 7817 } |
7756 | |
7757 __ bind(&done); | |
7758 | |
7759 __ StubReturn(1); | |
7760 } | 7818 } |
7761 | 7819 |
7762 | 7820 |
7763 void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) { | 7821 void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) { |
7764 // Check if the calling frame is an arguments adaptor frame. | 7822 // Check if the calling frame is an arguments adaptor frame. |
7765 Label adaptor; | 7823 Label adaptor; |
7766 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 7824 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
7767 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); | 7825 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); |
7768 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 7826 __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
7769 __ j(equal, &adaptor); | 7827 __ j(equal, &adaptor); |
(...skipping 1156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8926 __ add(Operand(dest), Immediate(2)); | 8984 __ add(Operand(dest), Immediate(2)); |
8927 } | 8985 } |
8928 __ sub(Operand(count), Immediate(1)); | 8986 __ sub(Operand(count), Immediate(1)); |
8929 __ j(not_zero, &loop); | 8987 __ j(not_zero, &loop); |
8930 } | 8988 } |
8931 | 8989 |
8932 | 8990 |
8933 #undef __ | 8991 #undef __ |
8934 | 8992 |
8935 } } // namespace v8::internal | 8993 } } // namespace v8::internal |
OLD | NEW |