| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 1214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1225 __ TailCallStub(&string_add_right_stub); | 1225 __ TailCallStub(&string_add_right_stub); |
| 1226 | 1226 |
| 1227 // Neither argument is a string. | 1227 // Neither argument is a string. |
| 1228 __ bind(&call_runtime); | 1228 __ bind(&call_runtime); |
| 1229 } | 1229 } |
| 1230 | 1230 |
| 1231 | 1231 |
| 1232 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 1232 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 1233 Label right_arg_changed, call_runtime; | 1233 Label right_arg_changed, call_runtime; |
| 1234 | 1234 |
| 1235 if (op_ == Token::MOD && has_fixed_right_arg_) { | 1235 if (op_ == Token::MOD && encoded_right_arg_.has_value) { |
| 1236 // It is guaranteed that the value will fit into a Smi, because if it | 1236 // It is guaranteed that the value will fit into a Smi, because if it |
| 1237 // didn't, we wouldn't be here, see BinaryOp_Patch. | 1237 // didn't, we wouldn't be here, see BinaryOp_Patch. |
| 1238 __ Cmp(rax, Smi::FromInt(fixed_right_arg_value())); | 1238 __ Cmp(rax, Smi::FromInt(fixed_right_arg_value())); |
| 1239 __ j(not_equal, &right_arg_changed); | 1239 __ j(not_equal, &right_arg_changed); |
| 1240 } | 1240 } |
| 1241 | 1241 |
| 1242 if (result_type_ == BinaryOpIC::UNINITIALIZED || | 1242 if (result_type_ == BinaryOpIC::UNINITIALIZED || |
| 1243 result_type_ == BinaryOpIC::SMI) { | 1243 result_type_ == BinaryOpIC::SMI) { |
| 1244 // Only allow smi results. | 1244 // Only allow smi results. |
| 1245 BinaryOpStub_GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS, op_); | 1245 BinaryOpStub_GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS, op_); |
| (...skipping 2183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3429 | 3429 |
| 3430 | 3430 |
| 3431 static void BranchIfNotInternalizedString(MacroAssembler* masm, | 3431 static void BranchIfNotInternalizedString(MacroAssembler* masm, |
| 3432 Label* label, | 3432 Label* label, |
| 3433 Register object, | 3433 Register object, |
| 3434 Register scratch) { | 3434 Register scratch) { |
| 3435 __ JumpIfSmi(object, label); | 3435 __ JumpIfSmi(object, label); |
| 3436 __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset)); | 3436 __ movq(scratch, FieldOperand(object, HeapObject::kMapOffset)); |
| 3437 __ movzxbq(scratch, | 3437 __ movzxbq(scratch, |
| 3438 FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3438 FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3439 // Ensure that no non-strings have the internalized bit set. | |
| 3440 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask); | |
| 3441 STATIC_ASSERT(kInternalizedTag != 0); | 3439 STATIC_ASSERT(kInternalizedTag != 0); |
| 3442 __ testb(scratch, Immediate(kIsInternalizedMask)); | 3440 __ and_(scratch, Immediate(kIsNotStringMask | kIsInternalizedMask)); |
| 3443 __ j(zero, label); | 3441 __ cmpb(scratch, Immediate(kInternalizedTag | kStringTag)); |
| 3442 __ j(not_equal, label); |
| 3444 } | 3443 } |
| 3445 | 3444 |
| 3446 | 3445 |
| 3447 void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { | 3446 void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { |
| 3448 Label check_unequal_objects, done; | 3447 Label check_unequal_objects, done; |
| 3449 Condition cc = GetCondition(); | 3448 Condition cc = GetCondition(); |
| 3450 Factory* factory = masm->isolate()->factory(); | 3449 Factory* factory = masm->isolate()->factory(); |
| 3451 | 3450 |
| 3452 Label miss; | 3451 Label miss; |
| 3453 CheckInputType(masm, rdx, left_, &miss); | 3452 CheckInputType(masm, rdx, left_, &miss); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3710 void StackCheckStub::Generate(MacroAssembler* masm) { | 3709 void StackCheckStub::Generate(MacroAssembler* masm) { |
| 3711 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); | 3710 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); |
| 3712 } | 3711 } |
| 3713 | 3712 |
| 3714 | 3713 |
| 3715 void InterruptStub::Generate(MacroAssembler* masm) { | 3714 void InterruptStub::Generate(MacroAssembler* masm) { |
| 3716 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); | 3715 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); |
| 3717 } | 3716 } |
| 3718 | 3717 |
| 3719 | 3718 |
| 3720 static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) { | |
| 3721 // Cache the called function in a global property cell. Cache states | |
| 3722 // are uninitialized, monomorphic (indicated by a JSFunction), and | |
| 3723 // megamorphic. | |
| 3724 // rbx : cache cell for call target | |
| 3725 // rdi : the function to call | |
| 3726 Isolate* isolate = masm->isolate(); | |
| 3727 Label initialize, done; | |
| 3728 | |
| 3729 // Load the cache state into rcx. | |
| 3730 __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset)); | |
| 3731 | |
| 3732 // A monomorphic cache hit or an already megamorphic state: invoke the | |
| 3733 // function without changing the state. | |
| 3734 __ cmpq(rcx, rdi); | |
| 3735 __ j(equal, &done, Label::kNear); | |
| 3736 __ Cmp(rcx, TypeFeedbackCells::MegamorphicSentinel(isolate)); | |
| 3737 __ j(equal, &done, Label::kNear); | |
| 3738 | |
| 3739 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | |
| 3740 // megamorphic. | |
| 3741 __ Cmp(rcx, TypeFeedbackCells::UninitializedSentinel(isolate)); | |
| 3742 __ j(equal, &initialize, Label::kNear); | |
| 3743 // MegamorphicSentinel is an immortal immovable object (undefined) so no | |
| 3744 // write-barrier is needed. | |
| 3745 __ Move(FieldOperand(rbx, Cell::kValueOffset), | |
| 3746 TypeFeedbackCells::MegamorphicSentinel(isolate)); | |
| 3747 __ jmp(&done, Label::kNear); | |
| 3748 | |
| 3749 // An uninitialized cache is patched with the function. | |
| 3750 __ bind(&initialize); | |
| 3751 __ movq(FieldOperand(rbx, Cell::kValueOffset), rdi); | |
| 3752 // No need for a write barrier here - cells are rescanned. | |
| 3753 | |
| 3754 __ bind(&done); | |
| 3755 } | |
| 3756 | |
| 3757 | |
| 3758 static void GenerateRecordCallTarget(MacroAssembler* masm) { | 3719 static void GenerateRecordCallTarget(MacroAssembler* masm) { |
| 3759 // Cache the called function in a global property cell. Cache states | 3720 // Cache the called function in a global property cell. Cache states |
| 3760 // are uninitialized, monomorphic (indicated by a JSFunction), and | 3721 // are uninitialized, monomorphic (indicated by a JSFunction), and |
| 3761 // megamorphic. | 3722 // megamorphic. |
| 3762 // rbx : cache cell for call target | 3723 // rbx : cache cell for call target |
| 3763 // rdi : the function to call | 3724 // rdi : the function to call |
| 3764 ASSERT(FLAG_optimize_constructed_arrays); | |
| 3765 Isolate* isolate = masm->isolate(); | 3725 Isolate* isolate = masm->isolate(); |
| 3766 Label initialize, done, miss, megamorphic, not_array_function; | 3726 Label initialize, done, miss, megamorphic, not_array_function; |
| 3767 | 3727 |
| 3768 // Load the cache state into rcx. | 3728 // Load the cache state into rcx. |
| 3769 __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset)); | 3729 __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset)); |
| 3770 | 3730 |
| 3771 // A monomorphic cache hit or an already megamorphic state: invoke the | 3731 // A monomorphic cache hit or an already megamorphic state: invoke the |
| 3772 // function without changing the state. | 3732 // function without changing the state. |
| 3773 __ cmpq(rcx, rdi); | 3733 __ cmpq(rcx, rdi); |
| 3774 __ j(equal, &done); | 3734 __ j(equal, &done); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3853 __ bind(&call); | 3813 __ bind(&call); |
| 3854 } | 3814 } |
| 3855 | 3815 |
| 3856 // Check that the function really is a JavaScript function. | 3816 // Check that the function really is a JavaScript function. |
| 3857 __ JumpIfSmi(rdi, &non_function); | 3817 __ JumpIfSmi(rdi, &non_function); |
| 3858 // Goto slow case if we do not have a function. | 3818 // Goto slow case if we do not have a function. |
| 3859 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 3819 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| 3860 __ j(not_equal, &slow); | 3820 __ j(not_equal, &slow); |
| 3861 | 3821 |
| 3862 if (RecordCallTarget()) { | 3822 if (RecordCallTarget()) { |
| 3863 if (FLAG_optimize_constructed_arrays) { | 3823 GenerateRecordCallTarget(masm); |
| 3864 GenerateRecordCallTarget(masm); | |
| 3865 } else { | |
| 3866 GenerateRecordCallTargetNoArray(masm); | |
| 3867 } | |
| 3868 } | 3824 } |
| 3869 | 3825 |
| 3870 // Fast-case: Just invoke the function. | 3826 // Fast-case: Just invoke the function. |
| 3871 ParameterCount actual(argc_); | 3827 ParameterCount actual(argc_); |
| 3872 | 3828 |
| 3873 if (ReceiverMightBeImplicit()) { | 3829 if (ReceiverMightBeImplicit()) { |
| 3874 Label call_as_function; | 3830 Label call_as_function; |
| 3875 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 3831 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 3876 __ j(equal, &call_as_function); | 3832 __ j(equal, &call_as_function); |
| 3877 __ InvokeFunction(rdi, | 3833 __ InvokeFunction(rdi, |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3932 // rdi : constructor function | 3888 // rdi : constructor function |
| 3933 Label slow, non_function_call; | 3889 Label slow, non_function_call; |
| 3934 | 3890 |
| 3935 // Check that function is not a smi. | 3891 // Check that function is not a smi. |
| 3936 __ JumpIfSmi(rdi, &non_function_call); | 3892 __ JumpIfSmi(rdi, &non_function_call); |
| 3937 // Check that function is a JSFunction. | 3893 // Check that function is a JSFunction. |
| 3938 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 3894 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| 3939 __ j(not_equal, &slow); | 3895 __ j(not_equal, &slow); |
| 3940 | 3896 |
| 3941 if (RecordCallTarget()) { | 3897 if (RecordCallTarget()) { |
| 3942 if (FLAG_optimize_constructed_arrays) { | 3898 GenerateRecordCallTarget(masm); |
| 3943 GenerateRecordCallTarget(masm); | |
| 3944 } else { | |
| 3945 GenerateRecordCallTargetNoArray(masm); | |
| 3946 } | |
| 3947 } | 3899 } |
| 3948 | 3900 |
| 3949 // Jump to the function-specific construct stub. | 3901 // Jump to the function-specific construct stub. |
| 3950 Register jmp_reg = FLAG_optimize_constructed_arrays ? rcx : rbx; | 3902 Register jmp_reg = rcx; |
| 3951 __ movq(jmp_reg, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 3903 __ movq(jmp_reg, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
| 3952 __ movq(jmp_reg, FieldOperand(jmp_reg, | 3904 __ movq(jmp_reg, FieldOperand(jmp_reg, |
| 3953 SharedFunctionInfo::kConstructStubOffset)); | 3905 SharedFunctionInfo::kConstructStubOffset)); |
| 3954 __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize)); | 3906 __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize)); |
| 3955 __ jmp(jmp_reg); | 3907 __ jmp(jmp_reg); |
| 3956 | 3908 |
| 3957 // rdi: called object | 3909 // rdi: called object |
| 3958 // rax: number of arguments | 3910 // rax: number of arguments |
| 3959 // rcx: object map | 3911 // rcx: object map |
| 3960 Label do_call; | 3912 Label do_call; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 3988 #endif | 3940 #endif |
| 3989 } | 3941 } |
| 3990 | 3942 |
| 3991 | 3943 |
| 3992 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 3944 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
| 3993 CEntryStub::GenerateAheadOfTime(isolate); | 3945 CEntryStub::GenerateAheadOfTime(isolate); |
| 3994 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 3946 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 3995 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 3947 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
| 3996 // It is important that the store buffer overflow stubs are generated first. | 3948 // It is important that the store buffer overflow stubs are generated first. |
| 3997 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); | 3949 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 3998 if (FLAG_optimize_constructed_arrays) { | 3950 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
| 3999 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | |
| 4000 } | |
| 4001 } | 3951 } |
| 4002 | 3952 |
| 4003 | 3953 |
| 4004 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 3954 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
| 4005 } | 3955 } |
| 4006 | 3956 |
| 4007 | 3957 |
| 4008 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { | 3958 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { |
| 4009 CEntryStub stub(1, kDontSaveFPRegs); | 3959 CEntryStub stub(1, kDontSaveFPRegs); |
| 4010 stub.GetCode(isolate)->set_is_pregenerated(true); | 3960 stub.GetCode(isolate)->set_is_pregenerated(true); |
| (...skipping 1876 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5887 Label miss; | 5837 Label miss; |
| 5888 Condition cond = masm->CheckEitherSmi(left, right, tmp1); | 5838 Condition cond = masm->CheckEitherSmi(left, right, tmp1); |
| 5889 __ j(cond, &miss, Label::kNear); | 5839 __ j(cond, &miss, Label::kNear); |
| 5890 | 5840 |
| 5891 // Check that both operands are internalized strings. | 5841 // Check that both operands are internalized strings. |
| 5892 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 5842 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 5893 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 5843 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 5894 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 5844 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 5895 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 5845 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 5896 STATIC_ASSERT(kInternalizedTag != 0); | 5846 STATIC_ASSERT(kInternalizedTag != 0); |
| 5897 __ and_(tmp1, tmp2); | 5847 __ and_(tmp1, Immediate(kIsNotStringMask | kIsInternalizedMask)); |
| 5898 __ testb(tmp1, Immediate(kIsInternalizedMask)); | 5848 __ cmpb(tmp1, Immediate(kInternalizedTag | kStringTag)); |
| 5899 __ j(zero, &miss, Label::kNear); | 5849 __ j(not_equal, &miss, Label::kNear); |
| 5850 |
| 5851 __ and_(tmp2, Immediate(kIsNotStringMask | kIsInternalizedMask)); |
| 5852 __ cmpb(tmp2, Immediate(kInternalizedTag | kStringTag)); |
| 5853 __ j(not_equal, &miss, Label::kNear); |
| 5900 | 5854 |
| 5901 // Internalized strings are compared by identity. | 5855 // Internalized strings are compared by identity. |
| 5902 Label done; | 5856 Label done; |
| 5903 __ cmpq(left, right); | 5857 __ cmpq(left, right); |
| 5904 // Make sure rax is non-zero. At this point input operands are | 5858 // Make sure rax is non-zero. At this point input operands are |
| 5905 // guaranteed to be non-zero. | 5859 // guaranteed to be non-zero. |
| 5906 ASSERT(right.is(rax)); | 5860 ASSERT(right.is(rax)); |
| 5907 __ j(not_equal, &done, Label::kNear); | 5861 __ j(not_equal, &done, Label::kNear); |
| 5908 STATIC_ASSERT(EQUAL == 0); | 5862 STATIC_ASSERT(EQUAL == 0); |
| 5909 STATIC_ASSERT(kSmiTag == 0); | 5863 STATIC_ASSERT(kSmiTag == 0); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 5932 __ j(cond, &miss, Label::kNear); | 5886 __ j(cond, &miss, Label::kNear); |
| 5933 | 5887 |
| 5934 // Check that both operands are unique names. This leaves the instance | 5888 // Check that both operands are unique names. This leaves the instance |
| 5935 // types loaded in tmp1 and tmp2. | 5889 // types loaded in tmp1 and tmp2. |
| 5936 STATIC_ASSERT(kInternalizedTag != 0); | 5890 STATIC_ASSERT(kInternalizedTag != 0); |
| 5937 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); | 5891 __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 5938 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); | 5892 __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 5939 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); | 5893 __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 5940 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); | 5894 __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 5941 | 5895 |
| 5942 Label succeed1; | 5896 __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear); |
| 5943 __ testb(tmp1, Immediate(kIsInternalizedMask)); | 5897 __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear); |
| 5944 __ j(not_zero, &succeed1, Label::kNear); | |
| 5945 __ cmpb(tmp1, Immediate(static_cast<uint8_t>(SYMBOL_TYPE))); | |
| 5946 __ j(not_equal, &miss, Label::kNear); | |
| 5947 __ bind(&succeed1); | |
| 5948 | |
| 5949 Label succeed2; | |
| 5950 __ testb(tmp2, Immediate(kIsInternalizedMask)); | |
| 5951 __ j(not_zero, &succeed2, Label::kNear); | |
| 5952 __ cmpb(tmp2, Immediate(static_cast<uint8_t>(SYMBOL_TYPE))); | |
| 5953 __ j(not_equal, &miss, Label::kNear); | |
| 5954 __ bind(&succeed2); | |
| 5955 | 5898 |
| 5956 // Unique names are compared by identity. | 5899 // Unique names are compared by identity. |
| 5957 Label done; | 5900 Label done; |
| 5958 __ cmpq(left, right); | 5901 __ cmpq(left, right); |
| 5959 // Make sure rax is non-zero. At this point input operands are | 5902 // Make sure rax is non-zero. At this point input operands are |
| 5960 // guaranteed to be non-zero. | 5903 // guaranteed to be non-zero. |
| 5961 ASSERT(right.is(rax)); | 5904 ASSERT(right.is(rax)); |
| 5962 __ j(not_equal, &done, Label::kNear); | 5905 __ j(not_equal, &done, Label::kNear); |
| 5963 STATIC_ASSERT(EQUAL == 0); | 5906 STATIC_ASSERT(EQUAL == 0); |
| 5964 STATIC_ASSERT(kSmiTag == 0); | 5907 STATIC_ASSERT(kSmiTag == 0); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6006 __ j(not_equal, ¬_same, Label::kNear); | 5949 __ j(not_equal, ¬_same, Label::kNear); |
| 6007 STATIC_ASSERT(EQUAL == 0); | 5950 STATIC_ASSERT(EQUAL == 0); |
| 6008 STATIC_ASSERT(kSmiTag == 0); | 5951 STATIC_ASSERT(kSmiTag == 0); |
| 6009 __ Move(rax, Smi::FromInt(EQUAL)); | 5952 __ Move(rax, Smi::FromInt(EQUAL)); |
| 6010 __ ret(0); | 5953 __ ret(0); |
| 6011 | 5954 |
| 6012 // Handle not identical strings. | 5955 // Handle not identical strings. |
| 6013 __ bind(¬_same); | 5956 __ bind(¬_same); |
| 6014 | 5957 |
| 6015 // Check that both strings are internalized strings. If they are, we're done | 5958 // Check that both strings are internalized strings. If they are, we're done |
| 6016 // because we already know they are not identical. | 5959 // because we already know they are not identical. We also know they are both |
| 5960 // strings. |
| 6017 if (equality) { | 5961 if (equality) { |
| 6018 Label do_compare; | 5962 Label do_compare; |
| 6019 STATIC_ASSERT(kInternalizedTag != 0); | 5963 STATIC_ASSERT(kInternalizedTag != 0); |
| 6020 __ and_(tmp1, tmp2); | 5964 __ and_(tmp1, tmp2); |
| 6021 __ testb(tmp1, Immediate(kIsInternalizedMask)); | 5965 __ testb(tmp1, Immediate(kIsInternalizedMask)); |
| 6022 __ j(zero, &do_compare, Label::kNear); | 5966 __ j(zero, &do_compare, Label::kNear); |
| 6023 // Make sure rax is non-zero. At this point input operands are | 5967 // Make sure rax is non-zero. At this point input operands are |
| 6024 // guaranteed to be non-zero. | 5968 // guaranteed to be non-zero. |
| 6025 ASSERT(right.is(rax)); | 5969 ASSERT(right.is(rax)); |
| 6026 __ ret(0); | 5970 __ ret(0); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6162 __ Cmp(entity_name, Handle<Name>(name)); | 6106 __ Cmp(entity_name, Handle<Name>(name)); |
| 6163 __ j(equal, miss); | 6107 __ j(equal, miss); |
| 6164 | 6108 |
| 6165 Label good; | 6109 Label good; |
| 6166 // Check for the hole and skip. | 6110 // Check for the hole and skip. |
| 6167 __ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex); | 6111 __ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex); |
| 6168 __ j(equal, &good, Label::kNear); | 6112 __ j(equal, &good, Label::kNear); |
| 6169 | 6113 |
| 6170 // Check if the entry name is not a unique name. | 6114 // Check if the entry name is not a unique name. |
| 6171 __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); | 6115 __ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
| 6172 __ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset), | 6116 __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 6173 Immediate(kIsInternalizedMask)); | 6117 miss); |
| 6174 __ j(not_zero, &good, Label::kNear); | |
| 6175 __ cmpb(FieldOperand(entity_name, Map::kInstanceTypeOffset), | |
| 6176 Immediate(static_cast<uint8_t>(SYMBOL_TYPE))); | |
| 6177 __ j(not_equal, miss); | |
| 6178 | |
| 6179 __ bind(&good); | 6118 __ bind(&good); |
| 6180 } | 6119 } |
| 6181 | 6120 |
| 6182 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP); | 6121 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP); |
| 6183 __ Push(Handle<Object>(name)); | 6122 __ Push(Handle<Object>(name)); |
| 6184 __ push(Immediate(name->Hash())); | 6123 __ push(Immediate(name->Hash())); |
| 6185 __ CallStub(&stub); | 6124 __ CallStub(&stub); |
| 6186 __ testq(r0, r0); | 6125 __ testq(r0, r0); |
| 6187 __ j(not_zero, miss); | 6126 __ j(not_zero, miss); |
| 6188 __ jmp(done); | 6127 __ jmp(done); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6294 // Stop if found the property. | 6233 // Stop if found the property. |
| 6295 __ cmpq(scratch, Operand(rsp, 3 * kPointerSize)); | 6234 __ cmpq(scratch, Operand(rsp, 3 * kPointerSize)); |
| 6296 __ j(equal, &in_dictionary); | 6235 __ j(equal, &in_dictionary); |
| 6297 | 6236 |
| 6298 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { | 6237 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 6299 // If we hit a key that is not a unique name during negative | 6238 // If we hit a key that is not a unique name during negative |
| 6300 // lookup we have to bailout as this key might be equal to the | 6239 // lookup we have to bailout as this key might be equal to the |
| 6301 // key we are looking for. | 6240 // key we are looking for. |
| 6302 | 6241 |
| 6303 // Check if the entry name is not a unique name. | 6242 // Check if the entry name is not a unique name. |
| 6304 Label cont; | |
| 6305 __ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 6243 __ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 6306 __ testb(FieldOperand(scratch, Map::kInstanceTypeOffset), | 6244 __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 6307 Immediate(kIsInternalizedMask)); | 6245 &maybe_in_dictionary); |
| 6308 __ j(not_zero, &cont); | |
| 6309 __ cmpb(FieldOperand(scratch, Map::kInstanceTypeOffset), | |
| 6310 Immediate(static_cast<uint8_t>(SYMBOL_TYPE))); | |
| 6311 __ j(not_equal, &maybe_in_dictionary); | |
| 6312 __ bind(&cont); | |
| 6313 } | 6246 } |
| 6314 } | 6247 } |
| 6315 | 6248 |
| 6316 __ bind(&maybe_in_dictionary); | 6249 __ bind(&maybe_in_dictionary); |
| 6317 // If we are doing negative lookup then probing failure should be | 6250 // If we are doing negative lookup then probing failure should be |
| 6318 // treated as a lookup success. For positive lookup probing failure | 6251 // treated as a lookup success. For positive lookup probing failure |
| 6319 // should be treated as lookup failure. | 6252 // should be treated as lookup failure. |
| 6320 if (mode_ == POSITIVE_LOOKUP) { | 6253 if (mode_ == POSITIVE_LOOKUP) { |
| 6321 __ movq(scratch, Immediate(0)); | 6254 __ movq(scratch, Immediate(0)); |
| 6322 __ Drop(1); | 6255 __ Drop(1); |
| (...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6942 // We should either have undefined in ebx or a valid cell | 6875 // We should either have undefined in ebx or a valid cell |
| 6943 Label okay_here; | 6876 Label okay_here; |
| 6944 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); | 6877 Handle<Map> cell_map = masm->isolate()->factory()->cell_map(); |
| 6945 __ Cmp(rbx, undefined_sentinel); | 6878 __ Cmp(rbx, undefined_sentinel); |
| 6946 __ j(equal, &okay_here); | 6879 __ j(equal, &okay_here); |
| 6947 __ Cmp(FieldOperand(rbx, 0), cell_map); | 6880 __ Cmp(FieldOperand(rbx, 0), cell_map); |
| 6948 __ Assert(equal, "Expected property cell in register rbx"); | 6881 __ Assert(equal, "Expected property cell in register rbx"); |
| 6949 __ bind(&okay_here); | 6882 __ bind(&okay_here); |
| 6950 } | 6883 } |
| 6951 | 6884 |
| 6952 if (FLAG_optimize_constructed_arrays) { | 6885 Label no_info, switch_ready; |
| 6953 Label no_info, switch_ready; | 6886 // Get the elements kind and case on that. |
| 6954 // Get the elements kind and case on that. | 6887 __ Cmp(rbx, undefined_sentinel); |
| 6955 __ Cmp(rbx, undefined_sentinel); | 6888 __ j(equal, &no_info); |
| 6956 __ j(equal, &no_info); | 6889 __ movq(rdx, FieldOperand(rbx, Cell::kValueOffset)); |
| 6957 __ movq(rdx, FieldOperand(rbx, Cell::kValueOffset)); | 6890 __ JumpIfNotSmi(rdx, &no_info); |
| 6958 __ JumpIfNotSmi(rdx, &no_info); | 6891 __ SmiToInteger32(rdx, rdx); |
| 6959 __ SmiToInteger32(rdx, rdx); | 6892 __ jmp(&switch_ready); |
| 6960 __ jmp(&switch_ready); | 6893 __ bind(&no_info); |
| 6961 __ bind(&no_info); | 6894 __ movq(rdx, Immediate(GetInitialFastElementsKind())); |
| 6962 __ movq(rdx, Immediate(GetInitialFastElementsKind())); | 6895 __ bind(&switch_ready); |
| 6963 __ bind(&switch_ready); | |
| 6964 | 6896 |
| 6965 if (argument_count_ == ANY) { | 6897 if (argument_count_ == ANY) { |
| 6966 Label not_zero_case, not_one_case; | 6898 Label not_zero_case, not_one_case; |
| 6967 __ testq(rax, rax); | 6899 __ testq(rax, rax); |
| 6968 __ j(not_zero, ¬_zero_case); | 6900 __ j(not_zero, ¬_zero_case); |
| 6969 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); | 6901 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); |
| 6970 | 6902 |
| 6971 __ bind(¬_zero_case); | 6903 __ bind(¬_zero_case); |
| 6972 __ cmpl(rax, Immediate(1)); | 6904 __ cmpl(rax, Immediate(1)); |
| 6973 __ j(greater, ¬_one_case); | 6905 __ j(greater, ¬_one_case); |
| 6974 CreateArrayDispatchOneArgument(masm); | 6906 CreateArrayDispatchOneArgument(masm); |
| 6975 | 6907 |
| 6976 __ bind(¬_one_case); | 6908 __ bind(¬_one_case); |
| 6977 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); | 6909 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); |
| 6978 } else if (argument_count_ == NONE) { | 6910 } else if (argument_count_ == NONE) { |
| 6979 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); | 6911 CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); |
| 6980 } else if (argument_count_ == ONE) { | 6912 } else if (argument_count_ == ONE) { |
| 6981 CreateArrayDispatchOneArgument(masm); | 6913 CreateArrayDispatchOneArgument(masm); |
| 6982 } else if (argument_count_ == MORE_THAN_ONE) { | 6914 } else if (argument_count_ == MORE_THAN_ONE) { |
| 6983 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); | 6915 CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); |
| 6984 } else { | |
| 6985 UNREACHABLE(); | |
| 6986 } | |
| 6987 } else { | 6916 } else { |
| 6988 Label generic_constructor; | 6917 UNREACHABLE(); |
| 6989 // Run the native code for the Array function called as constructor. | |
| 6990 ArrayNativeCode(masm, &generic_constructor); | |
| 6991 | |
| 6992 // Jump to the generic construct code in case the specialized code cannot | |
| 6993 // handle the construction. | |
| 6994 __ bind(&generic_constructor); | |
| 6995 Handle<Code> generic_construct_stub = | |
| 6996 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
| 6997 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | |
| 6998 } | 6918 } |
| 6999 } | 6919 } |
| 7000 | 6920 |
| 7001 | 6921 |
| 7002 void InternalArrayConstructorStub::GenerateCase( | 6922 void InternalArrayConstructorStub::GenerateCase( |
| 7003 MacroAssembler* masm, ElementsKind kind) { | 6923 MacroAssembler* masm, ElementsKind kind) { |
| 7004 Label not_zero_case, not_one_case; | 6924 Label not_zero_case, not_one_case; |
| 7005 Label normal_sequence; | 6925 Label normal_sequence; |
| 7006 | 6926 |
| 7007 __ testq(rax, rax); | 6927 __ testq(rax, rax); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7051 // Initial map for the builtin Array function should be a map. | 6971 // Initial map for the builtin Array function should be a map. |
| 7052 __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); | 6972 __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 7053 // Will both indicate a NULL and a Smi. | 6973 // Will both indicate a NULL and a Smi. |
| 7054 STATIC_ASSERT(kSmiTag == 0); | 6974 STATIC_ASSERT(kSmiTag == 0); |
| 7055 Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); | 6975 Condition not_smi = NegateCondition(masm->CheckSmi(rcx)); |
| 7056 __ Check(not_smi, "Unexpected initial map for Array function"); | 6976 __ Check(not_smi, "Unexpected initial map for Array function"); |
| 7057 __ CmpObjectType(rcx, MAP_TYPE, rcx); | 6977 __ CmpObjectType(rcx, MAP_TYPE, rcx); |
| 7058 __ Check(equal, "Unexpected initial map for Array function"); | 6978 __ Check(equal, "Unexpected initial map for Array function"); |
| 7059 } | 6979 } |
| 7060 | 6980 |
| 7061 if (FLAG_optimize_constructed_arrays) { | 6981 // Figure out the right elements kind |
| 7062 // Figure out the right elements kind | 6982 __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 7063 __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); | |
| 7064 | 6983 |
| 7065 // Load the map's "bit field 2" into |result|. We only need the first byte, | 6984 // Load the map's "bit field 2" into |result|. We only need the first byte, |
| 7066 // but the following masking takes care of that anyway. | 6985 // but the following masking takes care of that anyway. |
| 7067 __ movzxbq(rcx, FieldOperand(rcx, Map::kBitField2Offset)); | 6986 __ movzxbq(rcx, FieldOperand(rcx, Map::kBitField2Offset)); |
| 7068 // Retrieve elements_kind from bit field 2. | 6987 // Retrieve elements_kind from bit field 2. |
| 7069 __ and_(rcx, Immediate(Map::kElementsKindMask)); | 6988 __ and_(rcx, Immediate(Map::kElementsKindMask)); |
| 7070 __ shr(rcx, Immediate(Map::kElementsKindShift)); | 6989 __ shr(rcx, Immediate(Map::kElementsKindShift)); |
| 7071 | 6990 |
| 7072 if (FLAG_debug_code) { | 6991 if (FLAG_debug_code) { |
| 7073 Label done; | 6992 Label done; |
| 7074 __ cmpl(rcx, Immediate(FAST_ELEMENTS)); | 6993 __ cmpl(rcx, Immediate(FAST_ELEMENTS)); |
| 7075 __ j(equal, &done); | 6994 __ j(equal, &done); |
| 7076 __ cmpl(rcx, Immediate(FAST_HOLEY_ELEMENTS)); | 6995 __ cmpl(rcx, Immediate(FAST_HOLEY_ELEMENTS)); |
| 7077 __ Assert(equal, | 6996 __ Assert(equal, |
| 7078 "Invalid ElementsKind for InternalArray or InternalPackedArray"); | 6997 "Invalid ElementsKind for InternalArray or InternalPackedArray"); |
| 7079 __ bind(&done); | 6998 __ bind(&done); |
| 7080 } | 6999 } |
| 7081 | 7000 |
| 7082 Label fast_elements_case; | 7001 Label fast_elements_case; |
| 7083 __ cmpl(rcx, Immediate(FAST_ELEMENTS)); | 7002 __ cmpl(rcx, Immediate(FAST_ELEMENTS)); |
| 7084 __ j(equal, &fast_elements_case); | 7003 __ j(equal, &fast_elements_case); |
| 7085 GenerateCase(masm, FAST_HOLEY_ELEMENTS); | 7004 GenerateCase(masm, FAST_HOLEY_ELEMENTS); |
| 7086 | 7005 |
| 7087 __ bind(&fast_elements_case); | 7006 __ bind(&fast_elements_case); |
| 7088 GenerateCase(masm, FAST_ELEMENTS); | 7007 GenerateCase(masm, FAST_ELEMENTS); |
| 7089 } else { | |
| 7090 Label generic_constructor; | |
| 7091 // Run the native code for the Array function called as constructor. | |
| 7092 ArrayNativeCode(masm, &generic_constructor); | |
| 7093 | |
| 7094 // Jump to the generic construct code in case the specialized code cannot | |
| 7095 // handle the construction. | |
| 7096 __ bind(&generic_constructor); | |
| 7097 Handle<Code> generic_construct_stub = | |
| 7098 masm->isolate()->builtins()->JSConstructStubGeneric(); | |
| 7099 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | |
| 7100 } | |
| 7101 } | 7008 } |
| 7102 | 7009 |
| 7103 | 7010 |
| 7104 #undef __ | 7011 #undef __ |
| 7105 | 7012 |
| 7106 } } // namespace v8::internal | 7013 } } // namespace v8::internal |
| 7107 | 7014 |
| 7108 #endif // V8_TARGET_ARCH_X64 | 7015 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |