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-regexp.h" | 5 #include "src/builtins/builtins-regexp.h" |
6 | 6 |
7 #include "src/builtins/builtins-constructor.h" | 7 #include "src/builtins/builtins-constructor.h" |
8 #include "src/builtins/builtins-utils.h" | 8 #include "src/builtins/builtins-utils.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 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 | 474 |
475 // ES#sec-regexp.prototype.exec | 475 // ES#sec-regexp.prototype.exec |
476 // RegExp.prototype.exec ( string ) | 476 // RegExp.prototype.exec ( string ) |
477 // Implements the core of RegExp.prototype.exec but without actually | 477 // Implements the core of RegExp.prototype.exec but without actually |
478 // constructing the JSRegExpResult. Returns either null (if the RegExp did not | 478 // constructing the JSRegExpResult. Returns either null (if the RegExp did not |
479 // match) or a fixed array containing match indices as returned by | 479 // match) or a fixed array containing match indices as returned by |
480 // RegExpExecStub. | 480 // RegExpExecStub. |
481 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( | 481 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( |
482 Node* const context, Node* const regexp, Node* const string, | 482 Node* const context, Node* const regexp, Node* const string, |
483 Label* if_didnotmatch, const bool is_fastpath) { | 483 Label* if_didnotmatch, const bool is_fastpath) { |
484 Isolate* const isolate = this->isolate(); | |
485 | |
486 Node* const null = NullConstant(); | 484 Node* const null = NullConstant(); |
487 Node* const int_zero = IntPtrConstant(0); | 485 Node* const int_zero = IntPtrConstant(0); |
488 Node* const smi_zero = SmiConstant(Smi::kZero); | 486 Node* const smi_zero = SmiConstant(Smi::kZero); |
489 | 487 |
490 if (!is_fastpath) { | 488 if (!is_fastpath) { |
491 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, | 489 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, |
492 "RegExp.prototype.exec"); | 490 "RegExp.prototype.exec"); |
493 } | 491 } |
494 | 492 |
495 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string))); | 493 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string))); |
496 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE)); | 494 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE)); |
497 | 495 |
498 Variable var_result(this, MachineRepresentation::kTagged); | 496 Variable var_result(this, MachineRepresentation::kTagged); |
499 Label out(this); | 497 Label out(this); |
500 | 498 |
501 // Load lastIndex. | 499 // Load lastIndex. |
502 Variable var_lastindex(this, MachineRepresentation::kTagged); | 500 Variable var_lastindex(this, MachineRepresentation::kTagged); |
503 { | 501 { |
504 Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath); | 502 Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath); |
505 var_lastindex.Bind(regexp_lastindex); | 503 var_lastindex.Bind(regexp_lastindex); |
506 | 504 |
507 // Omit ToLength if lastindex is a non-negative smi. | 505 // Omit ToLength if lastindex is a non-negative smi. |
508 Label call_tolength(this, Label::kDeferred), next(this); | 506 Label call_tolength(this, Label::kDeferred), next(this); |
509 Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength); | 507 Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength); |
510 | 508 |
511 Bind(&call_tolength); | 509 Bind(&call_tolength); |
512 { | 510 { |
513 Callable tolength_callable = CodeFactory::ToLength(isolate); | |
514 var_lastindex.Bind( | 511 var_lastindex.Bind( |
515 CallStub(tolength_callable, context, regexp_lastindex)); | 512 CallBuiltin(Builtins::kToLength, context, regexp_lastindex)); |
516 Goto(&next); | 513 Goto(&next); |
517 } | 514 } |
518 | 515 |
519 Bind(&next); | 516 Bind(&next); |
520 } | 517 } |
521 | 518 |
522 // Check whether the regexp is global or sticky, which determines whether we | 519 // Check whether the regexp is global or sticky, which determines whether we |
523 // update last index later on. | 520 // update last index later on. |
524 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 521 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
525 Node* const is_global_or_sticky = WordAnd( | 522 Node* const is_global_or_sticky = WordAnd( |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 | 642 |
646 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); | 643 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); |
647 | 644 |
648 // The {value} is not a compatible receiver for this method. | 645 // The {value} is not a compatible receiver for this method. |
649 Bind(&throw_exception); | 646 Bind(&throw_exception); |
650 { | 647 { |
651 Node* const message_id = SmiConstant(Smi::FromInt(msg_template)); | 648 Node* const message_id = SmiConstant(Smi::FromInt(msg_template)); |
652 Node* const method_name_str = HeapConstant( | 649 Node* const method_name_str = HeapConstant( |
653 isolate()->factory()->NewStringFromAsciiChecked(method_name, TENURED)); | 650 isolate()->factory()->NewStringFromAsciiChecked(method_name, TENURED)); |
654 | 651 |
655 Callable callable = CodeFactory::ToString(isolate()); | 652 Node* const value_str = |
656 Node* const value_str = CallStub(callable, context, maybe_receiver); | 653 CallBuiltin(Builtins::kToString, context, maybe_receiver); |
657 | 654 |
658 CallRuntime(Runtime::kThrowTypeError, context, message_id, method_name_str, | 655 CallRuntime(Runtime::kThrowTypeError, context, message_id, method_name_str, |
659 value_str); | 656 value_str); |
660 Unreachable(); | 657 Unreachable(); |
661 } | 658 } |
662 | 659 |
663 Bind(&out); | 660 Bind(&out); |
664 return var_value_map.value(); | 661 return var_value_map.value(); |
665 } | 662 } |
666 | 663 |
(...skipping 1081 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1748 Variable var_length_; | 1745 Variable var_length_; |
1749 Variable var_capacity_; | 1746 Variable var_capacity_; |
1750 }; | 1747 }; |
1751 | 1748 |
1752 } // namespace | 1749 } // namespace |
1753 | 1750 |
1754 void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context, | 1751 void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context, |
1755 Node* const regexp, | 1752 Node* const regexp, |
1756 Node* const string, | 1753 Node* const string, |
1757 const bool is_fastpath) { | 1754 const bool is_fastpath) { |
1758 Isolate* const isolate = this->isolate(); | |
1759 | |
1760 Node* const null = NullConstant(); | 1755 Node* const null = NullConstant(); |
1761 Node* const int_zero = IntPtrConstant(0); | 1756 Node* const int_zero = IntPtrConstant(0); |
1762 Node* const smi_zero = SmiConstant(Smi::kZero); | 1757 Node* const smi_zero = SmiConstant(Smi::kZero); |
1763 | 1758 |
1764 Node* const is_global = | 1759 Node* const is_global = |
1765 FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath); | 1760 FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath); |
1766 | 1761 |
1767 Label if_isglobal(this), if_isnotglobal(this); | 1762 Label if_isglobal(this), if_isnotglobal(this); |
1768 Branch(is_global, &if_isglobal, &if_isnotglobal); | 1763 Branch(is_global, &if_isglobal, &if_isnotglobal); |
1769 | 1764 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1863 // Store the match, growing the fixed array if needed. | 1858 // Store the match, growing the fixed array if needed. |
1864 | 1859 |
1865 array.Push(match); | 1860 array.Push(match); |
1866 | 1861 |
1867 // Advance last index if the match is the empty string. | 1862 // Advance last index if the match is the empty string. |
1868 | 1863 |
1869 Node* const match_length = LoadStringLength(match); | 1864 Node* const match_length = LoadStringLength(match); |
1870 GotoIfNot(SmiEqual(match_length, smi_zero), &loop); | 1865 GotoIfNot(SmiEqual(match_length, smi_zero), &loop); |
1871 | 1866 |
1872 Node* last_index = LoadLastIndex(context, regexp, is_fastpath); | 1867 Node* last_index = LoadLastIndex(context, regexp, is_fastpath); |
1873 | 1868 last_index = CallBuiltin(Builtins::kToLength, context, last_index); |
1874 Callable tolength_callable = CodeFactory::ToLength(isolate); | |
1875 last_index = CallStub(tolength_callable, context, last_index); | |
1876 | 1869 |
1877 Node* const new_last_index = | 1870 Node* const new_last_index = |
1878 AdvanceStringIndex(string, last_index, is_unicode); | 1871 AdvanceStringIndex(string, last_index, is_unicode); |
1879 | 1872 |
1880 StoreLastIndex(context, regexp, new_last_index, is_fastpath); | 1873 StoreLastIndex(context, regexp, new_last_index, is_fastpath); |
1881 | 1874 |
1882 Goto(&loop); | 1875 Goto(&loop); |
1883 } | 1876 } |
1884 } | 1877 } |
1885 | 1878 |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2342 "RegExp.prototype.@@split"); | 2335 "RegExp.prototype.@@split"); |
2343 Node* const receiver = maybe_receiver; | 2336 Node* const receiver = maybe_receiver; |
2344 | 2337 |
2345 // Convert {maybe_string} to a String. | 2338 // Convert {maybe_string} to a String. |
2346 Node* const string = ToString(context, maybe_string); | 2339 Node* const string = ToString(context, maybe_string); |
2347 | 2340 |
2348 Label stub(this), runtime(this, Label::kDeferred); | 2341 Label stub(this), runtime(this, Label::kDeferred); |
2349 BranchIfFastRegExp(context, map, &stub, &runtime); | 2342 BranchIfFastRegExp(context, map, &stub, &runtime); |
2350 | 2343 |
2351 Bind(&stub); | 2344 Bind(&stub); |
2352 Callable split_callable = CodeFactory::RegExpSplit(isolate()); | 2345 Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, |
2353 Return(CallStub(split_callable, context, receiver, string, maybe_limit)); | 2346 maybe_limit)); |
2354 | 2347 |
2355 Bind(&runtime); | 2348 Bind(&runtime); |
2356 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, | 2349 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, |
2357 maybe_limit)); | 2350 maybe_limit)); |
2358 } | 2351 } |
2359 | 2352 |
2360 Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath( | 2353 Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath( |
2361 Node* context, Node* regexp, Node* string, Node* replace_callable) { | 2354 Node* context, Node* regexp, Node* string, Node* replace_callable) { |
2362 // The fast path is reached only if {receiver} is a global unmodified | 2355 // The fast path is reached only if {receiver} is a global unmodified |
2363 // JSRegExp instance and {replace_callable} is callable. | 2356 // JSRegExp instance and {replace_callable} is callable. |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2679 runtime(this, Label::kDeferred); | 2672 runtime(this, Label::kDeferred); |
2680 | 2673 |
2681 // 2. Is {replace_value} callable? | 2674 // 2. Is {replace_value} callable? |
2682 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring); | 2675 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring); |
2683 Branch(IsCallableMap(LoadMap(replace_value)), &if_iscallable, | 2676 Branch(IsCallableMap(LoadMap(replace_value)), &if_iscallable, |
2684 &checkreplacestring); | 2677 &checkreplacestring); |
2685 | 2678 |
2686 // 3. Does ToString({replace_value}) contain '$'? | 2679 // 3. Does ToString({replace_value}) contain '$'? |
2687 Bind(&checkreplacestring); | 2680 Bind(&checkreplacestring); |
2688 { | 2681 { |
2689 Callable tostring_callable = CodeFactory::ToString(isolate()); | |
2690 Node* const replace_string = | 2682 Node* const replace_string = |
2691 CallStub(tostring_callable, context, replace_value); | 2683 CallBuiltin(Builtins::kToString, context, replace_value); |
2692 | 2684 |
2693 Callable indexof_callable = CodeFactory::StringIndexOf(isolate()); | |
2694 Node* const dollar_string = HeapConstant( | 2685 Node* const dollar_string = HeapConstant( |
2695 isolate()->factory()->LookupSingleCharacterStringFromCode('$')); | 2686 isolate()->factory()->LookupSingleCharacterStringFromCode('$')); |
2696 Node* const dollar_ix = CallStub(indexof_callable, context, replace_string, | 2687 Node* const dollar_ix = |
2697 dollar_string, SmiConstant(0)); | 2688 CallBuiltin(Builtins::kStringIndexOf, context, replace_string, |
| 2689 dollar_string, SmiConstant(0)); |
2698 GotoIfNot(SmiEqual(dollar_ix, SmiConstant(-1)), &runtime); | 2690 GotoIfNot(SmiEqual(dollar_ix, SmiConstant(-1)), &runtime); |
2699 | 2691 |
2700 Return( | 2692 Return( |
2701 ReplaceSimpleStringFastPath(context, regexp, string, replace_string)); | 2693 ReplaceSimpleStringFastPath(context, regexp, string, replace_string)); |
2702 } | 2694 } |
2703 | 2695 |
2704 // {regexp} is unmodified and {replace_value} is callable. | 2696 // {regexp} is unmodified and {replace_value} is callable. |
2705 Bind(&if_iscallable); | 2697 Bind(&if_iscallable); |
2706 { | 2698 { |
2707 Node* const replace_fn = replace_value; | 2699 Node* const replace_fn = replace_value; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2751 // } | 2743 // } |
2752 // } | 2744 // } |
2753 | 2745 |
2754 // Ensure {maybe_receiver} is a JSReceiver. | 2746 // Ensure {maybe_receiver} is a JSReceiver. |
2755 Node* const map = ThrowIfNotJSReceiver( | 2747 Node* const map = ThrowIfNotJSReceiver( |
2756 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 2748 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, |
2757 "RegExp.prototype.@@replace"); | 2749 "RegExp.prototype.@@replace"); |
2758 Node* const receiver = maybe_receiver; | 2750 Node* const receiver = maybe_receiver; |
2759 | 2751 |
2760 // Convert {maybe_string} to a String. | 2752 // Convert {maybe_string} to a String. |
2761 Callable tostring_callable = CodeFactory::ToString(isolate()); | 2753 Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string); |
2762 Node* const string = CallStub(tostring_callable, context, maybe_string); | |
2763 | 2754 |
2764 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? | 2755 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? |
2765 Label stub(this), runtime(this, Label::kDeferred); | 2756 Label stub(this), runtime(this, Label::kDeferred); |
2766 BranchIfFastRegExp(context, map, &stub, &runtime); | 2757 BranchIfFastRegExp(context, map, &stub, &runtime); |
2767 | 2758 |
2768 Bind(&stub); | 2759 Bind(&stub); |
2769 Callable replace_callable = CodeFactory::RegExpReplace(isolate()); | 2760 Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, |
2770 Return(CallStub(replace_callable, context, receiver, string, replace_value)); | 2761 replace_value)); |
2771 | 2762 |
2772 Bind(&runtime); | 2763 Bind(&runtime); |
2773 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, | 2764 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, |
2774 replace_value)); | 2765 replace_value)); |
2775 } | 2766 } |
2776 | 2767 |
2777 // Simple string matching functionality for internal use which does not modify | 2768 // Simple string matching functionality for internal use which does not modify |
2778 // the last match info. | 2769 // the last match info. |
2779 TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) { | 2770 TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) { |
2780 Node* const regexp = Parameter(1); | 2771 Node* const regexp = Parameter(1); |
(...skipping 19 matching lines...) Expand all Loading... |
2800 Bind(&if_matched); | 2791 Bind(&if_matched); |
2801 { | 2792 { |
2802 Node* result = | 2793 Node* result = |
2803 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2794 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
2804 Return(result); | 2795 Return(result); |
2805 } | 2796 } |
2806 } | 2797 } |
2807 | 2798 |
2808 } // namespace internal | 2799 } // namespace internal |
2809 } // namespace v8 | 2800 } // namespace v8 |
OLD | NEW |