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