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

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

Issue 2539093002: [runtime] Port simple String.prototype.indexOf cases to TF Builtin (Closed)
Patch Set: merging with master 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
« no previous file with comments | « src/builtins/builtins-reflect.cc ('k') | src/builtins/builtins-utils.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
11 namespace v8 { 11 namespace v8 {
12 namespace internal { 12 namespace internal {
13 13
14 typedef CodeStubAssembler::ResultMode ResultMode; 14 typedef CodeStubAssembler::ResultMode ResultMode;
15 typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode; 15 typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode;
16 16
17 class StringBuiltinsAssembler : public CodeStubAssembler {
18 public:
19 explicit StringBuiltinsAssembler(compiler::CodeAssemblerState* state)
20 : CodeStubAssembler(state) {}
21
22 protected:
23 Node* LoadOneByteChar(Node* string, Node* index) {
24 return Load(MachineType::Uint8(), string, OneByteCharOffset(index));
25 }
26
27 Node* OneByteCharAddress(Node* string, Node* index) {
28 Node* offset = OneByteCharOffset(index);
29 return IntPtrAdd(BitcastTaggedToWord(string), offset);
30 }
31
32 Node* OneByteCharOffset(Node* index) {
33 return CharOffset(String::ONE_BYTE_ENCODING, index);
34 }
35
36 Node* CharOffset(String::Encoding encoding, Node* index) {
37 const int header = SeqOneByteString::kHeaderSize - kHeapObjectTag;
38 Node* offset = index;
39 if (encoding == String::TWO_BYTE_ENCODING) {
40 offset = IntPtrAddFoldConstants(offset, offset);
41 }
42 offset = IntPtrAddFoldConstants(offset, IntPtrConstant(header));
43 return offset;
44 }
45
46 void BranchIfSimpleOneByteStringInstanceType(Node* instance_type,
47 Label* if_true,
48 Label* if_false) {
49 const int kMask = kStringRepresentationMask | kStringEncodingMask;
50 const int kType = kOneByteStringTag | kSeqStringTag;
51 Branch(Word32Equal(Word32And(instance_type, Int32Constant(kMask)),
52 Int32Constant(kType)),
53 if_true, if_false);
54 }
55 };
56
17 namespace { 57 namespace {
18 58
19 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) { 59 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
20 // Here's pseudo-code for the algorithm below in case of kDontNegateResult 60 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
21 // mode; for kNegateResult mode we properly negate the result. 61 // mode; for kNegateResult mode we properly negate the result.
22 // 62 //
23 // if (lhs == rhs) return true; 63 // if (lhs == rhs) return true;
24 // if (lhs->length() != rhs->length()) return false; 64 // if (lhs->length() != rhs->length()) return false;
25 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { 65 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
26 // return false; 66 // return false;
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after
560 } 600 }
561 601
562 if (value->Number() < 0 || value->Number() > 0x10FFFF) { 602 if (value->Number() < 0 || value->Number() > 0x10FFFF) {
563 return false; 603 return false;
564 } 604 }
565 605
566 return true; 606 return true;
567 } 607 }
568 608
569 uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) { 609 uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) {
570 Handle<Object> value = args.at<Object>(1 + index); 610 Handle<Object> value = args.at(1 + index);
571 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1); 611 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1);
572 if (!IsValidCodePoint(isolate, value)) { 612 if (!IsValidCodePoint(isolate, value)) {
573 isolate->Throw(*isolate->factory()->NewRangeError( 613 isolate->Throw(*isolate->factory()->NewRangeError(
574 MessageTemplate::kInvalidCodePoint, value)); 614 MessageTemplate::kInvalidCodePoint, value));
575 return -1; 615 return -1;
576 } 616 }
577 return DoubleToUint32(value->Number()); 617 return DoubleToUint32(value->Number());
578 } 618 }
579 619
580 } // namespace 620 } // namespace
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
824 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2))); 864 Object::ToInteger(isolate, args.atOrUndefined(isolate, 2)));
825 865
826 double index = std::max(position->Number(), 0.0); 866 double index = std::max(position->Number(), 0.0);
827 index = std::min(index, static_cast<double>(str->length())); 867 index = std::min(index, static_cast<double>(str->length()));
828 868
829 int index_in_str = String::IndexOf(isolate, str, search_string, 869 int index_in_str = String::IndexOf(isolate, str, search_string,
830 static_cast<uint32_t>(index)); 870 static_cast<uint32_t>(index));
831 return *isolate->factory()->ToBoolean(index_in_str != -1); 871 return *isolate->factory()->ToBoolean(index_in_str != -1);
832 } 872 }
833 873
834 // ES6 section 21.1.3.8 String.prototype.indexOf ( searchString [ , position ] ) 874 // ES6 #sec-string.prototype.indexof
835 BUILTIN(StringPrototypeIndexOf) { 875 TF_BUILTIN(StringPrototypeIndexOf, StringBuiltinsAssembler) {
836 HandleScope handle_scope(isolate); 876 Variable search_string(this, MachineRepresentation::kTagged),
877 position(this, MachineRepresentation::kTagged);
878 Label call_runtime(this), call_runtime_unchecked(this), argc_0(this),
879 no_argc_0(this), argc_1(this), no_argc_1(this), argc_2(this),
880 fast_path(this), return_minus_1(this);
837 881
838 return String::IndexOf(isolate, args.receiver(), 882 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
839 args.atOrUndefined(isolate, 1), 883 Node* context = Parameter(BuiltinDescriptor::kContext);
840 args.atOrUndefined(isolate, 2)); 884
885 CodeStubArguments arguments(this, argc);
886 Node* receiver = arguments.GetReceiver();
887 // From now on use word-size argc value.
888 argc = arguments.GetLength();
889
890 GotoIf(IntPtrEqual(argc, IntPtrConstant(0)), &argc_0);
891 GotoIf(IntPtrEqual(argc, IntPtrConstant(1)), &argc_1);
892 Goto(&argc_2);
893 Bind(&argc_0);
894 {
895 Comment("0 Argument case");
896 Node* undefined = UndefinedConstant();
897 search_string.Bind(undefined);
898 position.Bind(undefined);
899 Goto(&call_runtime);
900 }
901 Bind(&argc_1);
902 {
903 Comment("1 Argument case");
904 search_string.Bind(arguments.AtIndex(0));
905 position.Bind(SmiConstant(0));
906 Goto(&fast_path);
907 }
908 Bind(&argc_2);
909 {
910 Comment("2 Argument case");
911 search_string.Bind(arguments.AtIndex(0));
912 position.Bind(arguments.AtIndex(1));
913 GotoUnless(TaggedIsSmi(position.value()), &call_runtime);
914 Goto(&fast_path);
915 }
916
917 Bind(&fast_path);
918 {
919 Comment("Fast Path");
920 Label zero_length_needle(this);
921 GotoIf(TaggedIsSmi(receiver), &call_runtime);
922 Node* needle = search_string.value();
923 GotoIf(TaggedIsSmi(needle), &call_runtime);
924 Node* instance_type = LoadInstanceType(receiver);
925 GotoUnless(IsStringInstanceType(instance_type), &call_runtime);
926
927 Node* needle_instance_type = LoadInstanceType(needle);
928 GotoUnless(IsStringInstanceType(needle_instance_type), &call_runtime);
929
930 // At this point we know that the receiver and the needle are Strings and
931 // that position is a Smi.
932
933 Node* needle_length = SmiUntag(LoadStringLength(needle));
934 // Use possibly faster runtime fallback for long search strings.
935 GotoIf(IntPtrLessThan(IntPtrConstant(1), needle_length),
936 &call_runtime_unchecked);
937 Node* string_length = SmiUntag(LoadStringLength(receiver));
938 Node* start_position = SmiUntag(position.value());
939
940 GotoIf(IntPtrEqual(IntPtrConstant(0), needle_length), &zero_length_needle);
941 // Check that the needle fits in the start position.
942 GotoUnless(IntPtrLessThanOrEqual(needle_length,
943 IntPtrSub(string_length, start_position)),
944 &return_minus_1);
945 // Only support one-byte strings on the fast path.
946 Label check_needle(this), continue_fast_path(this);
947 BranchIfSimpleOneByteStringInstanceType(instance_type, &check_needle,
948 &call_runtime_unchecked);
949 Bind(&check_needle);
950 BranchIfSimpleOneByteStringInstanceType(
951 needle_instance_type, &continue_fast_path, &call_runtime_unchecked);
952 Bind(&continue_fast_path);
953 {
954 Node* needle_byte =
955 ChangeInt32ToIntPtr(LoadOneByteChar(needle, IntPtrConstant(0)));
956 Node* start_address = OneByteCharAddress(receiver, start_position);
957 Node* search_length = IntPtrSub(string_length, start_position);
958 // Call out to the highly optimized memchr to perform the actual byte
959 // search.
960 Node* memchr =
961 ExternalConstant(ExternalReference::libc_memchr_function(isolate()));
962 Node* result_address =
963 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
964 MachineType::IntPtr(), MachineType::UintPtr(), memchr,
965 start_address, needle_byte, search_length);
966 GotoIf(WordEqual(result_address, IntPtrConstant(0)), &return_minus_1);
967 Node* result_index =
968 IntPtrAdd(IntPtrSub(result_address, start_address), start_position);
969 arguments.PopAndReturn(SmiTag(result_index));
970 }
971 Bind(&zero_length_needle);
972 {
973 Comment("0-length needle");
974 arguments.PopAndReturn(SmiTag(IntPtrMin(string_length, start_position)));
975 }
976 }
977
978 Bind(&return_minus_1);
979 { arguments.PopAndReturn(SmiConstant(-1)); }
980
981 Bind(&call_runtime);
982 {
983 Comment("Call Runtime");
984 Node* result = CallRuntime(Runtime::kStringIndexOf, context, receiver,
985 search_string.value(), position.value());
986 arguments.PopAndReturn(result);
987 }
988
989 Bind(&call_runtime_unchecked);
990 {
991 // Simplified version of the runtime call where the types of the arguments
992 // are already known due to type checks in this stub.
993 Comment("Call Runtime Unchecked");
994 Node* result =
995 CallRuntime(Runtime::kStringIndexOfUnchecked, context, receiver,
996 search_string.value(), position.value());
997 arguments.PopAndReturn(result);
998 }
841 } 999 }
842 1000
843 // ES6 section 21.1.3.9 1001 // ES6 section 21.1.3.9
844 // String.prototype.lastIndexOf ( searchString [ , position ] ) 1002 // String.prototype.lastIndexOf ( searchString [ , position ] )
845 BUILTIN(StringPrototypeLastIndexOf) { 1003 BUILTIN(StringPrototypeLastIndexOf) {
846 HandleScope handle_scope(isolate); 1004 HandleScope handle_scope(isolate);
847 return String::LastIndexOf(isolate, args.receiver(), 1005 return String::LastIndexOf(isolate, args.receiver(),
848 args.atOrUndefined(isolate, 1), 1006 args.atOrUndefined(isolate, 1),
849 args.atOrUndefined(isolate, 2)); 1007 args.atOrUndefined(isolate, 2));
850 } 1008 }
851 1009
852 // ES6 section 21.1.3.10 String.prototype.localeCompare ( that ) 1010 // ES6 section 21.1.3.10 String.prototype.localeCompare ( that )
853 // 1011 //
854 // This function is implementation specific. For now, we do not 1012 // This function is implementation specific. For now, we do not
855 // do anything locale specific. 1013 // do anything locale specific.
856 // If internationalization is enabled, then i18n.js will override this function 1014 // If internationalization is enabled, then i18n.js will override this function
857 // and provide the proper functionality, so this is just a fallback. 1015 // and provide the proper functionality, so this is just a fallback.
858 BUILTIN(StringPrototypeLocaleCompare) { 1016 BUILTIN(StringPrototypeLocaleCompare) {
859 HandleScope handle_scope(isolate); 1017 HandleScope handle_scope(isolate);
860 DCHECK_EQ(2, args.length()); 1018 DCHECK_EQ(2, args.length());
861 1019
862 TO_THIS_STRING(str1, "String.prototype.localeCompare"); 1020 TO_THIS_STRING(str1, "String.prototype.localeCompare");
863 Handle<String> str2; 1021 Handle<String> str2;
864 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1022 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str2,
865 isolate, str2, Object::ToString(isolate, args.at<Object>(1))); 1023 Object::ToString(isolate, args.at(1)));
866 1024
867 if (str1.is_identical_to(str2)) return Smi::kZero; // Equal. 1025 if (str1.is_identical_to(str2)) return Smi::kZero; // Equal.
868 int str1_length = str1->length(); 1026 int str1_length = str1->length();
869 int str2_length = str2->length(); 1027 int str2_length = str2->length();
870 1028
871 // Decide trivial cases without flattening. 1029 // Decide trivial cases without flattening.
872 if (str1_length == 0) { 1030 if (str1_length == 0) {
873 if (str2_length == 0) return Smi::kZero; // Equal. 1031 if (str2_length == 0) return Smi::kZero; // Equal.
874 return Smi::FromInt(-str2_length); 1032 return Smi::FromInt(-str2_length);
875 } else { 1033 } else {
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after
1462 Runtime::kThrowIncompatibleMethodReceiver, context, 1620 Runtime::kThrowIncompatibleMethodReceiver, context,
1463 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( 1621 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked(
1464 "String Iterator.prototype.next", TENURED)), 1622 "String Iterator.prototype.next", TENURED)),
1465 iterator); 1623 iterator);
1466 assembler.Return(result); // Never reached. 1624 assembler.Return(result); // Never reached.
1467 } 1625 }
1468 } 1626 }
1469 1627
1470 } // namespace internal 1628 } // namespace internal
1471 } // namespace v8 1629 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-reflect.cc ('k') | src/builtins/builtins-utils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698