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 |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |