OLD | NEW |
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.h" | 7 #include "src/builtins/builtins-constructor.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 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 | 469 |
470 // ES#sec-regexp.prototype.exec | 470 // ES#sec-regexp.prototype.exec |
471 // RegExp.prototype.exec ( string ) | 471 // RegExp.prototype.exec ( string ) |
472 // Implements the core of RegExp.prototype.exec but without actually | 472 // Implements the core of RegExp.prototype.exec but without actually |
473 // constructing the JSRegExpResult. Returns either null (if the RegExp did not | 473 // constructing the JSRegExpResult. Returns either null (if the RegExp did not |
474 // match) or a fixed array containing match indices as returned by | 474 // match) or a fixed array containing match indices as returned by |
475 // RegExpExecStub. | 475 // RegExpExecStub. |
476 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( | 476 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( |
477 Node* const context, Node* const regexp, Node* const string, | 477 Node* const context, Node* const regexp, Node* const string, |
478 Label* if_didnotmatch, const bool is_fastpath) { | 478 Label* if_didnotmatch, const bool is_fastpath) { |
479 Isolate* const isolate = this->isolate(); | |
480 | |
481 Node* const null = NullConstant(); | 479 Node* const null = NullConstant(); |
482 Node* const int_zero = IntPtrConstant(0); | 480 Node* const int_zero = IntPtrConstant(0); |
483 Node* const smi_zero = SmiConstant(Smi::kZero); | 481 Node* const smi_zero = SmiConstant(Smi::kZero); |
484 | 482 |
485 if (!is_fastpath) { | 483 if (!is_fastpath) { |
486 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, | 484 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, |
487 "RegExp.prototype.exec"); | 485 "RegExp.prototype.exec"); |
488 } | 486 } |
489 | 487 |
490 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string))); | 488 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string))); |
491 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE)); | 489 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE)); |
492 | 490 |
493 Variable var_result(this, MachineRepresentation::kTagged); | 491 Variable var_result(this, MachineRepresentation::kTagged); |
494 Label out(this); | 492 Label out(this); |
495 | 493 |
496 // Load lastIndex. | 494 // Load lastIndex. |
497 Variable var_lastindex(this, MachineRepresentation::kTagged); | 495 Variable var_lastindex(this, MachineRepresentation::kTagged); |
498 { | 496 { |
499 Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath); | 497 Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath); |
500 var_lastindex.Bind(regexp_lastindex); | 498 var_lastindex.Bind(regexp_lastindex); |
501 | 499 |
502 // Omit ToLength if lastindex is a non-negative smi. | 500 // Omit ToLength if lastindex is a non-negative smi. |
503 Label call_tolength(this, Label::kDeferred), next(this); | 501 Label call_tolength(this, Label::kDeferred), next(this); |
504 Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength); | 502 Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength); |
505 | 503 |
506 Bind(&call_tolength); | 504 Bind(&call_tolength); |
507 { | 505 { |
508 Callable tolength_callable = CodeFactory::ToLength(isolate); | |
509 var_lastindex.Bind( | 506 var_lastindex.Bind( |
510 CallStub(tolength_callable, context, regexp_lastindex)); | 507 CallBuiltin(Builtins::kToLength, context, regexp_lastindex)); |
511 Goto(&next); | 508 Goto(&next); |
512 } | 509 } |
513 | 510 |
514 Bind(&next); | 511 Bind(&next); |
515 } | 512 } |
516 | 513 |
517 // Check whether the regexp is global or sticky, which determines whether we | 514 // Check whether the regexp is global or sticky, which determines whether we |
518 // update last index later on. | 515 // update last index later on. |
519 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 516 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
520 Node* const is_global_or_sticky = WordAnd( | 517 Node* const is_global_or_sticky = WordAnd( |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 | 637 |
641 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); | 638 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception); |
642 | 639 |
643 // The {value} is not a compatible receiver for this method. | 640 // The {value} is not a compatible receiver for this method. |
644 Bind(&throw_exception); | 641 Bind(&throw_exception); |
645 { | 642 { |
646 Node* const message_id = SmiConstant(Smi::FromInt(msg_template)); | 643 Node* const message_id = SmiConstant(Smi::FromInt(msg_template)); |
647 Node* const method_name_str = HeapConstant( | 644 Node* const method_name_str = HeapConstant( |
648 isolate()->factory()->NewStringFromAsciiChecked(method_name, TENURED)); | 645 isolate()->factory()->NewStringFromAsciiChecked(method_name, TENURED)); |
649 | 646 |
650 Callable callable = CodeFactory::ToString(isolate()); | 647 Node* const value_str = |
651 Node* const value_str = CallStub(callable, context, maybe_receiver); | 648 CallBuiltin(Builtins::kToString, context, maybe_receiver); |
652 | 649 |
653 CallRuntime(Runtime::kThrowTypeError, context, message_id, method_name_str, | 650 CallRuntime(Runtime::kThrowTypeError, context, message_id, method_name_str, |
654 value_str); | 651 value_str); |
655 Unreachable(); | 652 Unreachable(); |
656 } | 653 } |
657 | 654 |
658 Bind(&out); | 655 Bind(&out); |
659 return var_value_map.value(); | 656 return var_value_map.value(); |
660 } | 657 } |
661 | 658 |
(...skipping 962 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1624 Variable var_length_; | 1621 Variable var_length_; |
1625 Variable var_capacity_; | 1622 Variable var_capacity_; |
1626 }; | 1623 }; |
1627 | 1624 |
1628 } // namespace | 1625 } // namespace |
1629 | 1626 |
1630 void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context, | 1627 void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context, |
1631 Node* const regexp, | 1628 Node* const regexp, |
1632 Node* const string, | 1629 Node* const string, |
1633 const bool is_fastpath) { | 1630 const bool is_fastpath) { |
1634 Isolate* const isolate = this->isolate(); | |
1635 | |
1636 Node* const null = NullConstant(); | 1631 Node* const null = NullConstant(); |
1637 Node* const int_zero = IntPtrConstant(0); | 1632 Node* const int_zero = IntPtrConstant(0); |
1638 Node* const smi_zero = SmiConstant(Smi::kZero); | 1633 Node* const smi_zero = SmiConstant(Smi::kZero); |
1639 | 1634 |
1640 Node* const is_global = | 1635 Node* const is_global = |
1641 FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath); | 1636 FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath); |
1642 | 1637 |
1643 Label if_isglobal(this), if_isnotglobal(this); | 1638 Label if_isglobal(this), if_isnotglobal(this); |
1644 Branch(is_global, &if_isglobal, &if_isnotglobal); | 1639 Branch(is_global, &if_isglobal, &if_isnotglobal); |
1645 | 1640 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1738 | 1733 |
1739 // Store the match, growing the fixed array if needed. | 1734 // Store the match, growing the fixed array if needed. |
1740 | 1735 |
1741 array.Push(match); | 1736 array.Push(match); |
1742 | 1737 |
1743 // Advance last index if the match is the empty string. | 1738 // Advance last index if the match is the empty string. |
1744 | 1739 |
1745 Node* const match_length = LoadStringLength(match); | 1740 Node* const match_length = LoadStringLength(match); |
1746 GotoIfNot(SmiEqual(match_length, smi_zero), &loop); | 1741 GotoIfNot(SmiEqual(match_length, smi_zero), &loop); |
1747 | 1742 |
1748 Node* last_index = LoadLastIndex(context, regexp, is_fastpath); | 1743 Node* const last_index = |
1749 | 1744 CallBuiltin(Builtins::kToLength, context, |
1750 Callable tolength_callable = CodeFactory::ToLength(isolate); | 1745 LoadLastIndex(context, regexp, is_fastpath)); |
1751 last_index = CallStub(tolength_callable, context, last_index); | |
1752 | |
1753 Node* const new_last_index = | 1746 Node* const new_last_index = |
1754 AdvanceStringIndex(string, last_index, is_unicode); | 1747 AdvanceStringIndex(string, last_index, is_unicode); |
1755 | 1748 |
1756 StoreLastIndex(context, regexp, new_last_index, is_fastpath); | 1749 StoreLastIndex(context, regexp, new_last_index, is_fastpath); |
1757 | 1750 |
1758 Goto(&loop); | 1751 Goto(&loop); |
1759 } | 1752 } |
1760 } | 1753 } |
1761 | 1754 |
1762 Bind(&out); | 1755 Bind(&out); |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2218 "RegExp.prototype.@@split"); | 2211 "RegExp.prototype.@@split"); |
2219 Node* const receiver = maybe_receiver; | 2212 Node* const receiver = maybe_receiver; |
2220 | 2213 |
2221 // Convert {maybe_string} to a String. | 2214 // Convert {maybe_string} to a String. |
2222 Node* const string = ToString(context, maybe_string); | 2215 Node* const string = ToString(context, maybe_string); |
2223 | 2216 |
2224 Label stub(this), runtime(this, Label::kDeferred); | 2217 Label stub(this), runtime(this, Label::kDeferred); |
2225 BranchIfFastRegExp(context, map, &stub, &runtime); | 2218 BranchIfFastRegExp(context, map, &stub, &runtime); |
2226 | 2219 |
2227 Bind(&stub); | 2220 Bind(&stub); |
2228 Callable split_callable = CodeFactory::RegExpSplit(isolate()); | 2221 Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, |
2229 Return(CallStub(split_callable, context, receiver, string, maybe_limit)); | 2222 maybe_limit)); |
2230 | 2223 |
2231 Bind(&runtime); | 2224 Bind(&runtime); |
2232 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, | 2225 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string, |
2233 maybe_limit)); | 2226 maybe_limit)); |
2234 } | 2227 } |
2235 | 2228 |
2236 Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath( | 2229 Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath( |
2237 Node* context, Node* regexp, Node* string, Node* replace_callable) { | 2230 Node* context, Node* regexp, Node* string, Node* replace_callable) { |
2238 // The fast path is reached only if {receiver} is a global unmodified | 2231 // The fast path is reached only if {receiver} is a global unmodified |
2239 // JSRegExp instance and {replace_callable} is callable. | 2232 // JSRegExp instance and {replace_callable} is callable. |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2557 runtime(this, Label::kDeferred); | 2550 runtime(this, Label::kDeferred); |
2558 | 2551 |
2559 // 2. Is {replace_value} callable? | 2552 // 2. Is {replace_value} callable? |
2560 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring); | 2553 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring); |
2561 Branch(IsCallableMap(LoadMap(replace_value)), &if_iscallable, | 2554 Branch(IsCallableMap(LoadMap(replace_value)), &if_iscallable, |
2562 &checkreplacestring); | 2555 &checkreplacestring); |
2563 | 2556 |
2564 // 3. Does ToString({replace_value}) contain '$'? | 2557 // 3. Does ToString({replace_value}) contain '$'? |
2565 Bind(&checkreplacestring); | 2558 Bind(&checkreplacestring); |
2566 { | 2559 { |
2567 Callable tostring_callable = CodeFactory::ToString(isolate()); | |
2568 Node* const replace_string = | 2560 Node* const replace_string = |
2569 CallStub(tostring_callable, context, replace_value); | 2561 CallBuiltin(Builtins::kToString, context, replace_value); |
2570 | 2562 |
2571 Callable indexof_callable = CodeFactory::StringIndexOf(isolate()); | |
2572 Node* const dollar_string = HeapConstant( | 2563 Node* const dollar_string = HeapConstant( |
2573 isolate()->factory()->LookupSingleCharacterStringFromCode('$')); | 2564 isolate()->factory()->LookupSingleCharacterStringFromCode('$')); |
2574 Node* const dollar_ix = CallStub(indexof_callable, context, replace_string, | 2565 Node* const dollar_ix = |
2575 dollar_string, SmiConstant(0)); | 2566 CallBuiltin(Builtins::kStringIndexOf, context, replace_string, |
| 2567 dollar_string, SmiConstant(0)); |
2576 GotoIfNot(SmiEqual(dollar_ix, SmiConstant(-1)), &runtime); | 2568 GotoIfNot(SmiEqual(dollar_ix, SmiConstant(-1)), &runtime); |
2577 | 2569 |
2578 Return( | 2570 Return( |
2579 ReplaceSimpleStringFastPath(context, regexp, string, replace_string)); | 2571 ReplaceSimpleStringFastPath(context, regexp, string, replace_string)); |
2580 } | 2572 } |
2581 | 2573 |
2582 // {regexp} is unmodified and {replace_value} is callable. | 2574 // {regexp} is unmodified and {replace_value} is callable. |
2583 Bind(&if_iscallable); | 2575 Bind(&if_iscallable); |
2584 { | 2576 { |
2585 Node* const replace_fn = replace_value; | 2577 Node* const replace_fn = replace_value; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2629 // } | 2621 // } |
2630 // } | 2622 // } |
2631 | 2623 |
2632 // Ensure {maybe_receiver} is a JSReceiver. | 2624 // Ensure {maybe_receiver} is a JSReceiver. |
2633 Node* const map = ThrowIfNotJSReceiver( | 2625 Node* const map = ThrowIfNotJSReceiver( |
2634 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, | 2626 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, |
2635 "RegExp.prototype.@@replace"); | 2627 "RegExp.prototype.@@replace"); |
2636 Node* const receiver = maybe_receiver; | 2628 Node* const receiver = maybe_receiver; |
2637 | 2629 |
2638 // Convert {maybe_string} to a String. | 2630 // Convert {maybe_string} to a String. |
2639 Callable tostring_callable = CodeFactory::ToString(isolate()); | 2631 Node* const string = CallBuiltin(Builtins::kToString, context, maybe_string); |
2640 Node* const string = CallStub(tostring_callable, context, maybe_string); | |
2641 | 2632 |
2642 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? | 2633 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? |
2643 Label stub(this), runtime(this, Label::kDeferred); | 2634 Label stub(this), runtime(this, Label::kDeferred); |
2644 BranchIfFastRegExp(context, map, &stub, &runtime); | 2635 BranchIfFastRegExp(context, map, &stub, &runtime); |
2645 | 2636 |
2646 Bind(&stub); | 2637 Bind(&stub); |
2647 Callable replace_callable = CodeFactory::RegExpReplace(isolate()); | 2638 Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, |
2648 Return(CallStub(replace_callable, context, receiver, string, replace_value)); | 2639 replace_value)); |
2649 | 2640 |
2650 Bind(&runtime); | 2641 Bind(&runtime); |
2651 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, | 2642 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string, |
2652 replace_value)); | 2643 replace_value)); |
2653 } | 2644 } |
2654 | 2645 |
2655 // Simple string matching functionality for internal use which does not modify | 2646 // Simple string matching functionality for internal use which does not modify |
2656 // the last match info. | 2647 // the last match info. |
2657 TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) { | 2648 TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) { |
2658 Node* const regexp = Parameter(1); | 2649 Node* const regexp = Parameter(1); |
(...skipping 19 matching lines...) Expand all Loading... |
2678 Bind(&if_matched); | 2669 Bind(&if_matched); |
2679 { | 2670 { |
2680 Node* result = | 2671 Node* result = |
2681 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2672 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
2682 Return(result); | 2673 Return(result); |
2683 } | 2674 } |
2684 } | 2675 } |
2685 | 2676 |
2686 } // namespace internal | 2677 } // namespace internal |
2687 } // namespace v8 | 2678 } // namespace v8 |
OLD | NEW |