| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/runtime/runtime-utils.h" | 5 #include "src/runtime/runtime-utils.h" |
| 6 | 6 |
| 7 #include "src/arguments.h" | 7 #include "src/arguments.h" |
| 8 #include "src/conversions-inl.h" | 8 #include "src/conversions-inl.h" |
| 9 #include "src/isolate-inl.h" | 9 #include "src/isolate-inl.h" |
| 10 #include "src/messages.h" | 10 #include "src/messages.h" |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 static const size_t kMaxRegexpIndicesListCapacity = 8 * KB; | 394 static const size_t kMaxRegexpIndicesListCapacity = 8 * KB; |
| 395 if (isolate->regexp_indices()->capacity() > kMaxRegexpIndicesListCapacity) { | 395 if (isolate->regexp_indices()->capacity() > kMaxRegexpIndicesListCapacity) { |
| 396 isolate->regexp_indices()->Clear(); // Throw away backing storage | 396 isolate->regexp_indices()->Clear(); // Throw away backing storage |
| 397 } | 397 } |
| 398 } | 398 } |
| 399 } // namespace | 399 } // namespace |
| 400 | 400 |
| 401 template <typename ResultSeqString> | 401 template <typename ResultSeqString> |
| 402 MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( | 402 MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( |
| 403 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> pattern_regexp, | 403 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> pattern_regexp, |
| 404 Handle<String> replacement, Handle<JSObject> last_match_info) { | 404 Handle<String> replacement, Handle<RegExpMatchInfo> last_match_info) { |
| 405 DCHECK(subject->IsFlat()); | 405 DCHECK(subject->IsFlat()); |
| 406 DCHECK(replacement->IsFlat()); | 406 DCHECK(replacement->IsFlat()); |
| 407 | 407 |
| 408 List<int>* indices = GetRewoundRegexpIndicesList(isolate); | 408 List<int>* indices = GetRewoundRegexpIndicesList(isolate); |
| 409 | 409 |
| 410 DCHECK_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); | 410 DCHECK_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); |
| 411 String* pattern = | 411 String* pattern = |
| 412 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); | 412 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); |
| 413 int subject_len = subject->length(); | 413 int subject_len = subject->length(); |
| 414 int pattern_len = pattern->length(); | 414 int pattern_len = pattern->length(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 indices->at(matches - 1) + pattern_len}; | 472 indices->at(matches - 1) + pattern_len}; |
| 473 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); | 473 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); |
| 474 | 474 |
| 475 TruncateRegexpIndicesList(isolate); | 475 TruncateRegexpIndicesList(isolate); |
| 476 | 476 |
| 477 return *result; | 477 return *result; |
| 478 } | 478 } |
| 479 | 479 |
| 480 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( | 480 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( |
| 481 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 481 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, |
| 482 Handle<String> replacement, Handle<JSObject> last_match_info) { | 482 Handle<String> replacement, Handle<RegExpMatchInfo> last_match_info) { |
| 483 DCHECK(subject->IsFlat()); | 483 DCHECK(subject->IsFlat()); |
| 484 DCHECK(replacement->IsFlat()); | 484 DCHECK(replacement->IsFlat()); |
| 485 | 485 |
| 486 int capture_count = regexp->CaptureCount(); | 486 int capture_count = regexp->CaptureCount(); |
| 487 int subject_length = subject->length(); | 487 int subject_length = subject->length(); |
| 488 | 488 |
| 489 // CompiledReplacement uses zone allocation. | 489 // CompiledReplacement uses zone allocation. |
| 490 Zone zone(isolate->allocator()); | 490 Zone zone(isolate->allocator()); |
| 491 CompiledReplacement compiled_replacement(&zone); | 491 CompiledReplacement compiled_replacement(&zone); |
| 492 bool simple_replace = | 492 bool simple_replace = |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 554 | 554 |
| 555 RegExpImpl::SetLastMatchInfo(last_match_info, subject, capture_count, | 555 RegExpImpl::SetLastMatchInfo(last_match_info, subject, capture_count, |
| 556 global_cache.LastSuccessfulMatch()); | 556 global_cache.LastSuccessfulMatch()); |
| 557 | 557 |
| 558 RETURN_RESULT_OR_FAILURE(isolate, builder.ToString()); | 558 RETURN_RESULT_OR_FAILURE(isolate, builder.ToString()); |
| 559 } | 559 } |
| 560 | 560 |
| 561 template <typename ResultSeqString> | 561 template <typename ResultSeqString> |
| 562 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( | 562 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( |
| 563 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 563 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, |
| 564 Handle<JSObject> last_match_info) { | 564 Handle<RegExpMatchInfo> last_match_info) { |
| 565 DCHECK(subject->IsFlat()); | 565 DCHECK(subject->IsFlat()); |
| 566 | 566 |
| 567 // Shortcut for simple non-regexp global replacements | 567 // Shortcut for simple non-regexp global replacements |
| 568 if (regexp->TypeTag() == JSRegExp::ATOM) { | 568 if (regexp->TypeTag() == JSRegExp::ATOM) { |
| 569 Handle<String> empty_string = isolate->factory()->empty_string(); | 569 Handle<String> empty_string = isolate->factory()->empty_string(); |
| 570 if (subject->IsOneByteRepresentation()) { | 570 if (subject->IsOneByteRepresentation()) { |
| 571 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( | 571 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( |
| 572 isolate, subject, regexp, empty_string, last_match_info); | 572 isolate, subject, regexp, empty_string, last_match_info); |
| 573 } else { | 573 } else { |
| 574 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( | 574 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 heap->CreateFillerObjectAt(end_of_string, delta, ClearRecordedSlots::kNo); | 653 heap->CreateFillerObjectAt(end_of_string, delta, ClearRecordedSlots::kNo); |
| 654 } | 654 } |
| 655 heap->AdjustLiveBytes(*answer, -delta, Heap::CONCURRENT_TO_SWEEPER); | 655 heap->AdjustLiveBytes(*answer, -delta, Heap::CONCURRENT_TO_SWEEPER); |
| 656 return *answer; | 656 return *answer; |
| 657 } | 657 } |
| 658 | 658 |
| 659 namespace { | 659 namespace { |
| 660 | 660 |
| 661 Object* StringReplaceGlobalRegExpWithStringHelper( | 661 Object* StringReplaceGlobalRegExpWithStringHelper( |
| 662 Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> subject, | 662 Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> subject, |
| 663 Handle<String> replacement, Handle<JSObject> last_match_info) { | 663 Handle<String> replacement, Handle<RegExpMatchInfo> last_match_info) { |
| 664 CHECK(regexp->GetFlags() & JSRegExp::kGlobal); | 664 CHECK(regexp->GetFlags() & JSRegExp::kGlobal); |
| 665 CHECK(last_match_info->HasFastObjectElements()); | |
| 666 | 665 |
| 667 subject = String::Flatten(subject); | 666 subject = String::Flatten(subject); |
| 668 | 667 |
| 669 if (replacement->length() == 0) { | 668 if (replacement->length() == 0) { |
| 670 if (subject->HasOnlyOneByteChars()) { | 669 if (subject->HasOnlyOneByteChars()) { |
| 671 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>( | 670 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>( |
| 672 isolate, subject, regexp, last_match_info); | 671 isolate, subject, regexp, last_match_info); |
| 673 } else { | 672 } else { |
| 674 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>( | 673 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>( |
| 675 isolate, subject, regexp, last_match_info); | 674 isolate, subject, regexp, last_match_info); |
| 676 } | 675 } |
| 677 } | 676 } |
| 678 | 677 |
| 679 replacement = String::Flatten(replacement); | 678 replacement = String::Flatten(replacement); |
| 680 | 679 |
| 681 return StringReplaceGlobalRegExpWithString(isolate, subject, regexp, | 680 return StringReplaceGlobalRegExpWithString(isolate, subject, regexp, |
| 682 replacement, last_match_info); | 681 replacement, last_match_info); |
| 683 } | 682 } |
| 684 | 683 |
| 685 } // namespace | 684 } // namespace |
| 686 | 685 |
| 687 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { | 686 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { |
| 688 HandleScope scope(isolate); | 687 HandleScope scope(isolate); |
| 689 DCHECK(args.length() == 4); | 688 DCHECK(args.length() == 4); |
| 690 | 689 |
| 691 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 690 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |
| 692 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); | 691 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); |
| 693 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); | 692 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); |
| 694 CONVERT_ARG_HANDLE_CHECKED(JSObject, last_match_info, 3); | 693 CONVERT_ARG_HANDLE_CHECKED(RegExpMatchInfo, last_match_info, 3); |
| 695 | 694 |
| 696 return StringReplaceGlobalRegExpWithStringHelper( | 695 return StringReplaceGlobalRegExpWithStringHelper( |
| 697 isolate, regexp, subject, replacement, last_match_info); | 696 isolate, regexp, subject, replacement, last_match_info); |
| 698 } | 697 } |
| 699 | 698 |
| 700 RUNTIME_FUNCTION(Runtime_StringSplit) { | 699 RUNTIME_FUNCTION(Runtime_StringSplit) { |
| 701 HandleScope handle_scope(isolate); | 700 HandleScope handle_scope(isolate); |
| 702 DCHECK(args.length() == 3); | 701 DCHECK(args.length() == 3); |
| 703 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 702 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |
| 704 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); | 703 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 804 | 803 |
| 805 return *regexp; | 804 return *regexp; |
| 806 } | 805 } |
| 807 | 806 |
| 808 RUNTIME_FUNCTION(Runtime_RegExpExec) { | 807 RUNTIME_FUNCTION(Runtime_RegExpExec) { |
| 809 HandleScope scope(isolate); | 808 HandleScope scope(isolate); |
| 810 DCHECK(args.length() == 4); | 809 DCHECK(args.length() == 4); |
| 811 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); | 810 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); |
| 812 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); | 811 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); |
| 813 CONVERT_INT32_ARG_CHECKED(index, 2); | 812 CONVERT_INT32_ARG_CHECKED(index, 2); |
| 814 CONVERT_ARG_HANDLE_CHECKED(JSObject, last_match_info, 3); | 813 CONVERT_ARG_HANDLE_CHECKED(RegExpMatchInfo, last_match_info, 3); |
| 815 // Due to the way the JS calls are constructed this must be less than the | 814 // Due to the way the JS calls are constructed this must be less than the |
| 816 // length of a string, i.e. it is always a Smi. We check anyway for security. | 815 // length of a string, i.e. it is always a Smi. We check anyway for security. |
| 817 CHECK(index >= 0); | 816 CHECK(index >= 0); |
| 818 CHECK(index <= subject->length()); | 817 CHECK(index <= subject->length()); |
| 819 isolate->counters()->regexp_entry_runtime()->Increment(); | 818 isolate->counters()->regexp_entry_runtime()->Increment(); |
| 820 RETURN_RESULT_OR_FAILURE( | 819 RETURN_RESULT_OR_FAILURE( |
| 821 isolate, RegExpImpl::Exec(regexp, subject, index, last_match_info)); | 820 isolate, RegExpImpl::Exec(regexp, subject, index, last_match_info)); |
| 822 } | 821 } |
| 823 | 822 |
| 824 | 823 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 870 return *regexp; | 869 return *regexp; |
| 871 } | 870 } |
| 872 | 871 |
| 873 RUNTIME_FUNCTION(Runtime_RegExpInternalReplace) { | 872 RUNTIME_FUNCTION(Runtime_RegExpInternalReplace) { |
| 874 HandleScope scope(isolate); | 873 HandleScope scope(isolate); |
| 875 DCHECK(args.length() == 3); | 874 DCHECK(args.length() == 3); |
| 876 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); | 875 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); |
| 877 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); | 876 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); |
| 878 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); | 877 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); |
| 879 | 878 |
| 880 static const int kInitialMatchSlots = 2; | 879 Handle<RegExpMatchInfo> internal_match_info = |
| 881 Handle<JSArray> internal_match_info = isolate->factory()->NewJSArray( | 880 isolate->regexp_internal_match_info(); |
| 882 FAST_ELEMENTS, 0, RegExpImpl::kLastMatchOverhead + kInitialMatchSlots, | |
| 883 INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); | |
| 884 | 881 |
| 885 return StringReplaceGlobalRegExpWithStringHelper( | 882 return StringReplaceGlobalRegExpWithStringHelper( |
| 886 isolate, regexp, subject, replacement, internal_match_info); | 883 isolate, regexp, subject, replacement, internal_match_info); |
| 887 } | 884 } |
| 888 | 885 |
| 889 namespace { | 886 namespace { |
| 890 | 887 |
| 891 class MatchInfoBackedMatch : public String::Match { | 888 class MatchInfoBackedMatch : public String::Match { |
| 892 public: | 889 public: |
| 893 MatchInfoBackedMatch(Isolate* isolate, Handle<String> subject, | 890 MatchInfoBackedMatch(Isolate* isolate, Handle<String> subject, |
| 894 Handle<JSObject> match_info) | 891 Handle<RegExpMatchInfo> match_info) |
| 895 : isolate_(isolate), match_info_(match_info) { | 892 : isolate_(isolate), match_info_(match_info) { |
| 896 subject_ = String::Flatten(subject); | 893 subject_ = String::Flatten(subject); |
| 897 } | 894 } |
| 898 | 895 |
| 899 Handle<String> GetMatch() override { | 896 Handle<String> GetMatch() override { |
| 900 return RegExpUtils::GenericCaptureGetter(isolate_, match_info_, 0, nullptr); | 897 return RegExpUtils::GenericCaptureGetter(isolate_, match_info_, 0, nullptr); |
| 901 } | 898 } |
| 902 | 899 |
| 903 MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { | 900 MaybeHandle<String> GetCapture(int i, bool* capture_exists) override { |
| 904 Handle<Object> capture_obj = | 901 Handle<Object> capture_obj = |
| 905 RegExpUtils::GenericCaptureGetter(isolate_, match_info_, i); | 902 RegExpUtils::GenericCaptureGetter(isolate_, match_info_, i); |
| 906 if (capture_obj->IsUndefined(isolate_)) { | 903 if (capture_obj->IsUndefined(isolate_)) { |
| 907 *capture_exists = false; | 904 *capture_exists = false; |
| 908 return isolate_->factory()->empty_string(); | 905 return isolate_->factory()->empty_string(); |
| 909 } | 906 } |
| 910 *capture_exists = true; | 907 *capture_exists = true; |
| 911 return Object::ToString(isolate_, capture_obj); | 908 return Object::ToString(isolate_, capture_obj); |
| 912 } | 909 } |
| 913 | 910 |
| 914 Handle<String> GetPrefix() override { | 911 Handle<String> GetPrefix() override { |
| 915 const int match_start = | 912 const int match_start = match_info_->Capture(0); |
| 916 RegExpUtils::GetLastMatchCapture(isolate_, match_info_, 0); | |
| 917 return isolate_->factory()->NewSubString(subject_, 0, match_start); | 913 return isolate_->factory()->NewSubString(subject_, 0, match_start); |
| 918 } | 914 } |
| 919 | 915 |
| 920 Handle<String> GetSuffix() override { | 916 Handle<String> GetSuffix() override { |
| 921 const int match_end = | 917 const int match_end = match_info_->Capture(1); |
| 922 RegExpUtils::GetLastMatchCapture(isolate_, match_info_, 1); | |
| 923 return isolate_->factory()->NewSubString(subject_, match_end, | 918 return isolate_->factory()->NewSubString(subject_, match_end, |
| 924 subject_->length()); | 919 subject_->length()); |
| 925 } | 920 } |
| 926 | 921 |
| 927 int CaptureCount() override { | 922 int CaptureCount() override { |
| 928 return RegExpUtils::GetLastMatchNumberOfCaptures(isolate_, match_info_) / 2; | 923 return match_info_->NumberOfCaptureRegisters() / 2; |
| 929 } | 924 } |
| 930 | 925 |
| 931 virtual ~MatchInfoBackedMatch() {} | 926 virtual ~MatchInfoBackedMatch() {} |
| 932 | 927 |
| 933 private: | 928 private: |
| 934 Isolate* isolate_; | 929 Isolate* isolate_; |
| 935 Handle<String> subject_; | 930 Handle<String> subject_; |
| 936 Handle<JSObject> match_info_; | 931 Handle<RegExpMatchInfo> match_info_; |
| 937 }; | 932 }; |
| 938 | 933 |
| 939 class VectorBackedMatch : public String::Match { | 934 class VectorBackedMatch : public String::Match { |
| 940 public: | 935 public: |
| 941 VectorBackedMatch(Isolate* isolate, Handle<String> subject, | 936 VectorBackedMatch(Isolate* isolate, Handle<String> subject, |
| 942 Handle<String> match, int match_position, | 937 Handle<String> match, int match_position, |
| 943 ZoneVector<Handle<Object>>* captures) | 938 ZoneVector<Handle<Object>>* captures) |
| 944 : isolate_(isolate), | 939 : isolate_(isolate), |
| 945 match_(match), | 940 match_(match), |
| 946 match_position_(match_position), | 941 match_position_(match_position), |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 Isolate* isolate_; | 973 Isolate* isolate_; |
| 979 Handle<String> subject_; | 974 Handle<String> subject_; |
| 980 Handle<String> match_; | 975 Handle<String> match_; |
| 981 const int match_position_; | 976 const int match_position_; |
| 982 ZoneVector<Handle<Object>>* captures_; | 977 ZoneVector<Handle<Object>>* captures_; |
| 983 }; | 978 }; |
| 984 | 979 |
| 985 // Only called from RegExpExecMultiple so it doesn't need to maintain | 980 // Only called from RegExpExecMultiple so it doesn't need to maintain |
| 986 // separate last match info. See comment on that function. | 981 // separate last match info. See comment on that function. |
| 987 template <bool has_capture> | 982 template <bool has_capture> |
| 988 MaybeHandle<Object> SearchRegExpMultiple(Isolate* isolate, | 983 MaybeHandle<Object> SearchRegExpMultiple( |
| 989 Handle<String> subject, | 984 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, |
| 990 Handle<JSRegExp> regexp, | 985 Handle<RegExpMatchInfo> last_match_array, |
| 991 Handle<JSObject> last_match_array, | 986 Handle<FixedArray> result_elements) { |
| 992 Handle<FixedArray> result_elements) { | |
| 993 DCHECK(subject->IsFlat()); | 987 DCHECK(subject->IsFlat()); |
| 994 DCHECK_NE(has_capture, regexp->CaptureCount() == 0); | 988 DCHECK_NE(has_capture, regexp->CaptureCount() == 0); |
| 995 | 989 |
| 996 int capture_count = regexp->CaptureCount(); | 990 int capture_count = regexp->CaptureCount(); |
| 997 int subject_length = subject->length(); | 991 int subject_length = subject->length(); |
| 998 | 992 |
| 999 static const int kMinLengthToCache = 0x1000; | 993 static const int kMinLengthToCache = 0x1000; |
| 1000 | 994 |
| 1001 if (subject_length > kMinLengthToCache) { | 995 if (subject_length > kMinLengthToCache) { |
| 1002 FixedArray* last_match_cache; | 996 FixedArray* last_match_cache; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1126 return isolate->factory()->null_value(); // No matches at all. | 1120 return isolate->factory()->null_value(); // No matches at all. |
| 1127 } | 1121 } |
| 1128 } | 1122 } |
| 1129 | 1123 |
| 1130 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets | 1124 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets |
| 1131 // lastMatchInfoOverride to maintain the last match info, so we don't need to | 1125 // lastMatchInfoOverride to maintain the last match info, so we don't need to |
| 1132 // set any other last match array info. | 1126 // set any other last match array info. |
| 1133 MaybeHandle<Object> RegExpExecMultiple(Isolate* isolate, | 1127 MaybeHandle<Object> RegExpExecMultiple(Isolate* isolate, |
| 1134 Handle<JSRegExp> regexp, | 1128 Handle<JSRegExp> regexp, |
| 1135 Handle<String> subject, | 1129 Handle<String> subject, |
| 1136 Handle<JSObject> last_match_info, | 1130 Handle<RegExpMatchInfo> last_match_info, |
| 1137 Handle<FixedArray> result_array) { | 1131 Handle<FixedArray> result_array) { |
| 1138 CHECK(last_match_info->HasFastObjectElements()); | |
| 1139 | |
| 1140 subject = String::Flatten(subject); | 1132 subject = String::Flatten(subject); |
| 1141 CHECK(regexp->GetFlags() & JSRegExp::kGlobal); | 1133 CHECK(regexp->GetFlags() & JSRegExp::kGlobal); |
| 1142 | 1134 |
| 1143 if (regexp->CaptureCount() == 0) { | 1135 if (regexp->CaptureCount() == 0) { |
| 1144 return SearchRegExpMultiple<false>(isolate, subject, regexp, | 1136 return SearchRegExpMultiple<false>(isolate, subject, regexp, |
| 1145 last_match_info, result_array); | 1137 last_match_info, result_array); |
| 1146 } else { | 1138 } else { |
| 1147 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info, | 1139 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info, |
| 1148 result_array); | 1140 result_array); |
| 1149 } | 1141 } |
| 1150 } | 1142 } |
| 1151 | 1143 |
| 1152 // Helper function for replacing regular expressions with the result of a | 1144 // Helper function for replacing regular expressions with the result of a |
| 1153 // function application in String.prototype.replace. | 1145 // function application in String.prototype.replace. |
| 1154 MaybeHandle<String> StringReplaceGlobalRegExpWithFunction( | 1146 MaybeHandle<String> StringReplaceGlobalRegExpWithFunction( |
| 1155 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 1147 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, |
| 1156 Handle<Object> replace_obj) { | 1148 Handle<Object> replace_obj) { |
| 1157 Factory* factory = isolate->factory(); | 1149 Factory* factory = isolate->factory(); |
| 1158 | 1150 |
| 1159 // TODO(jgruber): Convert result_array into a List<Handle<Object>> (or | 1151 // TODO(jgruber): Convert result_array into a List<Handle<Object>> (or |
| 1160 // similar) and adapt / remove FixedArrayBuilder. | 1152 // similar) and adapt / remove FixedArrayBuilder. |
| 1161 Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 1153 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); |
| 1162 Handle<FixedArray> result_array = factory->NewFixedArrayWithHoles(16); | 1154 Handle<FixedArray> result_array = factory->NewFixedArrayWithHoles(16); |
| 1163 | 1155 |
| 1164 Handle<Object> res; | 1156 Handle<Object> res; |
| 1165 ASSIGN_RETURN_ON_EXCEPTION(isolate, res, | 1157 ASSIGN_RETURN_ON_EXCEPTION(isolate, res, |
| 1166 RegExpExecMultiple(isolate, regexp, subject, | 1158 RegExpExecMultiple(isolate, regexp, subject, |
| 1167 last_match_info, result_array), | 1159 last_match_info, result_array), |
| 1168 String); | 1160 String); |
| 1169 | 1161 |
| 1170 // Reload the last match info since it might have changed in the meantime. | 1162 // Reload the last match info since it might have changed in the meantime. |
| 1171 last_match_info = isolate->regexp_last_match_info(); | 1163 last_match_info = isolate->regexp_last_match_info(); |
| 1172 | 1164 |
| 1173 if (res->IsNull(isolate)) return subject; // No matches at all. | 1165 if (res->IsNull(isolate)) return subject; // No matches at all. |
| 1174 | 1166 |
| 1175 result_array = Handle<FixedArray>::cast(res); | 1167 result_array = Handle<FixedArray>::cast(res); |
| 1176 const int result_length = result_array->length(); | 1168 const int result_length = result_array->length(); |
| 1177 | 1169 |
| 1178 const int num_captures = | 1170 const int num_captures = last_match_info->NumberOfCaptureRegisters() / 2; |
| 1179 RegExpUtils::GetLastMatchNumberOfCaptures(isolate, last_match_info) / 2; | |
| 1180 if (num_captures == 1) { | 1171 if (num_captures == 1) { |
| 1181 // If the number of captures is one then there are no explicit captures in | 1172 // If the number of captures is one then there are no explicit captures in |
| 1182 // the regexp, just the implicit capture that captures the whole match. In | 1173 // the regexp, just the implicit capture that captures the whole match. In |
| 1183 // this case we can simplify quite a bit and end up with something faster. | 1174 // this case we can simplify quite a bit and end up with something faster. |
| 1184 // The builder will consist of some integers that indicate slices of the | 1175 // The builder will consist of some integers that indicate slices of the |
| 1185 // input string and some replacements that were returned from the replace | 1176 // input string and some replacements that were returned from the replace |
| 1186 // function. | 1177 // function. |
| 1187 int match_start = 0; | 1178 int match_start = 0; |
| 1188 for (int i = 0; i < result_length; i++) { | 1179 for (int i = 0; i < result_length; i++) { |
| 1189 Handle<Object> elem = FixedArray::get(*result_array, i, isolate); | 1180 Handle<Object> elem = FixedArray::get(*result_array, i, isolate); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1302 } | 1293 } |
| 1303 | 1294 |
| 1304 UNREACHABLE(); | 1295 UNREACHABLE(); |
| 1305 return MaybeHandle<String>(); | 1296 return MaybeHandle<String>(); |
| 1306 } | 1297 } |
| 1307 | 1298 |
| 1308 MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( | 1299 MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( |
| 1309 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 1300 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, |
| 1310 Handle<Object> replace_obj) { | 1301 Handle<Object> replace_obj) { |
| 1311 Factory* factory = isolate->factory(); | 1302 Factory* factory = isolate->factory(); |
| 1312 Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 1303 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); |
| 1313 | 1304 |
| 1314 // TODO(jgruber): This is a pattern we could refactor. | 1305 // TODO(jgruber): This is a pattern we could refactor. |
| 1315 Handle<Object> match_indices_obj; | 1306 Handle<Object> match_indices_obj; |
| 1316 ASSIGN_RETURN_ON_EXCEPTION( | 1307 ASSIGN_RETURN_ON_EXCEPTION( |
| 1317 isolate, match_indices_obj, | 1308 isolate, match_indices_obj, |
| 1318 RegExpImpl::Exec(regexp, subject, 0, last_match_info), String); | 1309 RegExpImpl::Exec(regexp, subject, 0, last_match_info), String); |
| 1319 | 1310 |
| 1320 if (match_indices_obj->IsNull(isolate)) { | 1311 if (match_indices_obj->IsNull(isolate)) { |
| 1321 RETURN_ON_EXCEPTION(isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), | 1312 RETURN_ON_EXCEPTION(isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), |
| 1322 String); | 1313 String); |
| 1323 return subject; | 1314 return subject; |
| 1324 } | 1315 } |
| 1325 | 1316 |
| 1326 Handle<JSObject> match_indices = Handle<JSObject>::cast(match_indices_obj); | 1317 Handle<RegExpMatchInfo> match_indices = |
| 1318 Handle<RegExpMatchInfo>::cast(match_indices_obj); |
| 1327 | 1319 |
| 1328 const int index = RegExpUtils::GetLastMatchCapture(isolate, match_indices, 0); | 1320 const int index = match_indices->Capture(0); |
| 1329 const int end_of_match = | 1321 const int end_of_match = match_indices->Capture(1); |
| 1330 RegExpUtils::GetLastMatchCapture(isolate, match_indices, 1); | |
| 1331 | 1322 |
| 1332 IncrementalStringBuilder builder(isolate); | 1323 IncrementalStringBuilder builder(isolate); |
| 1333 builder.AppendString(factory->NewSubString(subject, 0, index)); | 1324 builder.AppendString(factory->NewSubString(subject, 0, index)); |
| 1334 | 1325 |
| 1335 // Compute the parameter list consisting of the match, captures, index, | 1326 // Compute the parameter list consisting of the match, captures, index, |
| 1336 // and subject for the replace function invocation. | 1327 // and subject for the replace function invocation. |
| 1337 // The number of captures plus one for the match. | 1328 // The number of captures plus one for the match. |
| 1338 const int m = | 1329 const int m = match_indices->NumberOfCaptureRegisters() / 2; |
| 1339 RegExpUtils::GetLastMatchNumberOfCaptures(isolate, match_indices) / 2; | |
| 1340 | 1330 |
| 1341 const int argc = m + 2; | 1331 const int argc = m + 2; |
| 1342 ScopedVector<Handle<Object>> argv(argc); | 1332 ScopedVector<Handle<Object>> argv(argc); |
| 1343 | 1333 |
| 1344 for (int j = 0; j < m; j++) { | 1334 for (int j = 0; j < m; j++) { |
| 1345 bool ok; | 1335 bool ok; |
| 1346 Handle<String> capture = | 1336 Handle<String> capture = |
| 1347 RegExpUtils::GenericCaptureGetter(isolate, match_indices, j, &ok); | 1337 RegExpUtils::GenericCaptureGetter(isolate, match_indices, j, &ok); |
| 1348 if (ok) { | 1338 if (ok) { |
| 1349 argv[j] = capture; | 1339 argv[j] = capture; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1385 const int flags = regexp->GetFlags(); | 1375 const int flags = regexp->GetFlags(); |
| 1386 const bool global = (flags & JSRegExp::kGlobal) != 0; | 1376 const bool global = (flags & JSRegExp::kGlobal) != 0; |
| 1387 | 1377 |
| 1388 const bool functional_replace = replace_obj->IsCallable(); | 1378 const bool functional_replace = replace_obj->IsCallable(); |
| 1389 if (!functional_replace) { | 1379 if (!functional_replace) { |
| 1390 Handle<String> replace; | 1380 Handle<String> replace; |
| 1391 ASSIGN_RETURN_ON_EXCEPTION(isolate, replace, | 1381 ASSIGN_RETURN_ON_EXCEPTION(isolate, replace, |
| 1392 Object::ToString(isolate, replace_obj), String); | 1382 Object::ToString(isolate, replace_obj), String); |
| 1393 replace = String::Flatten(replace); | 1383 replace = String::Flatten(replace); |
| 1394 | 1384 |
| 1395 Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 1385 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); |
| 1396 | 1386 |
| 1397 if (!global) { | 1387 if (!global) { |
| 1398 // Non-global regexp search, string replace. | 1388 // Non-global regexp search, string replace. |
| 1399 | 1389 |
| 1400 Handle<Object> match_indices_obj; | 1390 Handle<Object> match_indices_obj; |
| 1401 ASSIGN_RETURN_ON_EXCEPTION( | 1391 ASSIGN_RETURN_ON_EXCEPTION( |
| 1402 isolate, match_indices_obj, | 1392 isolate, match_indices_obj, |
| 1403 RegExpImpl::Exec(regexp, string, 0, last_match_info), String); | 1393 RegExpImpl::Exec(regexp, string, 0, last_match_info), String); |
| 1404 | 1394 |
| 1405 if (match_indices_obj->IsNull(isolate)) { | 1395 if (match_indices_obj->IsNull(isolate)) { |
| 1406 RETURN_ON_EXCEPTION( | 1396 RETURN_ON_EXCEPTION( |
| 1407 isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), String); | 1397 isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), String); |
| 1408 return string; | 1398 return string; |
| 1409 } | 1399 } |
| 1410 | 1400 |
| 1411 auto match_indices = Handle<JSReceiver>::cast(match_indices_obj); | 1401 auto match_indices = Handle<RegExpMatchInfo>::cast(match_indices_obj); |
| 1412 | 1402 |
| 1413 Handle<Object> start_index_obj = | 1403 const int start_index = match_indices->Capture(0); |
| 1414 JSReceiver::GetElement(isolate, match_indices, | 1404 const int end_index = match_indices->Capture(1); |
| 1415 RegExpImpl::kFirstCapture) | |
| 1416 .ToHandleChecked(); | |
| 1417 const int start_index = Handle<Smi>::cast(start_index_obj)->value(); | |
| 1418 | |
| 1419 Handle<Object> end_index_obj = | |
| 1420 JSReceiver::GetElement(isolate, match_indices, | |
| 1421 RegExpImpl::kFirstCapture + 1) | |
| 1422 .ToHandleChecked(); | |
| 1423 const int end_index = Handle<Smi>::cast(end_index_obj)->value(); | |
| 1424 | 1405 |
| 1425 IncrementalStringBuilder builder(isolate); | 1406 IncrementalStringBuilder builder(isolate); |
| 1426 builder.AppendString(factory->NewSubString(string, 0, start_index)); | 1407 builder.AppendString(factory->NewSubString(string, 0, start_index)); |
| 1427 | 1408 |
| 1428 if (replace->length() > 0) { | 1409 if (replace->length() > 0) { |
| 1429 MatchInfoBackedMatch m(isolate, string, last_match_info); | 1410 MatchInfoBackedMatch m(isolate, string, match_indices); |
| 1430 Handle<String> replacement; | 1411 Handle<String> replacement; |
| 1431 ASSIGN_RETURN_ON_EXCEPTION( | 1412 ASSIGN_RETURN_ON_EXCEPTION( |
| 1432 isolate, replacement, String::GetSubstitution(isolate, &m, replace), | 1413 isolate, replacement, String::GetSubstitution(isolate, &m, replace), |
| 1433 String); | 1414 String); |
| 1434 builder.AppendString(replacement); | 1415 builder.AppendString(replacement); |
| 1435 } | 1416 } |
| 1436 | 1417 |
| 1437 builder.AppendString( | 1418 builder.AppendString( |
| 1438 factory->NewSubString(string, end_index, string->length())); | 1419 factory->NewSubString(string, end_index, string->length())); |
| 1439 return builder.Finish(); | 1420 return builder.Finish(); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1675 | 1656 |
| 1676 RUNTIME_FUNCTION(Runtime_IsRegExp) { | 1657 RUNTIME_FUNCTION(Runtime_IsRegExp) { |
| 1677 SealHandleScope shs(isolate); | 1658 SealHandleScope shs(isolate); |
| 1678 DCHECK(args.length() == 1); | 1659 DCHECK(args.length() == 1); |
| 1679 CONVERT_ARG_CHECKED(Object, obj, 0); | 1660 CONVERT_ARG_CHECKED(Object, obj, 0); |
| 1680 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); | 1661 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); |
| 1681 } | 1662 } |
| 1682 | 1663 |
| 1683 } // namespace internal | 1664 } // namespace internal |
| 1684 } // namespace v8 | 1665 } // namespace v8 |
| OLD | NEW |