Revision: 25276
Author:   yang...@chromium.org
Date:     Wed Nov 12 08:04:41 2014 UTC
Log: Abstract string building in JSON-stringifier into IncrementalStringBuilder.

R=ish...@chromium.org

Review URL: https://codereview.chromium.org/713223002
https://code.google.com/p/v8/source/detail?r=25276

Added:
 /branches/bleeding_edge/src/string-builder.cc
 /branches/bleeding_edge/src/string-builder.h
Deleted:
 /branches/bleeding_edge/src/runtime/string-builder.h
Modified:
 /branches/bleeding_edge/BUILD.gn
 /branches/bleeding_edge/src/json-stringifier.h
 /branches/bleeding_edge/src/runtime/runtime-regexp.cc
 /branches/bleeding_edge/src/runtime/runtime-strings.cc
 /branches/bleeding_edge/tools/gyp/v8.gyp

=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/string-builder.cc Wed Nov 12 08:04:41 2014 UTC
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/string-builder.h"
+
+namespace v8 {
+namespace internal {
+
+MaybeHandle<String> ReplacementStringBuilder::ToString() {
+  Isolate* isolate = heap_->isolate();
+  if (array_builder_.length() == 0) {
+    return isolate->factory()->empty_string();
+  }
+
+  Handle<String> joined_string;
+  if (is_one_byte_) {
+    Handle<SeqOneByteString> seq;
+    ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, seq, isolate->factory()->NewRawOneByteString(character_count_),
+        String);
+
+    DisallowHeapAllocation no_gc;
+    uint8_t* char_buffer = seq->GetChars();
+ StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
+                              array_builder_.length());
+    joined_string = Handle<String>::cast(seq);
+  } else {
+    // Two-byte.
+    Handle<SeqTwoByteString> seq;
+    ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, seq, isolate->factory()->NewRawTwoByteString(character_count_),
+        String);
+
+    DisallowHeapAllocation no_gc;
+    uc16* char_buffer = seq->GetChars();
+ StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
+                              array_builder_.length());
+    joined_string = Handle<String>::cast(seq);
+  }
+  return joined_string;
+}
+
+
+IncrementalStringBuilder::IncrementalStringBuilder(Isolate* isolate)
+    : isolate_(isolate),
+      encoding_(String::ONE_BYTE_ENCODING),
+      overflowed_(false),
+      part_length_(kInitialPartLength),
+      current_index_(0) {
+  // Create an accumulator handle starting with the empty string.
+  accumulator_ = Handle<String>(isolate->heap()->empty_string(), isolate);
+  current_part_ =
+      factory()->NewRawOneByteString(part_length_).ToHandleChecked();
+}
+
+
+void IncrementalStringBuilder::Accumulate() {
+  // Only accumulate fully written strings. Shrink first if necessary.
+  DCHECK_EQ(current_index_, current_part()->length());
+  Handle<String> new_accumulator;
+ if (accumulator()->length() + current_part()->length() > String::kMaxLength) { + // Set the flag and carry on. Delay throwing the exception till the end.
+    new_accumulator = factory()->empty_string();
+    overflowed_ = true;
+  } else {
+    new_accumulator = factory()
+                          ->NewConsString(accumulator(), current_part())
+                          .ToHandleChecked();
+  }
+  set_accumulator(new_accumulator);
+}
+
+
+void IncrementalStringBuilder::Extend() {
+  Accumulate();
+  if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
+    part_length_ *= kPartLengthGrowthFactor;
+  }
+  Handle<String> new_part;
+  if (encoding_ == String::ONE_BYTE_ENCODING) {
+ new_part = factory()->NewRawOneByteString(part_length_).ToHandleChecked();
+  } else {
+ new_part = factory()->NewRawTwoByteString(part_length_).ToHandleChecked();
+  }
+ // Reuse the same handle to avoid being invalidated when exiting handle scope.
+  set_current_part(new_part);
+  current_index_ = 0;
+}
+
+
+MaybeHandle<String> IncrementalStringBuilder::Finish() {
+  ShrinkCurrentPart();
+  Accumulate();
+  if (overflowed_) {
+    THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), String);
+  }
+  return accumulator();
+}
+
+
+void IncrementalStringBuilder::AppendString(Handle<String> string) {
+  ShrinkCurrentPart();
+  part_length_ = kInitialPartLength;  // Allocate conservatively.
+  Extend();  // Attach current part and allocate new part.
+  Handle<String> concat =
+      factory()->NewConsString(accumulator(), string).ToHandleChecked();
+  set_accumulator(concat);
+}
+}
+}  // namespace v8::internal
=======================================
--- /dev/null
+++ /branches/bleeding_edge/src/string-builder.h Wed Nov 12 08:04:41 2014 UTC
@@ -0,0 +1,430 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_STRING_BUILDER_H_
+#define V8_STRING_BUILDER_H_
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+
+const int kStringBuilderConcatHelperLengthBits = 11;
+const int kStringBuilderConcatHelperPositionBits = 19;
+
+typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
+    StringBuilderSubstringLength;
+typedef BitField<int, kStringBuilderConcatHelperLengthBits,
+                 kStringBuilderConcatHelperPositionBits>
+    StringBuilderSubstringPosition;
+
+
+template <typename sinkchar>
+static inline void StringBuilderConcatHelper(String* special, sinkchar* sink,
+                                             FixedArray* fixed_array,
+                                             int array_length) {
+  DisallowHeapAllocation no_gc;
+  int position = 0;
+  for (int i = 0; i < array_length; i++) {
+    Object* element = fixed_array->get(i);
+    if (element->IsSmi()) {
+      // Smi encoding of position and length.
+      int encoded_slice = Smi::cast(element)->value();
+      int pos;
+      int len;
+      if (encoded_slice > 0) {
+        // Position and length encoded in one smi.
+        pos = StringBuilderSubstringPosition::decode(encoded_slice);
+        len = StringBuilderSubstringLength::decode(encoded_slice);
+      } else {
+        // Position and length encoded in two smis.
+        Object* obj = fixed_array->get(++i);
+        DCHECK(obj->IsSmi());
+        pos = Smi::cast(obj)->value();
+        len = -encoded_slice;
+      }
+      String::WriteToFlat(special, sink + position, pos, pos + len);
+      position += len;
+    } else {
+      String* string = String::cast(element);
+      int element_length = string->length();
+      String::WriteToFlat(string, sink + position, 0, element_length);
+      position += element_length;
+    }
+  }
+}
+
+
+// Returns the result length of the concatenation.
+// On illegal argument, -1 is returned.
+static inline int StringBuilderConcatLength(int special_length,
+                                            FixedArray* fixed_array,
+ int array_length, bool* one_byte) {
+  DisallowHeapAllocation no_gc;
+  int position = 0;
+  for (int i = 0; i < array_length; i++) {
+    int increment = 0;
+    Object* elt = fixed_array->get(i);
+    if (elt->IsSmi()) {
+      // Smi encoding of position and length.
+      int smi_value = Smi::cast(elt)->value();
+      int pos;
+      int len;
+      if (smi_value > 0) {
+        // Position and length encoded in one smi.
+        pos = StringBuilderSubstringPosition::decode(smi_value);
+        len = StringBuilderSubstringLength::decode(smi_value);
+      } else {
+        // Position and length encoded in two smis.
+        len = -smi_value;
+        // Get the position and check that it is a positive smi.
+        i++;
+        if (i >= array_length) return -1;
+        Object* next_smi = fixed_array->get(i);
+        if (!next_smi->IsSmi()) return -1;
+        pos = Smi::cast(next_smi)->value();
+        if (pos < 0) return -1;
+      }
+      DCHECK(pos >= 0);
+      DCHECK(len >= 0);
+      if (pos > special_length || len > special_length - pos) return -1;
+      increment = len;
+    } else if (elt->IsString()) {
+      String* element = String::cast(elt);
+      int element_length = element->length();
+      increment = element_length;
+      if (*one_byte && !element->HasOnlyOneByteChars()) {
+        *one_byte = false;
+      }
+    } else {
+      return -1;
+    }
+    if (increment > String::kMaxLength - position) {
+      return kMaxInt;  // Provoke throw on allocation.
+    }
+    position += increment;
+  }
+  return position;
+}
+
+
+class FixedArrayBuilder {
+ public:
+  explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
+ : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
+        length_(0),
+        has_non_smi_elements_(false) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    DCHECK(initial_capacity > 0);
+  }
+
+  explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
+      : array_(backing_store), length_(0), has_non_smi_elements_(false) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    DCHECK(backing_store->length() > 0);
+  }
+
+  bool HasCapacity(int elements) {
+    int length = array_->length();
+    int required_length = length_ + elements;
+    return (length >= required_length);
+  }
+
+  void EnsureCapacity(int elements) {
+    int length = array_->length();
+    int required_length = length_ + elements;
+    if (length < required_length) {
+      int new_length = length;
+      do {
+        new_length *= 2;
+      } while (new_length < required_length);
+      Handle<FixedArray> extended_array =
+ array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
+      array_->CopyTo(0, *extended_array, 0, length_);
+      array_ = extended_array;
+    }
+  }
+
+  void Add(Object* value) {
+    DCHECK(!value->IsSmi());
+    DCHECK(length_ < capacity());
+    array_->set(length_, value);
+    length_++;
+    has_non_smi_elements_ = true;
+  }
+
+  void Add(Smi* value) {
+    DCHECK(value->IsSmi());
+    DCHECK(length_ < capacity());
+    array_->set(length_, value);
+    length_++;
+  }
+
+  Handle<FixedArray> array() { return array_; }
+
+  int length() { return length_; }
+
+  int capacity() { return array_->length(); }
+
+  Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
+    JSArray::SetContent(target_array, array_);
+    target_array->set_length(Smi::FromInt(length_));
+    return target_array;
+  }
+
+
+ private:
+  Handle<FixedArray> array_;
+  int length_;
+  bool has_non_smi_elements_;
+};
+
+
+class ReplacementStringBuilder {
+ public:
+  ReplacementStringBuilder(Heap* heap, Handle<String> subject,
+                           int estimated_part_count)
+      : heap_(heap),
+        array_builder_(heap->isolate(), estimated_part_count),
+        subject_(subject),
+        character_count_(0),
+        is_one_byte_(subject->IsOneByteRepresentation()) {
+    // Require a non-zero initial size. Ensures that doubling the size to
+    // extend the array will work.
+    DCHECK(estimated_part_count > 0);
+  }
+
+  static inline void AddSubjectSlice(FixedArrayBuilder* builder, int from,
+                                     int to) {
+    DCHECK(from >= 0);
+    int length = to - from;
+    DCHECK(length > 0);
+    if (StringBuilderSubstringLength::is_valid(length) &&
+        StringBuilderSubstringPosition::is_valid(from)) {
+      int encoded_slice = StringBuilderSubstringLength::encode(length) |
+                          StringBuilderSubstringPosition::encode(from);
+      builder->Add(Smi::FromInt(encoded_slice));
+    } else {
+      // Otherwise encode as two smis.
+      builder->Add(Smi::FromInt(-length));
+      builder->Add(Smi::FromInt(from));
+    }
+  }
+
+
+ void EnsureCapacity(int elements) { array_builder_.EnsureCapacity(elements); }
+
+
+  void AddSubjectSlice(int from, int to) {
+    AddSubjectSlice(&array_builder_, from, to);
+    IncrementCharacterCount(to - from);
+  }
+
+
+  void AddString(Handle<String> string) {
+    int length = string->length();
+    DCHECK(length > 0);
+    AddElement(*string);
+    if (!string->IsOneByteRepresentation()) {
+      is_one_byte_ = false;
+    }
+    IncrementCharacterCount(length);
+  }
+
+
+  MaybeHandle<String> ToString();
+
+
+  void IncrementCharacterCount(int by) {
+    if (character_count_ > String::kMaxLength - by) {
+      STATIC_ASSERT(String::kMaxLength < kMaxInt);
+      character_count_ = kMaxInt;
+    } else {
+      character_count_ += by;
+    }
+  }
+
+ private:
+  void AddElement(Object* element) {
+    DCHECK(element->IsSmi() || element->IsString());
+    DCHECK(array_builder_.capacity() > array_builder_.length());
+    array_builder_.Add(element);
+  }
+
+  Heap* heap_;
+  FixedArrayBuilder array_builder_;
+  Handle<String> subject_;
+  int character_count_;
+  bool is_one_byte_;
+};
+
+
+class IncrementalStringBuilder {
+ public:
+  explicit IncrementalStringBuilder(Isolate* isolate);
+
+  INLINE(String::Encoding CurrentEncoding()) { return encoding_; }
+
+  template <typename SrcChar, typename DestChar>
+  INLINE(void Append(SrcChar c));
+
+  INLINE(void AppendCharacter(uint8_t c)) {
+    if (encoding_ == String::ONE_BYTE_ENCODING) {
+      Append<uint8_t, uint8_t>(c);
+    } else {
+      Append<uint8_t, uc16>(c);
+    }
+  }
+
+  INLINE(void AppendCString(const char* s)) {
+    const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
+    if (encoding_ == String::ONE_BYTE_ENCODING) {
+      while (*u != '\0') Append<uint8_t, uint8_t>(*(u++));
+    } else {
+      while (*u != '\0') Append<uint8_t, uc16>(*(u++));
+    }
+  }
+
+  INLINE(bool CurrentPartCanFit(int length)) {
+    return part_length_ - current_index_ > length;
+  }
+
+  void AppendString(Handle<String> string);
+
+  MaybeHandle<String> Finish();
+
+  // Change encoding to two-byte.
+  void ChangeEncoding() {
+    DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
+    ShrinkCurrentPart();
+    encoding_ = String::TWO_BYTE_ENCODING;
+    Extend();
+  }
+
+  template <typename DestChar>
+  class NoExtend {
+   public:
+    explicit NoExtend(Handle<String> string, int offset) {
+      DCHECK(string->IsSeqOneByteString() || string->IsSeqTwoByteString());
+      if (sizeof(DestChar) == 1) {
+        start_ = reinterpret_cast<DestChar*>(
+            Handle<SeqOneByteString>::cast(string)->GetChars() + offset);
+      } else {
+        start_ = reinterpret_cast<DestChar*>(
+            Handle<SeqTwoByteString>::cast(string)->GetChars() + offset);
+      }
+      cursor_ = start_;
+    }
+
+    INLINE(void Append(DestChar c)) { *(cursor_++) = c; }
+    INLINE(void AppendCString(const char* s)) {
+      const uint8_t* u = reinterpret_cast<const uint8_t*>(s);
+      while (*u != '\0') Append(*(u++));
+    }
+
+    int written() { return cursor_ - start_; }
+
+   private:
+    DestChar* start_;
+    DestChar* cursor_;
+    DisallowHeapAllocation no_gc_;
+  };
+
+  template <typename DestChar>
+  class NoExtendString : public NoExtend<DestChar> {
+   public:
+    NoExtendString(Handle<String> string, int required_length)
+        : NoExtend<DestChar>(string, 0), string_(string) {
+      DCHECK(string->length() >= required_length);
+    }
+
+    ~NoExtendString() {
+      Handle<SeqString> string = Handle<SeqString>::cast(string_);
+      int length = NoExtend<DestChar>::written();
+      *string_.location() = *SeqString::Truncate(string, length);
+    }
+
+   private:
+    Handle<String> string_;
+  };
+
+  template <typename DestChar>
+  class NoExtendBuilder : public NoExtend<DestChar> {
+   public:
+    NoExtendBuilder(IncrementalStringBuilder* builder, int required_length)
+ : NoExtend<DestChar>(builder->current_part(), builder->current_index_),
+          builder_(builder) {
+      DCHECK(builder->CurrentPartCanFit(required_length));
+    }
+
+    ~NoExtendBuilder() {
+      builder_->current_index_ += NoExtend<DestChar>::written();
+    }
+
+   private:
+    IncrementalStringBuilder* builder_;
+  };
+
+ private:
+  Factory* factory() { return isolate_->factory(); }
+
+  INLINE(Handle<String> accumulator()) { return accumulator_; }
+
+  INLINE(void set_accumulator(Handle<String> string)) {
+    *accumulator_.location() = *string;
+  }
+
+  INLINE(Handle<String> current_part()) { return current_part_; }
+
+  INLINE(void set_current_part(Handle<String> string)) {
+    *current_part_.location() = *string;
+  }
+
+  // Add the current part to the accumulator.
+  void Accumulate();
+
+  // Finish the current part and allocate a new part.
+  void Extend();
+
+  // Shrink current part to the right size.
+  void ShrinkCurrentPart() {
+    DCHECK(current_index_ < part_length_);
+    set_current_part(SeqString::Truncate(
+        Handle<SeqString>::cast(current_part()), current_index_));
+  }
+
+  static const int kInitialPartLength = 32;
+  static const int kMaxPartLength = 16 * 1024;
+  static const int kPartLengthGrowthFactor = 2;
+
+  Isolate* isolate_;
+  String::Encoding encoding_;
+  bool overflowed_;
+  int part_length_;
+  int current_index_;
+  Handle<String> accumulator_;
+  Handle<String> current_part_;
+};
+
+
+template <typename SrcChar, typename DestChar>
+void IncrementalStringBuilder::Append(SrcChar c) {
+  DCHECK_EQ(encoding_ == String::ONE_BYTE_ENCODING, sizeof(DestChar) == 1);
+  if (sizeof(DestChar) == 1) {
+    DCHECK_EQ(String::ONE_BYTE_ENCODING, encoding_);
+    SeqOneByteString::cast(*current_part_)
+        ->SeqOneByteStringSet(current_index_++, c);
+  } else {
+    DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding_);
+    SeqTwoByteString::cast(*current_part_)
+        ->SeqTwoByteStringSet(current_index_++, c);
+  }
+  if (current_index_ == part_length_) Extend();
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_STRING_BUILDER_H_
=======================================
--- /branches/bleeding_edge/src/runtime/string-builder.h Mon Oct 20 12:07:45 2014 UTC
+++ /dev/null
@@ -1,296 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_RUNTIME_STRING_BUILDER_H_
-#define V8_RUNTIME_STRING_BUILDER_H_
-
-namespace v8 {
-namespace internal {
-
-const int kStringBuilderConcatHelperLengthBits = 11;
-const int kStringBuilderConcatHelperPositionBits = 19;
-
-typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
-    StringBuilderSubstringLength;
-typedef BitField<int, kStringBuilderConcatHelperLengthBits,
-                 kStringBuilderConcatHelperPositionBits>
-    StringBuilderSubstringPosition;
-
-
-template <typename sinkchar>
-static inline void StringBuilderConcatHelper(String* special, sinkchar* sink,
-                                             FixedArray* fixed_array,
-                                             int array_length) {
-  DisallowHeapAllocation no_gc;
-  int position = 0;
-  for (int i = 0; i < array_length; i++) {
-    Object* element = fixed_array->get(i);
-    if (element->IsSmi()) {
-      // Smi encoding of position and length.
-      int encoded_slice = Smi::cast(element)->value();
-      int pos;
-      int len;
-      if (encoded_slice > 0) {
-        // Position and length encoded in one smi.
-        pos = StringBuilderSubstringPosition::decode(encoded_slice);
-        len = StringBuilderSubstringLength::decode(encoded_slice);
-      } else {
-        // Position and length encoded in two smis.
-        Object* obj = fixed_array->get(++i);
-        DCHECK(obj->IsSmi());
-        pos = Smi::cast(obj)->value();
-        len = -encoded_slice;
-      }
-      String::WriteToFlat(special, sink + position, pos, pos + len);
-      position += len;
-    } else {
-      String* string = String::cast(element);
-      int element_length = string->length();
-      String::WriteToFlat(string, sink + position, 0, element_length);
-      position += element_length;
-    }
-  }
-}
-
-
-// Returns the result length of the concatenation.
-// On illegal argument, -1 is returned.
-static inline int StringBuilderConcatLength(int special_length,
-                                            FixedArray* fixed_array,
- int array_length, bool* one_byte) {
-  DisallowHeapAllocation no_gc;
-  int position = 0;
-  for (int i = 0; i < array_length; i++) {
-    int increment = 0;
-    Object* elt = fixed_array->get(i);
-    if (elt->IsSmi()) {
-      // Smi encoding of position and length.
-      int smi_value = Smi::cast(elt)->value();
-      int pos;
-      int len;
-      if (smi_value > 0) {
-        // Position and length encoded in one smi.
-        pos = StringBuilderSubstringPosition::decode(smi_value);
-        len = StringBuilderSubstringLength::decode(smi_value);
-      } else {
-        // Position and length encoded in two smis.
-        len = -smi_value;
-        // Get the position and check that it is a positive smi.
-        i++;
-        if (i >= array_length) return -1;
-        Object* next_smi = fixed_array->get(i);
-        if (!next_smi->IsSmi()) return -1;
-        pos = Smi::cast(next_smi)->value();
-        if (pos < 0) return -1;
-      }
-      DCHECK(pos >= 0);
-      DCHECK(len >= 0);
-      if (pos > special_length || len > special_length - pos) return -1;
-      increment = len;
-    } else if (elt->IsString()) {
-      String* element = String::cast(elt);
-      int element_length = element->length();
-      increment = element_length;
-      if (*one_byte && !element->HasOnlyOneByteChars()) {
-        *one_byte = false;
-      }
-    } else {
-      return -1;
-    }
-    if (increment > String::kMaxLength - position) {
-      return kMaxInt;  // Provoke throw on allocation.
-    }
-    position += increment;
-  }
-  return position;
-}
-
-
-class FixedArrayBuilder {
- public:
-  explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
- : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
-        length_(0),
-        has_non_smi_elements_(false) {
-    // Require a non-zero initial size. Ensures that doubling the size to
-    // extend the array will work.
-    DCHECK(initial_capacity > 0);
-  }
-
-  explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
-      : array_(backing_store), length_(0), has_non_smi_elements_(false) {
-    // Require a non-zero initial size. Ensures that doubling the size to
-    // extend the array will work.
-    DCHECK(backing_store->length() > 0);
-  }
-
-  bool HasCapacity(int elements) {
-    int length = array_->length();
-    int required_length = length_ + elements;
-    return (length >= required_length);
-  }
-
-  void EnsureCapacity(int elements) {
-    int length = array_->length();
-    int required_length = length_ + elements;
-    if (length < required_length) {
-      int new_length = length;
-      do {
-        new_length *= 2;
-      } while (new_length < required_length);
-      Handle<FixedArray> extended_array =
- array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
-      array_->CopyTo(0, *extended_array, 0, length_);
-      array_ = extended_array;
-    }
-  }
-
-  void Add(Object* value) {
-    DCHECK(!value->IsSmi());
-    DCHECK(length_ < capacity());
-    array_->set(length_, value);
-    length_++;
-    has_non_smi_elements_ = true;
-  }
-
-  void Add(Smi* value) {
-    DCHECK(value->IsSmi());
-    DCHECK(length_ < capacity());
-    array_->set(length_, value);
-    length_++;
-  }
-
-  Handle<FixedArray> array() { return array_; }
-
-  int length() { return length_; }
-
-  int capacity() { return array_->length(); }
-
-  Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
-    JSArray::SetContent(target_array, array_);
-    target_array->set_length(Smi::FromInt(length_));
-    return target_array;
-  }
-
-
- private:
-  Handle<FixedArray> array_;
-  int length_;
-  bool has_non_smi_elements_;
-};
-
-
-class ReplacementStringBuilder {
- public:
-  ReplacementStringBuilder(Heap* heap, Handle<String> subject,
-                           int estimated_part_count)
-      : heap_(heap),
-        array_builder_(heap->isolate(), estimated_part_count),
-        subject_(subject),
-        character_count_(0),
-        is_one_byte_(subject->IsOneByteRepresentation()) {
-    // Require a non-zero initial size. Ensures that doubling the size to
-    // extend the array will work.
-    DCHECK(estimated_part_count > 0);
-  }
-
-  static inline void AddSubjectSlice(FixedArrayBuilder* builder, int from,
-                                     int to) {
-    DCHECK(from >= 0);
-    int length = to - from;
-    DCHECK(length > 0);
-    if (StringBuilderSubstringLength::is_valid(length) &&
-        StringBuilderSubstringPosition::is_valid(from)) {
-      int encoded_slice = StringBuilderSubstringLength::encode(length) |
-                          StringBuilderSubstringPosition::encode(from);
-      builder->Add(Smi::FromInt(encoded_slice));
-    } else {
-      // Otherwise encode as two smis.
-      builder->Add(Smi::FromInt(-length));
-      builder->Add(Smi::FromInt(from));
-    }
-  }
-
-
- void EnsureCapacity(int elements) { array_builder_.EnsureCapacity(elements); }
-
-
-  void AddSubjectSlice(int from, int to) {
-    AddSubjectSlice(&array_builder_, from, to);
-    IncrementCharacterCount(to - from);
-  }
-
-
-  void AddString(Handle<String> string) {
-    int length = string->length();
-    DCHECK(length > 0);
-    AddElement(*string);
-    if (!string->IsOneByteRepresentation()) {
-      is_one_byte_ = false;
-    }
-    IncrementCharacterCount(length);
-  }
-
-
-  MaybeHandle<String> ToString() {
-    Isolate* isolate = heap_->isolate();
-    if (array_builder_.length() == 0) {
-      return isolate->factory()->empty_string();
-    }
-
-    Handle<String> joined_string;
-    if (is_one_byte_) {
-      Handle<SeqOneByteString> seq;
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, seq,
- isolate->factory()->NewRawOneByteString(character_count_), String);
-
-      DisallowHeapAllocation no_gc;
-      uint8_t* char_buffer = seq->GetChars();
- StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
-                                array_builder_.length());
-      joined_string = Handle<String>::cast(seq);
-    } else {
-      // Two-byte.
-      Handle<SeqTwoByteString> seq;
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, seq,
- isolate->factory()->NewRawTwoByteString(character_count_), String);
-
-      DisallowHeapAllocation no_gc;
-      uc16* char_buffer = seq->GetChars();
- StringBuilderConcatHelper(*subject_, char_buffer, *array_builder_.array(),
-                                array_builder_.length());
-      joined_string = Handle<String>::cast(seq);
-    }
-    return joined_string;
-  }
-
-
-  void IncrementCharacterCount(int by) {
-    if (character_count_ > String::kMaxLength - by) {
-      STATIC_ASSERT(String::kMaxLength < kMaxInt);
-      character_count_ = kMaxInt;
-    } else {
-      character_count_ += by;
-    }
-  }
-
- private:
-  void AddElement(Object* element) {
-    DCHECK(element->IsSmi() || element->IsString());
-    DCHECK(array_builder_.capacity() > array_builder_.length());
-    array_builder_.Add(element);
-  }
-
-  Heap* heap_;
-  FixedArrayBuilder array_builder_;
-  Handle<String> subject_;
-  int character_count_;
-  bool is_one_byte_;
-};
-}
-}  // namespace v8::internal
-
-#endif  // V8_RUNTIME_STRING_BUILDER_H_
=======================================
--- /branches/bleeding_edge/BUILD.gn    Tue Nov 11 12:02:56 2014 UTC
+++ /branches/bleeding_edge/BUILD.gn    Wed Nov 12 08:04:41 2014 UTC
@@ -877,7 +877,6 @@
     "src/runtime/runtime-utils.h",
     "src/runtime/runtime.cc",
     "src/runtime/runtime.h",
-    "src/runtime/string-builder.h",
     "src/safepoint-table.cc",
     "src/safepoint-table.h",
     "src/sampler.cc",
@@ -897,6 +896,8 @@
     "src/snapshot-source-sink.cc",
     "src/snapshot-source-sink.h",
     "src/snapshot.h",
+    "src/string-builder.h",
+    "src/string-builder.c",
     "src/string-search.cc",
     "src/string-search.h",
     "src/string-stream.cc",
=======================================
--- /branches/bleeding_edge/src/json-stringifier.h Tue Nov 11 10:24:52 2014 UTC +++ /branches/bleeding_edge/src/json-stringifier.h Wed Nov 12 08:04:41 2014 UTC
@@ -8,6 +8,7 @@
 #include "src/v8.h"

 #include "src/conversions.h"
+#include "src/string-builder.h"
 #include "src/utils.h"

 namespace v8 {
@@ -24,41 +25,7 @@
       Handle<String> object));

  private:
-  static const int kInitialPartLength = 32;
-  static const int kMaxPartLength = 16 * 1024;
-  static const int kPartLengthGrowthFactor = 2;
-
   enum Result { UNCHANGED, SUCCESS, EXCEPTION };
-
-  void Accumulate();
-
-  void Extend();
-
-  void ChangeEncoding();
-
-  INLINE(void ShrinkCurrentPart());
-
-  template <bool is_one_byte, typename Char>
-  INLINE(void Append_(Char c));
-
-  template <bool is_one_byte, typename Char>
-  INLINE(void Append_(const Char* chars));
-
-  INLINE(void Append(uint8_t c)) {
-    if (is_one_byte_) {
-      Append_<true>(c);
-    } else {
-      Append_<false>(c);
-    }
-  }
-
-  INLINE(void AppendOneByte(const char* chars)) {
-    if (is_one_byte_) {
-      Append_<true>(reinterpret_cast<const uint8_t*>(chars));
-    } else {
-      Append_<false>(reinterpret_cast<const uint8_t*>(chars));
-    }
-  }

   MUST_USE_RESULT MaybeHandle<Object> ApplyToJsonFunction(
       Handle<Object> object,
@@ -69,14 +36,9 @@
                           bool deferred_comma,
                           bool deferred_key);

-  template <typename ResultType, typename Char>
-  INLINE(static Handle<String> StringifyString_(Isolate* isolate,
-                                                Vector<Char> vector,
-                                                Handle<String> result));
-
   // Entry point to serialize the object.
   INLINE(Result SerializeObject(Handle<Object> obj)) {
-    return Serialize_<false>(obj, false, factory_->empty_string());
+    return Serialize_<false>(obj, false, factory()->empty_string());
   }

   // Serialize an array element.
@@ -103,9 +65,9 @@
   Result Serialize_(Handle<Object> object, bool comma, Handle<Object> key);

void SerializeDeferredKey(bool deferred_comma, Handle<Object> deferred_key) {
-    if (deferred_comma) Append(',');
+    if (deferred_comma) builder_.AppendCharacter(',');
     SerializeString(Handle<String>::cast(deferred_key));
-    Append(':');
+    builder_.AppendCharacter(':');
   }

   Result SerializeSmi(Smi* object);
@@ -125,11 +87,11 @@
   void SerializeString(Handle<String> object);

   template <typename SrcChar, typename DestChar>
-  INLINE(static int SerializeStringUnchecked_(const SrcChar* src,
-                                              DestChar* dest,
-                                              int length));
+  INLINE(static void SerializeStringUnchecked_(
+      Vector<const SrcChar> src,
+      IncrementalStringBuilder::NoExtend<DestChar>* dest));

-  template <bool is_one_byte, typename Char>
+  template <typename SrcChar, typename DestChar>
   INLINE(void SerializeString_(Handle<String> string));

   template <typename Char>
@@ -141,26 +103,12 @@
   Result StackPush(Handle<Object> object);
   void StackPop();

-  INLINE(Handle<String> accumulator()) {
- return Handle<String>(String::cast(accumulator_store_->value()), isolate_);
-  }
-
-  INLINE(void set_accumulator(Handle<String> string)) {
-    return accumulator_store_->set_value(*string);
-  }
+  Factory* factory() { return isolate_->factory(); }

   Isolate* isolate_;
-  Factory* factory_;
-  // We use a value wrapper for the string accumulator to keep the
-  // (indirect) handle to it in the outermost handle scope.
-  Handle<JSValue> accumulator_store_;
-  Handle<String> current_part_;
+  IncrementalStringBuilder builder_;
   Handle<String> tojson_string_;
   Handle<JSArray> stack_;
-  int current_index_;
-  int part_length_;
-  bool is_one_byte_;
-  bool overflowed_;

   static const int kJsonEscapeTableEntrySize = 8;
   static const char* const JsonEscapeTable;
@@ -237,31 +185,16 @@


 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
-    : isolate_(isolate),
-      current_index_(0),
-      is_one_byte_(true),
-      overflowed_(false) {
-  factory_ = isolate_->factory();
-  accumulator_store_ = Handle<JSValue>::cast(
- Object::ToObject(isolate, factory_->empty_string()).ToHandleChecked());
-  part_length_ = kInitialPartLength;
- current_part_ = factory_->NewRawOneByteString(part_length_).ToHandleChecked();
-  tojson_string_ = factory_->toJSON_string();
-  stack_ = factory_->NewJSArray(8);
+    : isolate_(isolate), builder_(isolate) {
+  tojson_string_ = factory()->toJSON_string();
+  stack_ = factory()->NewJSArray(8);
 }


MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object) {
   Result result = SerializeObject(object);
-  if (result == UNCHANGED) return isolate_->factory()->undefined_value();
-  if (result == SUCCESS) {
-    ShrinkCurrentPart();
-    Accumulate();
-    if (overflowed_) {
-      THROW_NEW_ERROR(isolate_, NewInvalidStringLengthError(), Object);
-    }
-    return accumulator();
-  }
+  if (result == UNCHANGED) return factory()->undefined_value();
+  if (result == SUCCESS) return builder_.Finish();
   DCHECK(result == EXCEPTION);
   return MaybeHandle<Object>();
 }
@@ -281,58 +214,29 @@

   object = String::Flatten(object);
   DCHECK(object->IsFlat());
+  Handle<SeqString> result;
   if (object->IsOneByteRepresentationUnderneath()) {
-    Handle<String> result = isolate->factory()->NewRawOneByteString(
-        worst_case_length).ToHandleChecked();
-    DisallowHeapAllocation no_gc;
-    return StringifyString_<SeqOneByteString>(
-        isolate,
-        object->GetFlatContent().ToOneByteVector(),
-        result);
-  } else {
-    Handle<String> result = isolate->factory()->NewRawTwoByteString(
-        worst_case_length).ToHandleChecked();
-    DisallowHeapAllocation no_gc;
-    return StringifyString_<SeqTwoByteString>(
-        isolate,
-        object->GetFlatContent().ToUC16Vector(),
-        result);
-  }
-}
-
-
-template <typename ResultType, typename Char>
-Handle<String> BasicJsonStringifier::StringifyString_(Isolate* isolate,
-                                                      Vector<Char> vector,
- Handle<String> result) {
-  DisallowHeapAllocation no_gc;
-  int final_size = 0;
-  ResultType* dest = ResultType::cast(*result);
-  dest->Set(final_size++, '\"');
-  final_size += SerializeStringUnchecked_(vector.start(),
-                                          dest->GetChars() + 1,
-                                          vector.length());
-  dest->Set(final_size++, '\"');
-  return SeqString::Truncate(Handle<SeqString>::cast(result), final_size);
-}
-
-
-template <bool is_one_byte, typename Char>
-void BasicJsonStringifier::Append_(Char c) {
-  if (is_one_byte) {
-    SeqOneByteString::cast(*current_part_)->SeqOneByteStringSet(
-        current_index_++, c);
+    result = isolate->factory()
+                 ->NewRawOneByteString(worst_case_length)
+                 .ToHandleChecked();
+    IncrementalStringBuilder::NoExtendString<uint8_t> no_extend(
+        result, worst_case_length);
+    no_extend.Append('\"');
+    SerializeStringUnchecked_(object->GetFlatContent().ToOneByteVector(),
+                              &no_extend);
+    no_extend.Append('\"');
   } else {
-    SeqTwoByteString::cast(*current_part_)->SeqTwoByteStringSet(
-        current_index_++, c);
+    result = isolate->factory()
+                 ->NewRawTwoByteString(worst_case_length)
+                 .ToHandleChecked();
+    IncrementalStringBuilder::NoExtendString<uc16> no_extend(result,
+ worst_case_length);
+    no_extend.Append('\"');
+    SerializeStringUnchecked_(object->GetFlatContent().ToUC16Vector(),
+                              &no_extend);
+    no_extend.Append('\"');
   }
-  if (current_index_ == part_length_) Extend();
-}
-
-
-template <bool is_one_byte, typename Char>
-void BasicJsonStringifier::Append_(const Char* chars) {
-  for (; *chars != '\0'; chars++) Append_<is_one_byte, Char>(*chars);
+  return result;
 }


@@ -345,7 +249,7 @@
   if (!fun->IsJSFunction()) return object;

   // Call toJSON function.
-  if (key->IsSmi()) key = factory_->NumberToString(key);
+  if (key->IsSmi()) key = factory()->NumberToString(key);
   Handle<Object> argv[] = { key };
   HandleScope scope(isolate_);
   ASSIGN_RETURN_ON_EXCEPTION(
@@ -372,7 +276,7 @@
       if (elements->get(i) == *object) {
         AllowHeapAllocation allow_to_return_error;
         Handle<Object> error;
-        MaybeHandle<Object> maybe_error = factory_->NewTypeError(
+        MaybeHandle<Object> maybe_error = factory()->NewTypeError(
             "circular_structure", HandleVector<Object>(NULL, 0));
         if (maybe_error.ToHandle(&error)) isolate_->Throw(*error);
         return EXCEPTION;
@@ -416,15 +320,15 @@
       switch (Oddball::cast(*object)->kind()) {
         case Oddball::kFalse:
           if (deferred_string_key) SerializeDeferredKey(comma, key);
-          AppendOneByte("false");
+          builder_.AppendCString("false");
           return SUCCESS;
         case Oddball::kTrue:
           if (deferred_string_key) SerializeDeferredKey(comma, key);
-          AppendOneByte("true");
+          builder_.AppendCString("true");
           return SUCCESS;
         case Oddball::kNull:
           if (deferred_string_key) SerializeDeferredKey(comma, key);
-          AppendOneByte("null");
+          builder_.AppendCString("null");
           return SUCCESS;
         default:
           return UNCHANGED;
@@ -472,23 +376,11 @@
       EXCEPTION);
   if (result->IsUndefined()) return UNCHANGED;
   if (deferred_key) {
-    if (key->IsSmi()) key = factory_->NumberToString(key);
+    if (key->IsSmi()) key = factory()->NumberToString(key);
     SerializeDeferredKey(deferred_comma, key);
   }

-  Handle<String> result_string = Handle<String>::cast(result);
- // Shrink current part, attach it to the accumulator, also attach the result
-  // string to the accumulator, and allocate a new part.
-  ShrinkCurrentPart();  // Shrink.
-  part_length_ = kInitialPartLength;  // Allocate conservatively.
-  Extend();             // Attach current part and allocate new part.
-  // Attach result string to the accumulator.
-  Handle<String> cons;
-  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-      isolate_, cons,
-      factory_->NewConsString(accumulator(), result_string),
-      EXCEPTION);
-  set_accumulator(cons);
+  builder_.AppendString(Handle<String>::cast(result));
   return SUCCESS;
 }

@@ -511,7 +403,7 @@
     DCHECK(class_name == isolate_->heap()->Boolean_string());
     Object* value = JSValue::cast(*object)->value();
     DCHECK(value->IsBoolean());
-    AppendOneByte(value->IsTrue() ? "true" : "false");
+    builder_.AppendCString(value->IsTrue() ? "true" : "false");
   }
   return SUCCESS;
 }
@@ -521,7 +413,7 @@
   static const int kBufferSize = 100;
   char chars[kBufferSize];
   Vector<char> buffer(chars, kBufferSize);
-  AppendOneByte(IntToCString(object->value(), buffer));
+  builder_.AppendCString(IntToCString(object->value(), buffer));
   return SUCCESS;
 }

@@ -529,13 +421,13 @@
 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble(
     double number) {
   if (std::isinf(number) || std::isnan(number)) {
-    AppendOneByte("null");
+    builder_.AppendCString("null");
     return SUCCESS;
   }
   static const int kBufferSize = 100;
   char chars[kBufferSize];
   Vector<char> buffer(chars, kBufferSize);
-  AppendOneByte(DoubleToCString(number, buffer));
+  builder_.AppendCString(DoubleToCString(number, buffer));
   return SUCCESS;
 }

@@ -547,13 +439,13 @@
   if (stack_push != SUCCESS) return stack_push;
   uint32_t length = 0;
   CHECK(object->length()->ToArrayIndex(&length));
-  Append('[');
+  builder_.AppendCharacter('[');
   switch (object->GetElementsKind()) {
     case FAST_SMI_ELEMENTS: {
       Handle<FixedArray> elements(
           FixedArray::cast(object->elements()), isolate_);
       for (uint32_t i = 0; i < length; i++) {
-        if (i > 0) Append(',');
+        if (i > 0) builder_.AppendCharacter(',');
         SerializeSmi(Smi::cast(elements->get(i)));
       }
       break;
@@ -564,7 +456,7 @@
       Handle<FixedDoubleArray> elements(
           FixedDoubleArray::cast(object->elements()), isolate_);
       for (uint32_t i = 0; i < length; i++) {
-        if (i > 0) Append(',');
+        if (i > 0) builder_.AppendCharacter(',');
         SerializeDouble(elements->get_scalar(i));
       }
       break;
@@ -573,14 +465,14 @@
       Handle<FixedArray> elements(
           FixedArray::cast(object->elements()), isolate_);
       for (uint32_t i = 0; i < length; i++) {
-        if (i > 0) Append(',');
+        if (i > 0) builder_.AppendCharacter(',');
         Result result =
             SerializeElement(isolate_,
                              Handle<Object>(elements->get(i), isolate_),
                              i);
         if (result == SUCCESS) continue;
         if (result == UNCHANGED) {
-          AppendOneByte("null");
+          builder_.AppendCString("null");
         } else {
           return result;
         }
@@ -596,9 +488,8 @@
       break;
     }
   }
-  Append(']');
+  builder_.AppendCharacter(']');
   StackPop();
-  current_part_ = handle_scope.CloseAndEscape(current_part_);
   return SUCCESS;
 }

@@ -606,19 +497,19 @@
 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArraySlow(
     Handle<JSArray> object, uint32_t length) {
   for (uint32_t i = 0; i < length; i++) {
-    if (i > 0) Append(',');
+    if (i > 0) builder_.AppendCharacter(',');
     Handle<Object> element;
     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
         isolate_, element,
         Object::GetElement(isolate_, object, i),
         EXCEPTION);
     if (element->IsUndefined()) {
-      AppendOneByte("null");
+      builder_.AppendCString("null");
     } else {
       Result result = SerializeElement(isolate_, element, i);
       if (result == SUCCESS) continue;
       if (result == UNCHANGED) {
-        AppendOneByte("null");
+        builder_.AppendCString("null");
       } else {
         return result;
       }
@@ -635,7 +526,7 @@
   if (stack_push != SUCCESS) return stack_push;
   DCHECK(!object->IsJSGlobalProxy() && !object->IsGlobalObject());

-  Append('{');
+  builder_.AppendCharacter('{');
   bool comma = false;

   if (object->HasFastProperties() &&
@@ -687,7 +578,7 @@
         maybe_property = Object::GetPropertyOrElement(object, key_handle);
       } else {
         DCHECK(key->IsNumber());
- key_handle = factory_->NumberToString(Handle<Object>(key, isolate_)); + key_handle = factory()->NumberToString(Handle<Object>(key, isolate_));
         uint32_t index;
         if (key->IsSmi()) {
           maybe_property = Object::GetElement(
@@ -707,130 +598,67 @@
     }
   }

-  Append('}');
+  builder_.AppendCharacter('}');
   StackPop();
-  current_part_ = handle_scope.CloseAndEscape(current_part_);
   return SUCCESS;
 }
-
-
-void BasicJsonStringifier::ShrinkCurrentPart() {
-  DCHECK(current_index_ < part_length_);
- current_part_ = SeqString::Truncate(Handle<SeqString>::cast(current_part_),
-                                      current_index_);
-}
-
-
-void BasicJsonStringifier::Accumulate() {
- if (accumulator()->length() + current_part_->length() > String::kMaxLength) { - // Screw it. Simply set the flag and carry on. Throw exception at the end.
-    set_accumulator(factory_->empty_string());
-    overflowed_ = true;
-  } else {
-    set_accumulator(factory_->NewConsString(accumulator(),
- current_part_).ToHandleChecked());
-  }
-}
-
-
-void BasicJsonStringifier::Extend() {
-  Accumulate();
-  if (part_length_ <= kMaxPartLength / kPartLengthGrowthFactor) {
-    part_length_ *= kPartLengthGrowthFactor;
-  }
-  if (is_one_byte_) {
-    current_part_ =
-        factory_->NewRawOneByteString(part_length_).ToHandleChecked();
-  } else {
-    current_part_ =
-        factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
-  }
-  DCHECK(!current_part_.is_null());
-  current_index_ = 0;
-}
-
-
-void BasicJsonStringifier::ChangeEncoding() {
-  ShrinkCurrentPart();
-  Accumulate();
-  current_part_ =
-      factory_->NewRawTwoByteString(part_length_).ToHandleChecked();
-  DCHECK(!current_part_.is_null());
-  current_index_ = 0;
-  is_one_byte_ = false;
-}


 template <typename SrcChar, typename DestChar>
-int BasicJsonStringifier::SerializeStringUnchecked_(const SrcChar* src,
-                                                    DestChar* dest,
-                                                    int length) {
-  DestChar* dest_start = dest;
-
+void BasicJsonStringifier::SerializeStringUnchecked_(
+    Vector<const SrcChar> src,
+    IncrementalStringBuilder::NoExtend<DestChar>* dest) {
   // Assert that uc16 character is not truncated down to 8 bit.
   // The <uc16, char> version of this method must not be called.
-  DCHECK(sizeof(*dest) >= sizeof(*src));
+  DCHECK(sizeof(DestChar) >= sizeof(SrcChar));

-  for (int i = 0; i < length; i++) {
+  for (int i = 0; i < src.length(); i++) {
     SrcChar c = src[i];
     if (DoNotEscape(c)) {
-      *(dest++) = static_cast<DestChar>(c);
+      dest->Append(c);
     } else {
-      const uint8_t* chars = reinterpret_cast<const uint8_t*>(
-          &JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
-      while (*chars != '\0') *(dest++) = *(chars++);
+      dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
     }
   }
-
-  return static_cast<int>(dest - dest_start);
 }


-template <bool is_one_byte, typename Char>
+template <typename SrcChar, typename DestChar>
 void BasicJsonStringifier::SerializeString_(Handle<String> string) {
   int length = string->length();
-  Append_<is_one_byte, char>('"');
+  builder_.Append<uint8_t, DestChar>('"');
   // We make a rough estimate to find out if the current string can be
// serialized without allocating a new string part. The worst case length of // an escaped character is 6. Shifting the remainin string length right by 3
   // is a more pessimistic estimate, but faster to calculate.
-
-  if (((part_length_ - current_index_) >> 3) > length) {
+  int worst_case_length = length << 3;
+  if (builder_.CurrentPartCanFit(worst_case_length)) {
     DisallowHeapAllocation no_gc;
-    Vector<const Char> vector = GetCharVector<Char>(string);
-    if (is_one_byte) {
-      current_index_ += SerializeStringUnchecked_(
-          vector.start(),
- SeqOneByteString::cast(*current_part_)->GetChars() + current_index_,
-          length);
-    } else {
-      current_index_ += SerializeStringUnchecked_(
-          vector.start(),
- SeqTwoByteString::cast(*current_part_)->GetChars() + current_index_,
-          length);
-    }
+    Vector<const SrcChar> vector = GetCharVector<SrcChar>(string);
+    IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
+        &builder_, worst_case_length);
+    SerializeStringUnchecked_(vector, &no_extend);
   } else {
     String* string_location = NULL;
-    Vector<const Char> vector(NULL, 0);
+    Vector<const SrcChar> vector(NULL, 0);
     for (int i = 0; i < length; i++) {
       // If GC moved the string, we need to refresh the vector.
       if (*string != string_location) {
         DisallowHeapAllocation no_gc;
// This does not actually prevent the string from being relocated later.
-        vector = GetCharVector<Char>(string);
+        vector = GetCharVector<SrcChar>(string);
         string_location = *string;
       }
-      Char c = vector[i];
+      SrcChar c = vector[i];
       if (DoNotEscape(c)) {
-        Append_<is_one_byte, Char>(c);
+        builder_.Append<SrcChar, DestChar>(c);
       } else {
-        Append_<is_one_byte, uint8_t>(reinterpret_cast<const uint8_t*>(
-            &JsonEscapeTable[c * kJsonEscapeTableEntrySize]));
+ builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]);
       }
     }
   }

-  Append_<is_one_byte, uint8_t>('"');
+  builder_.Append<uint8_t, DestChar>('"');
 }


@@ -865,18 +693,18 @@

 void BasicJsonStringifier::SerializeString(Handle<String> object) {
   object = String::Flatten(object);
-  if (is_one_byte_) {
+  if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) {
     if (object->IsOneByteRepresentationUnderneath()) {
-      SerializeString_<true, uint8_t>(object);
+      SerializeString_<uint8_t, uint8_t>(object);
     } else {
-      ChangeEncoding();
+      builder_.ChangeEncoding();
       SerializeString(object);
     }
   } else {
     if (object->IsOneByteRepresentationUnderneath()) {
-      SerializeString_<false, uint8_t>(object);
+      SerializeString_<uint8_t, uc16>(object);
     } else {
-      SerializeString_<false, uc16>(object);
+      SerializeString_<uc16, uc16>(object);
     }
   }
 }
=======================================
--- /branches/bleeding_edge/src/runtime/runtime-regexp.cc Mon Oct 20 12:07:45 2014 UTC +++ /branches/bleeding_edge/src/runtime/runtime-regexp.cc Wed Nov 12 08:04:41 2014 UTC
@@ -8,7 +8,7 @@
 #include "src/jsregexp-inl.h"
 #include "src/jsregexp.h"
 #include "src/runtime/runtime-utils.h"
-#include "src/runtime/string-builder.h"
+#include "src/string-builder.h"
 #include "src/string-search.h"

 namespace v8 {
=======================================
--- /branches/bleeding_edge/src/runtime/runtime-strings.cc Thu Oct 23 05:57:01 2014 UTC +++ /branches/bleeding_edge/src/runtime/runtime-strings.cc Wed Nov 12 08:04:41 2014 UTC
@@ -8,7 +8,7 @@
 #include "src/jsregexp-inl.h"
 #include "src/jsregexp.h"
 #include "src/runtime/runtime-utils.h"
-#include "src/runtime/string-builder.h"
+#include "src/string-builder.h"
 #include "src/string-search.h"

 namespace v8 {
=======================================
--- /branches/bleeding_edge/tools/gyp/v8.gyp    Tue Nov 11 12:02:56 2014 UTC
+++ /branches/bleeding_edge/tools/gyp/v8.gyp    Wed Nov 12 08:04:41 2014 UTC
@@ -790,7 +790,6 @@
         '../../src/runtime/runtime-utils.h',
         '../../src/runtime/runtime.cc',
         '../../src/runtime/runtime.h',
-        '../../src/runtime/string-builder.h',
         '../../src/safepoint-table.cc',
         '../../src/safepoint-table.h',
         '../../src/sampler.cc',
@@ -810,6 +809,8 @@
         '../../src/snapshot.h',
         '../../src/snapshot-source-sink.cc',
         '../../src/snapshot-source-sink.h',
+        '../../src/string-builder.h',
+        '../../src/string-builder.cc',
         '../../src/string-search.cc',
         '../../src/string-search.h',
         '../../src/string-stream.cc',

--
--
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to