Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: src/builtins/builtins-string.cc

Issue 2638393002: [builtins] Add String.prototype.indexOf fast path in TF (Closed)
Patch Set: hardcode paramater massaging Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-factory.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698