| 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 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |