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

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

Issue 2415663007: [regexp] RegExp.prototype.replace fast-paths (Closed)
Patch Set: Remove unused variable Created 4 years, 2 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 | « no previous file | src/runtime/runtime.h » ('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 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 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-utils.h" 5 #include "src/builtins/builtins-utils.h"
6 #include "src/builtins/builtins.h" 6 #include "src/builtins/builtins.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/regexp/jsregexp.h" 9 #include "src/regexp/jsregexp.h"
10 #include "src/regexp/regexp-utils.h" 10 #include "src/regexp/regexp-utils.h"
(...skipping 732 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 } 743 }
744 744
745 // ES6 21.2.4.2. 745 // ES6 21.2.4.2.
746 BUILTIN(RegExpPrototypeSpeciesGetter) { 746 BUILTIN(RegExpPrototypeSpeciesGetter) {
747 HandleScope scope(isolate); 747 HandleScope scope(isolate);
748 return *args.receiver(); 748 return *args.receiver();
749 } 749 }
750 750
751 namespace { 751 namespace {
752 752
753 // Fast-path implementation for flag checks on an unmodified JSRegExp instance.
754 compiler::Node* FastFlagGetter(CodeStubAssembler* a,
755 compiler::Node* const regexp,
756 JSRegExp::Flag flag) {
757 typedef compiler::Node Node;
758
759 Node* const smi_zero = a->SmiConstant(Smi::kZero);
760 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset);
761 Node* const mask = a->SmiConstant(Smi::FromInt(flag));
762 Node* const is_flag_set = a->WordNotEqual(a->WordAnd(flags, mask), smi_zero);
763
764 return is_flag_set;
765 }
766
753 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, 767 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag,
754 v8::Isolate::UseCounterFeature counter, 768 v8::Isolate::UseCounterFeature counter,
755 const char* method_name) { 769 const char* method_name) {
756 typedef CodeStubAssembler::Label Label; 770 typedef CodeStubAssembler::Label Label;
757 typedef compiler::Node Node; 771 typedef compiler::Node Node;
758 772
759 Node* const receiver = a->Parameter(0); 773 Node* const receiver = a->Parameter(0);
760 Node* const context = a->Parameter(3); 774 Node* const context = a->Parameter(3);
761 775
762 Isolate* isolate = a->isolate(); 776 Isolate* isolate = a->isolate();
763 Node* const int_zero = a->IntPtrConstant(0);
764 777
765 // Check whether we have an unmodified regexp instance. 778 // Check whether we have an unmodified regexp instance.
766 Label if_isunmodifiedjsregexp(a), 779 Label if_isunmodifiedjsregexp(a),
767 if_isnotunmodifiedjsregexp(a, Label::kDeferred); 780 if_isnotunmodifiedjsregexp(a, Label::kDeferred);
768 781
769 a->GotoIf(a->TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp); 782 a->GotoIf(a->TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp);
770 783
771 Node* const receiver_map = a->LoadMap(receiver); 784 Node* const receiver_map = a->LoadMap(receiver);
772 Node* const instance_type = a->LoadMapInstanceType(receiver_map); 785 Node* const instance_type = a->LoadMapInstanceType(receiver_map);
773 786
774 a->Branch(a->Word32Equal(instance_type, a->Int32Constant(JS_REGEXP_TYPE)), 787 a->Branch(a->Word32Equal(instance_type, a->Int32Constant(JS_REGEXP_TYPE)),
775 &if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp); 788 &if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp);
776 789
777 a->Bind(&if_isunmodifiedjsregexp); 790 a->Bind(&if_isunmodifiedjsregexp);
778 { 791 {
779 // Refer to JSRegExp's flag property on the fast-path. 792 // Refer to JSRegExp's flag property on the fast-path.
780 Node* const flags_smi = 793 Node* const is_flag_set = FastFlagGetter(a, receiver, flag);
781 a->LoadObjectField(receiver, JSRegExp::kFlagsOffset); 794 a->Return(a->Select(is_flag_set, a->TrueConstant(), a->FalseConstant()));
jgruber 2016/10/15 18:23:18 TODO(me): Is this equivalent to a->Return(is_flag_
Yang 2016/10/17 13:30:54 Pretty sure you need to use Select, which turns th
782 Node* const flags_intptr = a->SmiUntag(flags_smi);
783 Node* const mask = a->IntPtrConstant(flag);
784 Node* const is_global =
785 a->WordNotEqual(a->WordAnd(flags_intptr, mask), int_zero);
786 a->Return(a->Select(is_global, a->TrueConstant(), a->FalseConstant()));
787 } 795 }
788 796
789 a->Bind(&if_isnotunmodifiedjsregexp); 797 a->Bind(&if_isnotunmodifiedjsregexp);
790 { 798 {
791 Node* const native_context = a->LoadNativeContext(context); 799 Node* const native_context = a->LoadNativeContext(context);
792 Node* const regexp_fun = 800 Node* const regexp_fun =
793 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); 801 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
794 Node* const initial_map = a->LoadObjectField( 802 Node* const initial_map = a->LoadObjectField(
795 regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 803 regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
796 Node* const initial_prototype = a->LoadMapPrototype(initial_map); 804 Node* const initial_prototype = a->LoadMapPrototype(initial_map);
(...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after
1565 typedef compiler::Node Node; 1573 typedef compiler::Node Node;
1566 1574
1567 Isolate* const isolate = a->isolate(); 1575 Isolate* const isolate = a->isolate();
1568 1576
1569 Node* const maybe_receiver = a->Parameter(0); 1577 Node* const maybe_receiver = a->Parameter(0);
1570 Node* const maybe_string = a->Parameter(1); 1578 Node* const maybe_string = a->Parameter(1);
1571 Node* const replace_value = a->Parameter(2); 1579 Node* const replace_value = a->Parameter(2);
1572 Node* const context = a->Parameter(5); 1580 Node* const context = a->Parameter(5);
1573 1581
1574 Node* const int_zero = a->IntPtrConstant(0); 1582 Node* const int_zero = a->IntPtrConstant(0);
1583 Node* const smi_zero = a->SmiConstant(Smi::kZero);
1575 1584
1576 // Ensure {receiver} is a JSReceiver. 1585 // Ensure {receiver} is a JSReceiver.
1577 Node* const map = 1586 Node* const map =
1578 ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver, 1587 ThrowIfNotJSReceiver(a, isolate, context, maybe_receiver,
1579 MessageTemplate::kIncompatibleMethodReceiver, 1588 MessageTemplate::kIncompatibleMethodReceiver,
1580 "RegExp.prototype.@@replace"); 1589 "RegExp.prototype.@@replace");
1581 Node* const receiver = maybe_receiver; 1590 Node* const receiver = maybe_receiver;
1582 1591
1583 // Convert {maybe_string} to a String. 1592 // Convert {maybe_string} to a String.
1584 Callable tostring_callable = CodeFactory::ToString(isolate); 1593 Callable tostring_callable = CodeFactory::ToString(isolate);
1585 Node* const string = a->CallStub(tostring_callable, context, maybe_string); 1594 Node* const string = a->CallStub(tostring_callable, context, maybe_string);
1586 1595
1587 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? 1596 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
1588 Label checkreplacecallable(a), runtime(a, Label::kDeferred), fastpath(a); 1597 Label checkreplacecallable(a), runtime(a, Label::kDeferred), fastpath(a);
1589 BranchIfFastPath(a, context, map, &checkreplacecallable, &runtime); 1598 BranchIfFastPath(a, context, map, &checkreplacecallable, &runtime);
1590 1599
1591 a->Bind(&checkreplacecallable); 1600 a->Bind(&checkreplacecallable);
1592 Node* const regexp = receiver; 1601 Node* const regexp = receiver;
1593 1602
1594 // 2. Is {replace_value} callable? 1603 // 2. Is {replace_value} callable?
1595 Label checkreplacestring(a); 1604 Label checkreplacestring(a), if_iscallable(a, Label::kDeferred);
1596 a->GotoIf(a->TaggedIsSmi(replace_value), &checkreplacestring); 1605 a->GotoIf(a->TaggedIsSmi(replace_value), &checkreplacestring);
1597 1606
1598 Node* const replace_value_map = a->LoadMap(replace_value); 1607 Node* const replace_value_map = a->LoadMap(replace_value);
1599 a->Branch( 1608 a->Branch(
1600 a->Word32Equal(a->Word32And(a->LoadMapBitField(replace_value_map), 1609 a->Word32Equal(a->Word32And(a->LoadMapBitField(replace_value_map),
1601 a->Int32Constant(1 << Map::kIsCallable)), 1610 a->Int32Constant(1 << Map::kIsCallable)),
1602 a->Int32Constant(0)), 1611 a->Int32Constant(0)),
1603 &checkreplacestring, &runtime); 1612 &checkreplacestring, &if_iscallable);
1604 1613
1605 // 3. Does ToString({replace_value}) contain '$'? 1614 // 3. Does ToString({replace_value}) contain '$'?
1606 a->Bind(&checkreplacestring); 1615 a->Bind(&checkreplacestring);
1607 { 1616 {
1608 Node* const replace_string = 1617 Node* const replace_string =
1609 a->CallStub(tostring_callable, context, replace_value); 1618 a->CallStub(tostring_callable, context, replace_value);
1610 1619
1611 Node* const dollar_char = a->IntPtrConstant('$'); 1620 Node* const dollar_char = a->IntPtrConstant('$');
1612 Node* const smi_minusone = a->SmiConstant(Smi::FromInt(-1)); 1621 Node* const smi_minusone = a->SmiConstant(Smi::FromInt(-1));
1613 a->GotoUnless(a->SmiEqual(a->StringIndexOfChar(context, replace_string, 1622 a->GotoUnless(a->SmiEqual(a->StringIndexOfChar(context, replace_string,
1614 dollar_char, int_zero), 1623 dollar_char, int_zero),
1615 smi_minusone), 1624 smi_minusone),
1616 &runtime); 1625 &runtime);
1617 1626
1618 a->Return(ReplaceFastPath(a, context, regexp, string, replace_string)); 1627 a->Return(ReplaceFastPath(a, context, regexp, string, replace_string));
1619 } 1628 }
1620 1629
1630 // {regexp} is unmodified and {replace_value} is callable.
1631 a->Bind(&if_iscallable);
1632 {
1633 Node* const replace_callable = replace_value;
1634
1635 // Check if the {regexp} is global.
1636 Label if_isglobal(a), if_isnotglobal(a);
1637 Node* const is_global = FastFlagGetter(a, regexp, JSRegExp::kGlobal);
1638 a->Branch(is_global, &if_isglobal, &if_isnotglobal);
1639
1640 a->Bind(&if_isglobal);
1641 {
1642 FastStoreLastIndex(a, context, regexp, smi_zero);
1643 Node* const result =
1644 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithFunction,
1645 context, string, regexp, replace_callable);
1646 a->Return(result);
1647 }
1648
1649 a->Bind(&if_isnotglobal);
1650 {
1651 Node* const result =
1652 a->CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction,
1653 context, string, regexp, replace_callable);
1654 a->Return(result);
1655 }
1656 }
1657
1621 a->Bind(&runtime); 1658 a->Bind(&runtime);
1622 { 1659 {
1623 Node* const result = a->CallRuntime(Runtime::kRegExpReplace, context, 1660 Node* const result = a->CallRuntime(Runtime::kRegExpReplace, context,
1624 receiver, string, replace_value); 1661 receiver, string, replace_value);
1625 a->Return(result); 1662 a->Return(result);
1626 } 1663 }
1627 } 1664 }
1628 1665
1629 // Simple string matching functionality for internal use which does not modify 1666 // Simple string matching functionality for internal use which does not modify
1630 // the last match info. 1667 // the last match info.
(...skipping 27 matching lines...) Expand all
1658 a->Bind(&if_matched); 1695 a->Bind(&if_matched);
1659 { 1696 {
1660 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, 1697 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context,
1661 match_indices, string); 1698 match_indices, string);
1662 a->Return(result); 1699 a->Return(result);
1663 } 1700 }
1664 } 1701 }
1665 1702
1666 } // namespace internal 1703 } // namespace internal
1667 } // namespace v8 1704 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | src/runtime/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698