| 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 | 4 |
| 5 #include "src/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
| 6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
| 7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
| 8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
| 9 #include "src/regexp/regexp-utils.h" | 9 #include "src/regexp/regexp-utils.h" |
| 10 | 10 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 if_true, if_false); | 53 if_true, if_false); |
| 54 } | 54 } |
| 55 | 55 |
| 56 void GenerateStringEqual(ResultMode mode); | 56 void GenerateStringEqual(ResultMode mode); |
| 57 void GenerateStringRelationalComparison(RelationalComparisonMode mode); | 57 void GenerateStringRelationalComparison(RelationalComparisonMode mode); |
| 58 | 58 |
| 59 Node* ToSmiBetweenZeroAnd(Node* context, Node* value, Node* limit); | 59 Node* ToSmiBetweenZeroAnd(Node* context, Node* value, Node* limit); |
| 60 | 60 |
| 61 Node* LoadSurrogatePairAt(Node* string, Node* length, Node* index, | 61 Node* LoadSurrogatePairAt(Node* string, Node* length, Node* index, |
| 62 UnicodeEncoding encoding); | 62 UnicodeEncoding encoding); |
| 63 |
| 64 void StringIndexOf(Node* context, Node* receiver, Node* instance_type, |
| 65 Node* search_string, Node* search_string_instance_type, |
| 66 Node* position, std::function<void(Node*)> f_return); |
| 63 }; | 67 }; |
| 64 | 68 |
| 65 void StringBuiltinsAssembler::GenerateStringEqual(ResultMode mode) { | 69 void StringBuiltinsAssembler::GenerateStringEqual(ResultMode mode) { |
| 66 // Here's pseudo-code for the algorithm below in case of kDontNegateResult | 70 // Here's pseudo-code for the algorithm below in case of kDontNegateResult |
| 67 // mode; for kNegateResult mode we properly negate the result. | 71 // mode; for kNegateResult mode we properly negate the result. |
| 68 // | 72 // |
| 69 // if (lhs == rhs) return true; | 73 // if (lhs == rhs) return true; |
| 70 // if (lhs->length() != rhs->length()) return false; | 74 // if (lhs->length() != rhs->length()) return false; |
| 71 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { | 75 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { |
| 72 // return false; | 76 // return false; |
| (...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 756 Handle<Object> position; | 760 Handle<Object> position; |
| 757 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 761 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 758 isolate, position, | 762 isolate, position, |
| 759 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2))); | 763 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2))); |
| 760 | 764 |
| 761 uint32_t index = str->ToValidIndex(*position); | 765 uint32_t index = str->ToValidIndex(*position); |
| 762 int index_in_str = String::IndexOf(isolate, str, search_string, index); | 766 int index_in_str = String::IndexOf(isolate, str, search_string, index); |
| 763 return *isolate->factory()->ToBoolean(index_in_str != -1); | 767 return *isolate->factory()->ToBoolean(index_in_str != -1); |
| 764 } | 768 } |
| 765 | 769 |
| 766 // ES6 #sec-string.prototype.indexof | 770 void StringBuiltinsAssembler::StringIndexOf( |
| 771 Node* context, Node* receiver, Node* instance_type, Node* search_string, |
| 772 Node* search_string_instance_type, Node* position, |
| 773 std::function<void(Node*)> f_return) { |
| 774 CSA_ASSERT(this, IsString(receiver)); |
| 775 CSA_ASSERT(this, IsString(search_string)); |
| 776 CSA_ASSERT(this, TaggedIsSmi(position)); |
| 777 |
| 778 Label zero_length_needle(this), call_runtime_unchecked(this), |
| 779 return_minus_1(this), check_search_string(this), continue_fast_path(this); |
| 780 |
| 781 Node* needle_length = SmiUntag(LoadStringLength(search_string)); |
| 782 // Use faster/complex runtime fallback for long search strings. |
| 783 GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length), |
| 784 &call_runtime_unchecked); |
| 785 Node* string_length = SmiUntag(LoadStringLength(receiver)); |
| 786 Node* start_position = SmiUntag(position); |
| 787 |
| 788 GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle); |
| 789 // Check that the needle fits in the start position. |
| 790 GotoUnless(IntPtrLessThanOrEqual(needle_length, |
| 791 IntPtrSub(string_length, start_position)), |
| 792 &return_minus_1); |
| 793 // Only support one-byte strings on the fast path. |
| 794 BranchIfSimpleOneByteStringInstanceType(instance_type, &check_search_string, |
| 795 &call_runtime_unchecked); |
| 796 Bind(&check_search_string); |
| 797 BranchIfSimpleOneByteStringInstanceType(search_string_instance_type, |
| 798 &continue_fast_path, |
| 799 &call_runtime_unchecked); |
| 800 Bind(&continue_fast_path); |
| 801 { |
| 802 Node* needle_byte = |
| 803 ChangeInt32ToIntPtr(LoadOneByteChar(search_string, IntPtrConstant(0))); |
| 804 Node* start_address = OneByteCharAddress(receiver, start_position); |
| 805 Node* search_length = IntPtrSub(string_length, start_position); |
| 806 // Call out to the highly optimized memchr to perform the actual byte |
| 807 // search. |
| 808 Node* memchr = |
| 809 ExternalConstant(ExternalReference::libc_memchr_function(isolate())); |
| 810 Node* result_address = |
| 811 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(), |
| 812 MachineType::IntPtr(), MachineType::UintPtr(), memchr, |
| 813 start_address, needle_byte, search_length); |
| 814 GotoIf(WordEqual(result_address, IntPtrConstant(0)), &return_minus_1); |
| 815 Node* result_index = |
| 816 IntPtrAdd(IntPtrSub(result_address, start_address), start_position); |
| 817 f_return(SmiTag(result_index)); |
| 818 } |
| 819 Bind(&return_minus_1); |
| 820 { f_return(SmiConstant(-1)); } |
| 821 Bind(&zero_length_needle); |
| 822 { |
| 823 Comment("0-length search_string"); |
| 824 f_return(SmiTag(IntPtrMin(string_length, start_position))); |
| 825 } |
| 826 Bind(&call_runtime_unchecked); |
| 827 { |
| 828 // Simplified version of the runtime call where the types of the arguments |
| 829 // are already known due to type checks in this stub. |
| 830 Comment("Call Runtime Unchecked"); |
| 831 Node* result = CallRuntime(Runtime::kStringIndexOfUnchecked, context, |
| 832 receiver, search_string, position); |
| 833 f_return(result); |
| 834 } |
| 835 } |
| 836 |
| 837 // ES6 String.prototype.indexOf(searchString [, position]) |
| 838 // #sec-string.prototype.indexof |
| 839 // Unchecked helper for builtins lowering. |
| 840 TF_BUILTIN(StringIndexOf, StringBuiltinsAssembler) { |
| 841 Node* receiver = Parameter(0); |
| 842 Node* search_string = Parameter(1); |
| 843 Node* position = Parameter(2); |
| 844 Node* context = Parameter(BuiltinDescriptor::kContext); |
| 845 |
| 846 Label call_runtime(this); |
| 847 |
| 848 Node* instance_type = LoadInstanceType(receiver); |
| 849 Node* search_string_instance_type = LoadInstanceType(search_string); |
| 850 |
| 851 StringIndexOf(context, receiver, instance_type, search_string, |
| 852 search_string_instance_type, position, [this](Node* result) { |
| 853 this->PopAndReturn(IntPtrConstant(1), result); |
| 854 }); |
| 855 } |
| 856 |
| 857 // ES6 String.prototype.indexOf(searchString [, position]) |
| 858 // #sec-string.prototype.indexof |
| 767 TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) { | 859 TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) { |
| 768 Variable search_string(this, MachineRepresentation::kTagged), | 860 Variable search_string(this, MachineRepresentation::kTagged), |
| 769 position(this, MachineRepresentation::kTagged); | 861 position(this, MachineRepresentation::kTagged); |
| 770 Label call_runtime(this), call_runtime_unchecked(this), argc_0(this), | 862 Label call_runtime(this), call_runtime_unchecked(this), argc_0(this), |
| 771 no_argc_0(this), argc_1(this), no_argc_1(this), argc_2(this), | 863 no_argc_0(this), argc_1(this), no_argc_1(this), argc_2(this), |
| 772 fast_path(this), return_minus_1(this); | 864 fast_path(this), return_minus_1(this); |
| 773 | 865 |
| 774 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); | 866 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); |
| 775 Node* context = Parameter(BuiltinDescriptor::kContext); | 867 Node* context = Parameter(BuiltinDescriptor::kContext); |
| 776 | 868 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 803 search_string.Bind(arguments.AtIndex(0)); | 895 search_string.Bind(arguments.AtIndex(0)); |
| 804 position.Bind(arguments.AtIndex(1)); | 896 position.Bind(arguments.AtIndex(1)); |
| 805 GotoUnless(TaggedIsSmi(position.value()), &call_runtime); | 897 GotoUnless(TaggedIsSmi(position.value()), &call_runtime); |
| 806 position.Bind(SmiMax(position.value(), SmiConstant(0))); | 898 position.Bind(SmiMax(position.value(), SmiConstant(0))); |
| 807 Goto(&fast_path); | 899 Goto(&fast_path); |
| 808 } | 900 } |
| 809 | 901 |
| 810 Bind(&fast_path); | 902 Bind(&fast_path); |
| 811 { | 903 { |
| 812 Comment("Fast Path"); | 904 Comment("Fast Path"); |
| 813 Label zero_length_needle(this); | |
| 814 GotoIf(TaggedIsSmi(receiver), &call_runtime); | 905 GotoIf(TaggedIsSmi(receiver), &call_runtime); |
| 815 Node* needle = search_string.value(); | 906 Node* needle = search_string.value(); |
| 816 GotoIf(TaggedIsSmi(needle), &call_runtime); | 907 GotoIf(TaggedIsSmi(needle), &call_runtime); |
| 908 |
| 817 Node* instance_type = LoadInstanceType(receiver); | 909 Node* instance_type = LoadInstanceType(receiver); |
| 818 GotoUnless(IsStringInstanceType(instance_type), &call_runtime); | 910 GotoUnless(IsStringInstanceType(instance_type), &call_runtime); |
| 819 | 911 |
| 820 Node* needle_instance_type = LoadInstanceType(needle); | 912 Node* needle_instance_type = LoadInstanceType(needle); |
| 821 GotoUnless(IsStringInstanceType(needle_instance_type), &call_runtime); | 913 GotoUnless(IsStringInstanceType(needle_instance_type), &call_runtime); |
| 822 | 914 |
| 823 // At this point we know that the receiver and the needle are Strings and | 915 StringIndexOf( |
| 824 // that position is a Smi. | 916 context, receiver, instance_type, needle, needle_instance_type, |
| 825 | 917 position.value(), |
| 826 Node* needle_length = SmiUntag(LoadStringLength(needle)); | 918 [&arguments](Node* result) { arguments.PopAndReturn(result); }); |
| 827 // Use possibly faster runtime fallback for long search strings. | |
| 828 GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length), | |
| 829 &call_runtime_unchecked); | |
| 830 Node* string_length = SmiUntag(LoadStringLength(receiver)); | |
| 831 Node* start_position = SmiUntag(position.value()); | |
| 832 | |
| 833 GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle); | |
| 834 // Check that the needle fits in the start position. | |
| 835 GotoUnless(IntPtrLessThanOrEqual(needle_length, | |
| 836 IntPtrSub(string_length, start_position)), | |
| 837 &return_minus_1); | |
| 838 // Only support one-byte strings on the fast path. | |
| 839 Label check_needle(this), continue_fast_path(this); | |
| 840 BranchIfSimpleOneByteStringInstanceType(instance_type, &check_needle, | |
| 841 &call_runtime_unchecked); | |
| 842 Bind(&check_needle); | |
| 843 BranchIfSimpleOneByteStringInstanceType( | |
| 844 needle_instance_type, &continue_fast_path, &call_runtime_unchecked); | |
| 845 Bind(&continue_fast_path); | |
| 846 { | |
| 847 Node* needle_byte = | |
| 848 ChangeInt32ToIntPtr(LoadOneByteChar(needle, IntPtrConstant(0))); | |
| 849 Node* start_address = OneByteCharAddress(receiver, start_position); | |
| 850 Node* search_length = IntPtrSub(string_length, start_position); | |
| 851 // Call out to the highly optimized memchr to perform the actual byte | |
| 852 // search. | |
| 853 Node* memchr = | |
| 854 ExternalConstant(ExternalReference::libc_memchr_function(isolate())); | |
| 855 Node* result_address = | |
| 856 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(), | |
| 857 MachineType::IntPtr(), MachineType::UintPtr(), memchr, | |
| 858 start_address, needle_byte, search_length); | |
| 859 GotoIf(WordEqual(result_address, IntPtrConstant(0)), &return_minus_1); | |
| 860 Node* result_index = | |
| 861 IntPtrAdd(IntPtrSub(result_address, start_address), start_position); | |
| 862 arguments.PopAndReturn(SmiTag(result_index)); | |
| 863 } | |
| 864 Bind(&zero_length_needle); | |
| 865 { | |
| 866 Comment("0-length needle"); | |
| 867 arguments.PopAndReturn(SmiTag(IntPtrMin(string_length, start_position))); | |
| 868 } | |
| 869 } | 919 } |
| 870 | 920 |
| 871 Bind(&return_minus_1); | |
| 872 { arguments.PopAndReturn(SmiConstant(-1)); } | |
| 873 | |
| 874 Bind(&call_runtime); | 921 Bind(&call_runtime); |
| 875 { | 922 { |
| 876 Comment("Call Runtime"); | 923 Comment("Call Runtime"); |
| 877 Node* result = CallRuntime(Runtime::kStringIndexOf, context, receiver, | 924 Node* result = CallRuntime(Runtime::kStringIndexOf, context, receiver, |
| 878 search_string.value(), position.value()); | 925 search_string.value(), position.value()); |
| 879 arguments.PopAndReturn(result); | 926 arguments.PopAndReturn(result); |
| 880 } | 927 } |
| 881 | |
| 882 Bind(&call_runtime_unchecked); | |
| 883 { | |
| 884 // Simplified version of the runtime call where the types of the arguments | |
| 885 // are already known due to type checks in this stub. | |
| 886 Comment("Call Runtime Unchecked"); | |
| 887 Node* result = | |
| 888 CallRuntime(Runtime::kStringIndexOfUnchecked, context, receiver, | |
| 889 search_string.value(), position.value()); | |
| 890 arguments.PopAndReturn(result); | |
| 891 } | |
| 892 } | 928 } |
| 893 | 929 |
| 894 // ES6 section 21.1.3.9 | 930 // ES6 section 21.1.3.9 |
| 895 // String.prototype.lastIndexOf ( searchString [ , position ] ) | 931 // String.prototype.lastIndexOf ( searchString [ , position ] ) |
| 896 BUILTIN(StringPrototypeLastIndexOf) { | 932 BUILTIN(StringPrototypeLastIndexOf) { |
| 897 HandleScope handle_scope(isolate); | 933 HandleScope handle_scope(isolate); |
| 898 return String::LastIndexOf(isolate, args.receiver(), | 934 return String::LastIndexOf(isolate, args.receiver(), |
| 899 args.atOrUndefined(isolate, 1), | 935 args.atOrUndefined(isolate, 1), |
| 900 args.atOrUndefined(isolate, 2)); | 936 args.atOrUndefined(isolate, 2)); |
| 901 } | 937 } |
| (...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1442 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, | 1478 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, |
| 1443 HeapConstant(factory()->NewStringFromAsciiChecked( | 1479 HeapConstant(factory()->NewStringFromAsciiChecked( |
| 1444 "String Iterator.prototype.next", TENURED)), | 1480 "String Iterator.prototype.next", TENURED)), |
| 1445 iterator); | 1481 iterator); |
| 1446 Return(result); // Never reached. | 1482 Return(result); // Never reached. |
| 1447 } | 1483 } |
| 1448 } | 1484 } |
| 1449 | 1485 |
| 1450 } // namespace internal | 1486 } // namespace internal |
| 1451 } // namespace v8 | 1487 } // namespace v8 |
| OLD | NEW |