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 |