| 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,
|
|
|