Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(182)

Side by Side Diff: src/runtime.cc

Issue 12177015: Refactor implementation for String.prototype.replace. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/runtime.h ('k') | src/string.js » ('j') | src/string.js » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 2870 matching lines...) Expand 10 before | Expand all | Expand 10 after
2881 limit, 2881 limit,
2882 zone); 2882 zone);
2883 } 2883 }
2884 } 2884 }
2885 } 2885 }
2886 } 2886 }
2887 } 2887 }
2888 2888
2889 2889
2890 template<typename ResultSeqString> 2890 template<typename ResultSeqString>
2891 MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString( 2891 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
2892 Isolate* isolate, 2892 Isolate* isolate,
2893 Handle<String> subject, 2893 Handle<String> subject,
2894 Handle<JSRegExp> pattern_regexp, 2894 Handle<JSRegExp> pattern_regexp,
2895 Handle<String> replacement, 2895 Handle<String> replacement,
2896 Handle<JSArray> last_match_info) { 2896 Handle<JSArray> last_match_info) {
2897 ASSERT(subject->IsFlat()); 2897 ASSERT(subject->IsFlat());
2898 ASSERT(replacement->IsFlat()); 2898 ASSERT(replacement->IsFlat());
2899 2899
2900 Zone* zone = isolate->runtime_zone(); 2900 Zone* zone = isolate->runtime_zone();
2901 ZoneScope zone_space(zone, DELETE_ON_EXIT); 2901 ZoneScope zone_space(zone, DELETE_ON_EXIT);
2902 ZoneList<int> indices(8, zone); 2902 ZoneList<int> indices(8, zone);
2903 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); 2903 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2904 String* pattern = 2904 String* pattern =
2905 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); 2905 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2906 int subject_len = subject->length(); 2906 int subject_len = subject->length();
2907 int pattern_len = pattern->length(); 2907 int pattern_len = pattern->length();
2908 int replacement_len = replacement->length(); 2908 int replacement_len = replacement->length();
2909 2909
2910 FindStringIndicesDispatch( 2910 FindStringIndicesDispatch(
2911 isolate, *subject, pattern, &indices, 0xffffffff, zone); 2911 isolate, *subject, pattern, &indices, 0xffffffff, zone);
2912 2912
2913 int matches = indices.length(); 2913 int matches = indices.length();
2914 if (matches == 0) { 2914 if (matches == 0) return *subject;
2915 return isolate->heap()->undefined_value();
2916 }
2917 2915
2918 // Detect integer overflow. 2916 // Detect integer overflow.
2919 int64_t result_len_64 = 2917 int64_t result_len_64 =
2920 (static_cast<int64_t>(replacement_len) - 2918 (static_cast<int64_t>(replacement_len) -
2921 static_cast<int64_t>(pattern_len)) * 2919 static_cast<int64_t>(pattern_len)) *
2922 static_cast<int64_t>(matches) + 2920 static_cast<int64_t>(matches) +
2923 static_cast<int64_t>(subject_len); 2921 static_cast<int64_t>(subject_len);
2924 if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11); 2922 if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11);
2925 int result_len = static_cast<int>(result_len_64); 2923 int result_len = static_cast<int>(result_len_64);
2926 2924
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
2966 } 2964 }
2967 2965
2968 int32_t match_indices[] = { indices.at(matches - 1), 2966 int32_t match_indices[] = { indices.at(matches - 1),
2969 indices.at(matches - 1) + pattern_len }; 2967 indices.at(matches - 1) + pattern_len };
2970 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); 2968 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
2971 2969
2972 return *result; 2970 return *result;
2973 } 2971 }
2974 2972
2975 2973
2976 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString( 2974 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString(
2977 Isolate* isolate, 2975 Isolate* isolate,
2978 Handle<String> subject, 2976 Handle<String> subject,
2979 Handle<JSRegExp> regexp, 2977 Handle<JSRegExp> regexp,
2980 Handle<String> replacement, 2978 Handle<String> replacement,
2981 Handle<JSArray> last_match_info) { 2979 Handle<JSArray> last_match_info) {
2982 ASSERT(subject->IsFlat()); 2980 ASSERT(subject->IsFlat());
2983 ASSERT(replacement->IsFlat()); 2981 ASSERT(replacement->IsFlat());
2984 2982
2985 bool is_global = regexp->GetFlags().is_global();
2986 int capture_count = regexp->CaptureCount(); 2983 int capture_count = regexp->CaptureCount();
2987 int subject_length = subject->length(); 2984 int subject_length = subject->length();
2988 2985
2989 // CompiledReplacement uses zone allocation. 2986 // CompiledReplacement uses zone allocation.
2990 Zone* zone = isolate->runtime_zone(); 2987 Zone* zone = isolate->runtime_zone();
2991 ZoneScope zonescope(zone, DELETE_ON_EXIT); 2988 ZoneScope zonescope(zone, DELETE_ON_EXIT);
2992 CompiledReplacement compiled_replacement(zone); 2989 CompiledReplacement compiled_replacement(zone);
2993 bool simple_replace = compiled_replacement.Compile(replacement, 2990 bool simple_replace = compiled_replacement.Compile(replacement,
2994 capture_count, 2991 capture_count,
2995 subject_length); 2992 subject_length);
2996 2993
2997 // Shortcut for simple non-regexp global replacements 2994 // Shortcut for simple non-regexp global replacements
2998 if (is_global && 2995 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
2999 regexp->TypeTag() == JSRegExp::ATOM &&
3000 simple_replace) {
3001 if (subject->IsOneByteConvertible() && 2996 if (subject->IsOneByteConvertible() &&
3002 replacement->IsOneByteConvertible()) { 2997 replacement->IsOneByteConvertible()) {
3003 return StringReplaceAtomRegExpWithString<SeqOneByteString>( 2998 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
3004 isolate, subject, regexp, replacement, last_match_info); 2999 isolate, subject, regexp, replacement, last_match_info);
3005 } else { 3000 } else {
3006 return StringReplaceAtomRegExpWithString<SeqTwoByteString>( 3001 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
3007 isolate, subject, regexp, replacement, last_match_info); 3002 isolate, subject, regexp, replacement, last_match_info);
3008 } 3003 }
3009 } 3004 }
3010 3005
3011 RegExpImpl::GlobalCache global_cache(regexp, subject, is_global, isolate); 3006 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
3012 if (global_cache.HasException()) return Failure::Exception(); 3007 if (global_cache.HasException()) return Failure::Exception();
3013 3008
3014 int32_t* current_match = global_cache.FetchNext(); 3009 int32_t* current_match = global_cache.FetchNext();
3015 if (current_match == NULL) { 3010 if (current_match == NULL) {
3016 if (global_cache.HasException()) return Failure::Exception(); 3011 if (global_cache.HasException()) return Failure::Exception();
3017 return isolate->heap()->undefined_value(); 3012 return *subject;
3018 } 3013 }
3019 3014
3020 // Guessing the number of parts that the final result string is built 3015 // Guessing the number of parts that the final result string is built
3021 // from. Global regexps can match any number of times, so we guess 3016 // from. Global regexps can match any number of times, so we guess
3022 // conservatively. 3017 // conservatively.
3023 int expected_parts = 3018 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
3024 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
3025 ReplacementStringBuilder builder(isolate->heap(), 3019 ReplacementStringBuilder builder(isolate->heap(),
3026 subject, 3020 subject,
3027 expected_parts); 3021 expected_parts);
3028 3022
3029 // Number of parts added by compiled replacement plus preceeding 3023 // Number of parts added by compiled replacement plus preceeding
3030 // string and possibly suffix after last match. It is possible for 3024 // string and possibly suffix after last match. It is possible for
3031 // all components to use two elements when encoded as two smis. 3025 // all components to use two elements when encoded as two smis.
3032 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); 3026 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
3033 3027
3034 int prev = 0; 3028 int prev = 0;
(...skipping 11 matching lines...) Expand all
3046 if (simple_replace) { 3040 if (simple_replace) {
3047 builder.AddString(replacement); 3041 builder.AddString(replacement);
3048 } else { 3042 } else {
3049 compiled_replacement.Apply(&builder, 3043 compiled_replacement.Apply(&builder,
3050 start, 3044 start,
3051 end, 3045 end,
3052 current_match); 3046 current_match);
3053 } 3047 }
3054 prev = end; 3048 prev = end;
3055 3049
3056 // Only continue checking for global regexps.
3057 if (!is_global) break;
3058
3059 current_match = global_cache.FetchNext(); 3050 current_match = global_cache.FetchNext();
3060 } while (current_match != NULL); 3051 } while (current_match != NULL);
3061 3052
3062 if (global_cache.HasException()) return Failure::Exception(); 3053 if (global_cache.HasException()) return Failure::Exception();
3063 3054
3064 if (prev < subject_length) { 3055 if (prev < subject_length) {
3065 builder.EnsureCapacity(2); 3056 builder.EnsureCapacity(2);
3066 builder.AddSubjectSlice(prev, subject_length); 3057 builder.AddSubjectSlice(prev, subject_length);
3067 } 3058 }
3068 3059
3069 RegExpImpl::SetLastMatchInfo(last_match_info, 3060 RegExpImpl::SetLastMatchInfo(last_match_info,
3070 subject, 3061 subject,
3071 capture_count, 3062 capture_count,
3072 global_cache.LastSuccessfulMatch()); 3063 global_cache.LastSuccessfulMatch());
3073 3064
3074 return *(builder.ToString()); 3065 return *(builder.ToString());
3075 } 3066 }
3076 3067
3077 3068
3078 template <typename ResultSeqString> 3069 template <typename ResultSeqString>
3079 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( 3070 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString(
3080 Isolate* isolate, 3071 Isolate* isolate,
3081 Handle<String> subject, 3072 Handle<String> subject,
3082 Handle<JSRegExp> regexp, 3073 Handle<JSRegExp> regexp,
3083 Handle<JSArray> last_match_info) { 3074 Handle<JSArray> last_match_info) {
3084 ASSERT(subject->IsFlat()); 3075 ASSERT(subject->IsFlat());
3085 3076
3086 bool is_global = regexp->GetFlags().is_global();
3087
3088 // Shortcut for simple non-regexp global replacements 3077 // Shortcut for simple non-regexp global replacements
3089 if (is_global && 3078 if (regexp->TypeTag() == JSRegExp::ATOM) {
3090 regexp->TypeTag() == JSRegExp::ATOM) {
3091 Handle<String> empty_string = isolate->factory()->empty_string(); 3079 Handle<String> empty_string = isolate->factory()->empty_string();
3092 if (subject->IsOneByteRepresentation()) { 3080 if (subject->IsOneByteRepresentation()) {
3093 return StringReplaceAtomRegExpWithString<SeqOneByteString>( 3081 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
3094 isolate, 3082 isolate, subject, regexp, empty_string, last_match_info);
3095 subject,
3096 regexp,
3097 empty_string,
3098 last_match_info);
3099 } else { 3083 } else {
3100 return StringReplaceAtomRegExpWithString<SeqTwoByteString>( 3084 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
3101 isolate, 3085 isolate, subject, regexp, empty_string, last_match_info);
3102 subject,
3103 regexp,
3104 empty_string,
3105 last_match_info);
3106 } 3086 }
3107 } 3087 }
3108 3088
3109 RegExpImpl::GlobalCache global_cache(regexp, subject, is_global, isolate); 3089 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
3110 if (global_cache.HasException()) return Failure::Exception(); 3090 if (global_cache.HasException()) return Failure::Exception();
3111 3091
3112 int32_t* current_match = global_cache.FetchNext(); 3092 int32_t* current_match = global_cache.FetchNext();
3113 if (current_match == NULL) { 3093 if (current_match == NULL) {
3114 if (global_cache.HasException()) return Failure::Exception(); 3094 if (global_cache.HasException()) return Failure::Exception();
3115 return isolate->heap()->undefined_value(); 3095 return *subject;
3116 } 3096 }
3117 3097
3118 int start = current_match[0]; 3098 int start = current_match[0];
3119 int end = current_match[1]; 3099 int end = current_match[1];
3120 int capture_count = regexp->CaptureCount(); 3100 int capture_count = regexp->CaptureCount();
3121 int subject_length = subject->length(); 3101 int subject_length = subject->length();
3122 3102
3123 int new_length = subject_length - (end - start); 3103 int new_length = subject_length - (end - start);
3124 if (new_length == 0) return isolate->heap()->empty_string(); 3104 if (new_length == 0) return isolate->heap()->empty_string();
3125 3105
3126 Handle<ResultSeqString> answer; 3106 Handle<ResultSeqString> answer;
3127 if (ResultSeqString::kHasAsciiEncoding) { 3107 if (ResultSeqString::kHasAsciiEncoding) {
3128 answer = Handle<ResultSeqString>::cast( 3108 answer = Handle<ResultSeqString>::cast(
3129 isolate->factory()->NewRawOneByteString(new_length)); 3109 isolate->factory()->NewRawOneByteString(new_length));
3130 } else { 3110 } else {
3131 answer = Handle<ResultSeqString>::cast( 3111 answer = Handle<ResultSeqString>::cast(
3132 isolate->factory()->NewRawTwoByteString(new_length)); 3112 isolate->factory()->NewRawTwoByteString(new_length));
3133 } 3113 }
3134 3114
3135 if (!is_global) {
3136 RegExpImpl::SetLastMatchInfo(
3137 last_match_info, subject, capture_count, current_match);
3138 if (start == end) {
3139 return *subject;
3140 } else {
3141 if (start > 0) {
3142 String::WriteToFlat(*subject, answer->GetChars(), 0, start);
3143 }
3144 if (end < subject_length) {
3145 String::WriteToFlat(
3146 *subject, answer->GetChars() + start, end, subject_length);
3147 }
3148 return *answer;
3149 }
3150 }
3151
3152 int prev = 0; 3115 int prev = 0;
3153 int position = 0; 3116 int position = 0;
3154 3117
3155 do { 3118 do {
3156 start = current_match[0]; 3119 start = current_match[0];
3157 end = current_match[1]; 3120 end = current_match[1];
3158 if (prev < start) { 3121 if (prev < start) {
3159 // Add substring subject[prev;start] to answer string. 3122 // Add substring subject[prev;start] to answer string.
3160 String::WriteToFlat( 3123 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
3161 *subject, answer->GetChars() + position, prev, start);
3162 position += start - prev; 3124 position += start - prev;
3163 } 3125 }
3164 prev = end; 3126 prev = end;
3165 3127
3166 current_match = global_cache.FetchNext(); 3128 current_match = global_cache.FetchNext();
3167 } while (current_match != NULL); 3129 } while (current_match != NULL);
3168 3130
3169 if (global_cache.HasException()) return Failure::Exception(); 3131 if (global_cache.HasException()) return Failure::Exception();
3170 3132
3171 RegExpImpl::SetLastMatchInfo(last_match_info, 3133 RegExpImpl::SetLastMatchInfo(last_match_info,
(...skipping 21 matching lines...) Expand all
3193 Address end_of_string = answer->address() + string_size; 3155 Address end_of_string = answer->address() + string_size;
3194 isolate->heap()->CreateFillerObjectAt(end_of_string, delta); 3156 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
3195 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) { 3157 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3196 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta); 3158 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
3197 } 3159 }
3198 3160
3199 return *answer; 3161 return *answer;
3200 } 3162 }
3201 3163
3202 3164
3203 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) { 3165 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) {
3204 ASSERT(args.length() == 4); 3166 ASSERT(args.length() == 4);
3205 3167
3206 HandleScope scope(isolate); 3168 HandleScope scope(isolate);
3207 3169
3208 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 3170 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3209 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); 3171 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
3210 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 3172 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3211 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 3173 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
3212 3174
3175 ASSERT(regexp->GetFlags().is_global());
3176
3213 if (!subject->IsFlat()) subject = FlattenGetString(subject); 3177 if (!subject->IsFlat()) subject = FlattenGetString(subject);
3214 3178
3215 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement); 3179 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement);
3216 3180
3217 ASSERT(last_match_info->HasFastObjectElements()); 3181 ASSERT(last_match_info->HasFastObjectElements());
3218 3182
3219 if (replacement->length() == 0) { 3183 if (replacement->length() == 0) {
3220 if (subject->IsOneByteConvertible()) { 3184 if (subject->IsOneByteConvertible()) {
3221 return StringReplaceRegExpWithEmptyString<SeqOneByteString>( 3185 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
3222 isolate, subject, regexp, last_match_info); 3186 isolate, subject, regexp, last_match_info);
3223 } else { 3187 } else {
3224 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>( 3188 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
3225 isolate, subject, regexp, last_match_info); 3189 isolate, subject, regexp, last_match_info);
3226 } 3190 }
3227 } 3191 }
3228 3192
3229 return StringReplaceRegExpWithString( 3193 return StringReplaceGlobalRegExpWithString(
3230 isolate, subject, regexp, replacement, last_match_info); 3194 isolate, subject, regexp, replacement, last_match_info);
3231 } 3195 }
3232 3196
3233 3197
3234 Handle<String> StringReplaceOneCharWithString(Isolate* isolate, 3198 Handle<String> StringReplaceOneCharWithString(Isolate* isolate,
3235 Handle<String> subject, 3199 Handle<String> subject,
3236 Handle<String> search, 3200 Handle<String> search,
3237 Handle<String> replace, 3201 Handle<String> replace,
3238 bool* found, 3202 bool* found,
3239 int recursion_limit) { 3203 int recursion_limit) {
(...skipping 10287 matching lines...) Expand 10 before | Expand all | Expand 10 after
13527 // Handle last resort GC and make sure to allow future allocations 13491 // Handle last resort GC and make sure to allow future allocations
13528 // to grow the heap without causing GCs (if possible). 13492 // to grow the heap without causing GCs (if possible).
13529 isolate->counters()->gc_last_resort_from_js()->Increment(); 13493 isolate->counters()->gc_last_resort_from_js()->Increment();
13530 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 13494 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13531 "Runtime::PerformGC"); 13495 "Runtime::PerformGC");
13532 } 13496 }
13533 } 13497 }
13534 13498
13535 13499
13536 } } // namespace v8::internal 13500 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime.h ('k') | src/string.js » ('j') | src/string.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698