Chromium Code Reviews| Index: src/runtime.cc |
| diff --git a/src/runtime.cc b/src/runtime.cc |
| index d87267029f18e585308f0251b62b0d04fd4b4f0b..5d6aeec2652092cd25a8bccbbce0d2b3f3f9db6f 100644 |
| --- a/src/runtime.cc |
| +++ b/src/runtime.cc |
| @@ -1564,6 +1564,88 @@ static Object* Runtime_CharFromCode(Arguments args) { |
| return CharFromCode(args[0]); |
| } |
| + |
| +class FixedArrayBuilder { |
| + public: |
| + explicit FixedArrayBuilder(int initial_capacity) |
| + : array_(Factory::NewFixedArrayWithHoles(initial_capacity)), |
| + length_(0) { |
| + // Require a non-zero initial size. Ensures that doubling the size to |
| + // extend the array will work. |
| + ASSERT(initial_capacity > 0); |
| + } |
| + |
| + explicit FixedArrayBuilder(Handle<FixedArray> backing_store) |
| + : array_(backing_store), |
| + length_(0) { |
| + // Require a non-zero initial size. Ensures that doubling the size to |
| + // extend the array will work. |
| + ASSERT(backing_store->length() > 0); |
| + } |
| + |
| + bool HasCapacity(int elements) { |
| + int length = array_->length(); |
| + int required_length = length_ + elements; |
| + return (length >= required_length); |
| + } |
| + |
| + void EnsureCapacity(int elements) { |
| + int length = array_->length(); |
| + int required_length = length_ + elements; |
| + if (length < required_length) { |
| + int new_length = length; |
| + do { |
| + new_length *= 2; |
| + } while (new_length < required_length); |
| + Handle<FixedArray> extended_array = |
| + Factory::NewFixedArrayWithHoles(new_length); |
| + array_->CopyTo(0, *extended_array, 0, length_); |
| + array_ = extended_array; |
| + } |
| + } |
| + |
| + void Add(Object* value) { |
| + ASSERT(length_ < capacity()); |
| + array_->set(length_, value); |
| + length_++; |
| + } |
| + |
| + void Add(Smi* value) { |
| + ASSERT(length_ < capacity()); |
| + array_->set(length_, value); |
| + length_++; |
| + } |
| + |
| + inline Handle<FixedArray> array() { |
|
fschneider
2010/03/25 10:26:06
I don't know enough how C++ compilers treat the in
Lasse Reichstein
2010/03/26 11:18:26
I think you are right. Inlining is default in this
|
| + return array_; |
| + } |
| + |
| + inline int length() { |
| + return length_; |
| + } |
| + |
| + inline int capacity() { |
| + return array_->length(); |
| + } |
| + |
| + inline Handle<JSArray> ToJSArray() { |
| + Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_); |
| + result_array->set_length(Smi::FromInt(length_)); |
| + return result_array; |
| + } |
| + |
| + inline Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { |
| + target_array->set_elements(*array_); |
| + target_array->set_length(Smi::FromInt(length_)); |
| + return target_array; |
| + } |
| + |
| + private: |
| + Handle<FixedArray> array_; |
| + int length_; |
| +}; |
| + |
| + |
| // Forward declarations. |
| static const int kStringBuilderConcatHelperLengthBits = 11; |
|
fschneider
2010/03/25 10:26:06
No need for static here. It is the default for C++
Lasse Reichstein
2010/03/26 11:18:26
Fixed.
|
| static const int kStringBuilderConcatHelperPositionBits = 19; |
| @@ -1577,12 +1659,12 @@ static inline void StringBuilderConcatHelper(String*, |
| typedef BitField<int, 0, 11> StringBuilderSubstringLength; |
|
fschneider
2010/03/25 10:26:06
Would be better to use the defined constants here.
Lasse Reichstein
2010/03/26 11:18:26
Very long, but changed anyway.
|
| typedef BitField<int, 11, 19> StringBuilderSubstringPosition; |
| + |
| class ReplacementStringBuilder { |
| public: |
| ReplacementStringBuilder(Handle<String> subject, int estimated_part_count) |
| - : subject_(subject), |
| - parts_(Factory::NewFixedArray(estimated_part_count)), |
| - part_count_(0), |
| + : array_builder_(estimated_part_count), |
| + subject_(subject), |
| character_count_(0), |
| is_ascii_(subject->IsAsciiRepresentation()) { |
| // Require a non-zero initial size. Ensures that doubling the size to |
| @@ -1590,38 +1672,35 @@ class ReplacementStringBuilder { |
| ASSERT(estimated_part_count > 0); |
| } |
| - void EnsureCapacity(int elements) { |
| - int length = parts_->length(); |
| - int required_length = part_count_ + elements; |
| - if (length < required_length) { |
| - int new_length = length; |
| - do { |
| - new_length *= 2; |
| - } while (new_length < required_length); |
| - Handle<FixedArray> extended_array = |
| - Factory::NewFixedArray(new_length); |
| - parts_->CopyTo(0, *extended_array, 0, part_count_); |
| - parts_ = extended_array; |
| - } |
| - } |
| - |
| - void AddSubjectSlice(int from, int to) { |
| + static inline void AddSubjectSlice(FixedArrayBuilder* builder, |
| + int from, |
| + int to) { |
| ASSERT(from >= 0); |
| int length = to - from; |
| ASSERT(length > 0); |
| - // Can we encode the slice in 11 bits for length and 19 bits for |
| - // start position - as used by StringBuilderConcatHelper? |
| if (StringBuilderSubstringLength::is_valid(length) && |
| StringBuilderSubstringPosition::is_valid(from)) { |
| int encoded_slice = StringBuilderSubstringLength::encode(length) | |
| StringBuilderSubstringPosition::encode(from); |
| - AddElement(Smi::FromInt(encoded_slice)); |
| + builder->Add(Smi::FromInt(encoded_slice)); |
| } else { |
| // Otherwise encode as two smis. |
| - AddElement(Smi::FromInt(-length)); |
| - AddElement(Smi::FromInt(from)); |
| + builder->Add(Smi::FromInt(-length)); |
| + builder->Add(Smi::FromInt(from)); |
| } |
| - IncrementCharacterCount(length); |
| + } |
| + |
| + |
| + void EnsureCapacity(int elements) { |
| + array_builder_.EnsureCapacity(elements); |
| + } |
| + |
| + |
| + void AddSubjectSlice(int from, int to) { |
| + AddSubjectSlice(&array_builder_, from, to); |
| + // Can we encode the slice in 11 bits for length and 19 bits for |
| + // start position - as used by StringBuilderConcatHelper? |
| + IncrementCharacterCount(to - from); |
| } |
| @@ -1637,7 +1716,7 @@ class ReplacementStringBuilder { |
| Handle<String> ToString() { |
| - if (part_count_ == 0) { |
| + if (array_builder_.length() == 0) { |
| return Factory::empty_string(); |
| } |
| @@ -1649,8 +1728,8 @@ class ReplacementStringBuilder { |
| char* char_buffer = seq->GetChars(); |
| StringBuilderConcatHelper(*subject_, |
| char_buffer, |
| - *parts_, |
| - part_count_); |
| + *array_builder_.array(), |
| + array_builder_.length()); |
| } else { |
| // Non-ASCII. |
| joined_string = NewRawTwoByteString(character_count_); |
| @@ -1659,8 +1738,8 @@ class ReplacementStringBuilder { |
| uc16* char_buffer = seq->GetChars(); |
| StringBuilderConcatHelper(*subject_, |
| char_buffer, |
| - *parts_, |
| - part_count_); |
| + *array_builder_.array(), |
| + array_builder_.length()); |
| } |
| return joined_string; |
| } |
| @@ -1673,6 +1752,13 @@ class ReplacementStringBuilder { |
| character_count_ += by; |
| } |
| + Handle<JSArray> GetParts() { |
| + Handle<JSArray> result = |
| + Factory::NewJSArrayWithElements(array_builder_.array()); |
| + result->set_length(Smi::FromInt(array_builder_.length())); |
| + return result; |
| + } |
| + |
| private: |
|
fschneider
2010/03/25 10:26:06
Extra empty line.
|
| Handle<String> NewRawAsciiString(int size) { |
| @@ -1687,14 +1773,12 @@ class ReplacementStringBuilder { |
| void AddElement(Object* element) { |
| ASSERT(element->IsSmi() || element->IsString()); |
| - ASSERT(parts_->length() > part_count_); |
| - parts_->set(part_count_, element); |
| - part_count_++; |
| + ASSERT(array_builder_.capacity() > array_builder_.length()); |
| + array_builder_.Add(element); |
| } |
| + FixedArrayBuilder array_builder_; |
| Handle<String> subject_; |
| - Handle<FixedArray> parts_; |
| - int part_count_; |
| int character_count_; |
| bool is_ascii_; |
| }; |
| @@ -2102,7 +2186,6 @@ static Object* Runtime_StringReplaceRegExpWithString(Arguments args) { |
| } |
| - |
| // Cap on the maximal shift in the Boyer-Moore implementation. By setting a |
| // limit, we can fix the size of tables. |
| static const int kBMMaxShift = 0xff; |
| @@ -2866,6 +2949,480 @@ static Object* Runtime_StringMatch(Arguments args) { |
| } |
| +// Two smis before and after the match, for very long strings. |
| +static const int kMaxBuilderEntriesPerRegExpMatch = 5; |
|
fschneider
2010/03/25 10:26:06
No need for static here either.
Lasse Reichstein
2010/03/26 11:18:26
Removed.
|
| + |
| + |
| +static void SetLastMatchInfoNoCaptures(Handle<String> subject, |
| + Handle<JSArray> last_match_info, |
| + int match_start, |
| + int match_end) { |
| + // Fill last_match_info with a single capture. |
| + last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); |
| + AssertNoAllocation no_gc; |
| + FixedArray* elements = FixedArray::cast(last_match_info->elements()); |
| + RegExpImpl::SetLastCaptureCount(elements, 2); |
| + RegExpImpl::SetLastInput(elements, *subject); |
| + RegExpImpl::SetLastSubject(elements, *subject); |
| + RegExpImpl::SetCapture(elements, 0, match_start); |
| + RegExpImpl::SetCapture(elements, 1, match_end); |
| +} |
| + |
| + |
| +template <typename schar> |
| +static bool SearchCharMultiple(Vector<schar> subject, |
| + String* pattern, |
| + schar pattern_char, |
| + FixedArrayBuilder* builder, |
| + int* match_pos) { |
| + // Position of last match. |
| + int pos = *match_pos; |
| + int subject_length = subject.length(); |
| + while (pos < subject_length) { |
| + int match_end = pos + 1; |
| + if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { |
| + *match_pos = pos; |
| + return false; |
| + } |
| + int new_pos = SingleCharIndexOf(subject, pattern_char, match_end); |
| + if (new_pos >= 0) { |
|
fschneider
2010/03/25 10:26:06
More compact if you reverse the condition:
if (ne
Lasse Reichstein
2010/03/26 11:18:26
I want to have the "fast case" as the first branch
|
| + // A match. |
|
fschneider
2010/03/25 10:26:06
Complete sentence for whole-line comments.
|
| + if (new_pos > match_end) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, match_end, new_pos); |
| + } |
| + pos = new_pos; |
| + builder->Add(pattern); |
| + } else { |
| + break; |
| + } |
| + } |
| + if (pos + 1 < subject_length) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, pos + 1, subject_length); |
| + } |
| + *match_pos = pos; |
| + return true; |
| +} |
| + |
| + |
| +static bool SearchCharMultiple(Handle<String> subject, |
| + Handle<String> pattern, |
| + Handle<JSArray> last_match_info, |
| + FixedArrayBuilder* builder) { |
| + ASSERT(subject->IsFlat()); |
| + ASSERT_EQ(1, pattern->length()); |
| + uc16 pattern_char = pattern->Get(0); |
|
fschneider
2010/03/25 10:26:06
ASSERT that pattern is a uc16-string?
Lasse Reichstein
2010/03/26 11:18:26
Not necessary. Get is generic and works on both ki
|
| + // Treating position before first as initial "previous match position". |
| + int match_pos = -1; |
| + |
| + for (;;) { // Break when search complete. |
| + builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| + AssertNoAllocation no_gc; |
| + if (subject->IsAsciiRepresentation()) { |
| + if (pattern_char > String::kMaxAsciiCharCode) { |
|
fschneider
2010/03/25 10:26:06
No need for multi-line if.
Lasse Reichstein
2010/03/26 11:18:26
How not?
|
| + break; |
| + } |
| + Vector<const char> subject_vector = subject->ToAsciiVector(); |
| + char pattern_ascii_char = static_cast<char>(pattern_char); |
| + bool complete = SearchCharMultiple<const char>(subject_vector, |
| + *pattern, |
| + pattern_ascii_char, |
| + builder, |
| + &match_pos); |
| + if (complete) break; |
| + } else { |
| + Vector<const uc16> subject_vector = subject->ToUC16Vector(); |
| + bool complete = SearchCharMultiple<const uc16>(subject_vector, |
| + *pattern, |
| + pattern_char, |
| + builder, |
| + &match_pos); |
| + if (complete) break; |
| + } |
| + } |
| + |
| + if (match_pos >= 0) { |
| + SetLastMatchInfoNoCaptures(subject, |
| + last_match_info, |
| + match_pos, |
| + match_pos + 1); |
| + return true; |
| + } |
| + return false; // No matches at all. |
| +} |
| + |
| + |
| +template <typename schar, typename pchar> |
| +static bool SearchStringMultiple(Vector<schar> subject, |
| + String* pattern, |
| + Vector<pchar> pattern_string, |
| + FixedArrayBuilder* builder, |
| + int* match_pos) { |
| + int pos = *match_pos; |
| + int subject_length = subject.length(); |
| + int pattern_length = pattern_string.length(); |
| + int max_search_start = subject_length - pattern_length; |
| + bool is_ascii = (sizeof(schar) == 1); |
| + StringSearchStrategy strategy = |
| + InitializeStringSearch(pattern_string, is_ascii); |
| + switch (strategy) { |
| + case SEARCH_FAIL: return false; |
| + case SEARCH_SHORT: { |
|
fschneider
2010/03/25 10:26:06
No need for { } block?
Lasse Reichstein
2010/03/26 11:18:26
Done.
|
| + while (pos <= max_search_start) { |
| + if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { |
| + *match_pos = pos; |
| + return false; |
| + } |
| + // Position of end of previous match. |
| + int match_end = pos + pattern_length; |
| + int new_pos = SimpleIndexOf(subject, pattern_string, match_end); |
| + if (new_pos >= 0) { |
|
fschneider
2010/03/25 10:26:06
Reverse condition here too?
if (new_pos < 0) brea
Lasse Reichstein
2010/03/26 11:18:26
Same argument as last time, I want the "then" bran
|
| + // A match. |
| + if (new_pos > match_end) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, |
| + match_end, |
| + new_pos); |
| + } |
| + pos = new_pos; |
| + builder->Add(pattern); |
| + } else { |
| + break; |
| + } |
| + } |
| + break; |
| + } |
| + case SEARCH_LONG: { |
|
fschneider
2010/03/25 10:26:06
No need for { } block?
Lasse Reichstein
2010/03/26 11:18:26
Done.
|
| + while (pos <= max_search_start) { |
| + if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { |
| + *match_pos = pos; |
| + return false; |
| + } |
| + int new_pos = ComplexIndexOf(subject, |
| + pattern_string, |
| + pos + pattern_length); |
| + if (new_pos >= 0) { |
|
fschneider
2010/03/25 10:26:06
And here?
if (new_pos < 0) break;
...
Lasse Reichstein
2010/03/26 11:18:26
Also retained.
|
| + // A match. |
| + if (new_pos > pos) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, pos, new_pos); |
| + } |
| + pos = new_pos; |
| + builder->Add(pattern); |
| + } else { |
| + break; |
| + } |
| + } |
| + break; |
| + } |
| + } |
| + if (pos < max_search_start) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, |
| + pos + pattern_length, |
| + subject_length); |
| + } |
| + *match_pos = pos; |
| + return true; |
| +} |
| + |
| + |
| +static bool SearchStringMultiple(Handle<String> subject, |
| + Handle<String> pattern, |
| + Handle<JSArray> last_match_info, |
| + FixedArrayBuilder* builder) { |
| + ASSERT(subject->IsFlat()); |
| + ASSERT(pattern->IsFlat()); |
| + ASSERT(pattern->length() > 1); |
| + |
| + // Treating as if a previous match was before first character. |
| + int match_pos = -pattern->length(); |
| + |
| + for (;;) { // Break when search complete. |
| + builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| + AssertNoAllocation no_gc; |
| + if (subject->IsAsciiRepresentation()) { |
| + Vector<const char> subject_vector = subject->ToAsciiVector(); |
| + if (pattern->IsAsciiRepresentation()) { |
| + if (SearchStringMultiple(subject_vector, |
| + *pattern, |
| + pattern->ToAsciiVector(), |
| + builder, |
| + &match_pos)) break; |
| + } else { |
| + if (SearchStringMultiple(subject_vector, |
| + *pattern, |
| + pattern->ToUC16Vector(), |
| + builder, |
| + &match_pos)) break; |
| + } |
| + } else { |
| + Vector<const uc16> subject_vector = subject->ToUC16Vector(); |
| + if (pattern->IsAsciiRepresentation()) { |
| + if (SearchStringMultiple(subject_vector, |
| + *pattern, |
| + pattern->ToAsciiVector(), |
| + builder, |
| + &match_pos)) break; |
| + } else { |
| + if (SearchStringMultiple(subject_vector, |
| + *pattern, |
| + pattern->ToUC16Vector(), |
| + builder, |
| + &match_pos)) break; |
| + } |
| + } |
| + } |
| + |
| + if (match_pos >= 0) { |
| + SetLastMatchInfoNoCaptures(subject, |
| + last_match_info, |
| + match_pos, |
| + match_pos + pattern->length()); |
| + return true; |
| + } |
| + return false; // No matches at all. |
| +} |
| + |
| + |
| +static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( |
| + Handle<String> subject, |
| + Handle<JSRegExp> regexp, |
| + Handle<JSArray> last_match_array, |
| + FixedArrayBuilder* builder) { |
| + ASSERT(subject->IsFlat()); |
| + int match_start = -1; |
| + int match_end = 0; |
| + int pos = 0; |
| + int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); |
| + if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; |
| + |
| + OffsetsVector registers(required_registers); |
| + Vector<int> register_vector(registers.vector(), registers.length()); |
| + int subject_length = subject->length(); |
| + |
| + for (;;) { // Break on failure, return on exception. |
| + RegExpImpl::IrregexpResult result = |
| + RegExpImpl::IrregexpExecOnce(regexp, |
| + subject, |
| + pos, |
| + register_vector); |
| + if (result == RegExpImpl::RE_SUCCESS) { |
| + match_start = register_vector[0]; |
| + builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| + if (match_end < match_start) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, |
| + match_end, |
| + match_start); |
| + } |
| + match_end = register_vector[1]; |
| + HandleScope loop_scope; |
| + builder->Add(*Factory::NewSubString(subject, match_start, match_end)); |
| + if (match_start != match_end) { |
| + pos = match_end; |
| + } else { |
| + pos = match_end + 1; |
| + if (pos > subject_length) break; |
| + } |
| + } else if (result == RegExpImpl::RE_FAILURE) { |
| + break; |
| + } else { |
| + ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); |
| + return result; |
| + } |
| + } |
| + |
| + if (match_start >= 0) { |
| + if (match_end < subject_length) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, |
| + match_end, |
| + subject_length); |
| + } |
| + SetLastMatchInfoNoCaptures(subject, |
| + last_match_array, |
| + match_start, |
| + match_end); |
| + return RegExpImpl::RE_SUCCESS; |
| + } else { |
| + return RegExpImpl::RE_FAILURE; // No matches at all. |
| + } |
| +} |
| + |
| + |
| +static RegExpImpl::IrregexpResult SearchRegExpMultiple( |
| + Handle<String> subject, |
| + Handle<JSRegExp> regexp, |
| + Handle<JSArray> last_match_array, |
| + FixedArrayBuilder* builder) { |
| + |
| + ASSERT(subject->IsFlat()); |
| + int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); |
| + if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; |
| + |
| + OffsetsVector registers(required_registers); |
| + Vector<int> register_vector(registers.vector(), registers.length()); |
| + |
| + RegExpImpl::IrregexpResult result = |
| + RegExpImpl::IrregexpExecOnce(regexp, |
| + subject, |
| + 0, |
| + register_vector); |
| + |
| + int capture_count = regexp->CaptureCount(); |
| + int subject_length = subject->length(); |
| + |
| + // Position to search from. |
| + int pos = 0; |
| + // End of previous match. Differs from pos if match was empty. |
| + int match_end = 0; |
| + if (result == RegExpImpl::RE_SUCCESS) { |
| + // Need to keep a copy of the previous match for creating last_match_info |
| + // at the end, so we have two vectors that we swap between. |
| + OffsetsVector registers2(required_registers); |
| + Vector<int> prev_register_vector(registers2.vector(), registers2.length()); |
| + |
| + do { |
| + int match_start = register_vector[0]; |
| + builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); |
| + if (match_end < match_start) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, |
| + match_end, |
| + match_start); |
| + } |
| + match_end = register_vector[1]; |
| + |
| + { |
| + // Avoid accumulating new handles inside loop. |
| + HandleScope temp_scope; |
| + // Arguments array to replace function is match, captures, index and |
| + // subject, i.e., 3 + capture count in total. |
| + Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count); |
| + elements->set(0, *Factory::NewSubString(subject, |
| + match_start, |
| + match_end)); |
| + for (int i = 1; i <= capture_count; i++) { |
| + Handle<String> substring = |
| + Factory::NewSubString(subject, |
| + register_vector[i * 2], |
| + register_vector[i * 2 + 1]); |
| + elements->set(i, *substring); |
| + } |
| + elements->set(capture_count + 1, Smi::FromInt(match_start)); |
| + elements->set(capture_count + 2, *subject); |
| + builder->Add(*Factory::NewJSArrayWithElements(elements)); |
| + } |
| + // Swap register vectors, so the last successful match is in |
| + // prev_register_vector. |
| + Vector<int> tmp = prev_register_vector; |
|
fschneider
2010/03/25 10:26:06
Could you have one stack-allocated instance of the
Lasse Reichstein
2010/03/26 11:18:26
Vector is a two-value struct. Allocating a single
|
| + prev_register_vector = register_vector; |
| + register_vector = tmp; |
| + |
| + if (match_end > match_start) { |
| + pos = match_end; |
| + } else { |
| + pos = match_end + 1; |
| + if (pos > subject_length) { |
| + break; |
| + } |
| + } |
| + |
| + result = RegExpImpl::IrregexpExecOnce(regexp, |
| + subject, |
| + pos, |
| + register_vector); |
| + } while (result == RegExpImpl::RE_SUCCESS); |
| + |
| + if (result != RegExpImpl::RE_EXCEPTION) { |
| + // Finished matching, with at least one match. |
| + if (match_end < subject_length) { |
| + ReplacementStringBuilder::AddSubjectSlice(builder, |
| + match_end, |
| + subject_length); |
| + } |
| + |
| + int last_match_capture_count = (capture_count + 1) * 2; |
| + int last_match_array_size = |
| + last_match_capture_count + RegExpImpl::kLastMatchOverhead; |
| + last_match_array->EnsureSize(last_match_array_size); |
| + AssertNoAllocation no_gc; |
| + FixedArray* elements = FixedArray::cast(last_match_array->elements()); |
| + RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); |
| + RegExpImpl::SetLastSubject(elements, *subject); |
| + RegExpImpl::SetLastInput(elements, *subject); |
| + for (int i = 0; i < last_match_capture_count; i++) { |
| + RegExpImpl::SetCapture(elements, i, prev_register_vector[i]); |
| + } |
| + return RegExpImpl::RE_SUCCESS; |
| + } |
| + } |
| + // No matches at all, return failure or exception result directly. |
| + return result; |
| +} |
| + |
| + |
| +static Object* Runtime_RegExpExecMultiple(Arguments args) { |
| + ASSERT(args.length() == 4); |
| + HandleScope handles; |
| + |
| + CONVERT_ARG_CHECKED(String, subject, 1); |
| + if (!subject->IsFlat()) { FlattenString(subject); } |
| + CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); |
| + CONVERT_ARG_CHECKED(JSArray, last_match_info, 2); |
| + CONVERT_ARG_CHECKED(JSArray, result_array, 3); |
| + |
| + ASSERT(last_match_info->HasFastElements()); |
| + ASSERT(regexp->GetFlags().is_global()); |
| + Handle<FixedArray> result_elements; |
| + if (result_array->HasFastElements()) { |
| + result_elements = |
| + Handle<FixedArray>(FixedArray::cast(result_array->elements())); |
| + } else { |
| + result_elements = Factory::NewFixedArrayWithHoles(16); |
| + } |
| + FixedArrayBuilder builder(result_elements); |
| + |
| + if (regexp->TypeTag() == JSRegExp::ATOM) { |
| + Handle<String> pattern( |
| + String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex))); |
| + int pattern_length = pattern->length(); |
| + if (pattern_length == 1) { |
|
fschneider
2010/03/25 10:26:06
Or just:
if (pattern->length() == 1 &&
Search
Lasse Reichstein
2010/03/26 11:18:26
That wouldn't return null if SearchCharMultiple re
|
| + if (SearchCharMultiple(subject, pattern, last_match_info, &builder)) { |
| + return *builder.ToJSArray(result_array); |
| + } |
| + return Heap::null_value(); |
| + } |
| + |
| + if (!pattern->IsFlat()) FlattenString(pattern); |
| + if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) { |
| + return *builder.ToJSArray(result_array); |
| + } |
| + return Heap::null_value(); |
| + } |
| + |
| + ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); |
| + |
| + int capture_count = regexp->CaptureCount(); |
| + if (capture_count == 0) { |
| + RegExpImpl::IrregexpResult result = |
| + SearchRegExpNoCaptureMultiple(subject, |
| + regexp, |
| + last_match_info, |
| + &builder); |
| + if (result == RegExpImpl::RE_SUCCESS) { |
| + return *builder.ToJSArray(result_array); |
| + } |
| + if (result == RegExpImpl::RE_FAILURE) { |
| + return Heap::null_value(); |
| + } |
| + ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); |
| + return Failure::Exception(); |
| + } |
| + |
| + RegExpImpl::IrregexpResult result = |
| + SearchRegExpMultiple(subject, regexp, last_match_info, &builder); |
| + if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); |
|
fschneider
2010/03/25 10:26:06
The test for the result seems duplicated. You coul
Lasse Reichstein
2010/03/26 11:18:26
Done.
|
| + if (result == RegExpImpl::RE_FAILURE) return Heap::null_value(); |
| + ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); |
| + return Failure::Exception(); |
| +} |
| + |
| + |
| static Object* Runtime_NumberToRadixString(Arguments args) { |
| NoHandleAllocation ha; |
| ASSERT(args.length() == 2); |