| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 0a3508dcccabf243d24dd5789a784cf73abeb544..ec2b2e48476812c75227e150dc5eb1d5790fb1cd 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -960,26 +960,42 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
|
| ASSERT(size >= ExternalString::kSize);
|
| bool is_ascii = this->IsAsciiRepresentation();
|
| bool is_symbol = this->IsSymbol();
|
| - int length = this->length();
|
| - int hash_field = this->hash_field();
|
| -
|
| - // Morph the object to an external string by adjusting the map and
|
| - // reinitializing the fields.
|
| - this->set_map(is_ascii ?
|
| - heap->external_string_with_ascii_data_map() :
|
| - heap->external_string_map());
|
| - ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
|
| - self->set_length(length);
|
| - self->set_hash_field(hash_field);
|
| - self->set_resource(resource);
|
| - // Additionally make the object into an external symbol if the original string
|
| - // was a symbol to start with.
|
| - if (is_symbol) {
|
| - self->Hash(); // Force regeneration of the hash value.
|
| - // Now morph this external string into a external symbol.
|
| - this->set_map(is_ascii ?
|
| - heap->external_symbol_with_ascii_data_map() :
|
| - heap->external_symbol_map());
|
| +
|
| + ExternalTwoByteString* externalized;
|
| +
|
| + if (this->length() >= ExternalString::kMinBufferedStringLength &&
|
| + size < ExternalString::kExtendedSize) {
|
| + ASSERT(this->IsConsString() || this->IsSlicedString());
|
| + // Cannot morph in place since size is too small.
|
| + externalized = ExternalTwoByteString::cast(
|
| + *(heap->isolate()->factory()->NewExternalStringFromTwoByte(resource)));
|
| + this->set_map(heap->sliced_string_map());
|
| + SlicedString* self = SlicedString::cast(this);
|
| + self->set_parent(externalized);
|
| + self->set_offset(0);
|
| + } else {
|
| + // Morph the string to an external string in place.
|
| + if (this->length() < ExternalString::kMinBufferedStringLength) {
|
| + this->set_map(
|
| + is_ascii ? (is_symbol ? heap->external_symbol_with_ascii_data_map()
|
| + : heap->external_string_with_ascii_data_map())
|
| + : (is_symbol ? heap->external_symbol_map()
|
| + : heap->external_string_map()));
|
| + } else {
|
| + this->set_map(
|
| + is_ascii
|
| + ? (is_symbol
|
| + ? heap->external_buffered_symbol_with_ascii_data_map()
|
| + : heap->external_buffered_string_with_ascii_data_map())
|
| + : (is_symbol ? heap->external_buffered_symbol_map()
|
| + : heap->external_buffered_string_map()));
|
| + }
|
| + externalized = ExternalTwoByteString::cast(this);
|
| + externalized->set_resource(resource);
|
| + if (is_symbol) externalized->Hash(); // Force rehashing.
|
| + if (externalized->IsBuffered()) {
|
| + externalized->set_buffer_index(ExternalString::kInvalidBufferIndex);
|
| + }
|
| }
|
|
|
| // Fill the remainder of the string with dead wood.
|
| @@ -1013,22 +1029,34 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
|
| }
|
| ASSERT(size >= ExternalString::kSize);
|
| bool is_symbol = this->IsSymbol();
|
| - int length = this->length();
|
| - int hash_field = this->hash_field();
|
| -
|
| - // Morph the object to an external string by adjusting the map and
|
| - // reinitializing the fields.
|
| - this->set_map(heap->external_ascii_string_map());
|
| - ExternalAsciiString* self = ExternalAsciiString::cast(this);
|
| - self->set_length(length);
|
| - self->set_hash_field(hash_field);
|
| - self->set_resource(resource);
|
| - // Additionally make the object into an external symbol if the original string
|
| - // was a symbol to start with.
|
| - if (is_symbol) {
|
| - self->Hash(); // Force regeneration of the hash value.
|
| - // Now morph this external string into a external symbol.
|
| - this->set_map(heap->external_ascii_symbol_map());
|
| +
|
| + ExternalAsciiString* externalized;
|
| +
|
| + if (this->length() >= ExternalString::kMinBufferedStringLength &&
|
| + size < ExternalString::kExtendedSize) {
|
| + ASSERT(this->IsConsString() || this->IsSlicedString());
|
| + // Cannot morph in place since size is too small.
|
| + externalized = ExternalAsciiString::cast(
|
| + *(heap->isolate()->factory()->NewExternalStringFromAscii(resource)));
|
| + this->set_map(heap->sliced_ascii_string_map());
|
| + SlicedString* self = SlicedString::cast(this);
|
| + self->set_parent(externalized);
|
| + self->set_offset(0);
|
| + } else {
|
| + // Morph the string to an external string in place.
|
| + if (this->length() < ExternalString::kMinBufferedStringLength) {
|
| + this->set_map(is_symbol ? heap->external_ascii_symbol_map()
|
| + : heap->external_ascii_string_map());
|
| + } else {
|
| + this->set_map(is_symbol ? heap->external_buffered_ascii_symbol_map()
|
| + : heap->external_buffered_ascii_string_map());
|
| + }
|
| + externalized = ExternalAsciiString::cast(this);
|
| + externalized->set_resource(resource);
|
| + if (is_symbol) externalized->Hash(); // Force rehashing.
|
| + if (externalized->IsBuffered()) {
|
| + externalized->set_buffer_index(ExternalString::kInvalidBufferIndex);
|
| + }
|
| }
|
|
|
| // Fill the remainder of the string with dead wood.
|
| @@ -6032,9 +6060,18 @@ const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
|
| }
|
|
|
|
|
| -uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
|
| +uint16_t ExternalAsciiString::ExternalAsciiStringGet(
|
| + int index, ExternalStringBufferFlag flag) {
|
| ASSERT(index >= 0 && index < length());
|
| - return resource()->data()[index];
|
| + const char* source = resource()->data();
|
| + if (flag == UPDATE_EXTERNAL_STRING_BUFFER && IsBuffered()) {
|
| + int buffer_start = Max(0, index - kBackwardBufferedChars);
|
| + int buffer_end = Min(length(), index + kForwardBufferedChars);
|
| + int size = (buffer_end - buffer_start) * kASCIISize;
|
| + set_buffer_index(buffer_start);
|
| + memcpy(buffer(), source + buffer_start, size);
|
| + }
|
| + return *(source + index);
|
| }
|
|
|
|
|
| @@ -6057,9 +6094,18 @@ const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
|
| }
|
|
|
|
|
| -uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
|
| +uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(
|
| + int index, ExternalStringBufferFlag flag) {
|
| ASSERT(index >= 0 && index < length());
|
| - return resource()->data()[index];
|
| + const uint16_t* source = resource()->data();
|
| + if (flag == UPDATE_EXTERNAL_STRING_BUFFER && IsBuffered()) {
|
| + int buffer_start = Max(0, index - kBackwardBufferedChars);
|
| + int buffer_end = Min(length(), index + kForwardBufferedChars);
|
| + int size = (buffer_end - buffer_start) * kUC16Size;
|
| + set_buffer_index(buffer_start);
|
| + memcpy(buffer(), source + buffer_start, size);
|
| + }
|
| + return *(source + index);
|
| }
|
|
|
|
|
| @@ -6490,13 +6536,14 @@ void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
|
| }
|
|
|
|
|
| -uint16_t ConsString::ConsStringGet(int index) {
|
| +uint16_t ConsString::ConsStringGet(
|
| + int index, ExternalStringBufferFlag flag) {
|
| ASSERT(index >= 0 && index < this->length());
|
|
|
| // Check for a flattened cons string
|
| if (second()->length() == 0) {
|
| String* left = first();
|
| - return left->Get(index);
|
| + return left->Get(index, flag);
|
| }
|
|
|
| String* string = String::cast(this);
|
| @@ -6512,7 +6559,7 @@ uint16_t ConsString::ConsStringGet(int index) {
|
| string = cons_string->second();
|
| }
|
| } else {
|
| - return string->Get(index);
|
| + return string->Get(index, flag);
|
| }
|
| }
|
|
|
| @@ -6521,8 +6568,9 @@ uint16_t ConsString::ConsStringGet(int index) {
|
| }
|
|
|
|
|
| -uint16_t SlicedString::SlicedStringGet(int index) {
|
| - return parent()->Get(offset() + index);
|
| +uint16_t SlicedString::SlicedStringGet(
|
| + int index, ExternalStringBufferFlag flag) {
|
| + return parent()->Get(offset() + index, flag);
|
| }
|
|
|
|
|
|
|