| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 1e9ec616f713e68a58afd944c8e9b98de09db300..5d89dc43e14f17744ad6675289d6702e6bb319f9 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -8853,34 +8853,47 @@ void FlatStringReader::PostGarbageCollection() {
|
| }
|
|
|
|
|
| -String* ConsStringIteratorOp::Operate(String* string,
|
| - unsigned* offset_out,
|
| - int32_t* type_out,
|
| - unsigned* length_out) {
|
| - ASSERT(string->IsConsString());
|
| - ConsString* cons_string = ConsString::cast(string);
|
| - // Set up search data.
|
| +void ConsStringIteratorOp::Initialize(ConsString* cons_string, int offset) {
|
| + ASSERT(cons_string != NULL);
|
| root_ = cons_string;
|
| - consumed_ = *offset_out;
|
| - // Now search.
|
| - return Search(offset_out, type_out, length_out);
|
| + consumed_ = offset;
|
| + // Force stack blown condition to trigger restart.
|
| + depth_ = 1;
|
| + maximum_depth_ = kStackSize + depth_;
|
| + ASSERT(StackBlown());
|
| }
|
|
|
|
|
| -String* ConsStringIteratorOp::Search(unsigned* offset_out,
|
| - int32_t* type_out,
|
| - unsigned* length_out) {
|
| +String* ConsStringIteratorOp::Continue(int* offset_out) {
|
| + ASSERT(depth_ != 0);
|
| + ASSERT_EQ(0, *offset_out);
|
| + bool blew_stack = StackBlown();
|
| + String* string = NULL;
|
| + // Get the next leaf if there is one.
|
| + if (!blew_stack) string = NextLeaf(&blew_stack);
|
| + // Restart search from root.
|
| + if (blew_stack) {
|
| + ASSERT(string == NULL);
|
| + string = Search(offset_out);
|
| + }
|
| + // Ensure future calls return null immediately.
|
| + if (string == NULL) Reset(NULL);
|
| + return string;
|
| +}
|
| +
|
| +
|
| +String* ConsStringIteratorOp::Search(int* offset_out) {
|
| ConsString* cons_string = root_;
|
| // Reset the stack, pushing the root string.
|
| depth_ = 1;
|
| maximum_depth_ = 1;
|
| frames_[0] = cons_string;
|
| - const unsigned consumed = consumed_;
|
| - unsigned offset = 0;
|
| + const int consumed = consumed_;
|
| + int offset = 0;
|
| while (true) {
|
| // Loop until the string is found which contains the target offset.
|
| String* string = cons_string->first();
|
| - unsigned length = string->length();
|
| + int length = string->length();
|
| int32_t type;
|
| if (consumed < offset + length) {
|
| // Target offset is in the left branch.
|
| @@ -8891,7 +8904,7 @@ String* ConsStringIteratorOp::Search(unsigned* offset_out,
|
| PushLeft(cons_string);
|
| continue;
|
| }
|
| - // Tell the stack we're done decending.
|
| + // Tell the stack we're done descending.
|
| AdjustMaximumDepth();
|
| } else {
|
| // Descend right.
|
| @@ -8903,7 +8916,6 @@ String* ConsStringIteratorOp::Search(unsigned* offset_out,
|
| if ((type & kStringRepresentationMask) == kConsStringTag) {
|
| cons_string = ConsString::cast(string);
|
| PushRight(cons_string);
|
| - // TODO(dcarney) Add back root optimization.
|
| continue;
|
| }
|
| // Need this to be updated for the current string.
|
| @@ -8911,11 +8923,11 @@ String* ConsStringIteratorOp::Search(unsigned* offset_out,
|
| // Account for the possibility of an empty right leaf.
|
| // This happens only if we have asked for an offset outside the string.
|
| if (length == 0) {
|
| - // Reset depth so future operations will return null immediately.
|
| - Reset();
|
| + // Reset so future operations will return null immediately.
|
| + Reset(NULL);
|
| return NULL;
|
| }
|
| - // Tell the stack we're done decending.
|
| + // Tell the stack we're done descending.
|
| AdjustMaximumDepth();
|
| // Pop stack so next iteration is in correct place.
|
| Pop();
|
| @@ -8924,8 +8936,6 @@ String* ConsStringIteratorOp::Search(unsigned* offset_out,
|
| // Adjust return values and exit.
|
| consumed_ = offset + length;
|
| *offset_out = consumed - offset;
|
| - *type_out = type;
|
| - *length_out = length;
|
| return string;
|
| }
|
| UNREACHABLE();
|
| @@ -8933,9 +8943,7 @@ String* ConsStringIteratorOp::Search(unsigned* offset_out,
|
| }
|
|
|
|
|
| -String* ConsStringIteratorOp::NextLeaf(bool* blew_stack,
|
| - int32_t* type_out,
|
| - unsigned* length_out) {
|
| +String* ConsStringIteratorOp::NextLeaf(bool* blew_stack) {
|
| while (true) {
|
| // Tree traversal complete.
|
| if (depth_ == 0) {
|
| @@ -8943,7 +8951,7 @@ String* ConsStringIteratorOp::NextLeaf(bool* blew_stack,
|
| return NULL;
|
| }
|
| // We've lost track of higher nodes.
|
| - if (maximum_depth_ - depth_ == kStackSize) {
|
| + if (StackBlown()) {
|
| *blew_stack = true;
|
| return NULL;
|
| }
|
| @@ -8954,16 +8962,13 @@ String* ConsStringIteratorOp::NextLeaf(bool* blew_stack,
|
| if ((type & kStringRepresentationMask) != kConsStringTag) {
|
| // Pop stack so next iteration is in correct place.
|
| Pop();
|
| - unsigned length = static_cast<unsigned>(string->length());
|
| + int length = string->length();
|
| // Could be a flattened ConsString.
|
| if (length == 0) continue;
|
| - *length_out = length;
|
| - *type_out = type;
|
| consumed_ += length;
|
| return string;
|
| }
|
| cons_string = ConsString::cast(string);
|
| - // TODO(dcarney) Add back root optimization.
|
| PushRight(cons_string);
|
| // Need to traverse all the way left.
|
| while (true) {
|
| @@ -8972,10 +8977,8 @@ String* ConsStringIteratorOp::NextLeaf(bool* blew_stack,
|
| type = string->map()->instance_type();
|
| if ((type & kStringRepresentationMask) != kConsStringTag) {
|
| AdjustMaximumDepth();
|
| - unsigned length = static_cast<unsigned>(string->length());
|
| + int length = string->length();
|
| ASSERT(length != 0);
|
| - *length_out = length;
|
| - *type_out = type;
|
| consumed_ += length;
|
| return string;
|
| }
|
| @@ -9250,25 +9253,29 @@ class StringComparator {
|
| 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 Init(String* string) {
|
| + ConsString* cons_string = String::VisitFlat(this, string);
|
| + op_->Reset(cons_string);
|
| + if (cons_string != NULL) {
|
| + int offset;
|
| + string = op_->Next(&offset);
|
| + String::VisitFlat(this, string, offset);
|
| + }
|
| }
|
|
|
| - inline void VisitOneByteString(const uint8_t* chars, unsigned length) {
|
| + inline void VisitOneByteString(const uint8_t* chars, int length) {
|
| is_one_byte_ = true;
|
| buffer8_ = chars;
|
| length_ = length;
|
| }
|
|
|
| - inline void VisitTwoByteString(const uint16_t* chars, unsigned length) {
|
| + inline void VisitTwoByteString(const uint16_t* chars, int length) {
|
| is_one_byte_ = false;
|
| buffer16_ = chars;
|
| length_ = length;
|
| }
|
|
|
| - void Advance(unsigned consumed) {
|
| + void Advance(int consumed) {
|
| ASSERT(consumed <= length_);
|
| // Still in buffer.
|
| if (length_ != consumed) {
|
| @@ -9281,18 +9288,16 @@ class StringComparator {
|
| return;
|
| }
|
| // Advance state.
|
| - ASSERT(op_->HasMore());
|
| - int32_t type = 0;
|
| - unsigned length = 0;
|
| - String* next = op_->ContinueOperation(&type, &length);
|
| + int offset;
|
| + String* next = op_->Next(&offset);
|
| + ASSERT_EQ(0, offset);
|
| ASSERT(next != NULL);
|
| - ConsStringNullOp null_op;
|
| - String::Visit(next, 0, *this, null_op, type, length);
|
| + String::VisitFlat(this, next);
|
| }
|
|
|
| ConsStringIteratorOp* const op_;
|
| bool is_one_byte_;
|
| - unsigned length_;
|
| + int length_;
|
| union {
|
| const uint8_t* buffer8_;
|
| const uint16_t* buffer16_;
|
| @@ -9310,18 +9315,18 @@ class StringComparator {
|
| }
|
|
|
| template<typename Chars1, typename Chars2>
|
| - static inline bool Equals(State* state_1, State* state_2, unsigned to_check) {
|
| + static inline bool Equals(State* state_1, State* state_2, int 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);
|
| + bool Equals(String* string_1, String* string_2) {
|
| + int length = string_1->length();
|
| + state_1_.Init(string_1);
|
| + state_2_.Init(string_2);
|
| while (true) {
|
| - unsigned to_check = Min(state_1_.length_, state_2_.length_);
|
| + int 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_) {
|
| @@ -9385,7 +9390,6 @@ bool String::SlowEquals(String* other) {
|
| // before we try to flatten the strings.
|
| if (this->Get(0) != other->Get(0)) return false;
|
|
|
| - // TODO(dcarney): Compare all types of flat strings with a Visitor.
|
| if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
|
| const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
|
| const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
|
| @@ -9396,7 +9400,7 @@ bool String::SlowEquals(String* other) {
|
| StringComparator comparator(isolate->objects_string_compare_iterator_a(),
|
| isolate->objects_string_compare_iterator_b());
|
|
|
| - return comparator.Equals(static_cast<unsigned>(len), this, other);
|
| + return comparator.Equals(this, other);
|
| }
|
|
|
|
|
| @@ -9531,49 +9535,31 @@ bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
|
| class IteratingStringHasher: public StringHasher {
|
| public:
|
| static inline uint32_t Hash(String* string, uint32_t seed) {
|
| - const unsigned len = static_cast<unsigned>(string->length());
|
| - IteratingStringHasher hasher(len, seed);
|
| - if (hasher.has_trivial_hash()) {
|
| - return hasher.GetHashField();
|
| - }
|
| - int32_t type = string->map()->instance_type();
|
| - ConsStringNullOp null_op;
|
| - String::Visit(string, 0, hasher, null_op, type, len);
|
| - // Flat strings terminate immediately.
|
| - if (hasher.consumed_ == len) {
|
| - ASSERT(!string->IsConsString());
|
| - return hasher.GetHashField();
|
| - }
|
| - ASSERT(string->IsConsString());
|
| + IteratingStringHasher hasher(string->length(), seed);
|
| + // Nothing to do.
|
| + if (hasher.has_trivial_hash()) return hasher.GetHashField();
|
| + ConsString* cons_string = String::VisitFlat(&hasher, string);
|
| + // The string was flat.
|
| + if (cons_string == NULL) return hasher.GetHashField();
|
| // This is a ConsString, iterate across it.
|
| - ConsStringIteratorOp op;
|
| - unsigned offset = 0;
|
| - unsigned leaf_length = len;
|
| - string = op.Operate(string, &offset, &type, &leaf_length);
|
| - while (true) {
|
| - ASSERT(hasher.consumed_ < len);
|
| - String::Visit(string, 0, hasher, null_op, type, leaf_length);
|
| - if (hasher.consumed_ == len) break;
|
| - string = op.ContinueOperation(&type, &leaf_length);
|
| - // This should be taken care of by the length check.
|
| - ASSERT(string != NULL);
|
| + ConsStringIteratorOp op(cons_string);
|
| + int offset;
|
| + while (NULL != (string = op.Next(&offset))) {
|
| + String::VisitFlat(&hasher, string, offset);
|
| }
|
| return hasher.GetHashField();
|
| }
|
| - inline void VisitOneByteString(const uint8_t* chars, unsigned length) {
|
| - AddCharacters(chars, static_cast<int>(length));
|
| - consumed_ += length;
|
| + inline void VisitOneByteString(const uint8_t* chars, int length) {
|
| + AddCharacters(chars, length);
|
| }
|
| - inline void VisitTwoByteString(const uint16_t* chars, unsigned length) {
|
| - AddCharacters(chars, static_cast<int>(length));
|
| - consumed_ += length;
|
| + inline void VisitTwoByteString(const uint16_t* chars, int length) {
|
| + AddCharacters(chars, length);
|
| }
|
|
|
| private:
|
| inline IteratingStringHasher(int len, uint32_t seed)
|
| - : StringHasher(len, seed),
|
| - consumed_(0) {}
|
| - unsigned consumed_;
|
| + : StringHasher(len, seed) {
|
| + }
|
| DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
|
| };
|
|
|
|
|