| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 3793 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3804 // Registers: | 3804 // Registers: |
| 3805 // dictionary_: NameDictionary to probe. | 3805 // dictionary_: NameDictionary to probe. |
| 3806 // result_: used as scratch. | 3806 // result_: used as scratch. |
| 3807 // index_: will hold an index of entry if lookup is successful. | 3807 // index_: will hold an index of entry if lookup is successful. |
| 3808 // might alias with result_. | 3808 // might alias with result_. |
| 3809 // Returns: | 3809 // Returns: |
| 3810 // result_ is zero if lookup failed, non zero otherwise. | 3810 // result_ is zero if lookup failed, non zero otherwise. |
| 3811 | 3811 |
| 3812 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; | 3812 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; |
| 3813 | 3813 |
| 3814 Register scratch = result_; | 3814 Register scratch = result(); |
| 3815 | 3815 |
| 3816 __ SmiToInteger32(scratch, FieldOperand(dictionary_, kCapacityOffset)); | 3816 __ SmiToInteger32(scratch, FieldOperand(dictionary(), kCapacityOffset)); |
| 3817 __ decl(scratch); | 3817 __ decl(scratch); |
| 3818 __ Push(scratch); | 3818 __ Push(scratch); |
| 3819 | 3819 |
| 3820 // If names of slots in range from 1 to kProbes - 1 for the hash value are | 3820 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 3821 // not equal to the name and kProbes-th slot is not used (its name is the | 3821 // not equal to the name and kProbes-th slot is not used (its name is the |
| 3822 // undefined value), it guarantees the hash table doesn't contain the | 3822 // undefined value), it guarantees the hash table doesn't contain the |
| 3823 // property. It's true even if some slots represent deleted properties | 3823 // property. It's true even if some slots represent deleted properties |
| 3824 // (their names are the null value). | 3824 // (their names are the null value). |
| 3825 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER, | 3825 StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER, |
| 3826 kPointerSize); | 3826 kPointerSize); |
| 3827 for (int i = kInlinedProbes; i < kTotalProbes; i++) { | 3827 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
| 3828 // Compute the masked index: (hash + i + i * i) & mask. | 3828 // Compute the masked index: (hash + i + i * i) & mask. |
| 3829 __ movp(scratch, args.GetArgumentOperand(1)); | 3829 __ movp(scratch, args.GetArgumentOperand(1)); |
| 3830 if (i > 0) { | 3830 if (i > 0) { |
| 3831 __ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i))); | 3831 __ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i))); |
| 3832 } | 3832 } |
| 3833 __ andp(scratch, Operand(rsp, 0)); | 3833 __ andp(scratch, Operand(rsp, 0)); |
| 3834 | 3834 |
| 3835 // Scale the index by multiplying by the entry size. | 3835 // Scale the index by multiplying by the entry size. |
| 3836 DCHECK(NameDictionary::kEntrySize == 3); | 3836 DCHECK(NameDictionary::kEntrySize == 3); |
| 3837 __ leap(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. | 3837 __ leap(index(), Operand(scratch, scratch, times_2, 0)); // index *= 3. |
| 3838 | 3838 |
| 3839 // Having undefined at this place means the name is not contained. | 3839 // Having undefined at this place means the name is not contained. |
| 3840 __ movp(scratch, Operand(dictionary_, | 3840 __ movp(scratch, Operand(dictionary(), index(), times_pointer_size, |
| 3841 index_, | |
| 3842 times_pointer_size, | |
| 3843 kElementsStartOffset - kHeapObjectTag)); | 3841 kElementsStartOffset - kHeapObjectTag)); |
| 3844 | 3842 |
| 3845 __ Cmp(scratch, isolate()->factory()->undefined_value()); | 3843 __ Cmp(scratch, isolate()->factory()->undefined_value()); |
| 3846 __ j(equal, ¬_in_dictionary); | 3844 __ j(equal, ¬_in_dictionary); |
| 3847 | 3845 |
| 3848 // Stop if found the property. | 3846 // Stop if found the property. |
| 3849 __ cmpp(scratch, args.GetArgumentOperand(0)); | 3847 __ cmpp(scratch, args.GetArgumentOperand(0)); |
| 3850 __ j(equal, &in_dictionary); | 3848 __ j(equal, &in_dictionary); |
| 3851 | 3849 |
| 3852 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { | 3850 if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) { |
| 3853 // If we hit a key that is not a unique name during negative | 3851 // If we hit a key that is not a unique name during negative |
| 3854 // lookup we have to bailout as this key might be equal to the | 3852 // lookup we have to bailout as this key might be equal to the |
| 3855 // key we are looking for. | 3853 // key we are looking for. |
| 3856 | 3854 |
| 3857 // Check if the entry name is not a unique name. | 3855 // Check if the entry name is not a unique name. |
| 3858 __ movp(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 3856 __ movp(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 3859 __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset), | 3857 __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 3860 &maybe_in_dictionary); | 3858 &maybe_in_dictionary); |
| 3861 } | 3859 } |
| 3862 } | 3860 } |
| 3863 | 3861 |
| 3864 __ bind(&maybe_in_dictionary); | 3862 __ bind(&maybe_in_dictionary); |
| 3865 // If we are doing negative lookup then probing failure should be | 3863 // If we are doing negative lookup then probing failure should be |
| 3866 // treated as a lookup success. For positive lookup probing failure | 3864 // treated as a lookup success. For positive lookup probing failure |
| 3867 // should be treated as lookup failure. | 3865 // should be treated as lookup failure. |
| 3868 if (mode_ == POSITIVE_LOOKUP) { | 3866 if (mode() == POSITIVE_LOOKUP) { |
| 3869 __ movp(scratch, Immediate(0)); | 3867 __ movp(scratch, Immediate(0)); |
| 3870 __ Drop(1); | 3868 __ Drop(1); |
| 3871 __ ret(2 * kPointerSize); | 3869 __ ret(2 * kPointerSize); |
| 3872 } | 3870 } |
| 3873 | 3871 |
| 3874 __ bind(&in_dictionary); | 3872 __ bind(&in_dictionary); |
| 3875 __ movp(scratch, Immediate(1)); | 3873 __ movp(scratch, Immediate(1)); |
| 3876 __ Drop(1); | 3874 __ Drop(1); |
| 3877 __ ret(2 * kPointerSize); | 3875 __ ret(2 * kPointerSize); |
| 3878 | 3876 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3901 Label skip_to_incremental_compacting; | 3899 Label skip_to_incremental_compacting; |
| 3902 | 3900 |
| 3903 // The first two instructions are generated with labels so as to get the | 3901 // The first two instructions are generated with labels so as to get the |
| 3904 // offset fixed up correctly by the bind(Label*) call. We patch it back and | 3902 // offset fixed up correctly by the bind(Label*) call. We patch it back and |
| 3905 // forth between a compare instructions (a nop in this position) and the | 3903 // forth between a compare instructions (a nop in this position) and the |
| 3906 // real branch when we start and stop incremental heap marking. | 3904 // real branch when we start and stop incremental heap marking. |
| 3907 // See RecordWriteStub::Patch for details. | 3905 // See RecordWriteStub::Patch for details. |
| 3908 __ jmp(&skip_to_incremental_noncompacting, Label::kNear); | 3906 __ jmp(&skip_to_incremental_noncompacting, Label::kNear); |
| 3909 __ jmp(&skip_to_incremental_compacting, Label::kFar); | 3907 __ jmp(&skip_to_incremental_compacting, Label::kFar); |
| 3910 | 3908 |
| 3911 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { | 3909 if (remembered_set_action() == EMIT_REMEMBERED_SET) { |
| 3912 __ RememberedSetHelper(object_, | 3910 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), |
| 3913 address_, | |
| 3914 value_, | |
| 3915 save_fp_regs_mode_, | |
| 3916 MacroAssembler::kReturnAtEnd); | 3911 MacroAssembler::kReturnAtEnd); |
| 3917 } else { | 3912 } else { |
| 3918 __ ret(0); | 3913 __ ret(0); |
| 3919 } | 3914 } |
| 3920 | 3915 |
| 3921 __ bind(&skip_to_incremental_noncompacting); | 3916 __ bind(&skip_to_incremental_noncompacting); |
| 3922 GenerateIncremental(masm, INCREMENTAL); | 3917 GenerateIncremental(masm, INCREMENTAL); |
| 3923 | 3918 |
| 3924 __ bind(&skip_to_incremental_compacting); | 3919 __ bind(&skip_to_incremental_compacting); |
| 3925 GenerateIncremental(masm, INCREMENTAL_COMPACTION); | 3920 GenerateIncremental(masm, INCREMENTAL_COMPACTION); |
| 3926 | 3921 |
| 3927 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. | 3922 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. |
| 3928 // Will be checked in IncrementalMarking::ActivateGeneratedStub. | 3923 // Will be checked in IncrementalMarking::ActivateGeneratedStub. |
| 3929 masm->set_byte_at(0, kTwoByteNopInstruction); | 3924 masm->set_byte_at(0, kTwoByteNopInstruction); |
| 3930 masm->set_byte_at(2, kFiveByteNopInstruction); | 3925 masm->set_byte_at(2, kFiveByteNopInstruction); |
| 3931 } | 3926 } |
| 3932 | 3927 |
| 3933 | 3928 |
| 3934 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { | 3929 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { |
| 3935 regs_.Save(masm); | 3930 regs_.Save(masm); |
| 3936 | 3931 |
| 3937 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { | 3932 if (remembered_set_action() == EMIT_REMEMBERED_SET) { |
| 3938 Label dont_need_remembered_set; | 3933 Label dont_need_remembered_set; |
| 3939 | 3934 |
| 3940 __ movp(regs_.scratch0(), Operand(regs_.address(), 0)); | 3935 __ movp(regs_.scratch0(), Operand(regs_.address(), 0)); |
| 3941 __ JumpIfNotInNewSpace(regs_.scratch0(), | 3936 __ JumpIfNotInNewSpace(regs_.scratch0(), |
| 3942 regs_.scratch0(), | 3937 regs_.scratch0(), |
| 3943 &dont_need_remembered_set); | 3938 &dont_need_remembered_set); |
| 3944 | 3939 |
| 3945 __ CheckPageFlag(regs_.object(), | 3940 __ CheckPageFlag(regs_.object(), |
| 3946 regs_.scratch0(), | 3941 regs_.scratch0(), |
| 3947 1 << MemoryChunk::SCAN_ON_SCAVENGE, | 3942 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 3948 not_zero, | 3943 not_zero, |
| 3949 &dont_need_remembered_set); | 3944 &dont_need_remembered_set); |
| 3950 | 3945 |
| 3951 // First notify the incremental marker if necessary, then update the | 3946 // First notify the incremental marker if necessary, then update the |
| 3952 // remembered set. | 3947 // remembered set. |
| 3953 CheckNeedsToInformIncrementalMarker( | 3948 CheckNeedsToInformIncrementalMarker( |
| 3954 masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode); | 3949 masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode); |
| 3955 InformIncrementalMarker(masm); | 3950 InformIncrementalMarker(masm); |
| 3956 regs_.Restore(masm); | 3951 regs_.Restore(masm); |
| 3957 __ RememberedSetHelper(object_, | 3952 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), |
| 3958 address_, | |
| 3959 value_, | |
| 3960 save_fp_regs_mode_, | |
| 3961 MacroAssembler::kReturnAtEnd); | 3953 MacroAssembler::kReturnAtEnd); |
| 3962 | 3954 |
| 3963 __ bind(&dont_need_remembered_set); | 3955 __ bind(&dont_need_remembered_set); |
| 3964 } | 3956 } |
| 3965 | 3957 |
| 3966 CheckNeedsToInformIncrementalMarker( | 3958 CheckNeedsToInformIncrementalMarker( |
| 3967 masm, kReturnOnNoNeedToInformIncrementalMarker, mode); | 3959 masm, kReturnOnNoNeedToInformIncrementalMarker, mode); |
| 3968 InformIncrementalMarker(masm); | 3960 InformIncrementalMarker(masm); |
| 3969 regs_.Restore(masm); | 3961 regs_.Restore(masm); |
| 3970 __ ret(0); | 3962 __ ret(0); |
| 3971 } | 3963 } |
| 3972 | 3964 |
| 3973 | 3965 |
| 3974 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { | 3966 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { |
| 3975 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); | 3967 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode()); |
| 3976 Register address = | 3968 Register address = |
| 3977 arg_reg_1.is(regs_.address()) ? kScratchRegister : regs_.address(); | 3969 arg_reg_1.is(regs_.address()) ? kScratchRegister : regs_.address(); |
| 3978 DCHECK(!address.is(regs_.object())); | 3970 DCHECK(!address.is(regs_.object())); |
| 3979 DCHECK(!address.is(arg_reg_1)); | 3971 DCHECK(!address.is(arg_reg_1)); |
| 3980 __ Move(address, regs_.address()); | 3972 __ Move(address, regs_.address()); |
| 3981 __ Move(arg_reg_1, regs_.object()); | 3973 __ Move(arg_reg_1, regs_.object()); |
| 3982 // TODO(gc) Can we just set address arg2 in the beginning? | 3974 // TODO(gc) Can we just set address arg2 in the beginning? |
| 3983 __ Move(arg_reg_2, address); | 3975 __ Move(arg_reg_2, address); |
| 3984 __ LoadAddress(arg_reg_3, | 3976 __ LoadAddress(arg_reg_3, |
| 3985 ExternalReference::isolate_address(isolate())); | 3977 ExternalReference::isolate_address(isolate())); |
| 3986 int argument_count = 3; | 3978 int argument_count = 3; |
| 3987 | 3979 |
| 3988 AllowExternalCallThatCantCauseGC scope(masm); | 3980 AllowExternalCallThatCantCauseGC scope(masm); |
| 3989 __ PrepareCallCFunction(argument_count); | 3981 __ PrepareCallCFunction(argument_count); |
| 3990 __ CallCFunction( | 3982 __ CallCFunction( |
| 3991 ExternalReference::incremental_marking_record_write_function(isolate()), | 3983 ExternalReference::incremental_marking_record_write_function(isolate()), |
| 3992 argument_count); | 3984 argument_count); |
| 3993 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_); | 3985 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode()); |
| 3994 } | 3986 } |
| 3995 | 3987 |
| 3996 | 3988 |
| 3997 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( | 3989 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( |
| 3998 MacroAssembler* masm, | 3990 MacroAssembler* masm, |
| 3999 OnNoNeedToInformIncrementalMarker on_no_need, | 3991 OnNoNeedToInformIncrementalMarker on_no_need, |
| 4000 Mode mode) { | 3992 Mode mode) { |
| 4001 Label on_black; | 3993 Label on_black; |
| 4002 Label need_incremental; | 3994 Label need_incremental; |
| 4003 Label need_incremental_pop_object; | 3995 Label need_incremental_pop_object; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 4016 // Let's look at the color of the object: If it is not black we don't have | 4008 // Let's look at the color of the object: If it is not black we don't have |
| 4017 // to inform the incremental marker. | 4009 // to inform the incremental marker. |
| 4018 __ JumpIfBlack(regs_.object(), | 4010 __ JumpIfBlack(regs_.object(), |
| 4019 regs_.scratch0(), | 4011 regs_.scratch0(), |
| 4020 regs_.scratch1(), | 4012 regs_.scratch1(), |
| 4021 &on_black, | 4013 &on_black, |
| 4022 Label::kNear); | 4014 Label::kNear); |
| 4023 | 4015 |
| 4024 regs_.Restore(masm); | 4016 regs_.Restore(masm); |
| 4025 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { | 4017 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { |
| 4026 __ RememberedSetHelper(object_, | 4018 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), |
| 4027 address_, | |
| 4028 value_, | |
| 4029 save_fp_regs_mode_, | |
| 4030 MacroAssembler::kReturnAtEnd); | 4019 MacroAssembler::kReturnAtEnd); |
| 4031 } else { | 4020 } else { |
| 4032 __ ret(0); | 4021 __ ret(0); |
| 4033 } | 4022 } |
| 4034 | 4023 |
| 4035 __ bind(&on_black); | 4024 __ bind(&on_black); |
| 4036 | 4025 |
| 4037 // Get the value from the slot. | 4026 // Get the value from the slot. |
| 4038 __ movp(regs_.scratch0(), Operand(regs_.address(), 0)); | 4027 __ movp(regs_.scratch0(), Operand(regs_.address(), 0)); |
| 4039 | 4028 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 4061 __ Push(regs_.object()); | 4050 __ Push(regs_.object()); |
| 4062 __ EnsureNotWhite(regs_.scratch0(), // The value. | 4051 __ EnsureNotWhite(regs_.scratch0(), // The value. |
| 4063 regs_.scratch1(), // Scratch. | 4052 regs_.scratch1(), // Scratch. |
| 4064 regs_.object(), // Scratch. | 4053 regs_.object(), // Scratch. |
| 4065 &need_incremental_pop_object, | 4054 &need_incremental_pop_object, |
| 4066 Label::kNear); | 4055 Label::kNear); |
| 4067 __ Pop(regs_.object()); | 4056 __ Pop(regs_.object()); |
| 4068 | 4057 |
| 4069 regs_.Restore(masm); | 4058 regs_.Restore(masm); |
| 4070 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { | 4059 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { |
| 4071 __ RememberedSetHelper(object_, | 4060 __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), |
| 4072 address_, | |
| 4073 value_, | |
| 4074 save_fp_regs_mode_, | |
| 4075 MacroAssembler::kReturnAtEnd); | 4061 MacroAssembler::kReturnAtEnd); |
| 4076 } else { | 4062 } else { |
| 4077 __ ret(0); | 4063 __ ret(0); |
| 4078 } | 4064 } |
| 4079 | 4065 |
| 4080 __ bind(&need_incremental_pop_object); | 4066 __ bind(&need_incremental_pop_object); |
| 4081 __ Pop(regs_.object()); | 4067 __ Pop(regs_.object()); |
| 4082 | 4068 |
| 4083 __ bind(&need_incremental); | 4069 __ bind(&need_incremental); |
| 4084 | 4070 |
| (...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4729 return_value_operand, | 4715 return_value_operand, |
| 4730 NULL); | 4716 NULL); |
| 4731 } | 4717 } |
| 4732 | 4718 |
| 4733 | 4719 |
| 4734 #undef __ | 4720 #undef __ |
| 4735 | 4721 |
| 4736 } } // namespace v8::internal | 4722 } } // namespace v8::internal |
| 4737 | 4723 |
| 4738 #endif // V8_TARGET_ARCH_X64 | 4724 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |