| 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 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 GotoIfNot(proto_has_initialmap, if_ismodified); | 726 GotoIfNot(proto_has_initialmap, if_ismodified); |
| 727 | 727 |
| 728 // The smi check is required to omit ToLength(lastIndex) calls with possible | 728 // The smi check is required to omit ToLength(lastIndex) calls with possible |
| 729 // user-code execution on the fast path. | 729 // user-code execution on the fast path. |
| 730 Node* const last_index = FastLoadLastIndex(object); | 730 Node* const last_index = FastLoadLastIndex(object); |
| 731 Branch(TaggedIsPositiveSmi(last_index), if_isunmodified, if_ismodified); | 731 Branch(TaggedIsPositiveSmi(last_index), if_isunmodified, if_ismodified); |
| 732 } | 732 } |
| 733 | 733 |
| 734 Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context, | 734 Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context, |
| 735 Node* const object) { | 735 Node* const object) { |
| 736 return IsFastRegExp(context, object, LoadMap(object)); | |
| 737 } | |
| 738 | |
| 739 Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context, | |
| 740 Node* const object, | |
| 741 Node* const map) { | |
| 742 Label yup(this), nope(this), out(this); | 736 Label yup(this), nope(this), out(this); |
| 743 VARIABLE(var_result, MachineRepresentation::kWord32); | 737 VARIABLE(var_result, MachineRepresentation::kWord32); |
| 744 | 738 |
| 745 BranchIfFastRegExp(context, object, map, &yup, &nope); | 739 BranchIfFastRegExp(context, object, LoadMap(object), &yup, &nope); |
| 746 | 740 |
| 747 BIND(&yup); | 741 BIND(&yup); |
| 748 var_result.Bind(Int32Constant(1)); | 742 var_result.Bind(Int32Constant(1)); |
| 749 Goto(&out); | 743 Goto(&out); |
| 750 | 744 |
| 751 BIND(&nope); | 745 BIND(&nope); |
| 752 var_result.Bind(Int32Constant(0)); | 746 var_result.Bind(Int32Constant(0)); |
| 753 Goto(&out); | 747 Goto(&out); |
| 754 | 748 |
| 755 BIND(&out); | 749 BIND(&out); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 777 } | 771 } |
| 778 | 772 |
| 779 // ES#sec-regexp.prototype.exec | 773 // ES#sec-regexp.prototype.exec |
| 780 // RegExp.prototype.exec ( string ) | 774 // RegExp.prototype.exec ( string ) |
| 781 TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) { | 775 TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) { |
| 782 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); | 776 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); |
| 783 Node* const maybe_string = Parameter(Descriptor::kString); | 777 Node* const maybe_string = Parameter(Descriptor::kString); |
| 784 Node* const context = Parameter(Descriptor::kContext); | 778 Node* const context = Parameter(Descriptor::kContext); |
| 785 | 779 |
| 786 // Ensure {maybe_receiver} is a JSRegExp. | 780 // Ensure {maybe_receiver} is a JSRegExp. |
| 787 Node* const regexp_map = ThrowIfNotInstanceType( | 781 ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE, |
| 788 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | 782 "RegExp.prototype.exec"); |
| 789 Node* const receiver = maybe_receiver; | 783 Node* const receiver = maybe_receiver; |
| 790 | 784 |
| 791 // Convert {maybe_string} to a String. | 785 // Convert {maybe_string} to a String. |
| 792 Node* const string = ToString(context, maybe_string); | 786 Node* const string = ToString(context, maybe_string); |
| 793 | 787 |
| 794 Label if_isfastpath(this), if_isslowpath(this); | 788 Label if_isfastpath(this), if_isslowpath(this); |
| 795 Branch(IsFastRegExpNoPrototype(context, receiver, regexp_map), &if_isfastpath, | 789 Branch(IsFastRegExpNoPrototype(context, receiver, LoadMap(receiver)), |
| 796 &if_isslowpath); | 790 &if_isfastpath, &if_isslowpath); |
| 797 | 791 |
| 798 BIND(&if_isfastpath); | 792 BIND(&if_isfastpath); |
| 799 { | 793 { |
| 800 Node* const result = | 794 Node* const result = |
| 801 RegExpPrototypeExecBody(context, receiver, string, true); | 795 RegExpPrototypeExecBody(context, receiver, string, true); |
| 802 Return(result); | 796 Return(result); |
| 803 } | 797 } |
| 804 | 798 |
| 805 BIND(&if_isslowpath); | 799 BIND(&if_isslowpath); |
| 806 { | 800 { |
| (...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1491 } | 1485 } |
| 1492 | 1486 |
| 1493 // ES#sec-regexp.prototype.test | 1487 // ES#sec-regexp.prototype.test |
| 1494 // RegExp.prototype.test ( S ) | 1488 // RegExp.prototype.test ( S ) |
| 1495 TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) { | 1489 TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) { |
| 1496 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); | 1490 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); |
| 1497 Node* const maybe_string = Parameter(Descriptor::kString); | 1491 Node* const maybe_string = Parameter(Descriptor::kString); |
| 1498 Node* const context = Parameter(Descriptor::kContext); | 1492 Node* const context = Parameter(Descriptor::kContext); |
| 1499 | 1493 |
| 1500 // Ensure {maybe_receiver} is a JSReceiver. | 1494 // Ensure {maybe_receiver} is a JSReceiver. |
| 1501 Node* const map = ThrowIfNotJSReceiver( | 1495 ThrowIfNotJSReceiver(context, maybe_receiver, |
| 1502 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 1496 MessageTemplate::kIncompatibleMethodReceiver, |
| 1503 "RegExp.prototype.test"); | 1497 "RegExp.prototype.test"); |
| 1504 Node* const receiver = maybe_receiver; | 1498 Node* const receiver = maybe_receiver; |
| 1505 | 1499 |
| 1506 // Convert {maybe_string} to a String. | 1500 // Convert {maybe_string} to a String. |
| 1507 Node* const string = ToString(context, maybe_string); | 1501 Node* const string = ToString(context, maybe_string); |
| 1508 | 1502 |
| 1509 Label fast_path(this), slow_path(this); | 1503 Label fast_path(this), slow_path(this); |
| 1510 BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); | 1504 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path, |
| 1505 &slow_path); |
| 1511 | 1506 |
| 1512 BIND(&fast_path); | 1507 BIND(&fast_path); |
| 1513 { | 1508 { |
| 1514 Label if_didnotmatch(this); | 1509 Label if_didnotmatch(this); |
| 1515 RegExpPrototypeExecBodyWithoutResult(context, receiver, string, | 1510 RegExpPrototypeExecBodyWithoutResult(context, receiver, string, |
| 1516 &if_didnotmatch, true); | 1511 &if_didnotmatch, true); |
| 1517 Return(TrueConstant()); | 1512 Return(TrueConstant()); |
| 1518 | 1513 |
| 1519 BIND(&if_didnotmatch); | 1514 BIND(&if_didnotmatch); |
| 1520 Return(FalseConstant()); | 1515 Return(FalseConstant()); |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1901 } | 1896 } |
| 1902 | 1897 |
| 1903 // ES#sec-regexp.prototype-@@match | 1898 // ES#sec-regexp.prototype-@@match |
| 1904 // RegExp.prototype [ @@match ] ( string ) | 1899 // RegExp.prototype [ @@match ] ( string ) |
| 1905 TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) { | 1900 TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) { |
| 1906 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); | 1901 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); |
| 1907 Node* const maybe_string = Parameter(Descriptor::kString); | 1902 Node* const maybe_string = Parameter(Descriptor::kString); |
| 1908 Node* const context = Parameter(Descriptor::kContext); | 1903 Node* const context = Parameter(Descriptor::kContext); |
| 1909 | 1904 |
| 1910 // Ensure {maybe_receiver} is a JSReceiver. | 1905 // Ensure {maybe_receiver} is a JSReceiver. |
| 1911 Node* const map = ThrowIfNotJSReceiver( | 1906 ThrowIfNotJSReceiver(context, maybe_receiver, |
| 1912 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 1907 MessageTemplate::kIncompatibleMethodReceiver, |
| 1913 "RegExp.prototype.@@match"); | 1908 "RegExp.prototype.@@match"); |
| 1914 Node* const receiver = maybe_receiver; | 1909 Node* const receiver = maybe_receiver; |
| 1915 | 1910 |
| 1916 // Convert {maybe_string} to a String. | 1911 // Convert {maybe_string} to a String. |
| 1917 Node* const string = ToString(context, maybe_string); | 1912 Node* const string = ToString(context, maybe_string); |
| 1918 | 1913 |
| 1919 Label fast_path(this), slow_path(this); | 1914 Label fast_path(this), slow_path(this); |
| 1920 BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); | 1915 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path, |
| 1916 &slow_path); |
| 1921 | 1917 |
| 1922 BIND(&fast_path); | 1918 BIND(&fast_path); |
| 1923 RegExpPrototypeMatchBody(context, receiver, string, true); | 1919 RegExpPrototypeMatchBody(context, receiver, string, true); |
| 1924 | 1920 |
| 1925 BIND(&slow_path); | 1921 BIND(&slow_path); |
| 1926 RegExpPrototypeMatchBody(context, receiver, string, false); | 1922 RegExpPrototypeMatchBody(context, receiver, string, false); |
| 1927 } | 1923 } |
| 1928 | 1924 |
| 1929 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast( | 1925 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast( |
| 1930 Node* const context, Node* const regexp, Node* const string) { | 1926 Node* const context, Node* const regexp, Node* const string) { |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2029 } | 2025 } |
| 2030 | 2026 |
| 2031 // ES#sec-regexp.prototype-@@search | 2027 // ES#sec-regexp.prototype-@@search |
| 2032 // RegExp.prototype [ @@search ] ( string ) | 2028 // RegExp.prototype [ @@search ] ( string ) |
| 2033 TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) { | 2029 TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) { |
| 2034 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); | 2030 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); |
| 2035 Node* const maybe_string = Parameter(Descriptor::kString); | 2031 Node* const maybe_string = Parameter(Descriptor::kString); |
| 2036 Node* const context = Parameter(Descriptor::kContext); | 2032 Node* const context = Parameter(Descriptor::kContext); |
| 2037 | 2033 |
| 2038 // Ensure {maybe_receiver} is a JSReceiver. | 2034 // Ensure {maybe_receiver} is a JSReceiver. |
| 2039 Node* const map = ThrowIfNotJSReceiver( | 2035 ThrowIfNotJSReceiver(context, maybe_receiver, |
| 2040 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 2036 MessageTemplate::kIncompatibleMethodReceiver, |
| 2041 "RegExp.prototype.@@search"); | 2037 "RegExp.prototype.@@search"); |
| 2042 Node* const receiver = maybe_receiver; | 2038 Node* const receiver = maybe_receiver; |
| 2043 | 2039 |
| 2044 // Convert {maybe_string} to a String. | 2040 // Convert {maybe_string} to a String. |
| 2045 Node* const string = ToString(context, maybe_string); | 2041 Node* const string = ToString(context, maybe_string); |
| 2046 | 2042 |
| 2047 Label fast_path(this), slow_path(this); | 2043 Label fast_path(this), slow_path(this); |
| 2048 BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); | 2044 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path, |
| 2045 &slow_path); |
| 2049 | 2046 |
| 2050 BIND(&fast_path); | 2047 BIND(&fast_path); |
| 2051 RegExpPrototypeSearchBodyFast(context, receiver, string); | 2048 RegExpPrototypeSearchBodyFast(context, receiver, string); |
| 2052 | 2049 |
| 2053 BIND(&slow_path); | 2050 BIND(&slow_path); |
| 2054 RegExpPrototypeSearchBodySlow(context, receiver, string); | 2051 RegExpPrototypeSearchBodySlow(context, receiver, string); |
| 2055 } | 2052 } |
| 2056 | 2053 |
| 2057 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, | 2054 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, |
| 2058 // {string} is a String, and {limit} is a Smi. | 2055 // {string} is a String, and {limit} is a Smi. |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2366 | 2363 |
| 2367 // ES#sec-regexp.prototype-@@split | 2364 // ES#sec-regexp.prototype-@@split |
| 2368 // RegExp.prototype [ @@split ] ( string, limit ) | 2365 // RegExp.prototype [ @@split ] ( string, limit ) |
| 2369 TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) { | 2366 TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) { |
| 2370 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); | 2367 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); |
| 2371 Node* const maybe_string = Parameter(Descriptor::kString); | 2368 Node* const maybe_string = Parameter(Descriptor::kString); |
| 2372 Node* const maybe_limit = Parameter(Descriptor::kLimit); | 2369 Node* const maybe_limit = Parameter(Descriptor::kLimit); |
| 2373 Node* const context = Parameter(Descriptor::kContext); | 2370 Node* const context = Parameter(Descriptor::kContext); |
| 2374 | 2371 |
| 2375 // Ensure {maybe_receiver} is a JSReceiver. | 2372 // Ensure {maybe_receiver} is a JSReceiver. |
| 2376 Node* const map = ThrowIfNotJSReceiver( | 2373 ThrowIfNotJSReceiver(context, maybe_receiver, |
| 2377 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 2374 MessageTemplate::kIncompatibleMethodReceiver, |
| 2378 "RegExp.prototype.@@split"); | 2375 "RegExp.prototype.@@split"); |
| 2379 Node* const receiver = maybe_receiver; | 2376 Node* const receiver = maybe_receiver; |
| 2380 | 2377 |
| 2381 // Convert {maybe_string} to a String. | 2378 // Convert {maybe_string} to a String. |
| 2382 Node* const string = ToString(context, maybe_string); | 2379 Node* const string = ToString(context, maybe_string); |
| 2383 | 2380 |
| 2384 Label stub(this), runtime(this, Label::kDeferred); | 2381 Label stub(this), runtime(this, Label::kDeferred); |
| 2385 BranchIfFastRegExp(context, receiver, map, &stub, &runtime); | 2382 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &stub, &runtime); |
| 2386 | 2383 |
| 2387 BIND(&stub); | 2384 BIND(&stub); |
| 2388 Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, | 2385 Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, |
| 2389 maybe_limit)); | 2386 maybe_limit)); |
| 2390 | 2387 |
| 2391 BIND(&runtime); | 2388 BIND(&runtime); |
| 2392 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, | 2389 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, |
| 2393 maybe_limit)); | 2390 maybe_limit)); |
| 2394 } | 2391 } |
| 2395 | 2392 |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2797 // } | 2794 // } |
| 2798 // } else { | 2795 // } else { |
| 2799 // if (replace.contains("$")) { | 2796 // if (replace.contains("$")) { |
| 2800 // CallRuntime(RegExpReplace) | 2797 // CallRuntime(RegExpReplace) |
| 2801 // } else { | 2798 // } else { |
| 2802 // ReplaceSimpleStringFastPath() // Bails to runtime for global regexps. | 2799 // ReplaceSimpleStringFastPath() // Bails to runtime for global regexps. |
| 2803 // } | 2800 // } |
| 2804 // } | 2801 // } |
| 2805 | 2802 |
| 2806 // Ensure {maybe_receiver} is a JSReceiver. | 2803 // Ensure {maybe_receiver} is a JSReceiver. |
| 2807 Node* const map = ThrowIfNotJSReceiver( | 2804 ThrowIfNotJSReceiver(context, maybe_receiver, |
| 2808 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 2805 MessageTemplate::kIncompatibleMethodReceiver, |
| 2809 "RegExp.prototype.@@replace"); | 2806 "RegExp.prototype.@@replace"); |
| 2810 Node* const receiver = maybe_receiver; | 2807 Node* const receiver = maybe_receiver; |
| 2811 | 2808 |
| 2812 // Convert {maybe_string} to a String. | 2809 // Convert {maybe_string} to a String. |
| 2813 Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string); | 2810 Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string); |
| 2814 | 2811 |
| 2815 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? | 2812 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? |
| 2816 Label stub(this), runtime(this, Label::kDeferred); | 2813 Label stub(this), runtime(this, Label::kDeferred); |
| 2817 BranchIfFastRegExp(context, receiver, map, &stub, &runtime); | 2814 BranchIfFastRegExp(context, receiver, LoadMap(receiver), &stub, &runtime); |
| 2818 | 2815 |
| 2819 BIND(&stub); | 2816 BIND(&stub); |
| 2820 Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, | 2817 Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, |
| 2821 replace_value)); | 2818 replace_value)); |
| 2822 | 2819 |
| 2823 BIND(&runtime); | 2820 BIND(&runtime); |
| 2824 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, | 2821 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, |
| 2825 replace_value)); | 2822 replace_value)); |
| 2826 } | 2823 } |
| 2827 | 2824 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2854 BIND(&if_matched); | 2851 BIND(&if_matched); |
| 2855 { | 2852 { |
| 2856 Node* result = | 2853 Node* result = |
| 2857 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2854 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
| 2858 Return(result); | 2855 Return(result); |
| 2859 } | 2856 } |
| 2860 } | 2857 } |
| 2861 | 2858 |
| 2862 } // namespace internal | 2859 } // namespace internal |
| 2863 } // namespace v8 | 2860 } // namespace v8 |
| OLD | NEW |