Chromium Code Reviews| 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 |