Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 3777 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3788 SetLastMatchInfoNoCaptures(subject, | 3788 SetLastMatchInfoNoCaptures(subject, |
| 3789 last_match_info, | 3789 last_match_info, |
| 3790 match_pos, | 3790 match_pos, |
| 3791 match_pos + pattern->length()); | 3791 match_pos + pattern->length()); |
| 3792 return true; | 3792 return true; |
| 3793 } | 3793 } |
| 3794 return false; // No matches at all. | 3794 return false; // No matches at all. |
| 3795 } | 3795 } |
| 3796 | 3796 |
| 3797 | 3797 |
| 3798 static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( | 3798 static int SearchRegExpNoCaptureMultiple( |
| 3799 Isolate* isolate, | 3799 Isolate* isolate, |
| 3800 Handle<String> subject, | 3800 Handle<String> subject, |
| 3801 Handle<JSRegExp> regexp, | 3801 Handle<JSRegExp> regexp, |
| 3802 Handle<JSArray> last_match_array, | 3802 Handle<JSArray> last_match_array, |
| 3803 FixedArrayBuilder* builder) { | 3803 FixedArrayBuilder* builder) { |
| 3804 ASSERT(subject->IsFlat()); | 3804 ASSERT(subject->IsFlat()); |
| 3805 ASSERT(regexp->CaptureCount() == 0); | |
| 3805 int match_start = -1; | 3806 int match_start = -1; |
| 3806 int match_end = 0; | 3807 int match_end = 0; |
| 3807 int pos = 0; | 3808 int pos = 0; |
| 3808 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); | 3809 int registers_per_match = RegExpImpl::IrregexpPrepare(regexp, subject); |
| 3809 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; | 3810 if (registers_per_match < 0) return RegExpImpl::RE_EXCEPTION; |
| 3810 | 3811 |
| 3811 OffsetsVector registers(required_registers, isolate); | 3812 int max_matches; |
| 3813 int num_registers = RegExpImpl::GlobalOffsetsVectorSize(regexp, | |
| 3814 registers_per_match, | |
| 3815 &max_matches); | |
| 3816 OffsetsVector registers(num_registers, isolate); | |
| 3812 Vector<int32_t> register_vector(registers.vector(), registers.length()); | 3817 Vector<int32_t> register_vector(registers.vector(), registers.length()); |
| 3813 int subject_length = subject->length(); | 3818 int subject_length = subject->length(); |
| 3814 bool first = true; | 3819 bool first = true; |
| 3820 for (;;) { // Break on failure, return on exception. | |
| 3821 int num_matches = RegExpImpl::IrregexpExecRaw(regexp, | |
| 3822 subject, | |
| 3823 pos, | |
| 3824 register_vector); | |
| 3825 if (num_matches > 0) { | |
| 3826 for (int match_index = 0; match_index < num_matches; match_index++) { | |
| 3827 int32_t* current_match = ®ister_vector[match_index * 2]; | |
| 3828 match_start = current_match[0]; | |
| 3829 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | |
| 3830 if (match_end < match_start) { | |
| 3831 ReplacementStringBuilder::AddSubjectSlice(builder, | |
| 3832 match_end, | |
| 3833 match_start); | |
| 3834 } | |
| 3835 match_end = current_match[1]; | |
| 3836 HandleScope loop_scope(isolate); | |
| 3837 if (!first) { | |
| 3838 builder->Add(*isolate->factory()->NewProperSubString(subject, | |
| 3839 match_start, | |
| 3840 match_end)); | |
| 3841 } else { | |
| 3842 builder->Add(*isolate->factory()->NewSubString(subject, | |
| 3843 match_start, | |
| 3844 match_end)); | |
| 3845 first = false; | |
| 3846 } | |
| 3847 } | |
| 3815 | 3848 |
| 3816 for (;;) { // Break on failure, return on exception. | 3849 // If we did not get the maximum number of matches, we can stop here |
| 3817 RegExpImpl::IrregexpResult result = | 3850 // since there are no matches left. |
| 3818 RegExpImpl::IrregexpExecOnce(regexp, | 3851 if (num_matches < max_matches) break; |
| 3819 subject, | 3852 |
| 3820 pos, | |
| 3821 register_vector); | |
| 3822 if (result == RegExpImpl::RE_SUCCESS) { | |
| 3823 match_start = register_vector[0]; | |
| 3824 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | |
| 3825 if (match_end < match_start) { | |
| 3826 ReplacementStringBuilder::AddSubjectSlice(builder, | |
| 3827 match_end, | |
| 3828 match_start); | |
| 3829 } | |
| 3830 match_end = register_vector[1]; | |
| 3831 HandleScope loop_scope(isolate); | |
| 3832 if (!first) { | |
| 3833 builder->Add(*isolate->factory()->NewProperSubString(subject, | |
| 3834 match_start, | |
| 3835 match_end)); | |
| 3836 } else { | |
| 3837 builder->Add(*isolate->factory()->NewSubString(subject, | |
| 3838 match_start, | |
| 3839 match_end)); | |
| 3840 } | |
| 3841 if (match_start != match_end) { | 3853 if (match_start != match_end) { |
| 3842 pos = match_end; | 3854 pos = match_end; |
| 3843 } else { | 3855 } else { |
| 3844 pos = match_end + 1; | 3856 pos = match_end + 1; |
| 3845 if (pos > subject_length) break; | 3857 if (pos > subject_length) break; |
| 3846 } | 3858 } |
| 3847 } else if (result == RegExpImpl::RE_FAILURE) { | 3859 } else if (num_matches == 0) { |
| 3848 break; | 3860 break; |
| 3849 } else { | 3861 } else { |
| 3850 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); | 3862 ASSERT_EQ(num_matches, RegExpImpl::RE_EXCEPTION); |
| 3851 return result; | 3863 return num_matches; |
|
Erik Corry
2012/05/22 08:32:46
Perhaps it is clearer to write "return RegExpImpl:
| |
| 3852 } | 3864 } |
| 3853 first = false; | |
| 3854 } | 3865 } |
| 3855 | 3866 |
| 3856 if (match_start >= 0) { | 3867 if (match_start >= 0) { |
| 3857 if (match_end < subject_length) { | 3868 if (match_end < subject_length) { |
| 3858 ReplacementStringBuilder::AddSubjectSlice(builder, | 3869 ReplacementStringBuilder::AddSubjectSlice(builder, |
| 3859 match_end, | 3870 match_end, |
| 3860 subject_length); | 3871 subject_length); |
| 3861 } | 3872 } |
| 3862 SetLastMatchInfoNoCaptures(subject, | 3873 SetLastMatchInfoNoCaptures(subject, |
| 3863 last_match_array, | 3874 last_match_array, |
| 3864 match_start, | 3875 match_start, |
| 3865 match_end); | 3876 match_end); |
| 3866 return RegExpImpl::RE_SUCCESS; | 3877 return RegExpImpl::RE_SUCCESS; |
| 3867 } else { | 3878 } else { |
| 3868 return RegExpImpl::RE_FAILURE; // No matches at all. | 3879 return RegExpImpl::RE_FAILURE; // No matches at all. |
| 3869 } | 3880 } |
| 3870 } | 3881 } |
| 3871 | 3882 |
| 3872 | 3883 |
| 3873 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain | 3884 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain |
| 3874 // separate last match info. See comment on that function. | 3885 // separate last match info. See comment on that function. |
| 3875 static RegExpImpl::IrregexpResult SearchRegExpMultiple( | 3886 static int SearchRegExpMultiple( |
| 3876 Isolate* isolate, | 3887 Isolate* isolate, |
| 3877 Handle<String> subject, | 3888 Handle<String> subject, |
| 3878 Handle<JSRegExp> regexp, | 3889 Handle<JSRegExp> regexp, |
| 3879 Handle<JSArray> last_match_array, | 3890 Handle<JSArray> last_match_array, |
| 3880 FixedArrayBuilder* builder) { | 3891 FixedArrayBuilder* builder) { |
| 3881 | 3892 |
| 3882 ASSERT(subject->IsFlat()); | 3893 ASSERT(subject->IsFlat()); |
| 3883 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); | 3894 int registers_per_match = RegExpImpl::IrregexpPrepare(regexp, subject); |
| 3884 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; | 3895 if (registers_per_match < 0) return RegExpImpl::RE_EXCEPTION; |
| 3885 | 3896 |
| 3886 OffsetsVector registers(required_registers, isolate); | 3897 int max_matches; |
| 3898 int num_registers = RegExpImpl::GlobalOffsetsVectorSize(regexp, | |
| 3899 registers_per_match, | |
| 3900 &max_matches); | |
| 3901 OffsetsVector registers(num_registers, isolate); | |
| 3887 Vector<int32_t> register_vector(registers.vector(), registers.length()); | 3902 Vector<int32_t> register_vector(registers.vector(), registers.length()); |
| 3888 | 3903 |
| 3889 RegExpImpl::IrregexpResult result = | 3904 int num_matches = RegExpImpl::IrregexpExecRaw(regexp, |
| 3890 RegExpImpl::IrregexpExecOnce(regexp, | 3905 subject, |
| 3891 subject, | 3906 0, |
| 3892 0, | 3907 register_vector); |
| 3893 register_vector); | |
| 3894 | 3908 |
| 3895 int capture_count = regexp->CaptureCount(); | 3909 int capture_count = regexp->CaptureCount(); |
| 3896 int subject_length = subject->length(); | 3910 int subject_length = subject->length(); |
| 3897 | 3911 |
| 3898 // Position to search from. | 3912 // Position to search from. |
| 3899 int pos = 0; | 3913 int pos = 0; |
| 3900 // End of previous match. Differs from pos if match was empty. | 3914 // End of previous match. Differs from pos if match was empty. |
| 3901 int match_end = 0; | 3915 int match_end = 0; |
| 3902 if (result == RegExpImpl::RE_SUCCESS) { | 3916 bool first = true; |
| 3903 bool first = true; | 3917 |
| 3918 if (num_matches > 0) { | |
| 3904 do { | 3919 do { |
| 3905 int match_start = register_vector[0]; | 3920 int match_start = 0; |
| 3906 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); | 3921 for (int match_index = 0; match_index < num_matches; match_index++) { |
| 3907 if (match_end < match_start) { | 3922 int32_t* current_match = |
| 3908 ReplacementStringBuilder::AddSubjectSlice(builder, | 3923 ®ister_vector[match_index * registers_per_match]; |
| 3909 match_end, | 3924 match_start = current_match[0]; |
| 3910 match_start); | 3925 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| 3926 if (match_end < match_start) { | |
| 3927 ReplacementStringBuilder::AddSubjectSlice(builder, | |
| 3928 match_end, | |
| 3929 match_start); | |
| 3930 } | |
| 3931 match_end = current_match[1]; | |
| 3932 | |
| 3933 { | |
| 3934 // Avoid accumulating new handles inside loop. | |
| 3935 HandleScope temp_scope(isolate); | |
| 3936 // Arguments array to replace function is match, captures, index and | |
| 3937 // subject, i.e., 3 + capture count in total. | |
| 3938 Handle<FixedArray> elements = | |
| 3939 isolate->factory()->NewFixedArray(3 + capture_count); | |
| 3940 Handle<String> match; | |
| 3941 if (!first) { | |
| 3942 match = isolate->factory()->NewProperSubString(subject, | |
| 3943 match_start, | |
| 3944 match_end); | |
| 3945 } else { | |
| 3946 match = isolate->factory()->NewSubString(subject, | |
| 3947 match_start, | |
| 3948 match_end); | |
| 3949 first = false; | |
| 3950 } | |
| 3951 elements->set(0, *match); | |
| 3952 for (int i = 1; i <= capture_count; i++) { | |
| 3953 int start = current_match[i * 2]; | |
| 3954 if (start >= 0) { | |
| 3955 int end = current_match[i * 2 + 1]; | |
| 3956 ASSERT(start <= end); | |
| 3957 Handle<String> substring = | |
| 3958 isolate->factory()->NewProperSubString(subject, start, end); | |
| 3959 elements->set(i, *substring); | |
| 3960 } else { | |
| 3961 ASSERT(current_match[i * 2 + 1] < 0); | |
| 3962 elements->set(i, isolate->heap()->undefined_value()); | |
| 3963 } | |
| 3964 } | |
| 3965 elements->set(capture_count + 1, Smi::FromInt(match_start)); | |
| 3966 elements->set(capture_count + 2, *subject); | |
| 3967 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements)); | |
| 3968 } | |
| 3911 } | 3969 } |
| 3912 match_end = register_vector[1]; | |
| 3913 | 3970 |
| 3914 { | 3971 // If we did not get the maximum number of matches, we can stop here |
| 3915 // Avoid accumulating new handles inside loop. | 3972 // since there are no matches left. |
| 3916 HandleScope temp_scope(isolate); | 3973 if (num_matches < max_matches) break; |
| 3917 // Arguments array to replace function is match, captures, index and | |
| 3918 // subject, i.e., 3 + capture count in total. | |
| 3919 Handle<FixedArray> elements = | |
| 3920 isolate->factory()->NewFixedArray(3 + capture_count); | |
| 3921 Handle<String> match; | |
| 3922 if (!first) { | |
| 3923 match = isolate->factory()->NewProperSubString(subject, | |
| 3924 match_start, | |
| 3925 match_end); | |
| 3926 } else { | |
| 3927 match = isolate->factory()->NewSubString(subject, | |
| 3928 match_start, | |
| 3929 match_end); | |
| 3930 } | |
| 3931 elements->set(0, *match); | |
| 3932 for (int i = 1; i <= capture_count; i++) { | |
| 3933 int start = register_vector[i * 2]; | |
| 3934 if (start >= 0) { | |
| 3935 int end = register_vector[i * 2 + 1]; | |
| 3936 ASSERT(start <= end); | |
| 3937 Handle<String> substring; | |
| 3938 if (!first) { | |
| 3939 substring = isolate->factory()->NewProperSubString(subject, | |
| 3940 start, | |
| 3941 end); | |
| 3942 } else { | |
| 3943 substring = isolate->factory()->NewSubString(subject, start, end); | |
| 3944 } | |
| 3945 elements->set(i, *substring); | |
| 3946 } else { | |
| 3947 ASSERT(register_vector[i * 2 + 1] < 0); | |
| 3948 elements->set(i, isolate->heap()->undefined_value()); | |
| 3949 } | |
| 3950 } | |
| 3951 elements->set(capture_count + 1, Smi::FromInt(match_start)); | |
| 3952 elements->set(capture_count + 2, *subject); | |
| 3953 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements)); | |
| 3954 } | |
| 3955 | 3974 |
| 3956 if (match_end > match_start) { | 3975 if (match_end > match_start) { |
| 3957 pos = match_end; | 3976 pos = match_end; |
| 3958 } else { | 3977 } else { |
| 3959 pos = match_end + 1; | 3978 pos = match_end + 1; |
| 3960 if (pos > subject_length) { | 3979 if (pos > subject_length) { |
| 3961 break; | 3980 break; |
| 3962 } | 3981 } |
| 3963 } | 3982 } |
| 3964 | 3983 |
| 3965 result = RegExpImpl::IrregexpExecOnce(regexp, | 3984 num_matches = RegExpImpl::IrregexpExecRaw(regexp, |
| 3966 subject, | 3985 subject, |
| 3967 pos, | 3986 pos, |
| 3968 register_vector); | 3987 register_vector); |
| 3969 first = false; | 3988 } while (num_matches > 0); |
| 3970 } while (result == RegExpImpl::RE_SUCCESS); | |
| 3971 | 3989 |
| 3972 if (result != RegExpImpl::RE_EXCEPTION) { | 3990 if (num_matches != RegExpImpl::RE_EXCEPTION) { |
| 3973 // Finished matching, with at least one match. | 3991 // Finished matching, with at least one match. |
| 3974 if (match_end < subject_length) { | 3992 if (match_end < subject_length) { |
| 3975 ReplacementStringBuilder::AddSubjectSlice(builder, | 3993 ReplacementStringBuilder::AddSubjectSlice(builder, |
| 3976 match_end, | 3994 match_end, |
| 3977 subject_length); | 3995 subject_length); |
| 3978 } | 3996 } |
| 3979 | 3997 |
| 3980 int last_match_capture_count = (capture_count + 1) * 2; | 3998 int last_match_capture_count = (capture_count + 1) * 2; |
| 3981 int last_match_array_size = | 3999 int last_match_array_size = |
| 3982 last_match_capture_count + RegExpImpl::kLastMatchOverhead; | 4000 last_match_capture_count + RegExpImpl::kLastMatchOverhead; |
| 3983 last_match_array->EnsureSize(last_match_array_size); | 4001 last_match_array->EnsureSize(last_match_array_size); |
| 3984 AssertNoAllocation no_gc; | 4002 AssertNoAllocation no_gc; |
| 3985 FixedArray* elements = FixedArray::cast(last_match_array->elements()); | 4003 FixedArray* elements = FixedArray::cast(last_match_array->elements()); |
| 3986 // We have to set this even though the rest of the last match array is | 4004 // We have to set this even though the rest of the last match array is |
| 3987 // ignored. | 4005 // ignored. |
| 3988 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); | 4006 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); |
| 3989 // These are also read without consulting the override. | 4007 // These are also read without consulting the override. |
| 3990 RegExpImpl::SetLastSubject(elements, *subject); | 4008 RegExpImpl::SetLastSubject(elements, *subject); |
| 3991 RegExpImpl::SetLastInput(elements, *subject); | 4009 RegExpImpl::SetLastInput(elements, *subject); |
| 3992 return RegExpImpl::RE_SUCCESS; | 4010 return RegExpImpl::RE_SUCCESS; |
| 3993 } | 4011 } |
| 3994 } | 4012 } |
| 3995 // No matches at all, return failure or exception result directly. | 4013 // No matches at all, return failure or exception result directly. |
| 3996 return result; | 4014 return num_matches; |
| 3997 } | 4015 } |
| 3998 | 4016 |
| 3999 | 4017 |
| 4000 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets | 4018 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets |
| 4001 // lastMatchInfoOverride to maintain the last match info, so we don't need to | 4019 // lastMatchInfoOverride to maintain the last match info, so we don't need to |
| 4002 // set any other last match array info. | 4020 // set any other last match array info. |
| 4003 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { | 4021 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { |
| 4004 ASSERT(args.length() == 4); | 4022 ASSERT(args.length() == 4); |
| 4005 HandleScope handles(isolate); | 4023 HandleScope handles(isolate); |
| 4006 | 4024 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 4028 ASSERT(pattern->IsFlat()); | 4046 ASSERT(pattern->IsFlat()); |
| 4029 if (SearchStringMultiple(isolate, subject, pattern, | 4047 if (SearchStringMultiple(isolate, subject, pattern, |
| 4030 last_match_info, &builder)) { | 4048 last_match_info, &builder)) { |
| 4031 return *builder.ToJSArray(result_array); | 4049 return *builder.ToJSArray(result_array); |
| 4032 } | 4050 } |
| 4033 return isolate->heap()->null_value(); | 4051 return isolate->heap()->null_value(); |
| 4034 } | 4052 } |
| 4035 | 4053 |
| 4036 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); | 4054 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); |
| 4037 | 4055 |
| 4038 RegExpImpl::IrregexpResult result; | 4056 int result; |
| 4039 if (regexp->CaptureCount() == 0) { | 4057 if (regexp->CaptureCount() == 0) { |
| 4040 result = SearchRegExpNoCaptureMultiple(isolate, | 4058 result = SearchRegExpNoCaptureMultiple(isolate, |
| 4041 subject, | 4059 subject, |
| 4042 regexp, | 4060 regexp, |
| 4043 last_match_info, | 4061 last_match_info, |
| 4044 &builder); | 4062 &builder); |
| 4045 } else { | 4063 } else { |
| 4046 result = SearchRegExpMultiple(isolate, | 4064 result = SearchRegExpMultiple(isolate, |
| 4047 subject, | 4065 subject, |
| 4048 regexp, | 4066 regexp, |
| (...skipping 9456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 13505 // Handle last resort GC and make sure to allow future allocations | 13523 // Handle last resort GC and make sure to allow future allocations |
| 13506 // to grow the heap without causing GCs (if possible). | 13524 // to grow the heap without causing GCs (if possible). |
| 13507 isolate->counters()->gc_last_resort_from_js()->Increment(); | 13525 isolate->counters()->gc_last_resort_from_js()->Increment(); |
| 13508 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 13526 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
| 13509 "Runtime::PerformGC"); | 13527 "Runtime::PerformGC"); |
| 13510 } | 13528 } |
| 13511 } | 13529 } |
| 13512 | 13530 |
| 13513 | 13531 |
| 13514 } } // namespace v8::internal | 13532 } } // namespace v8::internal |
| OLD | NEW |