| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 5030)
|
| +++ src/runtime.cc (working copy)
|
| @@ -2285,6 +2285,134 @@
|
| }
|
|
|
|
|
| +template <typename ResultSeqString>
|
| +static Object* StringReplaceRegExpWithEmptyString(String* 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();
|
| + }
|
| + Handle<ResultSeqString> answer;
|
| + if (ResultSeqString::kHasAsciiEncoding) {
|
| + 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,16 @@
|
|
|
| ASSERT(last_match_info->HasFastElements());
|
|
|
| + if (replacement->length() == 0) {
|
| + if (subject->HasOnlyAsciiChars()) {
|
| + return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
|
| + subject, regexp, last_match_info);
|
| + } else {
|
| + return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
|
| + subject, regexp, last_match_info);
|
| + }
|
| + }
|
| +
|
| return StringReplaceRegExpWithString(subject,
|
| regexp,
|
| replacement,
|
| @@ -5437,7 +5575,7 @@
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| CONVERT_DOUBLE_CHECKED(y, args[1]);
|
| - return Heap::AllocateHeapNumber(x + y);
|
| + return Heap::NumberFromDouble(x + y);
|
| }
|
|
|
|
|
| @@ -5447,7 +5585,7 @@
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| CONVERT_DOUBLE_CHECKED(y, args[1]);
|
| - return Heap::AllocateHeapNumber(x - y);
|
| + return Heap::NumberFromDouble(x - y);
|
| }
|
|
|
|
|
| @@ -5457,7 +5595,7 @@
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| CONVERT_DOUBLE_CHECKED(y, args[1]);
|
| - return Heap::AllocateHeapNumber(x * y);
|
| + return Heap::NumberFromDouble(x * y);
|
| }
|
|
|
|
|
| @@ -5466,7 +5604,7 @@
|
| ASSERT(args.length() == 1);
|
|
|
| CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| - return Heap::AllocateHeapNumber(-x);
|
| + return Heap::NumberFromDouble(-x);
|
| }
|
|
|
|
|
| @@ -6068,7 +6206,7 @@
|
| // custom powi() function than the generic pow().
|
| if (args[1]->IsSmi()) {
|
| int y = Smi::cast(args[1])->value();
|
| - return Heap::AllocateHeapNumber(powi(x, y));
|
| + return Heap::NumberFromDouble(powi(x, y));
|
| }
|
|
|
| CONVERT_DOUBLE_CHECKED(y, args[1]);
|
|
|