Revert "Handlify concat string and substring."
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 15:36:15 +0000 (15:36 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 15:36:15 +0000 (15:36 +0000)
This reverts r17490.

R=verwaest@chromium.org
BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17497 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 f131e50..cccc3e7 100644 (file)
@@ -287,43 +287,11 @@ Handle<SeqTwoByteString> Factory::NewRawTwoByteString(int length,
 }
 
 
-// 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;
-  }
+Handle<String> Factory::NewConsString(Handle<String> first,
+                                      Handle<String> second) {
+  CALL_HEAP_FUNCTION(isolate(),
+                     isolate()->heap()->AllocateConsString(*first, *second),
+                     String);
 }
 
 
@@ -339,99 +307,6 @@ 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();
@@ -446,89 +321,22 @@ Handle<String> Factory::NewFlatConcatString(Handle<String> first,
 }
 
 
-Handle<SlicedString> Factory::NewRawSlicedString(String::Encoding encoding) {
-  Handle<Map> map = (encoding == String::ONE_BYTE_ENCODING)
-      ? sliced_ascii_string_map() : sliced_string_map();
+Handle<String> Factory::NewSubString(Handle<String> str,
+                                     int begin,
+                                     int end) {
   CALL_HEAP_FUNCTION(isolate(),
-                     isolate()->heap()->Allocate(*map, NEW_SPACE),
-                     SlicedString);
+                     str->SubString(begin, end),
+                     String);
 }
 
 
 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());
-
-  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;
+  CALL_HEAP_FUNCTION(isolate(),
+                     isolate()->heap()->AllocateSubString(*str, begin, end),
+                     String);
 }
 
 
index 370f94e..d7761b9 100644 (file)
@@ -158,28 +158,23 @@ class Factory {
       PretenureFlag pretenure = NOT_TENURED);
 
   // Create a new cons string object which consists of a pair of strings.
-  Handle<String> NewConsString(Handle<String> left,
-                               Handle<String> right);
-
-  Handle<ConsString> NewRawConsString(String::Encoding encoding);
+  Handle<String> NewConsString(Handle<String> first,
+                               Handle<String> second);
 
   // 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 5ef0c46..f3928eb 100644 (file)
@@ -229,12 +229,11 @@ Handle<Object> GetProperty(Isolate* isolate,
 }
 
 
-Handle<String> LookupSingleCharacterStringFromCode(Isolate* isolate,
+Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate,
                                                    uint32_t index) {
   CALL_HEAP_FUNCTION(
       isolate,
-      isolate->heap()->LookupSingleCharacterStringFromCode(index),
-      String);
+      isolate->heap()->LookupSingleCharacterStringFromCode(index), Object);
 }
 
 
index 7cd1a78..890f4f5 100644 (file)
@@ -252,7 +252,7 @@ Handle<Object> GetProperty(Isolate* isolate,
                            Handle<Object> obj,
                            Handle<Object> key);
 
-Handle<String> LookupSingleCharacterStringFromCode(Isolate* isolate,
+Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate,
                                                    uint32_t index);
 
 Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray>,
index 2e4ef44..3093209 100644 (file)
@@ -3774,6 +3774,262 @@ 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 f793cc3..ea70f07 100644 (file)
@@ -1068,6 +1068,25 @@ 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 2084abb..5ea9b5a 100644 (file)
@@ -9280,6 +9280,14 @@ 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 7f8594a..99c160b 100644 (file)
@@ -8513,6 +8513,11 @@ 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 551d4d3..dd36a53 100644 (file)
@@ -4387,10 +4387,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
 
 
 RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
-  HandleScope scope(isolate);
+  SealHandleScope shs(isolate);
   ASSERT(args.length() == 3);
 
-  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
+  CONVERT_ARG_CHECKED(String, value, 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,10 +4407,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
   }
   RUNTIME_ASSERT(end >= start);
   RUNTIME_ASSERT(start >= 0);
-  RUNTIME_ASSERT(end <= string->length());
+  RUNTIME_ASSERT(end <= value->length());
   isolate->counters()->sub_string_runtime()->Increment();
-
-  return *isolate->factory()->NewSubString(string, start, end);
+  if (end - start == 1) {
+     return isolate->heap()->LookupSingleCharacterStringFromCode(
+         value->Get(start));
+  }
+  return value->SubString(start, end);
 }
 
 
@@ -6497,31 +6500,30 @@ static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
 
 
 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
-  HandleScope scope(isolate);
+  SealHandleScope shs(isolate);
   ASSERT(args.length() == 3);
 
-  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
+  CONVERT_ARG_CHECKED(String, s, 0);
   CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
   CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
 
-  string = FlattenGetString(string);
-  int length = string->length();
+  s->TryFlatten();
+  int length = s->length();
 
   int left = 0;
   if (trimLeft) {
-    while (left < length && IsTrimWhiteSpace(string->Get(left))) {
+    while (left < length && IsTrimWhiteSpace(s->Get(left))) {
       left++;
     }
   }
 
   int right = length;
   if (trimRight) {
-    while (right > left && IsTrimWhiteSpace(string->Get(right - 1))) {
+    while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
       right--;
     }
   }
-
-  return *isolate->factory()->NewSubString(string, left, right);
+  return s->SubString(left, right);
 }
 
 
@@ -6924,12 +6926,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) {
 
 
 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
-  HandleScope scope(isolate);
+  SealHandleScope shs(isolate);
   ASSERT(args.length() == 2);
-  CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
-  CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
+  CONVERT_ARG_CHECKED(String, str1, 0);
+  CONVERT_ARG_CHECKED(String, str2, 1);
   isolate->counters()->string_add_runtime()->Increment();
-  return *isolate->factory()->NewConsString(str1, str2);
+  return isolate->heap()->AllocateConsString(str1, str2);
 }
 
 
index 2fec04b..5b1dc36 100755 (executable)
@@ -222,15 +222,4 @@ 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));
+test_crankshaft();
\ No newline at end of file