| Index: src/runtime.cc
|
| diff --git a/src/runtime.cc b/src/runtime.cc
|
| index 492bca79469cf16d8d5d3abc29612bc72b65e4b4..fc3a9a5570a0f25f008a2304d51bfbde9e163cdc 100644
|
| --- a/src/runtime.cc
|
| +++ b/src/runtime.cc
|
| @@ -1226,6 +1226,129 @@ static Object* Runtime_RegExpExec(Arguments args) {
|
| return *result;
|
| }
|
|
|
| +static Object* Runtime_RegExpExecMultiple(Arguments args) {
|
| + HandleScope scope;
|
| + ASSERT(args.length() == 4);
|
| +
|
| + CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
|
| + CONVERT_ARG_CHECKED(String, subject, 1);
|
| + CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
|
| + CONVERT_ARG_CHECKED(JSArray, result_array, 3);
|
| + RUNTIME_ASSERT(last_match_info->HasFastElements());
|
| + RUNTIME_ASSERT(result_array->HasFastElements());
|
| + RUNTIME_ASSERT(regexp->GetFlags().is_global());
|
| +
|
| + ZoneScope zone(DELETE_ON_EXIT);
|
| + // TODO(lrn): Be much smarter about calling the regexp exec
|
| + // function in a loop! And split execution into Atom and Irregexp
|
| + // parts (atoms never have captures and can call StringMatch directly).
|
| + ZoneList<Smi*> captures(256);
|
| + // Number of captures per regexp match (excluding the match itself).
|
| +
|
| + int capture_count =
|
| + RegExpImpl::RegExpNumberOfCaptures(FixedArray::cast(regexp->data()));
|
| + int subject_length = subject->length();
|
| +
|
| + // Execute regexp once. If absolutely no match, we exit fast.
|
| + // Otherwise prepare to repeat execution.
|
| + Handle<Object> result =
|
| + RegExpImpl::Exec(regexp, subject, 0, last_match_info);
|
| + if (result.is_null()) {
|
| + return Failure::Exception();
|
| + }
|
| + if (result->IsNull()) {
|
| + // No match at all, return null.
|
| + return Smi::FromInt(0);
|
| + }
|
| +
|
| + ASSERT_EQ(*last_match_info, *result);
|
| + ASSERT(last_match_info->HasFastElements());
|
| +
|
| + // Include the match itself as a capture.
|
| + int capture_reg_count = (capture_count + 1) * 2;
|
| +
|
| + ASSERT_EQ(capture_reg_count,
|
| + Smi::cast(FixedArray::cast(last_match_info->elements())->
|
| + get(RegExpImpl::kLastCaptureCount))->value());
|
| +
|
| + int index;
|
| + int matches = 0;
|
| + do {
|
| + {
|
| + AssertNoAllocation no_gc;
|
| + ASSERT(last_match_info->HasFastElements());
|
| +
|
| + FixedArray* match_array = FixedArray::cast(last_match_info->elements());
|
| + Smi* match_start =
|
| + Smi::cast(match_array->get(RegExpImpl::kFirstCapture));
|
| + Smi* match_end =
|
| + Smi::cast(match_array->get(RegExpImpl::kFirstCapture + 1));
|
| + captures.Add(match_start);
|
| + captures.Add(match_end);
|
| + // TODO(lrn): Expand, if necessary, captures list in one go and
|
| + // use memcpy to copy captures.
|
| + for (int i = 2; i < capture_reg_count; i++) {
|
| + captures.Add(
|
| + Smi::cast(match_array->get(RegExpImpl::kFirstCapture + i)));
|
| + }
|
| + matches++;
|
| + index = match_end->value();
|
| + if (match_start == match_end) {
|
| + index++;
|
| + if (index > subject_length) {
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + result = RegExpImpl::Exec(regexp, subject, index, last_match_info);
|
| + if (result.is_null()) {
|
| + return Failure::Exception();
|
| + }
|
| + } while (!result->IsNull());
|
| +
|
| + // Done collecting match indices. Now create a result array on the format:
|
| + // - Smi number of captures (not including match) per match
|
| + // - for each match:
|
| + // - smi index of match
|
| + // - match substring
|
| + // - for each capture
|
| + // - captured substring, or undefined if capture is not participating.
|
| + int array_length = 1 + (2 + capture_count) * matches;
|
| + result_array->Resize(array_length);
|
| + result_array->set_length(Smi::FromInt(array_length));
|
| + Handle<FixedArray> elements(FixedArray::cast(result_array->elements()));
|
| +
|
| + elements->set(0, Smi::FromInt(capture_count));
|
| + int capture_index = 0;
|
| + int result_index = 1;
|
| + for (int i = 0; i < matches; i++) {
|
| + Smi* from = captures.at(capture_index);
|
| + Smi* to = captures.at(capture_index + 1);
|
| + elements->set(result_index, from);
|
| + elements->set(result_index + 1, *Factory::NewSubString(subject,
|
| + from->value(),
|
| + to->value()));
|
| + result_index += 2;
|
| + capture_index += 2;
|
| + for (int j = 0; j < capture_count; j++) {
|
| + int from = captures.at(capture_index)->value();
|
| + if (from >= 0) {
|
| + int to = captures.at(capture_index + 1)->value();
|
| + ASSERT(to >= 0);
|
| + elements->set(result_index,
|
| + *Factory::NewSubString(subject, from, to));
|
| + } else {
|
| + ASSERT(captures.at(capture_index + 1)->value() < 0);
|
| + elements->set(result_index, Heap::undefined_value());
|
| + }
|
| + capture_index += 2;
|
| + result_index++;
|
| + }
|
| + }
|
| +
|
| + return Smi::FromInt(matches);
|
| +}
|
| +
|
|
|
| static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) {
|
| HandleScope scope;
|
| @@ -5073,7 +5196,7 @@ static Object* FlatStringCompare(String* x, String* y) {
|
| Vector<const char> x_chars = x->ToAsciiVector();
|
| if (y->IsAsciiRepresentation()) {
|
| Vector<const char> y_chars = y->ToAsciiVector();
|
| - r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
|
| + r = memcmp(x_chars.start(), y_chars.start(), prefix_length);
|
| } else {
|
| Vector<const uc16> y_chars = y->ToUC16Vector();
|
| r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
|
| @@ -5121,10 +5244,8 @@ static Object* Runtime_StringCompare(Arguments args) {
|
| if (d < 0) return Smi::FromInt(LESS);
|
| else if (d > 0) return Smi::FromInt(GREATER);
|
|
|
| - Object* obj = Heap::PrepareForCompare(x);
|
| - if (obj->IsFailure()) return obj;
|
| - obj = Heap::PrepareForCompare(y);
|
| - if (obj->IsFailure()) return obj;
|
| + x->TryFlatten();
|
| + y->TryFlatten();
|
|
|
| return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
|
| : StringInputBufferCompare(x, y);
|
| @@ -5325,21 +5446,12 @@ static Object* Runtime_Math_round(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| Counters::math_round.Increment();
|
| - CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| -
|
| - if (x > 0 && x < Smi::kMaxValue) {
|
| - return Smi::FromInt(static_cast<int>(x + 0.5));
|
| - }
|
|
|
| + CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
|
| -
|
| - // if the magnitude is big enough, there's no place for fraction part. If we
|
| - // try to add 0.5 to this number, 1.0 will be added instead.
|
| - if (x >= 9007199254740991.0 || x <= -9007199254740991.0) {
|
| - return args[0];
|
| - }
|
| -
|
| - return Heap::NumberFromDouble(floor(x + 0.5));
|
| + double integer = ceil(x);
|
| + if (integer - x > 0.5) { integer -= 1.0; }
|
| + return Heap::NumberFromDouble(integer);
|
| }
|
|
|
|
|
|
|