Handlify concat string and substring.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 14:07:07 +0000 (14:07 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 14:07:07 +0000 (14:07 +0000)
R=ulan@chromium.org
BUG=

Review URL: https://codereview.chromium.org/50073005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17490 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/factory.cc
src/factory.h
src/handles.cc
src/handles.h
src/heap.cc
src/heap.h
src/objects.cc
src/objects.h
src/runtime.cc
test/mjsunit/string-slices.js

index cccc3e7..f131e50 100644 (file)
@@ -287,11 +287,43 @@ Handle<SeqTwoByteString> Factory::NewRawTwoByteString(int length,
 }
 
 
-Handle<String> Factory::NewConsString(Handle<String> first,
-                                      Handle<String> 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<String> 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<unsigned>(c1 | c2) <= String::kMaxOneByteCharCodeU) {
+    // We can do this.
+    ASSERT(IsPowerOf2(String::kMaxOneByteCharCodeU + 1));  // because of this.
+    Handle<SeqOneByteString> str = isolate->factory()->NewRawOneByteString(2);
+    uint8_t* dest = str->GetChars();
+    dest[0] = static_cast<uint8_t>(c1);
+    dest[1] = static_cast<uint8_t>(c2);
+    return str;
+  } else {
+    Handle<SeqTwoByteString> str = isolate->factory()->NewRawTwoByteString(2);
+    uc16* dest = str->GetChars();
+    dest[0] = c1;
+    dest[1] = c2;
+    return str;
+  }
 }
 
 
@@ -307,6 +339,99 @@ Handle<String> ConcatStringContent(Handle<StringType> result,
 }
 
 
+Handle<ConsString> Factory::NewRawConsString(String::Encoding encoding) {
+  Handle<Map> 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<String> Factory::NewConsString(Handle<String> left,
+                                      Handle<String> 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<String>::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<SeqOneByteString> result = NewRawOneByteString(length);
+      DisallowHeapAllocation no_gc;
+      uint8_t* dest = result->GetChars();
+      // Copy left part.
+      const uint8_t* src = left->IsExternalString()
+          ? Handle<ExternalAsciiString>::cast(left)->GetChars()
+          : Handle<SeqOneByteString>::cast(left)->GetChars();
+      for (int i = 0; i < left_length; i++) *dest++ = src[i];
+      // Copy right part.
+      src = right->IsExternalString()
+          ? Handle<ExternalAsciiString>::cast(right)->GetChars()
+          : Handle<SeqOneByteString>::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<uint8_t>(NewRawOneByteString(length), left, right)
+        : ConcatStringContent<uc16>(NewRawTwoByteString(length), left, right);
+  }
+
+  Handle<ConsString> 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<String> Factory::NewFlatConcatString(Handle<String> first,
                                             Handle<String> second) {
   int total_length = first->length() + second->length();
@@ -321,22 +446,89 @@ Handle<String> Factory::NewFlatConcatString(Handle<String> first,
 }
 
 
-Handle<String> Factory::NewSubString(Handle<String> str,
-                                     int begin,
-                                     int end) {
+Handle<SlicedString> Factory::NewRawSlicedString(String::Encoding encoding) {
+  Handle<Map> 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<String> Factory::NewProperSubString(Handle<String> 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<SeqOneByteString> result = NewRawOneByteString(length);
+      uint8_t* dest = result->GetChars();
+      DisallowHeapAllocation no_gc;
+      String::WriteToFlat(*str, dest, begin, end);
+      return result;
+    } else {
+      Handle<SeqTwoByteString> 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<ConsString> cons = Handle<ConsString>::cast(str);
+    int split = cons->first()->length();
+    if (split <= offset) {
+      // Slice is fully contained in the second part.
+      str = Handle<String>(cons->second(), isolate());
+      offset -= split;  // Adjust for offset.
+      continue;
+    } else if (offset + length <= split) {
+      // Slice is fully contained in the first part.
+      str = Handle<String>(cons->first(), isolate());
+      continue;
+    }
+    break;
+  }
+
+  if (str->IsSlicedString()) {
+    Handle<SlicedString> slice = Handle<SlicedString>::cast(str);
+    str = Handle<String>(slice->parent(), isolate());
+    offset += slice->offset();
+  } else {
+    str = FlattenGetString(str);
+  }
+
+  ASSERT(str->IsSeqString() || str->IsExternalString());
+  Handle<SlicedString> 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;
 }
 
 
index d7761b9..370f94e 100644 (file)
@@ -158,23 +158,28 @@ class Factory {
       PretenureFlag pretenure = NOT_TENURED);
 
   // Create a new cons string object which consists of a pair of strings.
-  Handle<String> NewConsString(Handle<String> first,
-                               Handle<String> second);
+  Handle<String> NewConsString(Handle<String> left,
+                               Handle<String> right);
+
+  Handle<ConsString> NewRawConsString(String::Encoding encoding);
 
   // Create a new sequential string containing the concatenation of the inputs.
   Handle<String> NewFlatConcatString(Handle<String> first,
                                      Handle<String> second);
 
-  // Create a new string object which holds a substring of a string.
-  Handle<String> NewSubString(Handle<String> str,
-                              int begin,
-                              int end);
-
   // Create a new string object which holds a proper substring of a string.
   Handle<String> NewProperSubString(Handle<String> str,
                                     int begin,
                                     int end);
 
+  // Create a new string object which holds a substring of a string.
+  Handle<String> NewSubString(Handle<String> str, int begin, int end) {
+    if (begin == 0 && end == str->length()) return str;
+    return NewProperSubString(str, begin, end);
+  }
+
+  Handle<SlicedString> 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,
index f3928eb..5ef0c46 100644 (file)
@@ -229,11 +229,12 @@ Handle<Object> GetProperty(Isolate* isolate,
 }
 
 
-Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate,
+Handle<String> LookupSingleCharacterStringFromCode(Isolate* isolate,
                                                    uint32_t index) {
   CALL_HEAP_FUNCTION(
       isolate,
-      isolate->heap()->LookupSingleCharacterStringFromCode(index), Object);
+      isolate->heap()->LookupSingleCharacterStringFromCode(index),
+      String);
 }
 
 
index 890f4f5..7cd1a78 100644 (file)
@@ -252,7 +252,7 @@ Handle<Object> GetProperty(Isolate* isolate,
                            Handle<Object> obj,
                            Handle<Object> key);
 
-Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate,
+Handle<String> LookupSingleCharacterStringFromCode(Isolate* isolate,
                                                    uint32_t index);
 
 Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray>,
index 3093209..2e4ef44 100644 (file)
@@ -3774,262 +3774,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<unsigned>(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<uint8_t>(c1);
-    dest[1] = static_cast<uint8_t>(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();
-  } else 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);
-  }
-
-  // Make an attempt to flatten the buffer to reduce access time.
-  buffer = buffer->TryFlattenGetString();
-
-  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();
index ea70f07..f793cc3 100644 (file)
@@ -1068,25 +1068,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
index 8bb603a..fb7f1ba 100644 (file)
@@ -9303,14 +9303,6 @@ uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> 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++) {
index e7586f5..a9316f2 100644 (file)
@@ -8522,11 +8522,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<const char> str, bool allow_prefix_match = false);
index dd36a53..551d4d3 100644 (file)
@@ -4387,10 +4387,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.
@@ -4407,13 +4407,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();
-  if (end - start == 1) {
-     return isolate->heap()->LookupSingleCharacterStringFromCode(
-         value->Get(start));
-  }
-  return value->SubString(start, end);
+
+  return *isolate->factory()->NewSubString(string, start, end);
 }
 
 
@@ -6500,30 +6497,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);
 }
 
 
@@ -6926,12 +6924,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);
 }
 
 
index 5b1dc36..2fec04b 100755 (executable)
@@ -222,4 +222,15 @@ function test_crankshaft() {
 
 test_crankshaft();
 %OptimizeFunctionOnNextCall(test_crankshaft);
-test_crankshaft();
\ No newline at end of file
+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));