Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: src/builtins/builtins-regexp-gen.cc

Issue 2797993002: [regexp] Ensure there are no shape changes on the fast path (Closed)
Patch Set: Add test Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-regexp-gen.h ('k') | src/builtins/builtins-string-gen.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/builtins/builtins-regexp-gen.h ('k') | src/builtins/builtins-string-gen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698