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

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

Issue 2539093002: [runtime] Port simple String.prototype.indexOf cases to TF Builtin (Closed)
Patch Set: call runtime for large strings Created 4 years 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.h" 5 #include "src/builtins/builtins.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h"
9 #include "src/regexp/regexp-utils.h" 10 #include "src/regexp/regexp-utils.h"
10 11
11 namespace v8 { 12 namespace v8 {
12 namespace internal { 13 namespace internal {
13 14
14 typedef CodeStubAssembler::ResultMode ResultMode; 15 typedef CodeStubAssembler::ResultMode ResultMode;
15 typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode; 16 typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode;
16 17
18 class StringBuiltinsAssembler : public CodeStubAssembler {
19 public:
20 explicit StringBuiltinsAssembler(compiler::CodeAssemblerState* state)
21 : CodeStubAssembler(state) {}
22
23 protected:
24 Node* LoadOneByteChar(Node* string, Node* index) {
25 return Load(MachineType::Uint8(), string, OneByteCharOffset(index));
26 }
27
28 Node* OneByteCharOffset(Node* index) {
29 return CharOffset(String::ONE_BYTE_ENCODING, index);
30 }
31
32 Node* CharOffset(String::Encoding encoding, Node* index) {
33 const int header = SeqOneByteString::kHeaderSize - kHeapObjectTag;
34 Node* offset = index;
35 if (encoding == String::TWO_BYTE_ENCODING) {
36 offset = IntPtrAddFoldConstants(offset, offset);
37 }
38 offset = IntPtrAddFoldConstants(offset, IntPtrConstant(header));
39 return offset;
40 }
41
42 void BranchIfSimpleOneByteStringInstanceType(Node* instance_type,
Jakob Kummerow 2016/12/06 06:58:40 high-level comment: using bit masks would probably
Camillo Bruni 2016/12/12 15:45:20 Replaced with the simpler version to check with th
43 Label* if_true,
44 Label* if_false) {
45 Label if_not_one_byte_internalize(this);
Jakob Kummerow 2016/12/06 06:58:40 nit: s/internalize/internalized/ (or you can call
46 Branch(IntPtrEqual(instance_type,
Jakob Kummerow 2016/12/06 06:58:40 This should be either Word32Equal/Int32Constant, o
47 Int32Constant(ONE_BYTE_INTERNALIZED_STRING_TYPE)),
48 if_true, &if_not_one_byte_internalize);
49 Bind(&if_not_one_byte_internalize);
50 Branch(IntPtrEqual(instance_type, Int32Constant(ONE_BYTE_STRING_TYPE)),
Jakob Kummerow 2016/12/06 06:58:40 same
51 if_true, if_false);
52 }
53 };
54
17 namespace { 55 namespace {
18 56
19 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) { 57 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
20 // Here's pseudo-code for the algorithm below in case of kDontNegateResult 58 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
21 // mode; for kNegateResult mode we properly negate the result. 59 // mode; for kNegateResult mode we properly negate the result.
22 // 60 //
23 // if (lhs == rhs) return true; 61 // if (lhs == rhs) return true;
24 // if (lhs->length() != rhs->length()) return false; 62 // if (lhs->length() != rhs->length()) return false;
25 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { 63 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
26 // return false; 64 // return false;
(...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 } 599 }
562 600
563 if (value->Number() < 0 || value->Number() > 0x10FFFF) { 601 if (value->Number() < 0 || value->Number() > 0x10FFFF) {
564 return false; 602 return false;
565 } 603 }
566 604
567 return true; 605 return true;
568 } 606 }
569 607
570 uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) { 608 uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) {
571 Handle<Object> value = args.at<Object>(1 + index); 609 Handle<Object> value = args.at(1 + index);
572 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1); 610 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1);
573 if (!IsValidCodePoint(isolate, value)) { 611 if (!IsValidCodePoint(isolate, value)) {
574 isolate->Throw(*isolate->factory()->NewRangeError( 612 isolate->Throw(*isolate->factory()->NewRangeError(
575 MessageTemplate::kInvalidCodePoint, value)); 613 MessageTemplate::kInvalidCodePoint, value));
576 return -1; 614 return -1;
577 } 615 }
578 return DoubleToUint32(value->Number()); 616 return DoubleToUint32(value->Number());
579 } 617 }
580 618
581 } // namespace 619 } // namespace
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2))); 863 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2)));
826 864
827 double index = std::max(position->Number(), 0.0); 865 double index = std::max(position->Number(), 0.0);
828 index = std::min(index, static_cast<double>(str->length())); 866 index = std::min(index, static_cast<double>(str->length()));
829 867
830 int index_in_str = String::IndexOf(isolate, str, search_string, 868 int index_in_str = String::IndexOf(isolate, str, search_string,
831 static_cast<uint32_t>(index)); 869 static_cast<uint32_t>(index));
832 return *isolate->factory()->ToBoolean(index_in_str != -1); 870 return *isolate->factory()->ToBoolean(index_in_str != -1);
833 } 871 }
834 872
835 // ES6 section 21.1.3.8 String.prototype.indexOf ( searchString [ , position ] ) 873 // ES6 #sec-string.prototype.indexof
836 BUILTIN(StringPrototypeIndexOf) { 874 TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) {
837 HandleScope handle_scope(isolate); 875 Variable search_string(this, MachineRepresentation::kTagged),
876 position(this, MachineRepresentation::kTagged);
877 Label call_runtime(this), argc_0(this), no_argc_0(this), argc_1(this),
878 no_argc_1(this), argc_2(this), fast_path(this), return_minus_1(this);
838 879
839 return String::IndexOf(isolate, args.receiver(), 880 // Parameter(0) = nof arguments.
Jakob Kummerow 2016/12/06 06:58:40 nit: this comment doesn't add anything (and runs t
Camillo Bruni 2016/12/12 15:45:20 removed.
840 args.atOrUndefined(isolate, 1), 881 Node* argc =
841 args.atOrUndefined(isolate, 2)); 882 ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
883 Node* context = Parameter(BuiltinDescriptor::kContext);
884
885 CodeStubArguments arguments(this, argc);
886 Node* const receiver = arguments.GetReceiver();
Jakob Kummerow 2016/12/06 06:58:40 Is there a particular reason for the "const" annot
Camillo Bruni 2016/12/12 15:45:20 mostly copy-paste habit, doubt that they will add
887
888 GotoIf(IntPtrEqual(argc, IntPtrConstant(0)), &argc_0);
889 GotoIf(IntPtrEqual(argc, IntPtrConstant(1)), &argc_1);
890 Goto(&argc_2);
891 Bind(&argc_0);
892 {
893 Comment("0 Argument case");
894 Node* const undefined = UndefinedConstant();
895 search_string.Bind(undefined);
896 position.Bind(undefined);
897 Goto(&call_runtime);
898 }
899 Bind(&argc_1);
900 {
901 Comment("1 Argument case");
902 search_string.Bind(arguments.AtIndex(0));
903 position.Bind(SmiConstant(0));
904 Goto(&fast_path);
905 }
906 Bind(&argc_2);
907 {
908 Comment("2 Argument case");
909 search_string.Bind(arguments.AtIndex(0));
910 position.Bind(arguments.AtIndex(1));
911 Goto(&fast_path);
912 }
913
914 Bind(&fast_path);
915 {
916 Label zero_length_needle(this);
917 GotoIf(TaggedIsSmi(receiver), &call_runtime);
918 Node* const instance_type = LoadInstanceType(receiver);
919 GotoUnless(IsStringInstanceType(instance_type), &call_runtime);
920
921 Node* const needle = search_string.value();
922 Node* const needle_instance_type = LoadInstanceType(needle);
923 GotoUnless(IsStringInstanceType(needle_instance_type), &call_runtime);
924 GotoUnless(TaggedIsSmi(position.value()), &call_runtime);
925
926 Node* const needle_length = SmiUntag(LoadStringLength(needle));
927 // Use possibly faster runtime fallback for long search strings.
928 GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length), &call_runtime);
929 Node* const string_length = SmiUntag(LoadStringLength(receiver));
930 Node* const start_position = SmiUntag(position.value());
931
932 GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle);
933 // Check that the needle fits in the start position.
934 GotoUnless(IntPtrLessThanOrEqual(needle_length,
935 IntPtrSub(string_length, start_position)),
936 &return_minus_1);
937 // Only support one-byte strings on the fast path.
938 Label check_needle(this), continue_fast_path(this);
939 BranchIfSimpleOneByteStringInstanceType(instance_type, &check_needle,
Jakob Kummerow 2016/12/06 06:58:40 How important is the zero_length_needle case? You
Camillo Bruni 2016/12/12 15:45:20 Not that important, but it's easy enough to implem
940 &call_runtime);
941 Bind(&check_needle);
942 BranchIfSimpleOneByteStringInstanceType(needle_instance_type,
943 &continue_fast_path, &call_runtime);
944 Bind(&continue_fast_path);
945
946 // Loops over 1-byte strings longer than 32 characters are implemented
947 // faster in C++ making use of faster vector operations.
948 GotoIf(IntPtrGreaterThan(string_length, IntPtrConstant(32)), &call_runtime);
Camillo Bruni 2016/12/05 16:32:33 I tried unrolling a loop of 8 and 16 iterations re
949
950 // Loop over the 1-byte string comparing against the single character of the
951 // needle.
952 MachineType type = MachineType::Uint8();
953 Node* const needle_byte = LoadOneByteChar(needle, IntPtrConstant(0));
954 Node* const start_offset = OneByteCharOffset(start_position);
955 Node* const end_offset = OneByteCharOffset(string_length);
956
957 Variable offset(this, MachineType::PointerRepresentation());
958
959 offset.Bind(start_offset);
960 Label loop(this, &offset), found(this);
961
962 Branch(WordEqual(offset.value(), end_offset), &return_minus_1, &loop);
963 Bind(&loop);
Jakob Kummerow 2016/12/06 06:58:40 Consider using BuildFastLoop().
964 {
965 Node* const byte = Load(type, receiver, offset.value());
966 GotoIf(IntPtrEqual(byte, needle_byte), &found);
Jakob Kummerow 2016/12/06 06:58:40 This should probably be Word32Equal.
967
968 offset.Bind(IntPtrAdd(offset.value(), IntPtrConstant(1)));
969 Branch(WordEqual(offset.value(), end_offset), &return_minus_1, &loop);
970 }
971 Bind(&found);
972 Node* const zero_offset = OneByteCharOffset(IntPtrConstant(0));
973 arguments.PopAndReturn(SmiTag(IntPtrSub(offset.value(), zero_offset)));
974
975 Bind(&zero_length_needle);
976 {
977 arguments.PopAndReturn(SmiTag(IntPtrMin(string_length, start_position)));
978 }
979 }
980
981 Bind(&return_minus_1);
982 { arguments.PopAndReturn(SmiConstant(-1)); }
983
984 Bind(&call_runtime);
985 {
986 Node* result =
987 CallRuntime(Runtime::kStringPrototypeIndexOf, context, receiver,
988 search_string.value(), position.value());
989 arguments.PopAndReturn(result);
990 }
842 } 991 }
843 992
844 // ES6 section 21.1.3.9 993 // ES6 section 21.1.3.9
845 // String.prototype.lastIndexOf ( searchString [ , position ] ) 994 // String.prototype.lastIndexOf ( searchString [ , position ] )
846 BUILTIN(StringPrototypeLastIndexOf) { 995 BUILTIN(StringPrototypeLastIndexOf) {
847 HandleScope handle_scope(isolate); 996 HandleScope handle_scope(isolate);
848 return String::LastIndexOf(isolate, args.receiver(), 997 return String::LastIndexOf(isolate, args.receiver(),
849 args.atOrUndefined(isolate, 1), 998 args.atOrUndefined(isolate, 1),
850 args.atOrUndefined(isolate, 2)); 999 args.atOrUndefined(isolate, 2));
851 } 1000 }
852 1001
853 // ES6 section 21.1.3.10 String.prototype.localeCompare ( that ) 1002 // ES6 section 21.1.3.10 String.prototype.localeCompare ( that )
854 // 1003 //
855 // This function is implementation specific. For now, we do not 1004 // This function is implementation specific. For now, we do not
856 // do anything locale specific. 1005 // do anything locale specific.
857 // If internationalization is enabled, then i18n.js will override this function 1006 // If internationalization is enabled, then i18n.js will override this function
858 // and provide the proper functionality, so this is just a fallback. 1007 // and provide the proper functionality, so this is just a fallback.
859 BUILTIN(StringPrototypeLocaleCompare) { 1008 BUILTIN(StringPrototypeLocaleCompare) {
860 HandleScope handle_scope(isolate); 1009 HandleScope handle_scope(isolate);
861 DCHECK_EQ(2, args.length()); 1010 DCHECK_EQ(2, args.length());
862 1011
863 TO_THIS_STRING(str1, "String.prototype.localeCompare"); 1012 TO_THIS_STRING(str1, "String.prototype.localeCompare");
864 Handle<String> str2; 1013 Handle<String> str2;
865 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1014 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str2,
866 isolate, str2, Object::ToString(isolate, args.at<Object>(1))); 1015 Object::ToString(isolate, args.at(1)));
867 1016
868 if (str1.is_identical_to(str2)) return Smi::kZero; // Equal. 1017 if (str1.is_identical_to(str2)) return Smi::kZero; // Equal.
869 int str1_length = str1->length(); 1018 int str1_length = str1->length();
870 int str2_length = str2->length(); 1019 int str2_length = str2->length();
871 1020
872 // Decide trivial cases without flattening. 1021 // Decide trivial cases without flattening.
873 if (str1_length == 0) { 1022 if (str1_length == 0) {
874 if (str2_length == 0) return Smi::kZero; // Equal. 1023 if (str2_length == 0) return Smi::kZero; // Equal.
875 return Smi::FromInt(-str2_length); 1024 return Smi::FromInt(-str2_length);
876 } else { 1025 } else {
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after
1466 Runtime::kThrowIncompatibleMethodReceiver, context, 1615 Runtime::kThrowIncompatibleMethodReceiver, context,
1467 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( 1616 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked(
1468 "String Iterator.prototype.next", TENURED)), 1617 "String Iterator.prototype.next", TENURED)),
1469 iterator); 1618 iterator);
1470 assembler.Return(result); // Never reached. 1619 assembler.Return(result); // Never reached.
1471 } 1620 }
1472 } 1621 }
1473 1622
1474 } // namespace internal 1623 } // namespace internal
1475 } // namespace v8 1624 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698