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

Unified Diff: src/runtime.cc

Issue 2809048: RegExp replace with empty string optimization by Sandholm. (Closed)
Patch Set: Addressed review comments. Created 10 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/factory.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/runtime.cc
diff --git a/src/runtime.cc b/src/runtime.cc
index a3eb09ffa8c564c13bb5e6dcf1eba24a6b8805ca..e3a150d907419a10273d1cd8923d6566e1973811 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2284,6 +2284,134 @@ static Object* StringReplaceRegExpWithString(String* subject,
return *(builder.ToString());
}
+template <typename ResultSeqString>
+static Object* StringReplaceRegExpWithEmptyString(ResultSeqString* subject,
+ JSRegExp* regexp,
+ JSArray* last_match_info) {
+ ASSERT(subject->IsFlat());
+
+ HandleScope handles;
+
+ Handle<String> subject_handle(subject);
+ Handle<JSRegExp> regexp_handle(regexp);
+ Handle<JSArray> last_match_info_handle(last_match_info);
+ Handle<Object> match = RegExpImpl::Exec(regexp_handle,
+ subject_handle,
+ 0,
+ last_match_info_handle);
+ if (match.is_null()) return Failure::Exception();
+ if (match->IsNull()) return *subject_handle;
+
+ ASSERT(last_match_info_handle->HasFastElements());
+
+ HandleScope loop_scope;
+ int start, end;
+ {
+ AssertNoAllocation match_info_array_is_not_in_a_handle;
+ FixedArray* match_info_array =
+ FixedArray::cast(last_match_info_handle->elements());
+
+ start = RegExpImpl::GetCapture(match_info_array, 0);
+ end = RegExpImpl::GetCapture(match_info_array, 1);
+ }
+
+ int length = subject->length();
+ int new_length = length - (end - start);
+ if (new_length == 0) {
+ return Heap::empty_string();
+ }
+ // TODO(sandholm) try to use types statically to determine this.
+ Handle<ResultSeqString> answer;
+ if (subject_handle->IsAsciiRepresentation()) {
+ answer =
+ Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
+ } else {
+ answer =
+ Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
+ }
+
+ // If the regexp isn't global, only match once.
+ if (!regexp_handle->GetFlags().is_global()) {
+ if (start > 0) {
+ String::WriteToFlat(*subject_handle,
+ answer->GetChars(),
+ 0,
+ start);
+ }
+ if (end < length) {
+ String::WriteToFlat(*subject_handle,
+ answer->GetChars() + start,
+ end,
+ length);
+ }
+ return *answer;
+ }
+
+ int prev = 0; // Index of end of last match.
+ int next = 0; // Start of next search (prev unless last match was empty).
+ int position = 0;
+
+ do {
+ if (prev < start) {
+ // Add substring subject[prev;start] to answer string.
+ String::WriteToFlat(*subject_handle,
+ answer->GetChars() + position,
+ prev,
+ start);
+ position += start - prev;
+ }
+ prev = end;
+ next = end;
+ // Continue from where the match ended, unless it was an empty match.
+ if (start == end) {
+ next++;
+ if (next > length) break;
+ }
+ match = RegExpImpl::Exec(regexp_handle,
+ subject_handle,
+ next,
+ last_match_info_handle);
+ if (match.is_null()) return Failure::Exception();
+ if (match->IsNull()) break;
+
+ ASSERT(last_match_info_handle->HasFastElements());
+ HandleScope loop_scope;
+ {
+ AssertNoAllocation match_info_array_is_not_in_a_handle;
+ FixedArray* match_info_array =
+ FixedArray::cast(last_match_info_handle->elements());
+ start = RegExpImpl::GetCapture(match_info_array, 0);
+ end = RegExpImpl::GetCapture(match_info_array, 1);
+ }
+ } while (true);
+
+ if (prev < length) {
+ // Add substring subject[prev;length] to answer string.
+ String::WriteToFlat(*subject_handle,
+ answer->GetChars() + position,
+ prev,
+ length);
+ position += length - prev;
+ }
+
+ if (position == 0) {
+ return Heap::empty_string();
+ }
+
+ // Shorten string and fill
+ int string_size = ResultSeqString::SizeFor(position);
+ int allocated_string_size = ResultSeqString::SizeFor(new_length);
+ int delta = allocated_string_size - string_size;
+
+ answer->set_length(position);
+ if (delta == 0) return *answer;
+
+ Address end_of_string = answer->address() + string_size;
+ Heap::CreateFillerObjectAt(end_of_string, delta);
+
+ return *answer;
+}
+
static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
ASSERT(args.length() == 4);
@@ -2311,6 +2439,18 @@ static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
ASSERT(last_match_info->HasFastElements());
+ if (replacement->length() == 0) {
+ if (subject->IsAsciiRepresentation()) {
+ return StringReplaceRegExpWithEmptyString(SeqAsciiString::cast(subject),
+ regexp,
+ last_match_info);
+ } else {
+ return StringReplaceRegExpWithEmptyString(SeqTwoByteString::cast(subject),
+ regexp,
+ last_match_info);
+ }
+ }
+
return StringReplaceRegExpWithString(subject,
regexp,
replacement,
« no previous file with comments | « src/factory.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698