| 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 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 // constructing the JSRegExpResult. Returns either null (if the RegExp did not | 475 // constructing the JSRegExpResult. Returns either null (if the RegExp did not |
| 476 // match) or a fixed array containing match indices as returned by | 476 // match) or a fixed array containing match indices as returned by |
| 477 // RegExpExecStub. | 477 // RegExpExecStub. |
| 478 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( | 478 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( |
| 479 Node* const context, Node* const regexp, Node* const string, | 479 Node* const context, Node* const regexp, Node* const string, |
| 480 Label* if_didnotmatch, const bool is_fastpath) { | 480 Label* if_didnotmatch, const bool is_fastpath) { |
| 481 Node* const null = NullConstant(); | 481 Node* const null = NullConstant(); |
| 482 Node* const int_zero = IntPtrConstant(0); | 482 Node* const int_zero = IntPtrConstant(0); |
| 483 Node* const smi_zero = SmiConstant(Smi::kZero); | 483 Node* const smi_zero = SmiConstant(Smi::kZero); |
| 484 | 484 |
| 485 if (!is_fastpath) { | 485 if (is_fastpath) { |
| 486 CSA_ASSERT(this, IsFastRegExpNoPrototype(context, regexp, LoadMap(regexp))); |
| 487 } else { |
| 486 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, | 488 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, |
| 487 "RegExp.prototype.exec"); | 489 "RegExp.prototype.exec"); |
| 488 } | 490 } |
| 489 | 491 |
| 490 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string))); | 492 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string))); |
| 491 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE)); | 493 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE)); |
| 492 | 494 |
| 493 Variable var_result(this, MachineRepresentation::kTagged); | 495 Variable var_result(this, MachineRepresentation::kTagged); |
| 494 Label out(this); | 496 Label out(this); |
| 495 | 497 |
| 496 // Load lastIndex. | 498 // Load lastIndex. |
| 497 Variable var_lastindex(this, MachineRepresentation::kTagged); | 499 Variable var_lastindex(this, MachineRepresentation::kTagged); |
| 498 { | 500 { |
| 499 Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath); | 501 Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath); |
| 500 var_lastindex.Bind(regexp_lastindex); | 502 var_lastindex.Bind(regexp_lastindex); |
| 501 | 503 |
| 502 // Omit ToLength if lastindex is a non-negative smi. | 504 if (is_fastpath) { |
| 503 Label call_tolength(this, Label::kDeferred), next(this); | 505 // ToLength on a positive smi is a nop and can be skipped. |
| 504 Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength); | 506 CSA_ASSERT(this, TaggedIsPositiveSmi(regexp_lastindex)); |
| 507 } else { |
| 508 // Omit ToLength if lastindex is a non-negative smi. |
| 509 Label call_tolength(this, Label::kDeferred), next(this); |
| 510 Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength); |
| 505 | 511 |
| 506 Bind(&call_tolength); | 512 Bind(&call_tolength); |
| 507 { | 513 { |
| 508 var_lastindex.Bind( | 514 var_lastindex.Bind( |
| 509 CallBuiltin(Builtins::kToLength, context, regexp_lastindex)); | 515 CallBuiltin(Builtins::kToLength, context, regexp_lastindex)); |
| 510 Goto(&next); | 516 Goto(&next); |
| 517 } |
| 518 |
| 519 Bind(&next); |
| 511 } | 520 } |
| 512 | |
| 513 Bind(&next); | |
| 514 } | 521 } |
| 515 | 522 |
| 516 // Check whether the regexp is global or sticky, which determines whether we | 523 // Check whether the regexp is global or sticky, which determines whether we |
| 517 // update last index later on. | 524 // update last index later on. |
| 518 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 525 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 519 Node* const is_global_or_sticky = WordAnd( | 526 Node* const is_global_or_sticky = WordAnd( |
| 520 SmiUntag(flags), IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); | 527 SmiUntag(flags), IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); |
| 521 Node* const should_update_last_index = | 528 Node* const should_update_last_index = |
| 522 WordNotEqual(is_global_or_sticky, int_zero); | 529 WordNotEqual(is_global_or_sticky, int_zero); |
| 523 | 530 |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 | 658 |
| 652 CallRuntime(Runtime::kThrowTypeError, context, message_id, method_name_str, | 659 CallRuntime(Runtime::kThrowTypeError, context, message_id, method_name_str, |
| 653 value_str); | 660 value_str); |
| 654 Unreachable(); | 661 Unreachable(); |
| 655 } | 662 } |
| 656 | 663 |
| 657 Bind(&out); | 664 Bind(&out); |
| 658 return var_value_map.value(); | 665 return var_value_map.value(); |
| 659 } | 666 } |
| 660 | 667 |
| 661 Node* RegExpBuiltinsAssembler::IsInitialRegExpMap(Node* context, Node* map) { | 668 Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(Node* const context, |
| 669 Node* const object, |
| 670 Node* const map) { |
| 671 Label out(this); |
| 672 Variable var_result(this, MachineRepresentation::kWord32); |
| 673 |
| 662 Node* const native_context = LoadNativeContext(context); | 674 Node* const native_context = LoadNativeContext(context); |
| 663 Node* const regexp_fun = | 675 Node* const regexp_fun = |
| 664 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 676 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
| 665 Node* const initial_map = | 677 Node* const initial_map = |
| 666 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 678 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 667 Node* const has_initialmap = WordEqual(map, initial_map); | 679 Node* const has_initialmap = WordEqual(map, initial_map); |
| 668 | 680 |
| 669 return has_initialmap; | 681 var_result.Bind(has_initialmap); |
| 682 GotoIfNot(has_initialmap, &out); |
| 683 |
| 684 // The smi check is required to omit ToLength(lastIndex) calls with possible |
| 685 // user-code execution on the fast path. |
| 686 Node* const last_index = FastLoadLastIndex(object); |
| 687 var_result.Bind(TaggedIsPositiveSmi(last_index)); |
| 688 Goto(&out); |
| 689 |
| 690 Bind(&out); |
| 691 return var_result.value(); |
| 670 } | 692 } |
| 671 | 693 |
| 672 // RegExp fast path implementations rely on unmodified JSRegExp instances. | 694 // RegExp fast path implementations rely on unmodified JSRegExp instances. |
| 673 // We use a fairly coarse granularity for this and simply check whether both | 695 // We use a fairly coarse granularity for this and simply check whether both |
| 674 // the regexp itself is unmodified (i.e. its map has not changed) and its | 696 // the regexp itself is unmodified (i.e. its map has not changed), its |
| 675 // prototype is unmodified. | 697 // prototype is unmodified, and lastIndex is a non-negative smi. |
| 676 void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context, | 698 void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context, |
| 699 Node* const object, |
| 677 Node* const map, | 700 Node* const map, |
| 678 Label* const if_isunmodified, | 701 Label* const if_isunmodified, |
| 679 Label* const if_ismodified) { | 702 Label* const if_ismodified) { |
| 703 CSA_ASSERT(this, WordEqual(LoadMap(object), map)); |
| 704 |
| 705 // TODO(ishell): Update this check once map changes for constant field |
| 706 // tracking are landing. |
| 707 |
| 680 Node* const native_context = LoadNativeContext(context); | 708 Node* const native_context = LoadNativeContext(context); |
| 681 Node* const regexp_fun = | 709 Node* const regexp_fun = |
| 682 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 710 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
| 683 Node* const initial_map = | 711 Node* const initial_map = |
| 684 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 712 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 685 Node* const has_initialmap = WordEqual(map, initial_map); | 713 Node* const has_initialmap = WordEqual(map, initial_map); |
| 686 | 714 |
| 687 GotoIfNot(has_initialmap, if_ismodified); | 715 GotoIfNot(has_initialmap, if_ismodified); |
| 688 | 716 |
| 689 Node* const initial_proto_initial_map = | 717 Node* const initial_proto_initial_map = |
| 690 LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX); | 718 LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX); |
| 691 Node* const proto_map = LoadMap(LoadMapPrototype(map)); | 719 Node* const proto_map = LoadMap(LoadMapPrototype(map)); |
| 692 Node* const proto_has_initialmap = | 720 Node* const proto_has_initialmap = |
| 693 WordEqual(proto_map, initial_proto_initial_map); | 721 WordEqual(proto_map, initial_proto_initial_map); |
| 694 | 722 |
| 695 // TODO(ishell): Update this check once map changes for constant field | 723 GotoIfNot(proto_has_initialmap, if_ismodified); |
| 696 // tracking are landing. | |
| 697 | 724 |
| 698 Branch(proto_has_initialmap, if_isunmodified, if_ismodified); | 725 // The smi check is required to omit ToLength(lastIndex) calls with possible |
| 726 // user-code execution on the fast path. |
| 727 Node* const last_index = FastLoadLastIndex(object); |
| 728 Branch(TaggedIsPositiveSmi(last_index), if_isunmodified, if_ismodified); |
| 699 } | 729 } |
| 700 | 730 |
| 701 Node* RegExpBuiltinsAssembler::IsFastRegExpMap(Node* const context, | 731 Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context, |
| 702 Node* const map) { | 732 Node* const object, |
| 733 Node* const map) { |
| 703 Label yup(this), nope(this), out(this); | 734 Label yup(this), nope(this), out(this); |
| 704 Variable var_result(this, MachineRepresentation::kWord32); | 735 Variable var_result(this, MachineRepresentation::kWord32); |
| 705 | 736 |
| 706 BranchIfFastRegExp(context, map, &yup, &nope); | 737 BranchIfFastRegExp(context, object, map, &yup, &nope); |
| 707 | 738 |
| 708 Bind(&yup); | 739 Bind(&yup); |
| 709 var_result.Bind(Int32Constant(1)); | 740 var_result.Bind(Int32Constant(1)); |
| 710 Goto(&out); | 741 Goto(&out); |
| 711 | 742 |
| 712 Bind(&nope); | 743 Bind(&nope); |
| 713 var_result.Bind(Int32Constant(0)); | 744 var_result.Bind(Int32Constant(0)); |
| 714 Goto(&out); | 745 Goto(&out); |
| 715 | 746 |
| 716 Bind(&out); | 747 Bind(&out); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 746 | 777 |
| 747 // Ensure {maybe_receiver} is a JSRegExp. | 778 // Ensure {maybe_receiver} is a JSRegExp. |
| 748 Node* const regexp_map = ThrowIfNotInstanceType( | 779 Node* const regexp_map = ThrowIfNotInstanceType( |
| 749 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | 780 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); |
| 750 Node* const receiver = maybe_receiver; | 781 Node* const receiver = maybe_receiver; |
| 751 | 782 |
| 752 // Convert {maybe_string} to a String. | 783 // Convert {maybe_string} to a String. |
| 753 Node* const string = ToString(context, maybe_string); | 784 Node* const string = ToString(context, maybe_string); |
| 754 | 785 |
| 755 Label if_isfastpath(this), if_isslowpath(this); | 786 Label if_isfastpath(this), if_isslowpath(this); |
| 756 Branch(IsInitialRegExpMap(context, regexp_map), &if_isfastpath, | 787 Branch(IsFastRegExpNoPrototype(context, receiver, regexp_map), &if_isfastpath, |
| 757 &if_isslowpath); | 788 &if_isslowpath); |
| 758 | 789 |
| 759 Bind(&if_isfastpath); | 790 Bind(&if_isfastpath); |
| 760 { | 791 { |
| 761 Node* const result = | 792 Node* const result = |
| 762 RegExpPrototypeExecBody(context, receiver, string, true); | 793 RegExpPrototypeExecBody(context, receiver, string, true); |
| 763 Return(result); | 794 Return(result); |
| 764 } | 795 } |
| 765 | 796 |
| 766 Bind(&if_isslowpath); | 797 Bind(&if_isslowpath); |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 953 TF_BUILTIN(RegExpPrototypeFlagsGetter, RegExpBuiltinsAssembler) { | 984 TF_BUILTIN(RegExpPrototypeFlagsGetter, RegExpBuiltinsAssembler) { |
| 954 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); | 985 Node* const maybe_receiver = Parameter(Descriptor::kReceiver); |
| 955 Node* const context = Parameter(Descriptor::kContext); | 986 Node* const context = Parameter(Descriptor::kContext); |
| 956 | 987 |
| 957 Node* const map = ThrowIfNotJSReceiver(context, maybe_receiver, | 988 Node* const map = ThrowIfNotJSReceiver(context, maybe_receiver, |
| 958 MessageTemplate::kRegExpNonObject, | 989 MessageTemplate::kRegExpNonObject, |
| 959 "RegExp.prototype.flags"); | 990 "RegExp.prototype.flags"); |
| 960 Node* const receiver = maybe_receiver; | 991 Node* const receiver = maybe_receiver; |
| 961 | 992 |
| 962 Label if_isfastpath(this), if_isslowpath(this, Label::kDeferred); | 993 Label if_isfastpath(this), if_isslowpath(this, Label::kDeferred); |
| 963 Branch(IsInitialRegExpMap(context, map), &if_isfastpath, &if_isslowpath); | 994 Branch(IsFastRegExpNoPrototype(context, receiver, map), &if_isfastpath, |
| 995 &if_isslowpath); |
| 964 | 996 |
| 965 Bind(&if_isfastpath); | 997 Bind(&if_isfastpath); |
| 966 Return(FlagsGetter(context, receiver, true)); | 998 Return(FlagsGetter(context, receiver, true)); |
| 967 | 999 |
| 968 Bind(&if_isslowpath); | 1000 Bind(&if_isslowpath); |
| 969 Return(FlagsGetter(context, receiver, false)); | 1001 Return(FlagsGetter(context, receiver, false)); |
| 970 } | 1002 } |
| 971 | 1003 |
| 972 // ES#sec-regexp-pattern-flags | 1004 // ES#sec-regexp-pattern-flags |
| 973 // RegExp ( pattern, flags ) | 1005 // RegExp ( pattern, flags ) |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1398 Node* context = Parameter(Descriptor::kContext); | 1430 Node* context = Parameter(Descriptor::kContext); |
| 1399 Node* receiver = Parameter(Descriptor::kReceiver); | 1431 Node* receiver = Parameter(Descriptor::kReceiver); |
| 1400 FlagGetter(context, receiver, JSRegExp::kUnicode, | 1432 FlagGetter(context, receiver, JSRegExp::kUnicode, |
| 1401 v8::Isolate::kRegExpPrototypeUnicodeGetter, | 1433 v8::Isolate::kRegExpPrototypeUnicodeGetter, |
| 1402 "RegExp.prototype.unicode"); | 1434 "RegExp.prototype.unicode"); |
| 1403 } | 1435 } |
| 1404 | 1436 |
| 1405 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 1437 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
| 1406 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp, | 1438 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp, |
| 1407 Node* string) { | 1439 Node* string) { |
| 1408 CSA_ASSERT(this, Word32BinaryNot(IsFastRegExpMap(context, LoadMap(regexp)))); | |
| 1409 | |
| 1410 Variable var_result(this, MachineRepresentation::kTagged); | 1440 Variable var_result(this, MachineRepresentation::kTagged); |
| 1411 Label out(this); | 1441 Label out(this); |
| 1412 | 1442 |
| 1413 // Take the slow path of fetching the exec property, calling it, and | 1443 // Take the slow path of fetching the exec property, calling it, and |
| 1414 // verifying its return value. | 1444 // verifying its return value. |
| 1415 | 1445 |
| 1416 // Get the exec property. | 1446 // Get the exec property. |
| 1417 Node* const exec = | 1447 Node* const exec = |
| 1418 GetProperty(context, regexp, isolate()->factory()->exec_string()); | 1448 GetProperty(context, regexp, isolate()->factory()->exec_string()); |
| 1419 | 1449 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1464 // Ensure {maybe_receiver} is a JSReceiver. | 1494 // Ensure {maybe_receiver} is a JSReceiver. |
| 1465 Node* const map = ThrowIfNotJSReceiver( | 1495 Node* const map = ThrowIfNotJSReceiver( |
| 1466 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 1496 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, |
| 1467 "RegExp.prototype.test"); | 1497 "RegExp.prototype.test"); |
| 1468 Node* const receiver = maybe_receiver; | 1498 Node* const receiver = maybe_receiver; |
| 1469 | 1499 |
| 1470 // Convert {maybe_string} to a String. | 1500 // Convert {maybe_string} to a String. |
| 1471 Node* const string = ToString(context, maybe_string); | 1501 Node* const string = ToString(context, maybe_string); |
| 1472 | 1502 |
| 1473 Label fast_path(this), slow_path(this); | 1503 Label fast_path(this), slow_path(this); |
| 1474 BranchIfFastRegExp(context, map, &fast_path, &slow_path); | 1504 BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); |
| 1475 | 1505 |
| 1476 Bind(&fast_path); | 1506 Bind(&fast_path); |
| 1477 { | 1507 { |
| 1478 Label if_didnotmatch(this); | 1508 Label if_didnotmatch(this); |
| 1479 RegExpPrototypeExecBodyWithoutResult(context, receiver, string, | 1509 RegExpPrototypeExecBodyWithoutResult(context, receiver, string, |
| 1480 &if_didnotmatch, true); | 1510 &if_didnotmatch, true); |
| 1481 Return(TrueConstant()); | 1511 Return(TrueConstant()); |
| 1482 | 1512 |
| 1483 Bind(&if_didnotmatch); | 1513 Bind(&if_didnotmatch); |
| 1484 Return(FalseConstant()); | 1514 Return(FalseConstant()); |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1793 | 1823 |
| 1794 // Store the match, growing the fixed array if needed. | 1824 // Store the match, growing the fixed array if needed. |
| 1795 | 1825 |
| 1796 array.Push(match); | 1826 array.Push(match); |
| 1797 | 1827 |
| 1798 // Advance last index if the match is the empty string. | 1828 // Advance last index if the match is the empty string. |
| 1799 | 1829 |
| 1800 Node* const match_length = LoadStringLength(match); | 1830 Node* const match_length = LoadStringLength(match); |
| 1801 GotoIfNot(SmiEqual(match_length, smi_zero), &loop); | 1831 GotoIfNot(SmiEqual(match_length, smi_zero), &loop); |
| 1802 | 1832 |
| 1803 Node* const last_index = | 1833 Node* last_index = LoadLastIndex(context, regexp, is_fastpath); |
| 1804 CallBuiltin(Builtins::kToLength, context, | 1834 if (is_fastpath) { |
| 1805 LoadLastIndex(context, regexp, is_fastpath)); | 1835 CSA_ASSERT(this, TaggedIsPositiveSmi(last_index)); |
| 1836 } else { |
| 1837 last_index = CallBuiltin(Builtins::kToLength, context, last_index); |
| 1838 } |
| 1839 |
| 1806 Node* const new_last_index = | 1840 Node* const new_last_index = |
| 1807 AdvanceStringIndex(string, last_index, is_unicode); | 1841 AdvanceStringIndex(string, last_index, is_unicode); |
| 1808 | 1842 |
| 1843 if (is_fastpath) { |
| 1844 // On the fast path, we can be certain that lastIndex can never be |
| 1845 // incremented to overflow the Smi range since the maximal string |
| 1846 // length is less than the maximal Smi value. |
| 1847 STATIC_ASSERT(String::kMaxLength < Smi::kMaxValue); |
| 1848 CSA_ASSERT(this, TaggedIsPositiveSmi(new_last_index)); |
| 1849 } |
| 1850 |
| 1809 StoreLastIndex(context, regexp, new_last_index, is_fastpath); | 1851 StoreLastIndex(context, regexp, new_last_index, is_fastpath); |
| 1810 | 1852 |
| 1811 Goto(&loop); | 1853 Goto(&loop); |
| 1812 } | 1854 } |
| 1813 } | 1855 } |
| 1814 | 1856 |
| 1815 Bind(&out); | 1857 Bind(&out); |
| 1816 { | 1858 { |
| 1817 // Wrap the match in a JSArray. | 1859 // Wrap the match in a JSArray. |
| 1818 | 1860 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1832 // Ensure {maybe_receiver} is a JSReceiver. | 1874 // Ensure {maybe_receiver} is a JSReceiver. |
| 1833 Node* const map = ThrowIfNotJSReceiver( | 1875 Node* const map = ThrowIfNotJSReceiver( |
| 1834 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 1876 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, |
| 1835 "RegExp.prototype.@@match"); | 1877 "RegExp.prototype.@@match"); |
| 1836 Node* const receiver = maybe_receiver; | 1878 Node* const receiver = maybe_receiver; |
| 1837 | 1879 |
| 1838 // Convert {maybe_string} to a String. | 1880 // Convert {maybe_string} to a String. |
| 1839 Node* const string = ToString(context, maybe_string); | 1881 Node* const string = ToString(context, maybe_string); |
| 1840 | 1882 |
| 1841 Label fast_path(this), slow_path(this); | 1883 Label fast_path(this), slow_path(this); |
| 1842 BranchIfFastRegExp(context, map, &fast_path, &slow_path); | 1884 BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); |
| 1843 | 1885 |
| 1844 Bind(&fast_path); | 1886 Bind(&fast_path); |
| 1845 RegExpPrototypeMatchBody(context, receiver, string, true); | 1887 RegExpPrototypeMatchBody(context, receiver, string, true); |
| 1846 | 1888 |
| 1847 Bind(&slow_path); | 1889 Bind(&slow_path); |
| 1848 RegExpPrototypeMatchBody(context, receiver, string, false); | 1890 RegExpPrototypeMatchBody(context, receiver, string, false); |
| 1849 } | 1891 } |
| 1850 | 1892 |
| 1851 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast( | 1893 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast( |
| 1852 Node* const context, Node* const regexp, Node* const string) { | 1894 Node* const context, Node* const regexp, Node* const string) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1954 // Ensure {maybe_receiver} is a JSReceiver. | 1996 // Ensure {maybe_receiver} is a JSReceiver. |
| 1955 Node* const map = ThrowIfNotJSReceiver( | 1997 Node* const map = ThrowIfNotJSReceiver( |
| 1956 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 1998 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, |
| 1957 "RegExp.prototype.@@search"); | 1999 "RegExp.prototype.@@search"); |
| 1958 Node* const receiver = maybe_receiver; | 2000 Node* const receiver = maybe_receiver; |
| 1959 | 2001 |
| 1960 // Convert {maybe_string} to a String. | 2002 // Convert {maybe_string} to a String. |
| 1961 Node* const string = ToString(context, maybe_string); | 2003 Node* const string = ToString(context, maybe_string); |
| 1962 | 2004 |
| 1963 Label fast_path(this), slow_path(this); | 2005 Label fast_path(this), slow_path(this); |
| 1964 BranchIfFastRegExp(context, map, &fast_path, &slow_path); | 2006 BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); |
| 1965 | 2007 |
| 1966 Bind(&fast_path); | 2008 Bind(&fast_path); |
| 1967 RegExpPrototypeSearchBodyFast(context, receiver, string); | 2009 RegExpPrototypeSearchBodyFast(context, receiver, string); |
| 1968 | 2010 |
| 1969 Bind(&slow_path); | 2011 Bind(&slow_path); |
| 1970 RegExpPrototypeSearchBodySlow(context, receiver, string); | 2012 RegExpPrototypeSearchBodySlow(context, receiver, string); |
| 1971 } | 2013 } |
| 1972 | 2014 |
| 1973 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, | 2015 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, |
| 1974 // {string} is a String, and {limit} is a Smi. | 2016 // {string} is a String, and {limit} is a Smi. |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2212 } | 2254 } |
| 2213 } | 2255 } |
| 2214 | 2256 |
| 2215 // Helper that skips a few initial checks. | 2257 // Helper that skips a few initial checks. |
| 2216 TF_BUILTIN(RegExpSplit, RegExpBuiltinsAssembler) { | 2258 TF_BUILTIN(RegExpSplit, RegExpBuiltinsAssembler) { |
| 2217 Node* const regexp = Parameter(Descriptor::kReceiver); | 2259 Node* const regexp = Parameter(Descriptor::kReceiver); |
| 2218 Node* const string = Parameter(Descriptor::kString); | 2260 Node* const string = Parameter(Descriptor::kString); |
| 2219 Node* const maybe_limit = Parameter(Descriptor::kLimit); | 2261 Node* const maybe_limit = Parameter(Descriptor::kLimit); |
| 2220 Node* const context = Parameter(Descriptor::kContext); | 2262 Node* const context = Parameter(Descriptor::kContext); |
| 2221 | 2263 |
| 2222 CSA_ASSERT(this, IsFastRegExpMap(context, LoadMap(regexp))); | 2264 CSA_ASSERT(this, IsFastRegExp(context, regexp, LoadMap(regexp))); |
| 2223 CSA_ASSERT(this, IsString(string)); | 2265 CSA_ASSERT(this, IsString(string)); |
| 2224 | 2266 |
| 2225 // TODO(jgruber): Even if map checks send us to the fast path, we still need | 2267 // TODO(jgruber): Even if map checks send us to the fast path, we still need |
| 2226 // to verify the constructor property and jump to the slow path if it has | 2268 // to verify the constructor property and jump to the slow path if it has |
| 2227 // been changed. | 2269 // been changed. |
| 2228 | 2270 |
| 2229 // Convert {maybe_limit} to a uint32, capping at the maximal smi value. | 2271 // Convert {maybe_limit} to a uint32, capping at the maximal smi value. |
| 2230 Variable var_limit(this, MachineRepresentation::kTagged); | 2272 Variable var_limit(this, MachineRepresentation::kTagged); |
| 2231 Label if_limitissmimax(this), limit_done(this); | 2273 Label if_limitissmimax(this), limit_done(this); |
| 2232 | 2274 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2266 // Ensure {maybe_receiver} is a JSReceiver. | 2308 // Ensure {maybe_receiver} is a JSReceiver. |
| 2267 Node* const map = ThrowIfNotJSReceiver( | 2309 Node* const map = ThrowIfNotJSReceiver( |
| 2268 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 2310 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, |
| 2269 "RegExp.prototype.@@split"); | 2311 "RegExp.prototype.@@split"); |
| 2270 Node* const receiver = maybe_receiver; | 2312 Node* const receiver = maybe_receiver; |
| 2271 | 2313 |
| 2272 // Convert {maybe_string} to a String. | 2314 // Convert {maybe_string} to a String. |
| 2273 Node* const string = ToString(context, maybe_string); | 2315 Node* const string = ToString(context, maybe_string); |
| 2274 | 2316 |
| 2275 Label stub(this), runtime(this, Label::kDeferred); | 2317 Label stub(this), runtime(this, Label::kDeferred); |
| 2276 BranchIfFastRegExp(context, map, &stub, &runtime); | 2318 BranchIfFastRegExp(context, receiver, map, &stub, &runtime); |
| 2277 | 2319 |
| 2278 Bind(&stub); | 2320 Bind(&stub); |
| 2279 Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, | 2321 Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, |
| 2280 maybe_limit)); | 2322 maybe_limit)); |
| 2281 | 2323 |
| 2282 Bind(&runtime); | 2324 Bind(&runtime); |
| 2283 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, | 2325 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, |
| 2284 maybe_limit)); | 2326 maybe_limit)); |
| 2285 } | 2327 } |
| 2286 | 2328 |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2592 return var_result.value(); | 2634 return var_result.value(); |
| 2593 } | 2635 } |
| 2594 | 2636 |
| 2595 // Helper that skips a few initial checks. | 2637 // Helper that skips a few initial checks. |
| 2596 TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) { | 2638 TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) { |
| 2597 Node* const regexp = Parameter(Descriptor::kReceiver); | 2639 Node* const regexp = Parameter(Descriptor::kReceiver); |
| 2598 Node* const string = Parameter(Descriptor::kString); | 2640 Node* const string = Parameter(Descriptor::kString); |
| 2599 Node* const replace_value = Parameter(Descriptor::kReplaceValue); | 2641 Node* const replace_value = Parameter(Descriptor::kReplaceValue); |
| 2600 Node* const context = Parameter(Descriptor::kContext); | 2642 Node* const context = Parameter(Descriptor::kContext); |
| 2601 | 2643 |
| 2602 CSA_ASSERT(this, IsFastRegExpMap(context, LoadMap(regexp))); | 2644 CSA_ASSERT(this, IsFastRegExp(context, regexp, LoadMap(regexp))); |
| 2603 CSA_ASSERT(this, IsString(string)); | 2645 CSA_ASSERT(this, IsString(string)); |
| 2604 | 2646 |
| 2605 Label checkreplacestring(this), if_iscallable(this), | 2647 Label checkreplacestring(this), if_iscallable(this), |
| 2606 runtime(this, Label::kDeferred); | 2648 runtime(this, Label::kDeferred); |
| 2607 | 2649 |
| 2608 // 2. Is {replace_value} callable? | 2650 // 2. Is {replace_value} callable? |
| 2609 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring); | 2651 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring); |
| 2610 Branch(IsCallableMap(LoadMap(replace_value)), &if_iscallable, | 2652 Branch(IsCallableMap(LoadMap(replace_value)), &if_iscallable, |
| 2611 &checkreplacestring); | 2653 &checkreplacestring); |
| 2612 | 2654 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2681 Node* const map = ThrowIfNotJSReceiver( | 2723 Node* const map = ThrowIfNotJSReceiver( |
| 2682 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 2724 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, |
| 2683 "RegExp.prototype.@@replace"); | 2725 "RegExp.prototype.@@replace"); |
| 2684 Node* const receiver = maybe_receiver; | 2726 Node* const receiver = maybe_receiver; |
| 2685 | 2727 |
| 2686 // Convert {maybe_string} to a String. | 2728 // Convert {maybe_string} to a String. |
| 2687 Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string); | 2729 Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string); |
| 2688 | 2730 |
| 2689 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? | 2731 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? |
| 2690 Label stub(this), runtime(this, Label::kDeferred); | 2732 Label stub(this), runtime(this, Label::kDeferred); |
| 2691 BranchIfFastRegExp(context, map, &stub, &runtime); | 2733 BranchIfFastRegExp(context, receiver, map, &stub, &runtime); |
| 2692 | 2734 |
| 2693 Bind(&stub); | 2735 Bind(&stub); |
| 2694 Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, | 2736 Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, |
| 2695 replace_value)); | 2737 replace_value)); |
| 2696 | 2738 |
| 2697 Bind(&runtime); | 2739 Bind(&runtime); |
| 2698 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, | 2740 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, |
| 2699 replace_value)); | 2741 replace_value)); |
| 2700 } | 2742 } |
| 2701 | 2743 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2725 Bind(&if_matched); | 2767 Bind(&if_matched); |
| 2726 { | 2768 { |
| 2727 Node* result = | 2769 Node* result = |
| 2728 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2770 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
| 2729 Return(result); | 2771 Return(result); |
| 2730 } | 2772 } |
| 2731 } | 2773 } |
| 2732 | 2774 |
| 2733 } // namespace internal | 2775 } // namespace internal |
| 2734 } // namespace v8 | 2776 } // namespace v8 |
| OLD | NEW |