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