Chromium Code Reviews| Index: src/api.cc |
| =================================================================== |
| --- src/api.cc (revision 11018) |
| +++ src/api.cc (working copy) |
| @@ -3694,6 +3694,93 @@ |
| } |
| +// Will fail with a negative answer if the recursion depth is too high. |
| +static int RecursivelySerializeToUtf8(i::String* string, |
| + char* buffer, |
| + int start, |
| + int end, |
| + int recursion_budget, |
| + int32_t previous_character, |
| + int32_t* last_character) { |
| + int utf8_bytes = 0; |
| + while (true) { |
| + if (string->IsAsciiRepresentation()) { |
| + i::String::WriteToFlat(string, buffer, start, end); |
| + *last_character = unibrow::Utf16::kNoPreviousCharacter; |
| + return utf8_bytes + end - start; |
| + } |
| + switch (i::StringShape(string).representation_tag()) { |
| + case i::kExternalStringTag: { |
| + const uint16_t* data = i::ExternalTwoByteString::cast(string)-> |
| + ExternalTwoByteStringGetData(start); |
| + char* current = buffer; |
| + for (int i = start; i < end; i++) { |
| + uint16_t character = data[i]; |
| + current += |
| + unibrow::Utf8::Encode(current, character, previous_character); |
| + previous_character = character; |
| + } |
| + *last_character = previous_character; |
| + return utf8_bytes + current - buffer; |
| + } |
| + case i::kSeqStringTag: { |
| + const uint16_t* data = |
| + i::SeqTwoByteString::cast(string)->SeqTwoByteStringGetData(start); |
| + char* current = buffer; |
| + for (int i = start; i < end; i++) { |
| + uint16_t character = data[i]; |
| + current += |
| + unibrow::Utf8::Encode(current, character, previous_character); |
| + previous_character = character; |
| + } |
| + *last_character = previous_character; |
| + return utf8_bytes + current - buffer; |
| + } |
| + case i::kSlicedStringTag: { |
| + i::SlicedString* slice = i::SlicedString::cast(string); |
| + unsigned offset = slice->offset(); |
| + string = slice->parent(); |
| + start += offset; |
| + end += offset; |
| + } |
|
fschneider
2012/03/20 09:45:49
Accidental fall-through here?
|
| + case i::kConsStringTag: { |
| + i::ConsString* cons_string = i::ConsString::cast(string); |
| + i::String* first = cons_string->first(); |
| + int boundary = first->length(); |
| + if (start >= boundary) { |
| + // Only need RHS. |
| + string = cons_string->second(); |
| + start -= boundary; |
| + end -= boundary; |
| + continue; |
| + } else if (end <= boundary) { |
| + // Only need LHS. |
| + string = first; |
| + } else { |
| + if (recursion_budget == 0) return -1; |
| + int extra_utf8_bytes = |
| + RecursivelySerializeToUtf8(first, |
| + buffer, |
| + start, |
| + boundary, |
| + recursion_budget - 1, |
| + previous_character, |
| + &previous_character); |
| + if (extra_utf8_bytes < 0) return extra_utf8_bytes; |
| + buffer += extra_utf8_bytes; |
| + utf8_bytes += extra_utf8_bytes; |
| + string = cons_string->second(); |
| + start = 0; |
| + end -= boundary; |
| + } |
| + } |
| + } |
| + } |
| + UNREACHABLE(); |
| + return 0; |
| +} |
| + |
| + |
| int String::WriteUtf8(char* buffer, |
| int capacity, |
| int* nchars_ref, |
| @@ -3703,11 +3790,12 @@ |
| LOG_API(isolate, "String::WriteUtf8"); |
| ENTER_V8(isolate); |
| i::Handle<i::String> str = Utils::OpenHandle(this); |
| + int string_length = str->length(); |
| if (str->IsAsciiRepresentation()) { |
| int len; |
| if (capacity == -1) { |
| capacity = str->length() + 1; |
| - len = str->length(); |
| + len = string_length; |
| } else { |
| len = i::Min(capacity, str->length()); |
| } |
| @@ -3720,6 +3808,42 @@ |
| return len; |
| } |
| + if (capacity == -1 || capacity >= string_length * 3) { |
| + int32_t previous = unibrow::Utf16::kNoPreviousCharacter; |
| + const int kMaxRecursion = 100; |
| + int utf8_bytes = |
| + RecursivelySerializeToUtf8(*str, |
| + buffer, |
| + 0, |
| + string_length, |
| + kMaxRecursion, |
| + previous, |
| + &previous); |
| + if (utf8_bytes >= 0) { |
| + // Success serializing with recursion. |
| + if ((options & NO_NULL_TERMINATION) == 0 && |
| + (capacity > utf8_bytes || capacity == -1)) { |
| + buffer[utf8_bytes++] = '\0'; |
| + } |
| + if (nchars_ref != NULL) *nchars_ref = string_length; |
| + return utf8_bytes; |
| + } |
| + FlattenString(str); |
| + // Recurse once. This time around the string is flat and the serializing |
| + // with recursion will certainly succeed. |
| + return WriteUtf8(buffer, capacity, nchars_ref, options); |
| + } else if (capacity >= string_length) { |
| + // First check that the buffer is large enough. If it is, then recurse |
| + // once without a capacity limit, which will get into the other branch of |
| + // this 'if'. |
| + int utf8_bytes = i::Utf8Length(str); |
| + if ((options & NO_NULL_TERMINATION) == 0) utf8_bytes++; |
| + if (utf8_bytes <= capacity) { |
| + return WriteUtf8(buffer, -1, nchars_ref, options); |
| + } |
| + } |
| + |
| + // Slow case. |
| i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer(); |
| isolate->string_tracker()->RecordWrite(str); |
| if (options & HINT_MANY_WRITES_EXPECTED) { |