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 4706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4717 } | 4717 } |
4718 } | 4718 } |
4719 } | 4719 } |
4720 | 4720 |
4721 | 4721 |
4722 class DeferredCountOperation: public DeferredCode { | 4722 class DeferredCountOperation: public DeferredCode { |
4723 public: | 4723 public: |
4724 DeferredCountOperation(CodeGenerator* generator, | 4724 DeferredCountOperation(CodeGenerator* generator, |
4725 bool is_postfix, | 4725 bool is_postfix, |
4726 bool is_increment, | 4726 bool is_increment, |
4727 int result_offset) | 4727 int target_size) |
4728 : DeferredCode(generator), | 4728 : DeferredCode(generator), |
4729 is_postfix_(is_postfix), | 4729 is_postfix_(is_postfix), |
4730 is_increment_(is_increment), | 4730 is_increment_(is_increment), |
4731 result_offset_(result_offset) { | 4731 target_size_(target_size) { |
4732 set_comment("[ DeferredCountOperation"); | 4732 set_comment("[ DeferredCountOperation"); |
4733 } | 4733 } |
4734 | 4734 |
4735 virtual void Generate(); | 4735 virtual void Generate(); |
4736 | 4736 |
4737 private: | 4737 private: |
4738 bool is_postfix_; | 4738 bool is_postfix_; |
4739 bool is_increment_; | 4739 bool is_increment_; |
4740 int result_offset_; | 4740 int target_size_; |
4741 }; | |
4742 | |
4743 | |
4744 class RevertToNumberStub: public CodeStub { | |
4745 public: | |
4746 explicit RevertToNumberStub(bool is_increment) | |
4747 : is_increment_(is_increment) { } | |
4748 | |
4749 private: | |
4750 bool is_increment_; | |
4751 | |
4752 Major MajorKey() { return RevertToNumber; } | |
4753 int MinorKey() { return is_increment_ ? 1 : 0; } | |
4754 void Generate(MacroAssembler* masm); | |
4755 | |
4756 #ifdef DEBUG | |
4757 void Print() { | |
4758 PrintF("RevertToNumberStub (is_increment %s)\n", | |
4759 is_increment_ ? "true" : "false"); | |
4760 } | |
4761 #endif | |
4762 }; | |
4763 | |
4764 | |
4765 class CounterOpStub: public CodeStub { | |
4766 public: | |
4767 CounterOpStub(int result_offset, bool is_postfix, bool is_increment) | |
4768 : result_offset_(result_offset), | |
4769 is_postfix_(is_postfix), | |
4770 is_increment_(is_increment) { } | |
4771 | |
4772 private: | |
4773 int result_offset_; | |
4774 bool is_postfix_; | |
4775 bool is_increment_; | |
4776 | |
4777 Major MajorKey() { return CounterOp; } | |
4778 int MinorKey() { | |
4779 return ((result_offset_ << 2) | | |
4780 (is_postfix_ ? 2 : 0) | | |
4781 (is_increment_ ? 1 : 0)); | |
4782 } | |
4783 void Generate(MacroAssembler* masm); | |
4784 | |
4785 #ifdef DEBUG | |
4786 void Print() { | |
4787 PrintF("CounterOpStub (result_offset %d), (is_postfix %s)," | |
4788 " (is_increment %s)\n", | |
4789 result_offset_, | |
4790 is_postfix_ ? "true" : "false", | |
4791 is_increment_ ? "true" : "false"); | |
4792 } | |
4793 #endif | |
4794 }; | 4741 }; |
4795 | 4742 |
4796 | 4743 |
4797 void DeferredCountOperation::Generate() { | 4744 void DeferredCountOperation::Generate() { |
4798 CodeGenerator* cgen = generator(); | 4745 CodeGenerator* cgen = generator(); |
4799 | |
4800 Result value(cgen); | 4746 Result value(cgen); |
4801 enter()->Bind(&value); | 4747 enter()->Bind(&value); |
4802 if (is_postfix_) { | 4748 VirtualFrame* frame = cgen->frame(); |
4803 RevertToNumberStub to_number_stub(is_increment_); | 4749 // Undo the optimistic smi operation. |
4804 value = generator()->frame()->CallStub(&to_number_stub, &value); | 4750 value.ToRegister(); |
| 4751 frame->Spill(value.reg()); |
| 4752 if (is_increment_) { |
| 4753 __ sub(Operand(value.reg()), Immediate(Smi::FromInt(1))); |
| 4754 } else { |
| 4755 __ add(Operand(value.reg()), Immediate(Smi::FromInt(1))); |
4805 } | 4756 } |
4806 | 4757 frame->Push(&value); |
4807 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); | 4758 value = frame->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1); |
4808 value = generator()->frame()->CallStub(&stub, &value); | 4759 frame->Push(&value); |
| 4760 if (is_postfix_) { // Fix up copy of old value with ToNumber(value). |
| 4761 // This is only safe because VisitCountOperation makes this frame slot |
| 4762 // beneath the reference a register, which is spilled at the above call. |
| 4763 // We cannot safely write to constants or copies below the water line. |
| 4764 frame->StoreToElementAt(target_size_ + 1); |
| 4765 } |
| 4766 frame->Push(Smi::FromInt(1)); |
| 4767 if (is_increment_) { |
| 4768 value = frame->CallRuntime(Runtime::kNumberAdd, 2); |
| 4769 } else { |
| 4770 value = frame->CallRuntime(Runtime::kNumberSub, 2); |
| 4771 } |
4809 exit_.Jump(&value); | 4772 exit_.Jump(&value); |
4810 } | 4773 } |
4811 | 4774 |
4812 | 4775 |
4813 void CodeGenerator::VisitCountOperation(CountOperation* node) { | 4776 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
4814 Comment cmnt(masm_, "[ CountOperation"); | 4777 Comment cmnt(masm_, "[ CountOperation"); |
4815 | 4778 |
4816 bool is_postfix = node->is_postfix(); | 4779 bool is_postfix = node->is_postfix(); |
4817 bool is_increment = node->op() == Token::INC; | 4780 bool is_increment = node->op() == Token::INC; |
4818 | 4781 |
4819 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 4782 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
4820 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 4783 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
4821 | 4784 |
4822 // Postfix: Make room for the result. | 4785 // Postfix operators need a stack slot under the reference to hold |
| 4786 // the old value while the new one is being stored. |
4823 if (is_postfix) { | 4787 if (is_postfix) { |
4824 frame_->Push(Smi::FromInt(0)); | 4788 frame_->Push(Smi::FromInt(0)); |
4825 } | 4789 } |
4826 | 4790 |
4827 { Reference target(this, node->expression()); | 4791 { Reference target(this, node->expression()); |
4828 if (target.is_illegal()) { | 4792 if (target.is_illegal()) { |
4829 // Spoof the virtual frame to have the expected height (one higher | 4793 // Spoof the virtual frame to have the expected height (one higher |
4830 // than on entry). | 4794 // than on entry). |
4831 if (!is_postfix) { | 4795 if (!is_postfix) { |
4832 frame_->Push(Smi::FromInt(0)); | 4796 frame_->Push(Smi::FromInt(0)); |
4833 } | 4797 } |
4834 return; | 4798 return; |
4835 } | 4799 } |
4836 target.TakeValue(NOT_INSIDE_TYPEOF); | 4800 target.TakeValue(NOT_INSIDE_TYPEOF); |
4837 | 4801 |
4838 DeferredCountOperation* deferred = | 4802 DeferredCountOperation* deferred = |
4839 new DeferredCountOperation(this, is_postfix, is_increment, | 4803 new DeferredCountOperation(this, is_postfix, |
4840 target.size() * kPointerSize); | 4804 is_increment, target.size()); |
4841 | 4805 |
4842 Result value = frame_->Pop(); | 4806 Result value = frame_->Pop(); |
4843 value.ToRegister(); | 4807 value.ToRegister(); |
4844 ASSERT(value.is_valid()); | |
4845 | 4808 |
4846 // Postfix: Store the old value as the result. | 4809 // Postfix: Store the old value as the result. |
4847 if (is_postfix) { | 4810 if (is_postfix) { |
4848 Result old_value = value; | 4811 // Explicitly back the slot for the old value with a new register. |
| 4812 // This improves performance in some cases. |
| 4813 Result old_value = allocator_->Allocate(); |
| 4814 ASSERT(old_value.is_valid()); |
| 4815 __ mov(old_value.reg(), value.reg()); |
| 4816 // SetElement must not create a constant element or a copy in this slot, |
| 4817 // since we will write to it, below the waterline, in deferred code. |
4849 frame_->SetElementAt(target.size(), &old_value); | 4818 frame_->SetElementAt(target.size(), &old_value); |
4850 } | 4819 } |
4851 | 4820 |
4852 // Perform optimistic increment/decrement. Ensure the value is | 4821 // Perform optimistic increment/decrement. Ensure the value is |
4853 // writable. | 4822 // writable. |
4854 frame_->Spill(value.reg()); | 4823 frame_->Spill(value.reg()); |
4855 ASSERT(allocator_->count(value.reg()) == 1); | 4824 ASSERT(allocator_->count(value.reg()) == 1); |
4856 | 4825 |
4857 // In order to combine the overflow and the smi check, we need to | 4826 // In order to combine the overflow and the smi check, we need to |
4858 // be able to allocate a byte register. We attempt to do so | 4827 // be able to allocate a byte register. We attempt to do so |
(...skipping 19 matching lines...) Expand all Loading... |
4878 // slow-case code. | 4847 // slow-case code. |
4879 // | 4848 // |
4880 // We combine the overflow and the smi check if we could | 4849 // We combine the overflow and the smi check if we could |
4881 // successfully allocate a temporary byte register. | 4850 // successfully allocate a temporary byte register. |
4882 if (tmp.is_valid()) { | 4851 if (tmp.is_valid()) { |
4883 __ setcc(overflow, tmp.reg()); | 4852 __ setcc(overflow, tmp.reg()); |
4884 __ or_(Operand(value.reg()), tmp.reg()); | 4853 __ or_(Operand(value.reg()), tmp.reg()); |
4885 tmp.Unuse(); | 4854 tmp.Unuse(); |
4886 __ test(value.reg(), Immediate(kSmiTagMask)); | 4855 __ test(value.reg(), Immediate(kSmiTagMask)); |
4887 deferred->enter()->Branch(not_zero, &value, not_taken); | 4856 deferred->enter()->Branch(not_zero, &value, not_taken); |
4888 } else { | 4857 } else { // Otherwise we test separately for overflow and smi check. |
4889 deferred->enter()->Branch(overflow, &value, not_taken); | 4858 deferred->enter()->Branch(overflow, &value, not_taken); |
4890 __ test(value.reg(), Immediate(kSmiTagMask)); | 4859 __ test(value.reg(), Immediate(kSmiTagMask)); |
4891 deferred->enter()->Branch(not_zero, &value, not_taken); | 4860 deferred->enter()->Branch(not_zero, &value, not_taken); |
4892 } | 4861 } |
4893 | 4862 |
4894 // Store the new value in the target if not const. | 4863 // Store the new value in the target if not const. |
4895 deferred->BindExit(&value); | 4864 deferred->BindExit(&value); |
4896 frame_->Push(&value); | 4865 frame_->Push(&value); |
4897 if (!is_const) { | 4866 if (!is_const) { |
4898 target.SetValue(NOT_CONST_INIT); | 4867 target.SetValue(NOT_CONST_INIT); |
(...skipping 1871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6770 // Slow-case: Non-function called. | 6739 // Slow-case: Non-function called. |
6771 __ bind(&slow); | 6740 __ bind(&slow); |
6772 __ Set(eax, Immediate(argc_)); | 6741 __ Set(eax, Immediate(argc_)); |
6773 __ Set(ebx, Immediate(0)); | 6742 __ Set(ebx, Immediate(0)); |
6774 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | 6743 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
6775 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); | 6744 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
6776 __ jmp(adaptor, RelocInfo::CODE_TARGET); | 6745 __ jmp(adaptor, RelocInfo::CODE_TARGET); |
6777 } | 6746 } |
6778 | 6747 |
6779 | 6748 |
6780 void RevertToNumberStub::Generate(MacroAssembler* masm) { | |
6781 // Revert optimistic increment/decrement. | |
6782 if (is_increment_) { | |
6783 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | |
6784 } else { | |
6785 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | |
6786 } | |
6787 | |
6788 __ pop(ecx); | |
6789 __ push(eax); | |
6790 __ push(ecx); | |
6791 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); | |
6792 // Code never returns due to JUMP_FUNCTION. | |
6793 } | |
6794 | |
6795 | |
6796 void CounterOpStub::Generate(MacroAssembler* masm) { | |
6797 // Store to the result on the stack (skip return address) before | |
6798 // performing the count operation. | |
6799 if (is_postfix_) { | |
6800 __ mov(Operand(esp, result_offset_ + kPointerSize), eax); | |
6801 } | |
6802 | |
6803 // Revert optimistic increment/decrement but only for prefix | |
6804 // counts. For postfix counts it has already been reverted before | |
6805 // the conversion to numbers. | |
6806 if (!is_postfix_) { | |
6807 if (is_increment_) { | |
6808 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | |
6809 } else { | |
6810 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | |
6811 } | |
6812 } | |
6813 | |
6814 // Compute the new value by calling the right JavaScript native. | |
6815 __ pop(ecx); | |
6816 __ push(eax); | |
6817 __ push(ecx); | |
6818 Builtins::JavaScript builtin = is_increment_ ? Builtins::INC : Builtins::DEC; | |
6819 __ InvokeBuiltin(builtin, JUMP_FUNCTION); | |
6820 // Code never returns due to JUMP_FUNCTION. | |
6821 } | |
6822 | |
6823 | 6749 |
6824 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { | 6750 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
6825 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code | 6751 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code |
6826 ExternalReference handler_address(Top::k_handler_address); | 6752 ExternalReference handler_address(Top::k_handler_address); |
6827 __ mov(edx, Operand::StaticVariable(handler_address)); | 6753 __ mov(edx, Operand::StaticVariable(handler_address)); |
6828 __ mov(ecx, Operand(edx, -1 * kPointerSize)); // get next in chain | 6754 __ mov(ecx, Operand(edx, -1 * kPointerSize)); // get next in chain |
6829 __ mov(Operand::StaticVariable(handler_address), ecx); | 6755 __ mov(Operand::StaticVariable(handler_address), ecx); |
6830 __ mov(esp, Operand(edx)); | 6756 __ mov(esp, Operand(edx)); |
6831 __ pop(edi); | 6757 __ pop(edi); |
6832 __ pop(ebp); | 6758 __ pop(ebp); |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7175 | 7101 |
7176 // Slow-case: Go through the JavaScript implementation. | 7102 // Slow-case: Go through the JavaScript implementation. |
7177 __ bind(&slow); | 7103 __ bind(&slow); |
7178 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7104 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
7179 } | 7105 } |
7180 | 7106 |
7181 | 7107 |
7182 #undef __ | 7108 #undef __ |
7183 | 7109 |
7184 } } // namespace v8::internal | 7110 } } // namespace v8::internal |
OLD | NEW |