From f7929d2a871c5c0536a90ecd05dd9f1e2ed545fa Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Mon, 23 Dec 2013 12:37:56 +0000 Subject: [PATCH] Reland "Handlify concat string and substring." This relands commit r17490. BUG= R=ulan@chromium.org Review URL: https://codereview.chromium.org/114943004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18408 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/factory.cc | 218 ++++++++++++++++++++++++++++++++--- src/factory.h | 19 ++-- src/handles.cc | 5 +- src/handles.h | 2 +- src/heap.cc | 258 ------------------------------------------ src/heap.h | 19 ---- src/objects.cc | 8 -- src/objects.h | 5 - src/runtime.cc | 32 +++--- test/cctest/test-api.cc | 18 ++- test/mjsunit/string-slices.js | 11 ++ 11 files changed, 257 insertions(+), 338 deletions(-) diff --git a/src/factory.cc b/src/factory.cc index c10111a..47a56a0 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -287,11 +287,43 @@ Handle Factory::NewRawTwoByteString(int length, } -Handle Factory::NewConsString(Handle first, - Handle second) { - CALL_HEAP_FUNCTION(isolate(), - isolate()->heap()->AllocateConsString(*first, *second), - String); +// Returns true for a character in a range. Both limits are inclusive. +static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { + // This makes uses of the the unsigned wraparound. + return character - from <= to - from; +} + + +static inline Handle MakeOrFindTwoCharacterString(Isolate* isolate, + uint16_t c1, + uint16_t c2) { + // Numeric strings have a different hash algorithm not known by + // LookupTwoCharsStringIfExists, so we skip this step for such strings. + if (!Between(c1, '0', '9') || !Between(c2, '0', '9')) { + String* result; + StringTable* table = isolate->heap()->string_table(); + if (table->LookupTwoCharsStringIfExists(c1, c2, &result)) { + return handle(result); + } + } + + // Now we know the length is 2, we might as well make use of that fact + // when building the new string. + if (static_cast(c1 | c2) <= String::kMaxOneByteCharCodeU) { + // We can do this. + ASSERT(IsPowerOf2(String::kMaxOneByteCharCodeU + 1)); // because of this. + Handle str = isolate->factory()->NewRawOneByteString(2); + uint8_t* dest = str->GetChars(); + dest[0] = static_cast(c1); + dest[1] = static_cast(c2); + return str; + } else { + Handle str = isolate->factory()->NewRawTwoByteString(2); + uc16* dest = str->GetChars(); + dest[0] = c1; + dest[1] = c2; + return str; + } } @@ -307,6 +339,99 @@ Handle ConcatStringContent(Handle result, } +Handle Factory::NewRawConsString(String::Encoding encoding) { + Handle map = (encoding == String::ONE_BYTE_ENCODING) + ? cons_ascii_string_map() : cons_string_map(); + CALL_HEAP_FUNCTION(isolate(), + isolate()->heap()->Allocate(*map, NEW_SPACE), + ConsString); +} + + +Handle Factory::NewConsString(Handle left, + Handle right) { + int left_length = left->length(); + if (left_length == 0) return right; + int right_length = right->length(); + if (right_length == 0) return left; + + int length = left_length + right_length; + + if (length == 2) { + uint16_t c1 = left->Get(0); + uint16_t c2 = right->Get(0); + return MakeOrFindTwoCharacterString(isolate(), c1, c2); + } + + // Make sure that an out of memory exception is thrown if the length + // of the new cons string is too large. + if (length > String::kMaxLength || length < 0) { + isolate()->context()->mark_out_of_memory(); + V8::FatalProcessOutOfMemory("String concatenation result too large."); + UNREACHABLE(); + return Handle::null(); + } + + bool left_is_one_byte = left->IsOneByteRepresentation(); + bool right_is_one_byte = right->IsOneByteRepresentation(); + bool is_one_byte = left_is_one_byte && right_is_one_byte; + bool is_one_byte_data_in_two_byte_string = false; + if (!is_one_byte) { + // At least one of the strings uses two-byte representation so we + // can't use the fast case code for short ASCII strings below, but + // we can try to save memory if all chars actually fit in ASCII. + is_one_byte_data_in_two_byte_string = + left->HasOnlyOneByteChars() && right->HasOnlyOneByteChars(); + if (is_one_byte_data_in_two_byte_string) { + isolate()->counters()->string_add_runtime_ext_to_ascii()->Increment(); + } + } + + // If the resulting string is small make a flat string. + if (length < ConsString::kMinLength) { + // Note that neither of the two inputs can be a slice because: + STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength); + ASSERT(left->IsFlat()); + ASSERT(right->IsFlat()); + + if (is_one_byte) { + Handle result = NewRawOneByteString(length); + DisallowHeapAllocation no_gc; + uint8_t* dest = result->GetChars(); + // Copy left part. + const uint8_t* src = left->IsExternalString() + ? Handle::cast(left)->GetChars() + : Handle::cast(left)->GetChars(); + for (int i = 0; i < left_length; i++) *dest++ = src[i]; + // Copy right part. + src = right->IsExternalString() + ? Handle::cast(right)->GetChars() + : Handle::cast(right)->GetChars(); + for (int i = 0; i < right_length; i++) *dest++ = src[i]; + return result; + } + + return (is_one_byte_data_in_two_byte_string) + ? ConcatStringContent(NewRawOneByteString(length), left, right) + : ConcatStringContent(NewRawTwoByteString(length), left, right); + } + + Handle result = NewRawConsString( + (is_one_byte || is_one_byte_data_in_two_byte_string) + ? String::ONE_BYTE_ENCODING + : String::TWO_BYTE_ENCODING); + + DisallowHeapAllocation no_gc; + WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); + + result->set_hash_field(String::kEmptyHashField); + result->set_length(length); + result->set_first(*left, mode); + result->set_second(*right, mode); + return result; +} + + Handle Factory::NewFlatConcatString(Handle first, Handle second) { int total_length = first->length() + second->length(); @@ -320,22 +445,89 @@ Handle Factory::NewFlatConcatString(Handle first, } -Handle Factory::NewSubString(Handle str, - int begin, - int end) { +Handle Factory::NewRawSlicedString(String::Encoding encoding) { + Handle map = (encoding == String::ONE_BYTE_ENCODING) + ? sliced_ascii_string_map() : sliced_string_map(); CALL_HEAP_FUNCTION(isolate(), - str->SubString(begin, end), - String); + isolate()->heap()->Allocate(*map, NEW_SPACE), + SlicedString); } Handle Factory::NewProperSubString(Handle str, int begin, int end) { +#if VERIFY_HEAP + if (FLAG_verify_heap) str->StringVerify(); +#endif ASSERT(begin > 0 || end < str->length()); - CALL_HEAP_FUNCTION(isolate(), - isolate()->heap()->AllocateSubString(*str, begin, end), - String); + + int length = end - begin; + if (length <= 0) return empty_string(); + if (length == 1) { + return LookupSingleCharacterStringFromCode(isolate(), str->Get(begin)); + } + if (length == 2) { + // Optimization for 2-byte strings often used as keys in a decompression + // dictionary. Check whether we already have the string in the string + // table to prevent creation of many unnecessary strings. + uint16_t c1 = str->Get(begin); + uint16_t c2 = str->Get(begin + 1); + return MakeOrFindTwoCharacterString(isolate(), c1, c2); + } + + if (!FLAG_string_slices || length < SlicedString::kMinLength) { + if (str->IsOneByteRepresentation()) { + Handle result = NewRawOneByteString(length); + uint8_t* dest = result->GetChars(); + DisallowHeapAllocation no_gc; + String::WriteToFlat(*str, dest, begin, end); + return result; + } else { + Handle result = NewRawTwoByteString(length); + uc16* dest = result->GetChars(); + DisallowHeapAllocation no_gc; + String::WriteToFlat(*str, dest, begin, end); + return result; + } + } + + int offset = begin; + + while (str->IsConsString()) { + Handle cons = Handle::cast(str); + int split = cons->first()->length(); + if (split <= offset) { + // Slice is fully contained in the second part. + str = Handle(cons->second(), isolate()); + offset -= split; // Adjust for offset. + continue; + } else if (offset + length <= split) { + // Slice is fully contained in the first part. + str = Handle(cons->first(), isolate()); + continue; + } + break; + } + + if (str->IsSlicedString()) { + Handle slice = Handle::cast(str); + str = Handle(slice->parent(), isolate()); + offset += slice->offset(); + } else { + str = FlattenGetString(str); + } + + ASSERT(str->IsSeqString() || str->IsExternalString()); + Handle slice = NewRawSlicedString( + str->IsOneByteRepresentation() ? String::ONE_BYTE_ENCODING + : String::TWO_BYTE_ENCODING); + + slice->set_hash_field(String::kEmptyHashField); + slice->set_length(length); + slice->set_parent(*str); + slice->set_offset(offset); + return slice; } diff --git a/src/factory.h b/src/factory.h index 92086d4..94e89f5 100644 --- a/src/factory.h +++ b/src/factory.h @@ -158,23 +158,28 @@ class Factory { PretenureFlag pretenure = NOT_TENURED); // Create a new cons string object which consists of a pair of strings. - Handle NewConsString(Handle first, - Handle second); + Handle NewConsString(Handle left, + Handle right); + + Handle NewRawConsString(String::Encoding encoding); // Create a new sequential string containing the concatenation of the inputs. Handle NewFlatConcatString(Handle first, Handle second); - // Create a new string object which holds a substring of a string. - Handle NewSubString(Handle str, - int begin, - int end); - // Create a new string object which holds a proper substring of a string. Handle NewProperSubString(Handle str, int begin, int end); + // Create a new string object which holds a substring of a string. + Handle NewSubString(Handle str, int begin, int end) { + if (begin == 0 && end == str->length()) return str; + return NewProperSubString(str, begin, end); + } + + Handle NewRawSlicedString(String::Encoding encoding); + // Creates a new external String object. There are two String encodings // in the system: ASCII and two byte. Unlike other String types, it does // not make sense to have a UTF-8 factory function for external strings, diff --git a/src/handles.cc b/src/handles.cc index 8bf3b0c..bc8d2d7 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -211,11 +211,12 @@ Handle GetProperty(Isolate* isolate, } -Handle LookupSingleCharacterStringFromCode(Isolate* isolate, +Handle LookupSingleCharacterStringFromCode(Isolate* isolate, uint32_t index) { CALL_HEAP_FUNCTION( isolate, - isolate->heap()->LookupSingleCharacterStringFromCode(index), Object); + isolate->heap()->LookupSingleCharacterStringFromCode(index), + String); } diff --git a/src/handles.h b/src/handles.h index 7fef919..d42d1bd 100644 --- a/src/handles.h +++ b/src/handles.h @@ -245,7 +245,7 @@ Handle GetProperty(Isolate* isolate, Handle obj, Handle key); -Handle LookupSingleCharacterStringFromCode(Isolate* isolate, +Handle LookupSingleCharacterStringFromCode(Isolate* isolate, uint32_t index); Handle AddKeysFromJSArray(Handle, diff --git a/src/heap.cc b/src/heap.cc index 7477450..f827a02 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -3820,264 +3820,6 @@ MaybeObject* Heap::AllocateJSMessageObject(String* type, } - -// Returns true for a character in a range. Both limits are inclusive. -static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { - // This makes uses of the the unsigned wraparound. - return character - from <= to - from; -} - - -MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString( - Heap* heap, - uint16_t c1, - uint16_t c2) { - String* result; - // Numeric strings have a different hash algorithm not known by - // LookupTwoCharsStringIfExists, so we skip this step for such strings. - if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) && - heap->string_table()->LookupTwoCharsStringIfExists(c1, c2, &result)) { - return result; - // Now we know the length is 2, we might as well make use of that fact - // when building the new string. - } else if (static_cast(c1 | c2) <= String::kMaxOneByteCharCodeU) { - // We can do this. - ASSERT(IsPowerOf2(String::kMaxOneByteCharCodeU + 1)); // because of this. - Object* result; - { MaybeObject* maybe_result = heap->AllocateRawOneByteString(2); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); - dest[0] = static_cast(c1); - dest[1] = static_cast(c2); - return result; - } else { - Object* result; - { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - uc16* dest = SeqTwoByteString::cast(result)->GetChars(); - dest[0] = c1; - dest[1] = c2; - return result; - } -} - - -MaybeObject* Heap::AllocateConsString(String* first, String* second) { - int first_length = first->length(); - if (first_length == 0) { - return second; - } - - int second_length = second->length(); - if (second_length == 0) { - return first; - } - - int length = first_length + second_length; - - // Optimization for 2-byte strings often used as keys in a decompression - // dictionary. Check whether we already have the string in the string - // table to prevent creation of many unneccesary strings. - if (length == 2) { - uint16_t c1 = first->Get(0); - uint16_t c2 = second->Get(0); - return MakeOrFindTwoCharacterString(this, c1, c2); - } - - bool first_is_one_byte = first->IsOneByteRepresentation(); - bool second_is_one_byte = second->IsOneByteRepresentation(); - bool is_one_byte = first_is_one_byte && second_is_one_byte; - // Make sure that an out of memory exception is thrown if the length - // of the new cons string is too large. - if (length > String::kMaxLength || length < 0) { - isolate()->context()->mark_out_of_memory(); - return Failure::OutOfMemoryException(0x4); - } - - bool is_one_byte_data_in_two_byte_string = false; - if (!is_one_byte) { - // At least one of the strings uses two-byte representation so we - // can't use the fast case code for short ASCII strings below, but - // we can try to save memory if all chars actually fit in ASCII. - is_one_byte_data_in_two_byte_string = - first->HasOnlyOneByteChars() && second->HasOnlyOneByteChars(); - if (is_one_byte_data_in_two_byte_string) { - isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment(); - } - } - - // If the resulting string is small make a flat string. - if (length < ConsString::kMinLength) { - // Note that neither of the two inputs can be a slice because: - STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength); - ASSERT(first->IsFlat()); - ASSERT(second->IsFlat()); - if (is_one_byte) { - Object* result; - { MaybeObject* maybe_result = AllocateRawOneByteString(length); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - // Copy the characters into the new object. - uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); - // Copy first part. - const uint8_t* src; - if (first->IsExternalString()) { - src = ExternalAsciiString::cast(first)->GetChars(); - } else { - src = SeqOneByteString::cast(first)->GetChars(); - } - for (int i = 0; i < first_length; i++) *dest++ = src[i]; - // Copy second part. - if (second->IsExternalString()) { - src = ExternalAsciiString::cast(second)->GetChars(); - } else { - src = SeqOneByteString::cast(second)->GetChars(); - } - for (int i = 0; i < second_length; i++) *dest++ = src[i]; - return result; - } else { - if (is_one_byte_data_in_two_byte_string) { - Object* result; - { MaybeObject* maybe_result = AllocateRawOneByteString(length); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - // Copy the characters into the new object. - uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); - String::WriteToFlat(first, dest, 0, first_length); - String::WriteToFlat(second, dest + first_length, 0, second_length); - isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment(); - return result; - } - - Object* result; - { MaybeObject* maybe_result = AllocateRawTwoByteString(length); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - // Copy the characters into the new object. - uc16* dest = SeqTwoByteString::cast(result)->GetChars(); - String::WriteToFlat(first, dest, 0, first_length); - String::WriteToFlat(second, dest + first_length, 0, second_length); - return result; - } - } - - Map* map = (is_one_byte || is_one_byte_data_in_two_byte_string) ? - cons_ascii_string_map() : cons_string_map(); - - Object* result; - { MaybeObject* maybe_result = Allocate(map, NEW_SPACE); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - - DisallowHeapAllocation no_gc; - ConsString* cons_string = ConsString::cast(result); - WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc); - cons_string->set_length(length); - cons_string->set_hash_field(String::kEmptyHashField); - cons_string->set_first(first, mode); - cons_string->set_second(second, mode); - return result; -} - - -MaybeObject* Heap::AllocateSubString(String* buffer, - int start, - int end, - PretenureFlag pretenure) { - int length = end - start; - if (length <= 0) { - return empty_string(); - } - - // Make an attempt to flatten the buffer to reduce access time. - buffer = buffer->TryFlattenGetString(); - - if (length == 1) { - return LookupSingleCharacterStringFromCode(buffer->Get(start)); - } else if (length == 2) { - // Optimization for 2-byte strings often used as keys in a decompression - // dictionary. Check whether we already have the string in the string - // table to prevent creation of many unnecessary strings. - uint16_t c1 = buffer->Get(start); - uint16_t c2 = buffer->Get(start + 1); - return MakeOrFindTwoCharacterString(this, c1, c2); - } - - if (!FLAG_string_slices || - !buffer->IsFlat() || - length < SlicedString::kMinLength || - pretenure == TENURED) { - Object* result; - // WriteToFlat takes care of the case when an indirect string has a - // different encoding from its underlying string. These encodings may - // differ because of externalization. - bool is_one_byte = buffer->IsOneByteRepresentation(); - { MaybeObject* maybe_result = is_one_byte - ? AllocateRawOneByteString(length, pretenure) - : AllocateRawTwoByteString(length, pretenure); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - String* string_result = String::cast(result); - // Copy the characters into the new object. - if (is_one_byte) { - ASSERT(string_result->IsOneByteRepresentation()); - uint8_t* dest = SeqOneByteString::cast(string_result)->GetChars(); - String::WriteToFlat(buffer, dest, start, end); - } else { - ASSERT(string_result->IsTwoByteRepresentation()); - uc16* dest = SeqTwoByteString::cast(string_result)->GetChars(); - String::WriteToFlat(buffer, dest, start, end); - } - return result; - } - - ASSERT(buffer->IsFlat()); -#if VERIFY_HEAP - if (FLAG_verify_heap) { - buffer->StringVerify(); - } -#endif - - Object* result; - // When slicing an indirect string we use its encoding for a newly created - // slice and don't check the encoding of the underlying string. This is safe - // even if the encodings are different because of externalization. If an - // indirect ASCII string is pointing to a two-byte string, the two-byte char - // codes of the underlying string must still fit into ASCII (because - // externalization must not change char codes). - { Map* map = buffer->IsOneByteRepresentation() - ? sliced_ascii_string_map() - : sliced_string_map(); - MaybeObject* maybe_result = Allocate(map, NEW_SPACE); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - - DisallowHeapAllocation no_gc; - SlicedString* sliced_string = SlicedString::cast(result); - sliced_string->set_length(length); - sliced_string->set_hash_field(String::kEmptyHashField); - if (buffer->IsConsString()) { - ConsString* cons = ConsString::cast(buffer); - ASSERT(cons->second()->length() == 0); - sliced_string->set_parent(cons->first()); - sliced_string->set_offset(start); - } else if (buffer->IsSlicedString()) { - // Prevent nesting sliced strings. - SlicedString* parent_slice = SlicedString::cast(buffer); - sliced_string->set_parent(parent_slice->parent()); - sliced_string->set_offset(start + parent_slice->offset()); - } else { - sliced_string->set_parent(buffer); - sliced_string->set_offset(start); - } - ASSERT(sliced_string->parent()->IsSeqString() || - sliced_string->parent()->IsExternalString()); - return result; -} - - MaybeObject* Heap::AllocateExternalStringFromAscii( const ExternalAsciiString::Resource* resource) { size_t length = resource->length(); diff --git a/src/heap.h b/src/heap.h index d05f019..bedd1ea 100644 --- a/src/heap.h +++ b/src/heap.h @@ -1071,25 +1071,6 @@ class Heap { Object* stack_trace, Object* stack_frames); - // Allocates a new cons string object. - // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation - // failed. - // Please note this does not perform a garbage collection. - MUST_USE_RESULT MaybeObject* AllocateConsString(String* first, - String* second); - - // Allocates a new sub string object which is a substring of an underlying - // string buffer stretching from the index start (inclusive) to the index - // end (exclusive). - // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation - // failed. - // Please note this does not perform a garbage collection. - MUST_USE_RESULT MaybeObject* AllocateSubString( - String* buffer, - int start, - int end, - PretenureFlag pretenure = NOT_TENURED); - // Allocate a new external string object, which is backed by a string // resource that resides outside the V8 heap. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation diff --git a/src/objects.cc b/src/objects.cc index aa7f500..8c5f903 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -9298,14 +9298,6 @@ uint32_t StringHasher::ComputeUtf8Hash(Vector chars, } -MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) { - Heap* heap = GetHeap(); - if (start == 0 && end == length()) return this; - MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure); - return result; -} - - void String::PrintOn(FILE* file) { int length = this->length(); for (int i = 0; i < length; i++) { diff --git a/src/objects.h b/src/objects.h index 0fa8304..7abee00 100644 --- a/src/objects.h +++ b/src/objects.h @@ -8647,11 +8647,6 @@ class String: public Name { // ASCII and two byte string types. bool MarkAsUndetectable(); - // Return a substring. - MUST_USE_RESULT MaybeObject* SubString(int from, - int to, - PretenureFlag pretenure = NOT_TENURED); - // String equality operations. inline bool Equals(String* other); bool IsUtf8EqualTo(Vector str, bool allow_prefix_match = false); diff --git a/src/runtime.cc b/src/runtime.cc index f2f37f7..7d23455 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -4449,10 +4449,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { - SealHandleScope shs(isolate); + HandleScope scope(isolate); ASSERT(args.length() == 3); - CONVERT_ARG_CHECKED(String, value, 0); + CONVERT_ARG_HANDLE_CHECKED(String, string, 0); int start, end; // We have a fast integer-only case here to avoid a conversion to double in // the common case where from and to are Smis. @@ -4469,9 +4469,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { } RUNTIME_ASSERT(end >= start); RUNTIME_ASSERT(start >= 0); - RUNTIME_ASSERT(end <= value->length()); + RUNTIME_ASSERT(end <= string->length()); isolate->counters()->sub_string_runtime()->Increment(); - return value->SubString(start, end); + + return *isolate->factory()->NewSubString(string, start, end); } @@ -6552,30 +6553,31 @@ static inline bool IsTrimWhiteSpace(unibrow::uchar c) { RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) { - SealHandleScope shs(isolate); + HandleScope scope(isolate); ASSERT(args.length() == 3); - CONVERT_ARG_CHECKED(String, s, 0); + CONVERT_ARG_HANDLE_CHECKED(String, string, 0); CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); - s->TryFlatten(); - int length = s->length(); + string = FlattenGetString(string); + int length = string->length(); int left = 0; if (trimLeft) { - while (left < length && IsTrimWhiteSpace(s->Get(left))) { + while (left < length && IsTrimWhiteSpace(string->Get(left))) { left++; } } int right = length; if (trimRight) { - while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { + while (right > left && IsTrimWhiteSpace(string->Get(right - 1))) { right--; } } - return s->SubString(left, right); + + return *isolate->factory()->NewSubString(string, left, right); } @@ -6978,12 +6980,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) { RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { - SealHandleScope shs(isolate); + HandleScope scope(isolate); ASSERT(args.length() == 2); - CONVERT_ARG_CHECKED(String, str1, 0); - CONVERT_ARG_CHECKED(String, str2, 1); + CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); + CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); isolate->counters()->string_add_runtime()->Increment(); - return isolate->heap()->AllocateConsString(str1, str2); + return *isolate->factory()->NewConsString(str1, str2); } diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index cb1ad4f..7e699af 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -4435,6 +4435,11 @@ TEST(OutOfMemoryNested) { } +void OOMCallback(const char* location, const char* message) { + exit(0); +} + + TEST(HugeConsStringOutOfMemory) { // It's not possible to read a snapshot into a heap with different dimensions. if (i::Snapshot::IsEnabled()) return; @@ -4446,19 +4451,17 @@ TEST(HugeConsStringOutOfMemory) { v8::SetResourceConstraints(CcTest::isolate(), &constraints); // Execute a script that causes out of memory. - v8::V8::IgnoreOutOfMemoryException(); + v8::V8::SetFatalErrorHandler(OOMCallback); LocalContext context; v8::HandleScope scope(context->GetIsolate()); // Build huge string. This should fail with out of memory exception. - Local result = CompileRun( + CompileRun( "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();" "for (var i = 0; i < 22; i++) { str = str + str; }"); - // Check for out of memory state. - CHECK(result.IsEmpty()); - CHECK(context->HasOutOfMemoryException()); + CHECK(false); // Should not return. } @@ -6972,11 +6975,6 @@ static const char* js_code_causing_huge_string_flattening = "str.match(/X/);"; -void OOMCallback(const char* location, const char* message) { - exit(0); -} - - TEST(RegexpOutOfMemory) { // Execute a script that causes out of memory when flattening a string. v8::HandleScope scope(CcTest::isolate()); diff --git a/test/mjsunit/string-slices.js b/test/mjsunit/string-slices.js index f5e1d91..2fec04b 100755 --- a/test/mjsunit/string-slices.js +++ b/test/mjsunit/string-slices.js @@ -223,3 +223,14 @@ function test_crankshaft() { test_crankshaft(); %OptimizeFunctionOnNextCall(test_crankshaft); test_crankshaft(); + +var s1 = "12345678901234567890"; +var s2 = "abcdefghijklmnopqrstuvwxyz"; +var c1 = s1 + s2; +var c2 = s1 + c1 + s2; +assertEquals("234567890123456789", c1.substring(1, 19)); +assertEquals("bcdefghijklmno", c1.substring(21, 35)); +assertEquals("2345678901234567890abcdefghijklmno", c1.substring(1, 35)); +assertEquals("234567890123456789", c2.substring(1, 19)); +assertEquals("bcdefghijklmno", c2.substring(41, 55)); +assertEquals("2345678901234567890abcdefghijklmno", c2.substring(21, 55)); -- 2.7.4