| Index: src/objects.cc | 
| diff --git a/src/objects.cc b/src/objects.cc | 
| index 20553eb64bc94889c24418fab89dca2eeadf3346..e1d6da6df8518eb80212d79d311c3cfc4a76ea48 100644 | 
| --- a/src/objects.cc | 
| +++ b/src/objects.cc | 
| @@ -1048,8 +1048,7 @@ void String::StringShortPrint(StringStream* accumulator) { | 
| return; | 
| } | 
|  | 
| -  ConsStringIteratorOp op; | 
| -  StringCharacterStream stream(this, &op); | 
| +  StringInputBuffer buf(this); | 
|  | 
| bool truncated = false; | 
| if (len > kMaxShortPrintLength) { | 
| @@ -1058,17 +1057,17 @@ void String::StringShortPrint(StringStream* accumulator) { | 
| } | 
| bool ascii = true; | 
| for (int i = 0; i < len; i++) { | 
| -    uint16_t c = stream.GetNext(); | 
| +    int c = buf.GetNext(); | 
|  | 
| if (c < 32 || c >= 127) { | 
| ascii = false; | 
| } | 
| } | 
| -  stream.Reset(this); | 
| +  buf.Reset(this); | 
| if (ascii) { | 
| accumulator->Add("<String[%u]: ", length()); | 
| for (int i = 0; i < len; i++) { | 
| -      accumulator->Put(static_cast<char>(stream.GetNext())); | 
| +      accumulator->Put(buf.GetNext()); | 
| } | 
| accumulator->Put('>'); | 
| } else { | 
| @@ -1076,7 +1075,7 @@ void String::StringShortPrint(StringStream* accumulator) { | 
| // characters and that backslashes are therefore escaped. | 
| accumulator->Add("<String[%u]\\: ", length()); | 
| for (int i = 0; i < len; i++) { | 
| -      uint16_t c = stream.GetNext(); | 
| +      int c = buf.GetNext(); | 
| if (c == '\n') { | 
| accumulator->Add("\\n"); | 
| } else if (c == '\r') { | 
| @@ -1086,7 +1085,7 @@ void String::StringShortPrint(StringStream* accumulator) { | 
| } else if (c < 32 || c > 126) { | 
| accumulator->Add("\\x%02x", c); | 
| } else { | 
| -        accumulator->Put(static_cast<char>(c)); | 
| +        accumulator->Put(c); | 
| } | 
| } | 
| if (truncated) { | 
| @@ -1538,16 +1537,15 @@ MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, | 
| } | 
|  | 
|  | 
| -static bool IsIdentifier(UnicodeCache* cache, String* string) { | 
| +static bool IsIdentifier(UnicodeCache* cache, | 
| +                         unibrow::CharacterStream* buffer) { | 
| // Checks whether the buffer contains an identifier (no escape). | 
| -  if (string->length() == 0) return false; | 
| -  ConsStringIteratorOp op; | 
| -  StringCharacterStream stream(string, &op); | 
| -  if (!cache->IsIdentifierStart(stream.GetNext())) { | 
| +  if (!buffer->has_more()) return false; | 
| +  if (!cache->IsIdentifierStart(buffer->GetNext())) { | 
| return false; | 
| } | 
| -  while (stream.HasMore()) { | 
| -    if (!cache->IsIdentifierPart(stream.GetNext())) { | 
| +  while (buffer->has_more()) { | 
| +    if (!cache->IsIdentifierPart(buffer->GetNext())) { | 
| return false; | 
| } | 
| } | 
| @@ -1568,7 +1566,8 @@ MaybeObject* JSObject::AddFastProperty(String* name, | 
| // hidden symbols) and is not a real identifier. | 
| // Normalize the object if it will have too many fast properties. | 
| Isolate* isolate = GetHeap()->isolate(); | 
| -  if ((!IsIdentifier(isolate->unicode_cache(), name) | 
| +  StringInputBuffer buffer(name); | 
| +  if ((!IsIdentifier(isolate->unicode_cache(), &buffer) | 
| && name != isolate->heap()->hidden_symbol()) || | 
| (map()->unused_property_fields() == 0 && | 
| TooManyFastProperties(properties()->length(), store_mode))) { | 
| @@ -6595,14 +6594,14 @@ SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls, | 
| if (length < 0) length = kMaxInt - offset; | 
|  | 
| // Compute the size of the UTF-8 string. Start at the specified offset. | 
| -  Access<ConsStringIteratorOp> op( | 
| -      heap->isolate()->objects_string_iterator()); | 
| -  StringCharacterStream stream(this, op.value(), offset); | 
| +  Access<StringInputBuffer> buffer( | 
| +      heap->isolate()->objects_string_input_buffer()); | 
| +  buffer->Reset(offset, this); | 
| int character_position = offset; | 
| int utf8_bytes = 0; | 
| int last = unibrow::Utf16::kNoPreviousCharacter; | 
| -  while (stream.HasMore() && character_position++ < offset + length) { | 
| -    uint16_t character = stream.GetNext(); | 
| +  while (buffer->has_more() && character_position++ < offset + length) { | 
| +    uint16_t character = buffer->GetNext(); | 
| utf8_bytes += unibrow::Utf8::Length(character, last); | 
| last = character; | 
| } | 
| @@ -6614,12 +6613,13 @@ SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls, | 
| char* result = NewArray<char>(utf8_bytes + 1); | 
|  | 
| // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset. | 
| -  stream.Reset(this, offset); | 
| +  buffer->Rewind(); | 
| +  buffer->Seek(offset); | 
| character_position = offset; | 
| int utf8_byte_position = 0; | 
| last = unibrow::Utf16::kNoPreviousCharacter; | 
| -  while (stream.HasMore() && character_position++ < offset + length) { | 
| -    uint16_t character = stream.GetNext(); | 
| +  while (buffer->has_more() && character_position++ < offset + length) { | 
| +    uint16_t character = buffer->GetNext(); | 
| if (allow_nulls == DISALLOW_NULLS && character == 0) { | 
| character = ' '; | 
| } | 
| @@ -6671,15 +6671,15 @@ SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) { | 
| } | 
| Heap* heap = GetHeap(); | 
|  | 
| -  Access<ConsStringIteratorOp> op( | 
| -      heap->isolate()->objects_string_iterator()); | 
| -  StringCharacterStream stream(this, op.value()); | 
| +  Access<StringInputBuffer> buffer( | 
| +      heap->isolate()->objects_string_input_buffer()); | 
| +  buffer->Reset(this); | 
|  | 
| uc16* result = NewArray<uc16>(length() + 1); | 
|  | 
| int i = 0; | 
| -  while (stream.HasMore()) { | 
| -    uint16_t character = stream.GetNext(); | 
| +  while (buffer->has_more()) { | 
| +    uint16_t character = buffer->GetNext(); | 
| result[i++] = character; | 
| } | 
| result[i] = 0; | 
| @@ -7457,28 +7457,46 @@ void String::WriteToFlat(String* src, | 
| } | 
|  | 
|  | 
| +template <typename IteratorA, typename IteratorB> | 
| +static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) { | 
| +  // General slow case check.  We know that the ia and ib iterators | 
| +  // have the same length. | 
| +  while (ia->has_more()) { | 
| +    uint32_t ca = ia->GetNext(); | 
| +    uint32_t cb = ib->GetNext(); | 
| +    ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode); | 
| +    ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode); | 
| +    if (ca != cb) | 
| +      return false; | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| + | 
| // Compares the contents of two strings by reading and comparing | 
| // int-sized blocks of characters. | 
| template <typename Char> | 
| -static inline bool CompareRawStringContents(const Char* const a, | 
| -                                            const Char* const b, | 
| -                                            int length) { | 
| +static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) { | 
| +  int length = a.length(); | 
| +  ASSERT_EQ(length, b.length()); | 
| +  const Char* pa = a.start(); | 
| +  const Char* pb = b.start(); | 
| int i = 0; | 
| #ifndef V8_HOST_CAN_READ_UNALIGNED | 
| // If this architecture isn't comfortable reading unaligned ints | 
| // then we have to check that the strings are aligned before | 
| // comparing them blockwise. | 
| const int kAlignmentMask = sizeof(uint32_t) - 1;  // NOLINT | 
| -  uint32_t pa_addr = reinterpret_cast<uint32_t>(a); | 
| -  uint32_t pb_addr = reinterpret_cast<uint32_t>(b); | 
| +  uint32_t pa_addr = reinterpret_cast<uint32_t>(pa); | 
| +  uint32_t pb_addr = reinterpret_cast<uint32_t>(pb); | 
| if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) { | 
| #endif | 
| const int kStepSize = sizeof(int) / sizeof(Char);  // NOLINT | 
| int endpoint = length - kStepSize; | 
| // Compare blocks until we reach near the end of the string. | 
| for (; i <= endpoint; i += kStepSize) { | 
| -      uint32_t wa = *reinterpret_cast<const uint32_t*>(a + i); | 
| -      uint32_t wb = *reinterpret_cast<const uint32_t*>(b + i); | 
| +      uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i); | 
| +      uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i); | 
| if (wa != wb) { | 
| return false; | 
| } | 
| @@ -7496,145 +7514,25 @@ static inline bool CompareRawStringContents(const Char* const a, | 
| } | 
|  | 
|  | 
| -template<typename Chars1, typename Chars2> | 
| -class RawStringComparator : public AllStatic { | 
| - public: | 
| -  static inline bool compare(const Chars1* a, const Chars2* b, int len) { | 
| -    ASSERT(sizeof(Chars1) != sizeof(Chars2)); | 
| -    for (int i = 0; i < len; i++) { | 
| -      if (a[i] != b[i]) { | 
| -        return false; | 
| -      } | 
| -    } | 
| -    return true; | 
| -  } | 
| -}; | 
| - | 
| - | 
| -template<> | 
| -class RawStringComparator<uint16_t, uint16_t> { | 
| - public: | 
| -  static inline bool compare(const uint16_t* a, const uint16_t* b, int len) { | 
| -    return CompareRawStringContents(a, b, len); | 
| -  } | 
| -}; | 
| - | 
| - | 
| -template<> | 
| -class RawStringComparator<uint8_t, uint8_t> { | 
| - public: | 
| -  static inline bool compare(const uint8_t* a, const uint8_t* b, int len) { | 
| -    return CompareRawStringContents(a, b, len); | 
| -  } | 
| -}; | 
| - | 
| - | 
| -class StringComparator { | 
| -  class State { | 
| -   public: | 
| -    explicit inline State(ConsStringIteratorOp* op) | 
| -      : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {} | 
| - | 
| -    inline void Init(String* string, unsigned len) { | 
| -      op_->Reset(); | 
| -      int32_t type = string->map()->instance_type(); | 
| -      String::Visit(string, 0, *this, *op_, type, len); | 
| -    } | 
| - | 
| -    inline void VisitOneByteString(const uint8_t* chars, unsigned length) { | 
| -      is_one_byte_ = true; | 
| -      buffer8_ = chars; | 
| -      length_ = length; | 
| -    } | 
| - | 
| -    inline void VisitTwoByteString(const uint16_t* chars, unsigned length) { | 
| -      is_one_byte_ = false; | 
| -      buffer16_ = chars; | 
| -      length_ = length; | 
| -    } | 
| - | 
| -    void Advance(unsigned consumed) { | 
| -      ASSERT(consumed <= length_); | 
| -      // Still in buffer. | 
| -      if (length_ != consumed) { | 
| -        if (is_one_byte_) { | 
| -          buffer8_ += consumed; | 
| -        } else { | 
| -          buffer16_ += consumed; | 
| -        } | 
| -        length_ -= consumed; | 
| -        return; | 
| -      } | 
| -      // Advance state. | 
| -      ASSERT(op_->HasMore()); | 
| -      int32_t type = 0; | 
| -      unsigned length = 0; | 
| -      String* next = op_->ContinueOperation(&type, &length); | 
| -      ASSERT(next != NULL); | 
| -      ConsStringNullOp null_op; | 
| -      String::Visit(next, 0, *this, null_op, type, length); | 
| -    } | 
| - | 
| -    ConsStringIteratorOp* const op_; | 
| -    bool is_one_byte_; | 
| -    unsigned length_; | 
| -    union { | 
| -      const uint8_t* buffer8_; | 
| -      const uint16_t* buffer16_; | 
| -    }; | 
| -    DISALLOW_IMPLICIT_CONSTRUCTORS(State); | 
| -  }; | 
| - | 
| - public: | 
| -  inline StringComparator(ConsStringIteratorOp* op_1, | 
| -                          ConsStringIteratorOp* op_2) | 
| -    : state_1_(op_1), | 
| -      state_2_(op_2) { | 
| -  } | 
| - | 
| -  template<typename Chars1, typename Chars2> | 
| -  static inline bool Equals(State* state_1, State* state_2, unsigned to_check) { | 
| -    const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_); | 
| -    const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_); | 
| -    return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check); | 
| -  } | 
| - | 
| -  bool Equals(unsigned length, String* string_1, String* string_2) { | 
| -    ASSERT(length != 0); | 
| -    state_1_.Init(string_1, length); | 
| -    state_2_.Init(string_2, length); | 
| -    while (true) { | 
| -      unsigned to_check = Min(state_1_.length_, state_2_.length_); | 
| -      ASSERT(to_check > 0 && to_check <= length); | 
| -      bool is_equal; | 
| -      if (state_1_.is_one_byte_) { | 
| -        if (state_2_.is_one_byte_) { | 
| -          is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check); | 
| -        } else { | 
| -          is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check); | 
| -        } | 
| -      } else { | 
| -        if (state_2_.is_one_byte_) { | 
| -          is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check); | 
| -        } else { | 
| -          is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check); | 
| -        } | 
| -      } | 
| -      // Looping done. | 
| -      if (!is_equal) return false; | 
| -      length -= to_check; | 
| -      // Exit condition. Strings are equal. | 
| -      if (length == 0) return true; | 
| -      state_1_.Advance(to_check); | 
| -      state_2_.Advance(to_check); | 
| +template <typename IteratorA> | 
| +static inline bool CompareStringContentsPartial(Isolate* isolate, | 
| +                                                IteratorA* ia, | 
| +                                                String* b) { | 
| +  String::FlatContent content = b->GetFlatContent(); | 
| +  if (content.IsFlat()) { | 
| +    if (content.IsAscii()) { | 
| +      VectorIterator<char> ib(content.ToAsciiVector()); | 
| +      return CompareStringContents(ia, &ib); | 
| +    } else { | 
| +      VectorIterator<uc16> ib(content.ToUC16Vector()); | 
| +      return CompareStringContents(ia, &ib); | 
| } | 
| +  } else { | 
| +    isolate->objects_string_compare_buffer_b()->Reset(0, b); | 
| +    return CompareStringContents(ia, | 
| +                                 isolate->objects_string_compare_buffer_b()); | 
| } | 
| - | 
| - private: | 
| -  State state_1_; | 
| -  State state_2_; | 
| -  DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator); | 
| -}; | 
| +} | 
|  | 
|  | 
| bool String::SlowEquals(String* other) { | 
| @@ -7670,19 +7568,58 @@ bool String::SlowEquals(String* other) { | 
| String* lhs = this->TryFlattenGetString(); | 
| String* rhs = other->TryFlattenGetString(); | 
|  | 
| -  // TODO(dcarney): Compare all types of flat strings with a Visitor. | 
| if (StringShape(lhs).IsSequentialAscii() && | 
| StringShape(rhs).IsSequentialAscii()) { | 
| const char* str1 = SeqOneByteString::cast(lhs)->GetChars(); | 
| const char* str2 = SeqOneByteString::cast(rhs)->GetChars(); | 
| -    return CompareRawStringContents(str1, str2, len); | 
| +    return CompareRawStringContents(Vector<const char>(str1, len), | 
| +                                    Vector<const char>(str2, len)); | 
| } | 
|  | 
| Isolate* isolate = GetIsolate(); | 
| -  StringComparator comparator(isolate->objects_string_compare_iterator_a(), | 
| -                              isolate->objects_string_compare_iterator_b()); | 
| - | 
| -  return comparator.Equals(static_cast<unsigned>(len), lhs, rhs); | 
| +  String::FlatContent lhs_content = lhs->GetFlatContent(); | 
| +  String::FlatContent rhs_content = rhs->GetFlatContent(); | 
| +  if (lhs_content.IsFlat()) { | 
| +    if (lhs_content.IsAscii()) { | 
| +      Vector<const char> vec1 = lhs_content.ToAsciiVector(); | 
| +      if (rhs_content.IsFlat()) { | 
| +        if (rhs_content.IsAscii()) { | 
| +          Vector<const char> vec2 = rhs_content.ToAsciiVector(); | 
| +          return CompareRawStringContents(vec1, vec2); | 
| +        } else { | 
| +          VectorIterator<char> buf1(vec1); | 
| +          VectorIterator<uc16> ib(rhs_content.ToUC16Vector()); | 
| +          return CompareStringContents(&buf1, &ib); | 
| +        } | 
| +      } else { | 
| +        VectorIterator<char> buf1(vec1); | 
| +        isolate->objects_string_compare_buffer_b()->Reset(0, rhs); | 
| +        return CompareStringContents(&buf1, | 
| +            isolate->objects_string_compare_buffer_b()); | 
| +      } | 
| +    } else { | 
| +      Vector<const uc16> vec1 = lhs_content.ToUC16Vector(); | 
| +      if (rhs_content.IsFlat()) { | 
| +        if (rhs_content.IsAscii()) { | 
| +          VectorIterator<uc16> buf1(vec1); | 
| +          VectorIterator<char> ib(rhs_content.ToAsciiVector()); | 
| +          return CompareStringContents(&buf1, &ib); | 
| +        } else { | 
| +          Vector<const uc16> vec2(rhs_content.ToUC16Vector()); | 
| +          return CompareRawStringContents(vec1, vec2); | 
| +        } | 
| +      } else { | 
| +        VectorIterator<uc16> buf1(vec1); | 
| +        isolate->objects_string_compare_buffer_b()->Reset(0, rhs); | 
| +        return CompareStringContents(&buf1, | 
| +            isolate->objects_string_compare_buffer_b()); | 
| +      } | 
| +    } | 
| +  } else { | 
| +    isolate->objects_string_compare_buffer_a()->Reset(0, lhs); | 
| +    return CompareStringContentsPartial(isolate, | 
| +        isolate->objects_string_compare_buffer_a(), rhs); | 
| +  } | 
| } | 
|  | 
|  | 
| @@ -7827,12 +7764,11 @@ uint32_t String::ComputeAndSetHash() { | 
| } | 
|  | 
|  | 
| -bool String::ComputeArrayIndex(uint32_t* index) { | 
| -  int length = this->length(); | 
| +bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer, | 
| +                               uint32_t* index, | 
| +                               int length) { | 
| if (length == 0 || length > kMaxArrayIndexSize) return false; | 
| -  ConsStringIteratorOp op; | 
| -  StringCharacterStream stream(this, &op); | 
| -  uint16_t ch = stream.GetNext(); | 
| +  uc32 ch = buffer->GetNext(); | 
|  | 
| // If the string begins with a '0' character, it must only consist | 
| // of it to be a legal array index. | 
| @@ -7845,8 +7781,8 @@ bool String::ComputeArrayIndex(uint32_t* index) { | 
| int d = ch - '0'; | 
| if (d < 0 || d > 9) return false; | 
| uint32_t result = d; | 
| -  while (stream.HasMore()) { | 
| -    d = stream.GetNext() - '0'; | 
| +  while (buffer->has_more()) { | 
| +    d = buffer->GetNext() - '0'; | 
| if (d < 0 || d > 9) return false; | 
| // Check that the new result is below the 32 bit limit. | 
| if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; | 
| @@ -7867,7 +7803,8 @@ bool String::SlowAsArrayIndex(uint32_t* index) { | 
| *index = (kArrayIndexHashMask & field) >> kHashShift; | 
| return true; | 
| } else { | 
| -    return ComputeArrayIndex(index); | 
| +    StringInputBuffer buffer(this); | 
| +    return ComputeArrayIndex(&buffer, index, length()); | 
| } | 
| } | 
|  | 
|  |