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* receiver, Node* instance_type, Node* search_string, |
| 65 Node* search_string_instance_type, Node* position, |
| 66 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 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 Handle<Object> position; | 782 Handle<Object> position; |
779 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 783 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
780 isolate, position, | 784 isolate, position, |
781 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2))); | 785 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2))); |
782 | 786 |
783 uint32_t index = str->ToValidIndex(*position); | 787 uint32_t index = str->ToValidIndex(*position); |
784 int index_in_str = String::IndexOf(isolate, str, search_string, index); | 788 int index_in_str = String::IndexOf(isolate, str, search_string, index); |
785 return *isolate->factory()->ToBoolean(index_in_str != -1); | 789 return *isolate->factory()->ToBoolean(index_in_str != -1); |
786 } | 790 } |
787 | 791 |
788 // ES6 #sec-string.prototype.indexof | 792 void StringBuiltinsAssembler::StringIndexOf( |
| 793 Node* receiver, Node* instance_type, Node* search_string, |
| 794 Node* search_string_instance_type, Node* position, |
| 795 std::function<void(Node*)> f_return) { |
| 796 CSA_ASSERT(this, IsString(receiver)); |
| 797 CSA_ASSERT(this, IsString(search_string)); |
| 798 CSA_ASSERT(this, TaggedIsSmi(position)); |
| 799 |
| 800 Label zero_length_needle(this), call_runtime_unchecked(this), |
| 801 return_minus_1(this), check_search_string(this), continue_fast_path(this); |
| 802 |
| 803 Node* needle_length = SmiUntag(LoadStringLength(search_string)); |
| 804 // Use faster/complex runtime fallback for long search strings. |
| 805 GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length), |
| 806 &call_runtime_unchecked); |
| 807 Node* string_length = SmiUntag(LoadStringLength(receiver)); |
| 808 Node* start_position = SmiUntag(position); |
| 809 |
| 810 GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle); |
| 811 // Check that the needle fits in the start position. |
| 812 GotoUnless(IntPtrLessThanOrEqual(needle_length, |
| 813 IntPtrSub(string_length, start_position)), |
| 814 &return_minus_1); |
| 815 // Only support one-byte strings on the fast path. |
| 816 BranchIfSimpleOneByteStringInstanceType(instance_type, &check_search_string, |
| 817 &call_runtime_unchecked); |
| 818 Bind(&check_search_string); |
| 819 BranchIfSimpleOneByteStringInstanceType(search_string_instance_type, |
| 820 &continue_fast_path, |
| 821 &call_runtime_unchecked); |
| 822 Bind(&continue_fast_path); |
| 823 { |
| 824 Node* needle_byte = |
| 825 ChangeInt32ToIntPtr(LoadOneByteChar(search_string, IntPtrConstant(0))); |
| 826 Node* start_address = OneByteCharAddress(receiver, start_position); |
| 827 Node* search_length = IntPtrSub(string_length, start_position); |
| 828 // Call out to the highly optimized memchr to perform the actual byte |
| 829 // search. |
| 830 Node* memchr = |
| 831 ExternalConstant(ExternalReference::libc_memchr_function(isolate())); |
| 832 Node* result_address = |
| 833 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(), |
| 834 MachineType::IntPtr(), MachineType::UintPtr(), memchr, |
| 835 start_address, needle_byte, search_length); |
| 836 GotoIf(WordEqual(result_address, IntPtrConstant(0)), &return_minus_1); |
| 837 Node* result_index = |
| 838 IntPtrAdd(IntPtrSub(result_address, start_address), start_position); |
| 839 f_return(SmiTag(result_index)); |
| 840 } |
| 841 Bind(&return_minus_1); |
| 842 { f_return(SmiConstant(-1)); } |
| 843 Bind(&zero_length_needle); |
| 844 { |
| 845 Comment("0-length search_string"); |
| 846 f_return(SmiTag(IntPtrMin(string_length, start_position))); |
| 847 } |
| 848 Bind(&call_runtime_unchecked); |
| 849 { |
| 850 // Simplified version of the runtime call where the types of the arguments |
| 851 // are already known due to type checks in this stub. |
| 852 Comment("Call Runtime Unchecked"); |
| 853 Node* result = CallRuntime(Runtime::kStringIndexOfUnchecked, SmiConstant(0), |
| 854 receiver, search_string, position); |
| 855 f_return(result); |
| 856 } |
| 857 } |
| 858 |
| 859 // ES6 String.prototype.indexOf(searchString [, position]) |
| 860 // #sec-string.prototype.indexof |
| 861 // Unchecked helper for builtins lowering. |
| 862 TF_BUILTIN(StringIndexOf, StringBuiltinsAssembler) { |
| 863 Node* receiver = Parameter(0); |
| 864 Node* search_string = Parameter(1); |
| 865 Node* position = Parameter(2); |
| 866 |
| 867 Label call_runtime(this); |
| 868 |
| 869 Node* instance_type = LoadInstanceType(receiver); |
| 870 Node* search_string_instance_type = LoadInstanceType(search_string); |
| 871 |
| 872 StringIndexOf(receiver, instance_type, search_string, |
| 873 search_string_instance_type, position, |
| 874 [this](Node* result) { this->Return(result); }); |
| 875 } |
| 876 |
| 877 // ES6 String.prototype.indexOf(searchString [, position]) |
| 878 // #sec-string.prototype.indexof |
789 TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) { | 879 TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) { |
790 Variable search_string(this, MachineRepresentation::kTagged), | 880 Variable search_string(this, MachineRepresentation::kTagged), |
791 position(this, MachineRepresentation::kTagged); | 881 position(this, MachineRepresentation::kTagged); |
792 Label call_runtime(this), call_runtime_unchecked(this), argc_0(this), | 882 Label call_runtime(this), call_runtime_unchecked(this), argc_0(this), |
793 no_argc_0(this), argc_1(this), no_argc_1(this), argc_2(this), | 883 no_argc_0(this), argc_1(this), no_argc_1(this), argc_2(this), |
794 fast_path(this), return_minus_1(this); | 884 fast_path(this), return_minus_1(this); |
795 | 885 |
796 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); | 886 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); |
797 Node* context = Parameter(BuiltinDescriptor::kContext); | 887 Node* context = Parameter(BuiltinDescriptor::kContext); |
798 | 888 |
(...skipping 26 matching lines...) Expand all Loading... |
825 search_string.Bind(arguments.AtIndex(0)); | 915 search_string.Bind(arguments.AtIndex(0)); |
826 position.Bind(arguments.AtIndex(1)); | 916 position.Bind(arguments.AtIndex(1)); |
827 GotoUnless(TaggedIsSmi(position.value()), &call_runtime); | 917 GotoUnless(TaggedIsSmi(position.value()), &call_runtime); |
828 position.Bind(SmiMax(position.value(), SmiConstant(0))); | 918 position.Bind(SmiMax(position.value(), SmiConstant(0))); |
829 Goto(&fast_path); | 919 Goto(&fast_path); |
830 } | 920 } |
831 | 921 |
832 Bind(&fast_path); | 922 Bind(&fast_path); |
833 { | 923 { |
834 Comment("Fast Path"); | 924 Comment("Fast Path"); |
835 Label zero_length_needle(this); | |
836 GotoIf(TaggedIsSmi(receiver), &call_runtime); | 925 GotoIf(TaggedIsSmi(receiver), &call_runtime); |
837 Node* needle = search_string.value(); | 926 Node* needle = search_string.value(); |
838 GotoIf(TaggedIsSmi(needle), &call_runtime); | 927 GotoIf(TaggedIsSmi(needle), &call_runtime); |
| 928 |
839 Node* instance_type = LoadInstanceType(receiver); | 929 Node* instance_type = LoadInstanceType(receiver); |
840 GotoUnless(IsStringInstanceType(instance_type), &call_runtime); | 930 GotoUnless(IsStringInstanceType(instance_type), &call_runtime); |
841 | 931 |
842 Node* needle_instance_type = LoadInstanceType(needle); | 932 Node* needle_instance_type = LoadInstanceType(needle); |
843 GotoUnless(IsStringInstanceType(needle_instance_type), &call_runtime); | 933 GotoUnless(IsStringInstanceType(needle_instance_type), &call_runtime); |
844 | 934 |
845 // At this point we know that the receiver and the needle are Strings and | 935 StringIndexOf( |
846 // that position is a Smi. | 936 receiver, instance_type, needle, needle_instance_type, position.value(), |
847 | 937 [&arguments](Node* result) { arguments.PopAndReturn(result); }); |
848 Node* needle_length = SmiUntag(LoadStringLength(needle)); | |
849 // Use possibly faster runtime fallback for long search strings. | |
850 GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length), | |
851 &call_runtime_unchecked); | |
852 Node* string_length = SmiUntag(LoadStringLength(receiver)); | |
853 Node* start_position = SmiUntag(position.value()); | |
854 | |
855 GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle); | |
856 // Check that the needle fits in the start position. | |
857 GotoUnless(IntPtrLessThanOrEqual(needle_length, | |
858 IntPtrSub(string_length, start_position)), | |
859 &return_minus_1); | |
860 // Only support one-byte strings on the fast path. | |
861 Label check_needle(this), continue_fast_path(this); | |
862 BranchIfSimpleOneByteStringInstanceType(instance_type, &check_needle, | |
863 &call_runtime_unchecked); | |
864 Bind(&check_needle); | |
865 BranchIfSimpleOneByteStringInstanceType( | |
866 needle_instance_type, &continue_fast_path, &call_runtime_unchecked); | |
867 Bind(&continue_fast_path); | |
868 { | |
869 Node* needle_byte = | |
870 ChangeInt32ToIntPtr(LoadOneByteChar(needle, IntPtrConstant(0))); | |
871 Node* start_address = OneByteCharAddress(receiver, start_position); | |
872 Node* search_length = IntPtrSub(string_length, start_position); | |
873 // Call out to the highly optimized memchr to perform the actual byte | |
874 // search. | |
875 Node* memchr = | |
876 ExternalConstant(ExternalReference::libc_memchr_function(isolate())); | |
877 Node* result_address = | |
878 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(), | |
879 MachineType::IntPtr(), MachineType::UintPtr(), memchr, | |
880 start_address, needle_byte, search_length); | |
881 GotoIf(WordEqual(result_address, IntPtrConstant(0)), &return_minus_1); | |
882 Node* result_index = | |
883 IntPtrAdd(IntPtrSub(result_address, start_address), start_position); | |
884 arguments.PopAndReturn(SmiTag(result_index)); | |
885 } | |
886 Bind(&zero_length_needle); | |
887 { | |
888 Comment("0-length needle"); | |
889 arguments.PopAndReturn(SmiTag(IntPtrMin(string_length, start_position))); | |
890 } | |
891 } | 938 } |
892 | 939 |
893 Bind(&return_minus_1); | |
894 { arguments.PopAndReturn(SmiConstant(-1)); } | |
895 | |
896 Bind(&call_runtime); | 940 Bind(&call_runtime); |
897 { | 941 { |
898 Comment("Call Runtime"); | 942 Comment("Call Runtime"); |
899 Node* result = CallRuntime(Runtime::kStringIndexOf, context, receiver, | 943 Node* result = CallRuntime(Runtime::kStringIndexOf, context, receiver, |
900 search_string.value(), position.value()); | 944 search_string.value(), position.value()); |
901 arguments.PopAndReturn(result); | 945 arguments.PopAndReturn(result); |
902 } | 946 } |
903 | |
904 Bind(&call_runtime_unchecked); | |
905 { | |
906 // Simplified version of the runtime call where the types of the arguments | |
907 // are already known due to type checks in this stub. | |
908 Comment("Call Runtime Unchecked"); | |
909 Node* result = | |
910 CallRuntime(Runtime::kStringIndexOfUnchecked, context, receiver, | |
911 search_string.value(), position.value()); | |
912 arguments.PopAndReturn(result); | |
913 } | |
914 } | 947 } |
915 | 948 |
916 // ES6 section 21.1.3.9 | 949 // ES6 section 21.1.3.9 |
917 // String.prototype.lastIndexOf ( searchString [ , position ] ) | 950 // String.prototype.lastIndexOf ( searchString [ , position ] ) |
918 BUILTIN(StringPrototypeLastIndexOf) { | 951 BUILTIN(StringPrototypeLastIndexOf) { |
919 HandleScope handle_scope(isolate); | 952 HandleScope handle_scope(isolate); |
920 return String::LastIndexOf(isolate, args.receiver(), | 953 return String::LastIndexOf(isolate, args.receiver(), |
921 args.atOrUndefined(isolate, 1), | 954 args.atOrUndefined(isolate, 1), |
922 args.atOrUndefined(isolate, 2)); | 955 args.atOrUndefined(isolate, 2)); |
923 } | 956 } |
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1464 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, | 1497 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, |
1465 HeapConstant(factory()->NewStringFromAsciiChecked( | 1498 HeapConstant(factory()->NewStringFromAsciiChecked( |
1466 "String Iterator.prototype.next", TENURED)), | 1499 "String Iterator.prototype.next", TENURED)), |
1467 iterator); | 1500 iterator); |
1468 Return(result); // Never reached. | 1501 Return(result); // Never reached. |
1469 } | 1502 } |
1470 } | 1503 } |
1471 | 1504 |
1472 } // namespace internal | 1505 } // namespace internal |
1473 } // namespace v8 | 1506 } // namespace v8 |
OLD | NEW |