OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |