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

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

Issue 2638393002: [builtins] Add String.prototype.indexOf fast path in TF (Closed)
Patch Set: update comments Created 3 years, 11 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
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* 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
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
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
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
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-factory.h » ('j') | src/compiler/js-builtin-reducer.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698