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 |