OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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 #include "src/code-stub-assembler.h" | 4 #include "src/code-stub-assembler.h" |
5 #include "src/code-factory.h" | 5 #include "src/code-factory.h" |
6 #include "src/frames-inl.h" | 6 #include "src/frames-inl.h" |
7 #include "src/frames.h" | 7 #include "src/frames.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 2880 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2891 STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE); | 2891 STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE); |
2892 return Int32LessThanOrEqual(instance_type, | 2892 return Int32LessThanOrEqual(instance_type, |
2893 Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)); | 2893 Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)); |
2894 } | 2894 } |
2895 | 2895 |
2896 Node* CodeStubAssembler::IsStringInstanceType(Node* instance_type) { | 2896 Node* CodeStubAssembler::IsStringInstanceType(Node* instance_type) { |
2897 STATIC_ASSERT(INTERNALIZED_STRING_TYPE == FIRST_TYPE); | 2897 STATIC_ASSERT(INTERNALIZED_STRING_TYPE == FIRST_TYPE); |
2898 return Int32LessThan(instance_type, Int32Constant(FIRST_NONSTRING_TYPE)); | 2898 return Int32LessThan(instance_type, Int32Constant(FIRST_NONSTRING_TYPE)); |
2899 } | 2899 } |
2900 | 2900 |
2901 Node* CodeStubAssembler::IsOneByteStringInstanceType(Node* instance_type) { | |
2902 CSA_ASSERT(this, IsStringInstanceType(instance_type)); | |
2903 return Word32Equal( | |
2904 Word32And(instance_type, Int32Constant(kStringEncodingMask)), | |
2905 Int32Constant(kOneByteStringTag)); | |
2906 } | |
2907 | |
2908 Node* CodeStubAssembler::IsSequentialStringInstanceType(Node* instance_type) { | |
2909 CSA_ASSERT(this, IsStringInstanceType(instance_type)); | |
2910 return Word32Equal( | |
2911 Word32And(instance_type, Int32Constant(kStringRepresentationMask)), | |
2912 Int32Constant(kSeqStringTag)); | |
2913 } | |
2914 | |
2901 Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) { | 2915 Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) { |
2902 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | 2916 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
2903 return Int32GreaterThanOrEqual(instance_type, | 2917 return Int32GreaterThanOrEqual(instance_type, |
2904 Int32Constant(FIRST_JS_RECEIVER_TYPE)); | 2918 Int32Constant(FIRST_JS_RECEIVER_TYPE)); |
2905 } | 2919 } |
2906 | 2920 |
2907 Node* CodeStubAssembler::IsJSReceiver(Node* object) { | 2921 Node* CodeStubAssembler::IsJSReceiver(Node* object) { |
2908 STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE); | 2922 STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE); |
2909 return IsJSReceiverInstanceType(LoadInstanceType(object)); | 2923 return IsJSReceiverInstanceType(LoadInstanceType(object)); |
2910 } | 2924 } |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3252 // given character range using CopyStringCharacters. | 3266 // given character range using CopyStringCharacters. |
3253 // |from_string| must be a sequential string. |from_index| and | 3267 // |from_string| must be a sequential string. |from_index| and |
3254 // |character_count| must be Smis s.t. | 3268 // |character_count| must be Smis s.t. |
3255 // 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. | 3269 // 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. |
3256 Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, | 3270 Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, |
3257 Node* from, Node* from_instance_type, | 3271 Node* from, Node* from_instance_type, |
3258 Node* from_index, Node* character_count) { | 3272 Node* from_index, Node* character_count) { |
3259 typedef CodeStubAssembler::Label Label; | 3273 typedef CodeStubAssembler::Label Label; |
3260 typedef CodeStubAssembler::Variable Variable; | 3274 typedef CodeStubAssembler::Variable Variable; |
3261 | 3275 |
3262 Label end(a), two_byte_sequential(a); | 3276 Label end(a), one_byte_sequential(a), two_byte_sequential(a); |
3263 Variable var_result(a, MachineRepresentation::kTagged); | 3277 Variable var_result(a, MachineRepresentation::kTagged); |
3264 | 3278 |
3265 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 3279 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
3266 | 3280 |
3267 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | 3281 a->Branch(a->IsOneByteStringInstanceType(from_instance_type), |
jgruber
2017/03/13 12:27:37
Drive-by simplification.
| |
3268 a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type, | 3282 &one_byte_sequential, &two_byte_sequential); |
3269 a->Int32Constant(kStringEncodingMask)), | |
3270 a->Int32Constant(0)), | |
3271 &two_byte_sequential); | |
3272 | 3283 |
3273 // The subject string is a sequential one-byte string. | 3284 // The subject string is a sequential one-byte string. |
3285 a->Bind(&one_byte_sequential); | |
3274 { | 3286 { |
3275 Node* result = | 3287 Node* result = |
3276 a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); | 3288 a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); |
3277 a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, | 3289 a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, |
3278 String::ONE_BYTE_ENCODING, | 3290 String::ONE_BYTE_ENCODING, |
3279 String::ONE_BYTE_ENCODING, | 3291 String::ONE_BYTE_ENCODING, |
3280 CodeStubAssembler::SMI_PARAMETERS); | 3292 CodeStubAssembler::SMI_PARAMETERS); |
3281 var_result.Bind(result); | 3293 var_result.Bind(result); |
3282 | 3294 |
3283 a->Goto(&end); | 3295 a->Goto(&end); |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3548 Node* const instance_type) { | 3560 Node* const instance_type) { |
3549 CSA_ASSERT(a, a->IsStringInstanceType(instance_type)); | 3561 CSA_ASSERT(a, a->IsStringInstanceType(instance_type)); |
3550 STATIC_ASSERT(kShortExternalStringTag != 0); | 3562 STATIC_ASSERT(kShortExternalStringTag != 0); |
3551 return a->Word32NotEqual( | 3563 return a->Word32NotEqual( |
3552 a->Word32And(instance_type, a->Int32Constant(kShortExternalStringMask)), | 3564 a->Word32And(instance_type, a->Int32Constant(kShortExternalStringMask)), |
3553 a->Int32Constant(0)); | 3565 a->Int32Constant(0)); |
3554 } | 3566 } |
3555 | 3567 |
3556 } // namespace | 3568 } // namespace |
3557 | 3569 |
3570 void CodeStubAssembler::TryUnpackString(Variable* var_string, | |
jgruber
2017/03/13 12:27:37
String unpacking is getting messy, planning on ref
| |
3571 Variable* var_offset, | |
3572 Variable* var_instance_type, | |
3573 Label* if_bailout) { | |
3574 DCHECK_EQ(var_string->rep(), MachineType::PointerRepresentation()); | |
3575 DCHECK_EQ(var_offset->rep(), MachineType::PointerRepresentation()); | |
3576 DCHECK_EQ(var_instance_type->rep(), MachineRepresentation::kWord32); | |
3577 CSA_ASSERT(this, IsString(var_string->value())); | |
3578 | |
3579 Label out(this); | |
3580 | |
3581 VariableList vars({var_string, var_offset, var_instance_type}, zone()); | |
3582 Label dispatch(this, vars); | |
3583 Label if_isdirect(this); | |
3584 Label if_iscons(this, Label::kDeferred); | |
3585 Label if_isexternal(this, Label::kDeferred); | |
3586 Label if_issliced(this, Label::kDeferred); | |
3587 Label if_isthin(this, Label::kDeferred); | |
3588 | |
3589 Goto(&dispatch); | |
3590 | |
3591 // Dispatch based on string representation. | |
3592 Bind(&dispatch); | |
3593 { | |
3594 int32_t values[] = { | |
3595 kSeqStringTag, kConsStringTag, kExternalStringTag, | |
3596 kSlicedStringTag, kThinStringTag, | |
3597 }; | |
3598 Label* labels[] = { | |
3599 &if_isdirect, &if_iscons, &if_isexternal, &if_issliced, &if_isthin, | |
3600 }; | |
3601 STATIC_ASSERT(arraysize(values) == arraysize(labels)); | |
3602 | |
3603 Node* const representation = Word32And( | |
3604 var_instance_type->value(), Int32Constant(kStringRepresentationMask)); | |
3605 Switch(representation, if_bailout, values, labels, arraysize(values)); | |
3606 } | |
3607 | |
3608 // Cons string. Check whether it is flat, then fetch first part. | |
3609 // Flat cons strings have an empty second part. | |
3610 Bind(&if_iscons); | |
3611 { | |
3612 Node* const string = var_string->value(); | |
3613 GotoIfNot(IsEmptyString(LoadObjectField(string, ConsString::kSecondOffset)), | |
3614 if_bailout); | |
3615 | |
3616 Node* const lhs = LoadObjectField(string, ConsString::kFirstOffset); | |
3617 var_string->Bind(BitcastTaggedToWord(lhs)); | |
3618 var_instance_type->Bind(LoadInstanceType(lhs)); | |
3619 | |
3620 Goto(&dispatch); | |
3621 } | |
3622 | |
3623 // Sliced string. Fetch parent and correct start index by offset. | |
3624 Bind(&if_issliced); | |
3625 { | |
3626 Node* const string = var_string->value(); | |
3627 Node* const sliced_offset = | |
3628 LoadObjectField(string, SlicedString::kOffsetOffset); | |
3629 var_offset->Bind(IntPtrAdd(var_offset->value(), SmiUntag(sliced_offset))); | |
3630 | |
3631 Node* const parent = LoadObjectField(string, SlicedString::kParentOffset); | |
3632 var_string->Bind(BitcastTaggedToWord(parent)); | |
3633 var_instance_type->Bind(LoadInstanceType(parent)); | |
3634 | |
3635 Goto(&dispatch); | |
3636 } | |
3637 | |
3638 // Thin string. Fetch the actual string. | |
3639 Bind(&if_isthin); | |
3640 { | |
3641 Node* const string = var_string->value(); | |
3642 Node* const actual_string = | |
3643 LoadObjectField(string, ThinString::kActualOffset); | |
3644 Node* const actual_instance_type = LoadInstanceType(actual_string); | |
3645 CSA_ASSERT(this, IsSequentialStringInstanceType(actual_instance_type)); | |
3646 | |
3647 var_string->Bind(BitcastTaggedToWord(actual_string)); | |
3648 var_instance_type->Bind(actual_instance_type); | |
3649 | |
3650 Goto(&if_isdirect); | |
3651 } | |
3652 | |
3653 // External string. | |
3654 Bind(&if_isexternal); | |
3655 { | |
3656 Node* const string = var_string->value(); | |
3657 Node* const faked_seq_string = | |
3658 TryDerefExternalString(string, var_instance_type->value(), if_bailout); | |
3659 | |
3660 STATIC_ASSERT(kSeqStringTag == 0x0); | |
3661 Node* const faked_seq_instance_type = Word32Xor( | |
3662 var_instance_type->value(), Int32Constant(kExternalStringTag)); | |
3663 CSA_ASSERT(this, IsSequentialStringInstanceType(faked_seq_instance_type)); | |
3664 | |
3665 var_string->Bind(faked_seq_string); | |
3666 var_instance_type->Bind(faked_seq_instance_type); | |
3667 | |
3668 Goto(&if_isdirect); | |
3669 } | |
3670 | |
3671 Bind(&if_isdirect); | |
3672 } | |
3673 | |
3558 Node* CodeStubAssembler::TryDerefExternalString(Node* const string, | 3674 Node* CodeStubAssembler::TryDerefExternalString(Node* const string, |
3559 Node* const instance_type, | 3675 Node* const instance_type, |
3560 Label* if_bailout) { | 3676 Label* if_bailout) { |
3561 Label out(this); | 3677 Label out(this); |
3562 | 3678 |
3563 USE(IsExternalStringInstanceType); | 3679 USE(IsExternalStringInstanceType); |
3564 CSA_ASSERT(this, IsExternalStringInstanceType(this, instance_type)); | 3680 CSA_ASSERT(this, IsExternalStringInstanceType(this, instance_type)); |
3565 GotoIf(IsShortExternalStringInstanceType(this, instance_type), if_bailout); | 3681 GotoIf(IsShortExternalStringInstanceType(this, instance_type), if_bailout); |
3566 | 3682 |
3567 // Move the pointer so that offset-wise, it looks like a sequential string. | 3683 // Move the pointer so that offset-wise, it looks like a sequential string. |
(...skipping 2018 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5586 // This method is used for binary op and compare feedback. These | 5702 // This method is used for binary op and compare feedback. These |
5587 // vector nodes are initialized with a smi 0, so we can simply OR | 5703 // vector nodes are initialized with a smi 0, so we can simply OR |
5588 // our new feedback in place. | 5704 // our new feedback in place. |
5589 Node* previous_feedback = LoadFixedArrayElement(feedback_vector, slot_id); | 5705 Node* previous_feedback = LoadFixedArrayElement(feedback_vector, slot_id); |
5590 Node* combined_feedback = SmiOr(previous_feedback, feedback); | 5706 Node* combined_feedback = SmiOr(previous_feedback, feedback); |
5591 StoreFixedArrayElement(feedback_vector, slot_id, combined_feedback, | 5707 StoreFixedArrayElement(feedback_vector, slot_id, combined_feedback, |
5592 SKIP_WRITE_BARRIER); | 5708 SKIP_WRITE_BARRIER); |
5593 } | 5709 } |
5594 | 5710 |
5595 Node* CodeStubAssembler::LoadReceiverMap(Node* receiver) { | 5711 Node* CodeStubAssembler::LoadReceiverMap(Node* receiver) { |
5596 Variable var_receiver_map(this, MachineRepresentation::kTagged); | 5712 return Select(TaggedIsSmi(receiver), |
jgruber
2017/03/13 12:27:37
Drive-by simplification.
| |
5597 Label load_smi_map(this, Label::kDeferred), load_receiver_map(this), | 5713 [=] { return LoadRoot(Heap::kHeapNumberMapRootIndex); }, |
5598 if_result(this); | 5714 [=] { return LoadMap(receiver); }, |
5599 | 5715 MachineRepresentation::kTagged); |
5600 Branch(TaggedIsSmi(receiver), &load_smi_map, &load_receiver_map); | |
5601 Bind(&load_smi_map); | |
5602 { | |
5603 var_receiver_map.Bind(LoadRoot(Heap::kHeapNumberMapRootIndex)); | |
5604 Goto(&if_result); | |
5605 } | |
5606 Bind(&load_receiver_map); | |
5607 { | |
5608 var_receiver_map.Bind(LoadMap(receiver)); | |
5609 Goto(&if_result); | |
5610 } | |
5611 Bind(&if_result); | |
5612 return var_receiver_map.value(); | |
5613 } | 5716 } |
5614 | 5717 |
5615 Node* CodeStubAssembler::TryToIntptr(Node* key, Label* miss) { | 5718 Node* CodeStubAssembler::TryToIntptr(Node* key, Label* miss) { |
5616 Variable var_intptr_key(this, MachineType::PointerRepresentation()); | 5719 Variable var_intptr_key(this, MachineType::PointerRepresentation()); |
5617 Label done(this, &var_intptr_key), key_is_smi(this); | 5720 Label done(this, &var_intptr_key), key_is_smi(this); |
5618 GotoIf(TaggedIsSmi(key), &key_is_smi); | 5721 GotoIf(TaggedIsSmi(key), &key_is_smi); |
5619 // Try to convert a heap number to a Smi. | 5722 // Try to convert a heap number to a Smi. |
5620 GotoIfNot(IsHeapNumberMap(LoadMap(key)), miss); | 5723 GotoIfNot(IsHeapNumberMap(LoadMap(key)), miss); |
5621 { | 5724 { |
5622 Node* value = LoadHeapNumberValue(key); | 5725 Node* value = LoadHeapNumberValue(key); |
(...skipping 2697 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8320 formatted.c_str(), TENURED); | 8423 formatted.c_str(), TENURED); |
8321 CallRuntime(Runtime::kGlobalPrint, NoContextConstant(), | 8424 CallRuntime(Runtime::kGlobalPrint, NoContextConstant(), |
8322 HeapConstant(string)); | 8425 HeapConstant(string)); |
8323 } | 8426 } |
8324 CallRuntime(Runtime::kDebugPrint, NoContextConstant(), tagged_value); | 8427 CallRuntime(Runtime::kDebugPrint, NoContextConstant(), tagged_value); |
8325 #endif | 8428 #endif |
8326 } | 8429 } |
8327 | 8430 |
8328 } // namespace internal | 8431 } // namespace internal |
8329 } // namespace v8 | 8432 } // namespace v8 |
OLD | NEW |