OLD | NEW |
---|---|
1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 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-regexp-gen.h" | 5 #include "src/builtins/builtins-regexp-gen.h" |
6 | 6 |
7 #include "src/builtins/builtins-constructor-gen.h" | 7 #include "src/builtins/builtins-constructor-gen.h" |
8 #include "src/builtins/builtins-utils-gen.h" | 8 #include "src/builtins/builtins-utils-gen.h" |
9 #include "src/builtins/builtins.h" | 9 #include "src/builtins/builtins.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
93 | 93 |
94 StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER); | 94 StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER); |
95 | 95 |
96 // If no captures exist we can skip named capture handling as well. | 96 // If no captures exist we can skip named capture handling as well. |
97 GotoIf(SmiEqual(num_results, SmiConstant(1)), &out); | 97 GotoIf(SmiEqual(num_results, SmiConstant(1)), &out); |
98 | 98 |
99 // Store all remaining captures. | 99 // Store all remaining captures. |
100 Node* const limit = IntPtrAdd( | 100 Node* const limit = IntPtrAdd( |
101 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); | 101 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); |
102 | 102 |
103 Variable var_from_cursor( | 103 VARIABLE(var_from_cursor, MachineType::PointerRepresentation(), |
104 this, MachineType::PointerRepresentation(), | 104 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); |
105 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); | |
106 VARIABLE(var_to_cursor, MachineType::PointerRepresentation(), | 105 VARIABLE(var_to_cursor, MachineType::PointerRepresentation(), |
107 IntPtrConstant(1)); | 106 IntPtrConstant(1)); |
108 | 107 |
109 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; | 108 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; |
110 Label loop(this, 2, vars); | 109 Label loop(this, 2, vars); |
111 | 110 |
112 Goto(&loop); | 111 Goto(&loop); |
113 BIND(&loop); | 112 BIND(&loop); |
114 { | 113 { |
115 Node* const from_cursor = var_from_cursor.value(); | 114 Node* const from_cursor = var_from_cursor.value(); |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
479 // match) or a fixed array containing match indices as returned by | 478 // match) or a fixed array containing match indices as returned by |
480 // RegExpExecStub. | 479 // RegExpExecStub. |
481 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( | 480 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( |
482 Node* const context, Node* const regexp, Node* const string, | 481 Node* const context, Node* const regexp, Node* const string, |
483 Label* if_didnotmatch, const bool is_fastpath) { | 482 Label* if_didnotmatch, const bool is_fastpath) { |
484 Node* const null = NullConstant(); | 483 Node* const null = NullConstant(); |
485 Node* const int_zero = IntPtrConstant(0); | 484 Node* const int_zero = IntPtrConstant(0); |
486 Node* const smi_zero = SmiConstant(Smi::kZero); | 485 Node* const smi_zero = SmiConstant(Smi::kZero); |
487 | 486 |
488 if (is_fastpath) { | 487 if (is_fastpath) { |
489 CSA_ASSERT(this, IsFastRegExpNoPrototype(context, regexp, LoadMap(regexp))); | 488 CSA_ASSERT(this, IsFastRegExpNoPrototype(context, regexp)); |
490 } else { | 489 } else { |
491 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, | 490 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, |
492 "RegExp.prototype.exec"); | 491 "RegExp.prototype.exec"); |
493 } | 492 } |
494 | 493 |
495 CSA_ASSERT(this, IsString(string)); | 494 CSA_ASSERT(this, IsString(string)); |
496 CSA_ASSERT(this, IsJSRegExp(regexp)); | 495 CSA_ASSERT(this, IsJSRegExp(regexp)); |
497 | 496 |
498 VARIABLE(var_result, MachineRepresentation::kTagged); | 497 VARIABLE(var_result, MachineRepresentation::kTagged); |
499 Label out(this); | 498 Label out(this); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
687 // The smi check is required to omit ToLength(lastIndex) calls with possible | 686 // The smi check is required to omit ToLength(lastIndex) calls with possible |
688 // user-code execution on the fast path. | 687 // user-code execution on the fast path. |
689 Node* const last_index = FastLoadLastIndex(object); | 688 Node* const last_index = FastLoadLastIndex(object); |
690 var_result.Bind(TaggedIsPositiveSmi(last_index)); | 689 var_result.Bind(TaggedIsPositiveSmi(last_index)); |
691 Goto(&out); | 690 Goto(&out); |
692 | 691 |
693 BIND(&out); | 692 BIND(&out); |
694 return var_result.value(); | 693 return var_result.value(); |
695 } | 694 } |
696 | 695 |
696 Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(Node* const context, | |
697 Node* const object) { | |
698 CSA_ASSERT(this, TaggedIsNotSmi(object)); | |
Camillo Bruni
2017/04/11 09:21:13
Probably even: IsJSReceiver(object)
jgruber
2017/04/11 09:57:24
All I want to assert here is that we can load a ma
| |
699 return IsFastRegExpNoPrototype(context, object, LoadMap(object)); | |
700 } | |
701 | |
697 // RegExp fast path implementations rely on unmodified JSRegExp instances. | 702 // RegExp fast path implementations rely on unmodified JSRegExp instances. |
698 // We use a fairly coarse granularity for this and simply check whether both | 703 // We use a fairly coarse granularity for this and simply check whether both |
699 // the regexp itself is unmodified (i.e. its map has not changed), its | 704 // the regexp itself is unmodified (i.e. its map has not changed), its |
700 // prototype is unmodified, and lastIndex is a non-negative smi. | 705 // prototype is unmodified, and lastIndex is a non-negative smi. |
701 void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context, | 706 void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context, |
702 Node* const object, | 707 Node* const object, |
703 Node* const map, | 708 Node* const map, |
704 Label* const if_isunmodified, | 709 Label* const if_isunmodified, |
705 Label* const if_ismodified) { | 710 Label* const if_ismodified) { |
706 CSA_ASSERT(this, WordEqual(LoadMap(object), map)); | 711 CSA_ASSERT(this, WordEqual(LoadMap(object), map)); |
(...skipping 17 matching lines...) Expand all Loading... | |
724 WordEqual(proto_map, initial_proto_initial_map); | 729 WordEqual(proto_map, initial_proto_initial_map); |
725 | 730 |
726 GotoIfNot(proto_has_initialmap, if_ismodified); | 731 GotoIfNot(proto_has_initialmap, if_ismodified); |
727 | 732 |
728 // The smi check is required to omit ToLength(lastIndex) calls with possible | 733 // The smi check is required to omit ToLength(lastIndex) calls with possible |
729 // user-code execution on the fast path. | 734 // user-code execution on the fast path. |
730 Node* const last_index = FastLoadLastIndex(object); | 735 Node* const last_index = FastLoadLastIndex(object); |
731 Branch(TaggedIsPositiveSmi(last_index), if_isunmodified, if_ismodified); | 736 Branch(TaggedIsPositiveSmi(last_index), if_isunmodified, if_ismodified); |
732 } | 737 } |
733 | 738 |
739 void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context, | |
740 Node* const object, | |
741 Label* const if_isunmodified, | |
742 Label* const if_ismodified) { | |
743 CSA_ASSERT(this, TaggedIsNotSmi(object)); | |
Camillo Bruni
2017/04/11 09:21:13
same here
| |
744 BranchIfFastRegExp(context, object, LoadMap(object), if_isunmodified, | |
745 if_ismodified); | |
746 } | |
747 | |
734 Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context, | 748 Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context, |
735 Node* const object) { | 749 Node* const object) { |
736 Label yup(this), nope(this), out(this); | 750 Label yup(this), nope(this), out(this); |
737 VARIABLE(var_result, MachineRepresentation::kWord32); | 751 VARIABLE(var_result, MachineRepresentation::kWord32); |
738 | 752 |
739 BranchIfFastRegExp(context, object, LoadMap(object), &yup, &nope); | 753 BranchIfFastRegExp(context, object, &yup, &nope); |
740 | 754 |
741 BIND(&yup); | 755 BIND(&yup); |
742 var_result.Bind(Int32Constant(1)); | 756 var_result.Bind(Int32Constant(1)); |
743 Goto(&out); | 757 Goto(&out); |
744 | 758 |
745 BIND(&nope); | 759 BIND(&nope); |
746 var_result.Bind(Int32Constant(0)); | 760 var_result.Bind(Int32Constant(0)); |
747 Goto(&out); | 761 Goto(&out); |
748 | 762 |
749 BIND(&out); | 763 BIND(&out); |
750 return var_result.value(); | 764 return var_result.value(); |
751 } | 765 } |
752 | 766 |
753 void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* context, Node* map, | 767 void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* const context, |
768 Node* const object, | |
754 Label* if_isunmodified, | 769 Label* if_isunmodified, |
755 Label* if_ismodified) { | 770 Label* if_ismodified) { |
771 // Could be a Smi. | |
772 Node* const map = LoadReceiverMap(object); | |
773 | |
756 Node* const native_context = LoadNativeContext(context); | 774 Node* const native_context = LoadNativeContext(context); |
757 Node* const initial_regexp_result_map = | 775 Node* const initial_regexp_result_map = |
758 LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | 776 LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
759 | 777 |
760 Branch(WordEqual(map, initial_regexp_result_map), if_isunmodified, | 778 Branch(WordEqual(map, initial_regexp_result_map), if_isunmodified, |
761 if_ismodified); | 779 if_ismodified); |
762 } | 780 } |
763 | 781 |
764 // Slow path stub for RegExpPrototypeExec to decrease code size. | 782 // Slow path stub for RegExpPrototypeExec to decrease code size. |
765 TF_BUILTIN(RegExpPrototypeExecSlow, RegExpBuiltinsAssembler) { | 783 TF_BUILTIN(RegExpPrototypeExecSlow, RegExpBuiltinsAssembler) { |
(...skipping 13 matching lines...) Expand all Loading... | |
779 | 797 |
780 // Ensure {maybe_receiver} is a JSRegExp. | 798 // Ensure {maybe_receiver} is a JSRegExp. |
781 ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE, | 799 ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE, |
782 "RegExp.prototype.exec"); | 800 "RegExp.prototype.exec"); |
783 Node* const receiver = maybe_receiver; | 801 Node* const receiver = maybe_receiver; |
784 | 802 |
785 // Convert {maybe_string} to a String. | 803 // Convert {maybe_string} to a String. |
786 Node* const string = ToString(context, maybe_string); | 804 Node* const string = ToString(context, maybe_string); |
787 | 805 |
788 Label if_isfastpath(this), if_isslowpath(this); | 806 Label if_isfastpath(this), if_isslowpath(this); |
789 Branch(IsFastRegExpNoPrototype(context, receiver, LoadMap(receiver)), | 807 Branch(IsFastRegExpNoPrototype(context, receiver), &if_isfastpath, |
790 &if_isfastpath, &if_isslowpath); | 808 &if_isslowpath); |
791 | 809 |
792 BIND(&if_isfastpath); | 810 BIND(&if_isfastpath); |
793 { | 811 { |
794 Node* const result = | 812 Node* const result = |
795 RegExpPrototypeExecBody(context, receiver, string, true); | 813 RegExpPrototypeExecBody(context, receiver, string, true); |
796 Return(result); | 814 Return(result); |
797 } | 815 } |
798 | 816 |
799 BIND(&if_isslowpath); | 817 BIND(&if_isslowpath); |
800 { | 818 { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
883 #undef CASE_FOR_FLAG | 901 #undef CASE_FOR_FLAG |
884 } | 902 } |
885 | 903 |
886 // Allocate a string of the required length and fill it with the corresponding | 904 // Allocate a string of the required length and fill it with the corresponding |
887 // char for each set flag. | 905 // char for each set flag. |
888 | 906 |
889 { | 907 { |
890 Node* const result = AllocateSeqOneByteString(context, var_length.value()); | 908 Node* const result = AllocateSeqOneByteString(context, var_length.value()); |
891 Node* const flags_intptr = var_flags.value(); | 909 Node* const flags_intptr = var_flags.value(); |
892 | 910 |
893 Variable var_offset( | 911 VARIABLE(var_offset, MachineType::PointerRepresentation(), |
894 this, MachineType::PointerRepresentation(), | 912 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
895 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
896 | 913 |
897 #define CASE_FOR_FLAG(FLAG, CHAR) \ | 914 #define CASE_FOR_FLAG(FLAG, CHAR) \ |
898 do { \ | 915 do { \ |
899 Label next(this); \ | 916 Label next(this); \ |
900 GotoIfNot(IsSetWord(flags_intptr, FLAG), &next); \ | 917 GotoIfNot(IsSetWord(flags_intptr, FLAG), &next); \ |
901 Node* const value = Int32Constant(CHAR); \ | 918 Node* const value = Int32Constant(CHAR); \ |
902 StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ | 919 StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ |
903 var_offset.value(), value); \ | 920 var_offset.value(), value); \ |
904 var_offset.Bind(IntPtrAdd(var_offset.value(), int_one)); \ | 921 var_offset.Bind(IntPtrAdd(var_offset.value(), int_one)); \ |
905 Goto(&next); \ | 922 Goto(&next); \ |
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1494 // Ensure {maybe_receiver} is a JSReceiver. | 1511 // Ensure {maybe_receiver} is a JSReceiver. |
1495 ThrowIfNotJSReceiver(context, maybe_receiver, | 1512 ThrowIfNotJSReceiver(context, maybe_receiver, |
1496 MessageTemplate::kIncompatibleMethodReceiver, | 1513 MessageTemplate::kIncompatibleMethodReceiver, |
1497 "RegExp.prototype.test"); | 1514 "RegExp.prototype.test"); |
1498 Node* const receiver = maybe_receiver; | 1515 Node* const receiver = maybe_receiver; |
1499 | 1516 |
1500 // Convert {maybe_string} to a String. | 1517 // Convert {maybe_string} to a String. |
1501 Node* const string = ToString(context, maybe_string); | 1518 Node* const string = ToString(context, maybe_string); |
1502 | 1519 |
1503 Label fast_path(this), slow_path(this); | 1520 Label fast_path(this), slow_path(this); |
1504 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path, | 1521 BranchIfFastRegExp(context, receiver, &fast_path, &slow_path); |
1505 &slow_path); | |
1506 | 1522 |
1507 BIND(&fast_path); | 1523 BIND(&fast_path); |
1508 { | 1524 { |
1509 Label if_didnotmatch(this); | 1525 Label if_didnotmatch(this); |
1510 RegExpPrototypeExecBodyWithoutResult(context, receiver, string, | 1526 RegExpPrototypeExecBodyWithoutResult(context, receiver, string, |
1511 &if_didnotmatch, true); | 1527 &if_didnotmatch, true); |
1512 Return(TrueConstant()); | 1528 Return(TrueConstant()); |
1513 | 1529 |
1514 BIND(&if_didnotmatch); | 1530 BIND(&if_didnotmatch); |
1515 Return(FalseConstant()); | 1531 Return(FalseConstant()); |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1809 } else { | 1825 } else { |
1810 DCHECK(!is_fastpath); | 1826 DCHECK(!is_fastpath); |
1811 Node* const result = RegExpExec(context, regexp, string); | 1827 Node* const result = RegExpExec(context, regexp, string); |
1812 | 1828 |
1813 Label load_match(this); | 1829 Label load_match(this); |
1814 Branch(WordEqual(result, null), &if_didnotmatch, &load_match); | 1830 Branch(WordEqual(result, null), &if_didnotmatch, &load_match); |
1815 | 1831 |
1816 BIND(&load_match); | 1832 BIND(&load_match); |
1817 { | 1833 { |
1818 Label fast_result(this), slow_result(this); | 1834 Label fast_result(this), slow_result(this); |
1819 BranchIfFastRegExpResult(context, LoadMap(result), &fast_result, | 1835 BranchIfFastRegExpResult(context, result, &fast_result, &slow_result); |
1820 &slow_result); | |
1821 | 1836 |
1822 BIND(&fast_result); | 1837 BIND(&fast_result); |
1823 { | 1838 { |
1824 Node* const result_fixed_array = LoadElements(result); | 1839 Node* const result_fixed_array = LoadElements(result); |
1825 Node* const match = LoadFixedArrayElement(result_fixed_array, 0); | 1840 Node* const match = LoadFixedArrayElement(result_fixed_array, 0); |
1826 | 1841 |
1827 // The match is guaranteed to be a string on the fast path. | 1842 // The match is guaranteed to be a string on the fast path. |
1828 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(match))); | 1843 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(match))); |
1829 | 1844 |
1830 var_match.Bind(match); | 1845 var_match.Bind(match); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1905 // Ensure {maybe_receiver} is a JSReceiver. | 1920 // Ensure {maybe_receiver} is a JSReceiver. |
1906 ThrowIfNotJSReceiver(context, maybe_receiver, | 1921 ThrowIfNotJSReceiver(context, maybe_receiver, |
1907 MessageTemplate::kIncompatibleMethodReceiver, | 1922 MessageTemplate::kIncompatibleMethodReceiver, |
1908 "RegExp.prototype.@@match"); | 1923 "RegExp.prototype.@@match"); |
1909 Node* const receiver = maybe_receiver; | 1924 Node* const receiver = maybe_receiver; |
1910 | 1925 |
1911 // Convert {maybe_string} to a String. | 1926 // Convert {maybe_string} to a String. |
1912 Node* const string = ToString(context, maybe_string); | 1927 Node* const string = ToString(context, maybe_string); |
1913 | 1928 |
1914 Label fast_path(this), slow_path(this); | 1929 Label fast_path(this), slow_path(this); |
1915 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path, | 1930 BranchIfFastRegExp(context, receiver, &fast_path, &slow_path); |
1916 &slow_path); | |
1917 | 1931 |
1918 BIND(&fast_path); | 1932 BIND(&fast_path); |
1919 RegExpPrototypeMatchBody(context, receiver, string, true); | 1933 RegExpPrototypeMatchBody(context, receiver, string, true); |
1920 | 1934 |
1921 BIND(&slow_path); | 1935 BIND(&slow_path); |
1922 RegExpPrototypeMatchBody(context, receiver, string, false); | 1936 RegExpPrototypeMatchBody(context, receiver, string, false); |
1923 } | 1937 } |
1924 | 1938 |
1925 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast( | 1939 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast( |
1926 Node* const context, Node* const regexp, Node* const string) { | 1940 Node* const context, Node* const regexp, Node* const string) { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1999 { | 2013 { |
2000 Label next(this); | 2014 Label next(this); |
2001 GotoIfNot(WordEqual(exec_result, NullConstant()), &next); | 2015 GotoIfNot(WordEqual(exec_result, NullConstant()), &next); |
2002 Return(SmiConstant(-1)); | 2016 Return(SmiConstant(-1)); |
2003 BIND(&next); | 2017 BIND(&next); |
2004 } | 2018 } |
2005 | 2019 |
2006 // Return the index of the match. | 2020 // Return the index of the match. |
2007 { | 2021 { |
2008 Label fast_result(this), slow_result(this, Label::kDeferred); | 2022 Label fast_result(this), slow_result(this, Label::kDeferred); |
2009 BranchIfFastRegExpResult(context, LoadMap(exec_result), &fast_result, | 2023 BranchIfFastRegExpResult(context, exec_result, &fast_result, &slow_result); |
2010 &slow_result); | |
2011 | 2024 |
2012 BIND(&fast_result); | 2025 BIND(&fast_result); |
2013 { | 2026 { |
2014 Node* const index = | 2027 Node* const index = |
2015 LoadObjectField(exec_result, JSRegExpResult::kIndexOffset); | 2028 LoadObjectField(exec_result, JSRegExpResult::kIndexOffset); |
2016 Return(index); | 2029 Return(index); |
2017 } | 2030 } |
2018 | 2031 |
2019 BIND(&slow_result); | 2032 BIND(&slow_result); |
2020 { | 2033 { |
(...skipping 13 matching lines...) Expand all Loading... | |
2034 // Ensure {maybe_receiver} is a JSReceiver. | 2047 // Ensure {maybe_receiver} is a JSReceiver. |
2035 ThrowIfNotJSReceiver(context, maybe_receiver, | 2048 ThrowIfNotJSReceiver(context, maybe_receiver, |
2036 MessageTemplate::kIncompatibleMethodReceiver, | 2049 MessageTemplate::kIncompatibleMethodReceiver, |
2037 "RegExp.prototype.@@search"); | 2050 "RegExp.prototype.@@search"); |
2038 Node* const receiver = maybe_receiver; | 2051 Node* const receiver = maybe_receiver; |
2039 | 2052 |
2040 // Convert {maybe_string} to a String. | 2053 // Convert {maybe_string} to a String. |
2041 Node* const string = ToString(context, maybe_string); | 2054 Node* const string = ToString(context, maybe_string); |
2042 | 2055 |
2043 Label fast_path(this), slow_path(this); | 2056 Label fast_path(this), slow_path(this); |
2044 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path, | 2057 BranchIfFastRegExp(context, receiver, &fast_path, &slow_path); |
2045 &slow_path); | |
2046 | 2058 |
2047 BIND(&fast_path); | 2059 BIND(&fast_path); |
2048 RegExpPrototypeSearchBodyFast(context, receiver, string); | 2060 RegExpPrototypeSearchBodyFast(context, receiver, string); |
2049 | 2061 |
2050 BIND(&slow_path); | 2062 BIND(&slow_path); |
2051 RegExpPrototypeSearchBodySlow(context, receiver, string); | 2063 RegExpPrototypeSearchBodySlow(context, receiver, string); |
2052 } | 2064 } |
2053 | 2065 |
2054 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, | 2066 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, |
2055 // {string} is a String, and {limit} is a Smi. | 2067 // {string} is a String, and {limit} is a Smi. |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2321 GotoIf(IsUndefined(maybe_limit), &if_limitissmimax); | 2333 GotoIf(IsUndefined(maybe_limit), &if_limitissmimax); |
2322 GotoIf(TaggedIsPositiveSmi(maybe_limit), &limit_done); | 2334 GotoIf(TaggedIsPositiveSmi(maybe_limit), &limit_done); |
2323 | 2335 |
2324 Node* const limit = ToUint32(context, maybe_limit); | 2336 Node* const limit = ToUint32(context, maybe_limit); |
2325 { | 2337 { |
2326 // ToUint32(limit) could potentially change the shape of the RegExp | 2338 // ToUint32(limit) could potentially change the shape of the RegExp |
2327 // object. Recheck that we are still on the fast path and bail to runtime | 2339 // object. Recheck that we are still on the fast path and bail to runtime |
2328 // otherwise. | 2340 // otherwise. |
2329 { | 2341 { |
2330 Label next(this); | 2342 Label next(this); |
2331 BranchIfFastRegExp(context, regexp, LoadMap(regexp), &next, &runtime); | 2343 BranchIfFastRegExp(context, regexp, &next, &runtime); |
2332 Bind(&next); | 2344 BIND(&next); |
2333 } | 2345 } |
2334 | 2346 |
2335 GotoIfNot(TaggedIsSmi(limit), &if_limitissmimax); | 2347 GotoIfNot(TaggedIsSmi(limit), &if_limitissmimax); |
2336 | 2348 |
2337 var_limit.Bind(limit); | 2349 var_limit.Bind(limit); |
2338 Goto(&limit_done); | 2350 Goto(&limit_done); |
2339 } | 2351 } |
2340 | 2352 |
2341 BIND(&if_limitissmimax); | 2353 BIND(&if_limitissmimax); |
2342 { | 2354 { |
2343 // TODO(jgruber): In this case, we can probably avoid generation of limit | 2355 // TODO(jgruber): In this case, we can probably avoid generation of limit |
2344 // checks in Generate_RegExpPrototypeSplitBody. | 2356 // checks in Generate_RegExpPrototypeSplitBody. |
2345 var_limit.Bind(SmiConstant(Smi::kMaxValue)); | 2357 var_limit.Bind(SmiConstant(Smi::kMaxValue)); |
2346 Goto(&limit_done); | 2358 Goto(&limit_done); |
2347 } | 2359 } |
2348 | 2360 |
2349 BIND(&limit_done); | 2361 BIND(&limit_done); |
2350 { | 2362 { |
2351 Node* const limit = var_limit.value(); | 2363 Node* const limit = var_limit.value(); |
2352 RegExpPrototypeSplitBody(context, regexp, string, limit); | 2364 RegExpPrototypeSplitBody(context, regexp, string, limit); |
2353 } | 2365 } |
2354 | 2366 |
2355 Bind(&runtime); | 2367 BIND(&runtime); |
2356 { | 2368 { |
2357 // The runtime call passes in limit to ensure the second ToUint32(limit) | 2369 // The runtime call passes in limit to ensure the second ToUint32(limit) |
2358 // call is not observable. | 2370 // call is not observable. |
2359 CSA_ASSERT(this, IsHeapNumberMap(LoadReceiverMap(limit))); | 2371 CSA_ASSERT(this, IsHeapNumberMap(LoadReceiverMap(limit))); |
2360 Return(CallRuntime(Runtime::kRegExpSplit, context, regexp, string, limit)); | 2372 Return(CallRuntime(Runtime::kRegExpSplit, context, regexp, string, limit)); |
2361 } | 2373 } |
2362 } | 2374 } |
2363 | 2375 |
2364 // ES#sec-regexp.prototype-@@split | 2376 // ES#sec-regexp.prototype-@@split |
2365 // RegExp.prototype [ @@split ] ( string, limit ) | 2377 // RegExp.prototype [ @@split ] ( string, limit ) |
2366 TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) { | 2378 TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) { |
2367 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); | 2379 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); |
2368 Node* const maybe_string = Parameter(Descriptor::kString); | 2380 Node* const maybe_string = Parameter(Descriptor::kString); |
2369 Node* const maybe_limit = Parameter(Descriptor::kLimit); | 2381 Node* const maybe_limit = Parameter(Descriptor::kLimit); |
2370 Node* const context = Parameter(Descriptor::kContext); | 2382 Node* const context = Parameter(Descriptor::kContext); |
2371 | 2383 |
2372 // Ensure {maybe_receiver} is a JSReceiver. | 2384 // Ensure {maybe_receiver} is a JSReceiver. |
2373 ThrowIfNotJSReceiver(context, maybe_receiver, | 2385 ThrowIfNotJSReceiver(context, maybe_receiver, |
2374 MessageTemplate::kIncompatibleMethodReceiver, | 2386 MessageTemplate::kIncompatibleMethodReceiver, |
2375 "RegExp.prototype.@@split"); | 2387 "RegExp.prototype.@@split"); |
2376 Node* const receiver = maybe_receiver; | 2388 Node* const receiver = maybe_receiver; |
2377 | 2389 |
2378 // Convert {maybe_string} to a String. | 2390 // Convert {maybe_string} to a String. |
2379 Node* const string = ToString(context, maybe_string); | 2391 Node* const string = ToString(context, maybe_string); |
2380 | 2392 |
2381 Label stub(this), runtime(this, Label::kDeferred); | 2393 Label stub(this), runtime(this, Label::kDeferred); |
2382 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &stub, &runtime); | 2394 BranchIfFastRegExp(context, receiver, &stub, &runtime); |
2383 | 2395 |
2384 BIND(&stub); | 2396 BIND(&stub); |
2385 Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, | 2397 Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, |
2386 maybe_limit)); | 2398 maybe_limit)); |
2387 | 2399 |
2388 BIND(&runtime); | 2400 BIND(&runtime); |
2389 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, | 2401 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, |
2390 maybe_limit)); | 2402 maybe_limit)); |
2391 } | 2403 } |
2392 | 2404 |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2728 BIND(&checkreplacestring); | 2740 BIND(&checkreplacestring); |
2729 { | 2741 { |
2730 Node* const replace_string = | 2742 Node* const replace_string = |
2731 CallBuiltin(Builtins::kToString, context, replace_value); | 2743 CallBuiltin(Builtins::kToString, context, replace_value); |
2732 | 2744 |
2733 // ToString(replaceValue) could potentially change the shape of the RegExp | 2745 // ToString(replaceValue) could potentially change the shape of the RegExp |
2734 // object. Recheck that we are still on the fast path and bail to runtime | 2746 // object. Recheck that we are still on the fast path and bail to runtime |
2735 // otherwise. | 2747 // otherwise. |
2736 { | 2748 { |
2737 Label next(this); | 2749 Label next(this); |
2738 BranchIfFastRegExp(context, regexp, LoadMap(regexp), &next, &runtime); | 2750 BranchIfFastRegExp(context, regexp, &next, &runtime); |
2739 Bind(&next); | 2751 BIND(&next); |
2740 } | 2752 } |
2741 | 2753 |
2742 Node* const dollar_string = HeapConstant( | 2754 Node* const dollar_string = HeapConstant( |
2743 isolate()->factory()->LookupSingleCharacterStringFromCode('$')); | 2755 isolate()->factory()->LookupSingleCharacterStringFromCode('$')); |
2744 Node* const dollar_ix = | 2756 Node* const dollar_ix = |
2745 CallBuiltin(Builtins::kStringIndexOf, context, replace_string, | 2757 CallBuiltin(Builtins::kStringIndexOf, context, replace_string, |
2746 dollar_string, SmiConstant(0)); | 2758 dollar_string, SmiConstant(0)); |
2747 GotoIfNot(SmiEqual(dollar_ix, SmiConstant(-1)), &runtime); | 2759 GotoIfNot(SmiEqual(dollar_ix, SmiConstant(-1)), &runtime); |
2748 | 2760 |
2749 Return( | 2761 Return( |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2804 ThrowIfNotJSReceiver(context, maybe_receiver, | 2816 ThrowIfNotJSReceiver(context, maybe_receiver, |
2805 MessageTemplate::kIncompatibleMethodReceiver, | 2817 MessageTemplate::kIncompatibleMethodReceiver, |
2806 "RegExp.prototype.@@replace"); | 2818 "RegExp.prototype.@@replace"); |
2807 Node* const receiver = maybe_receiver; | 2819 Node* const receiver = maybe_receiver; |
2808 | 2820 |
2809 // Convert {maybe_string} to a String. | 2821 // Convert {maybe_string} to a String. |
2810 Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string); | 2822 Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string); |
2811 | 2823 |
2812 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? | 2824 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? |
2813 Label stub(this), runtime(this, Label::kDeferred); | 2825 Label stub(this), runtime(this, Label::kDeferred); |
2814 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &stub, &runtime); | 2826 BranchIfFastRegExp(context, receiver, &stub, &runtime); |
2815 | 2827 |
2816 BIND(&stub); | 2828 BIND(&stub); |
2817 Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, | 2829 Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, |
2818 replace_value)); | 2830 replace_value)); |
2819 | 2831 |
2820 BIND(&runtime); | 2832 BIND(&runtime); |
2821 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, | 2833 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, |
2822 replace_value)); | 2834 replace_value)); |
2823 } | 2835 } |
2824 | 2836 |
(...skipping 26 matching lines...) Expand all Loading... | |
2851 BIND(&if_matched); | 2863 BIND(&if_matched); |
2852 { | 2864 { |
2853 Node* result = | 2865 Node* result = |
2854 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2866 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
2855 Return(result); | 2867 Return(result); |
2856 } | 2868 } |
2857 } | 2869 } |
2858 | 2870 |
2859 } // namespace internal | 2871 } // namespace internal |
2860 } // namespace v8 | 2872 } // namespace v8 |
OLD | NEW |