Chromium Code Reviews| 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 |