From 7b1e8304892cf1668bb1733246f3a26582daab34 Mon Sep 17 00:00:00 2001 From: "dcarney@chromium.org" Date: Tue, 29 Apr 2014 13:09:31 +0000 Subject: [PATCH] Remove String::Visit R=yangguo@chromium.org BUG= Review URL: https://codereview.chromium.org/254763008 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@21046 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/objects-inl.h | 143 +++++++++----------------------------- src/objects.cc | 166 ++++++++++++++++++++------------------------ src/objects.h | 75 +++++++++----------- test/cctest/test-strings.cc | 49 ++++++------- 4 files changed, 159 insertions(+), 274 deletions(-) diff --git a/src/objects-inl.h b/src/objects-inl.h index ddeaede..3939802 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -3130,96 +3130,60 @@ String* String::GetUnderlying() { } -template -void String::Visit( - String* string, - unsigned offset, - Visitor& visitor, - ConsOp& cons_op, - int32_t type, - unsigned length) { - ASSERT(length == static_cast(string->length())); +template +ConsString* String::VisitFlat(Visitor* visitor, + String* string, + const int offset) { + int slice_offset = offset; + const int length = string->length(); ASSERT(offset <= length); - unsigned slice_offset = offset; while (true) { - ASSERT(type == string->map()->instance_type()); - + int32_t type = string->map()->instance_type(); switch (type & (kStringRepresentationMask | kStringEncodingMask)) { case kSeqStringTag | kOneByteStringTag: - visitor.VisitOneByteString( + visitor->VisitOneByteString( SeqOneByteString::cast(string)->GetChars() + slice_offset, length - offset); - return; + return NULL; case kSeqStringTag | kTwoByteStringTag: - visitor.VisitTwoByteString( + visitor->VisitTwoByteString( SeqTwoByteString::cast(string)->GetChars() + slice_offset, length - offset); - return; + return NULL; case kExternalStringTag | kOneByteStringTag: - visitor.VisitOneByteString( + visitor->VisitOneByteString( ExternalAsciiString::cast(string)->GetChars() + slice_offset, length - offset); - return; + return NULL; case kExternalStringTag | kTwoByteStringTag: - visitor.VisitTwoByteString( + visitor->VisitTwoByteString( ExternalTwoByteString::cast(string)->GetChars() + slice_offset, length - offset); - return; + return NULL; case kSlicedStringTag | kOneByteStringTag: case kSlicedStringTag | kTwoByteStringTag: { SlicedString* slicedString = SlicedString::cast(string); slice_offset += slicedString->offset(); string = slicedString->parent(); - type = string->map()->instance_type(); continue; } case kConsStringTag | kOneByteStringTag: case kConsStringTag | kTwoByteStringTag: - string = cons_op.Operate(string, &offset, &type, &length); - if (string == NULL) return; - slice_offset = offset; - ASSERT(length == static_cast(string->length())); - continue; + return ConsString::cast(string); default: UNREACHABLE(); - return; + return NULL; } } } -// TODO(dcarney): Remove this class after conversion to VisitFlat. -class ConsStringCaptureOp { - public: - inline ConsStringCaptureOp() : cons_string_(NULL) {} - inline String* Operate(String* string, unsigned*, int32_t*, unsigned*) { - cons_string_ = ConsString::cast(string); - return NULL; - } - ConsString* cons_string_; -}; - - -template -ConsString* String::VisitFlat(Visitor* visitor, - String* string, - int offset, - int length, - int32_t type) { - ASSERT(length >= 0 && length == string->length()); - ASSERT(offset >= 0 && offset <= length); - ConsStringCaptureOp op; - Visit(string, offset, *visitor, op, type, static_cast(length)); - return op.cons_string_; -} - - uint16_t SeqOneByteString::SeqOneByteStringGet(int index) { ASSERT(index >= 0 && index < length()); return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); @@ -3399,12 +3363,7 @@ const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData( } -String* ConsStringNullOp::Operate(String*, unsigned*, int32_t*, unsigned*) { - return NULL; -} - - -unsigned ConsStringIteratorOp::OffsetForDepth(unsigned depth) { +int ConsStringIteratorOp::OffsetForDepth(int depth) { return depth & kDepthMask; } @@ -3432,45 +3391,9 @@ void ConsStringIteratorOp::Pop() { } -bool ConsStringIteratorOp::HasMore() { - return depth_ != 0; -} - - -void ConsStringIteratorOp::Reset() { - depth_ = 0; -} - - -String* ConsStringIteratorOp::ContinueOperation(int32_t* type_out, - unsigned* length_out) { - bool blew_stack = false; - String* string = NextLeaf(&blew_stack, type_out, length_out); - // String found. - if (string != NULL) { - // Verify output. - ASSERT(*length_out == static_cast(string->length())); - ASSERT(*type_out == string->map()->instance_type()); - return string; - } - // Traversal complete. - if (!blew_stack) return NULL; - // Restart search from root. - unsigned offset_out; - string = Search(&offset_out, type_out, length_out); - // Verify output. - ASSERT(string == NULL || offset_out == 0); - ASSERT(string == NULL || - *length_out == static_cast(string->length())); - ASSERT(string == NULL || *type_out == string->map()->instance_type()); - return string; -} - - uint16_t StringCharacterStream::GetNext() { ASSERT(buffer8_ != NULL && end_ != NULL); // Advance cursor if needed. - // TODO(dcarney): Ensure uses of the api call HasMore first and avoid this. if (buffer8_ == end_) HasMore(); ASSERT(buffer8_ < end_); return is_one_byte_ ? *buffer8_++ : *buffer16_++; @@ -3479,41 +3402,39 @@ uint16_t StringCharacterStream::GetNext() { StringCharacterStream::StringCharacterStream(String* string, ConsStringIteratorOp* op, - unsigned offset) + int offset) : is_one_byte_(false), op_(op) { Reset(string, offset); } -void StringCharacterStream::Reset(String* string, unsigned offset) { - op_->Reset(); +void StringCharacterStream::Reset(String* string, int offset) { buffer8_ = NULL; end_ = NULL; - int32_t type = string->map()->instance_type(); - unsigned length = string->length(); - String::Visit(string, offset, *this, *op_, type, length); + ConsString* cons_string = String::VisitFlat(this, string, offset); + op_->Reset(cons_string, offset); + if (cons_string != NULL) { + string = op_->Next(&offset); + if (string != NULL) String::VisitFlat(this, string, offset); + } } bool StringCharacterStream::HasMore() { if (buffer8_ != end_) return true; - if (!op_->HasMore()) return false; - unsigned length; - int32_t type; - String* string = op_->ContinueOperation(&type, &length); + int offset; + String* string = op_->Next(&offset); + ASSERT_EQ(offset, 0); if (string == NULL) return false; - ASSERT(!string->IsConsString()); - ASSERT(string->length() != 0); - ConsStringNullOp null_op; - String::Visit(string, 0, *this, null_op, type, length); + String::VisitFlat(this, string); ASSERT(buffer8_ != end_); return true; } void StringCharacterStream::VisitOneByteString( - const uint8_t* chars, unsigned length) { + const uint8_t* chars, int length) { is_one_byte_ = true; buffer8_ = chars; end_ = chars + length; @@ -3521,7 +3442,7 @@ void StringCharacterStream::VisitOneByteString( void StringCharacterStream::VisitTwoByteString( - const uint16_t* chars, unsigned length) { + const uint16_t* chars, int length) { is_one_byte_ = false; buffer16_ = chars; end_ = reinterpret_cast(chars + length); diff --git a/src/objects.cc b/src/objects.cc index 1e9418e..f357e88 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -8826,34 +8826,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. @@ -8864,7 +8877,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. @@ -8876,7 +8889,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. @@ -8884,11 +8896,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(); @@ -8897,8 +8909,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(); @@ -8906,9 +8916,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) { @@ -8916,7 +8924,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; } @@ -8927,16 +8935,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(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) { @@ -8945,10 +8950,8 @@ String* ConsStringIteratorOp::NextLeaf(bool* blew_stack, type = string->map()->instance_type(); if ((type & kStringRepresentationMask) != kConsStringTag) { AdjustMaximumDepth(); - unsigned length = static_cast(string->length()); + int length = string->length(); ASSERT(length != 0); - *length_out = length; - *type_out = type; consumed_ += length; return string; } @@ -9223,25 +9226,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) { @@ -9254,18 +9261,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_; @@ -9283,18 +9288,18 @@ class StringComparator { } template - 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(state_1->buffer8_); const Chars2* b = reinterpret_cast(state_2->buffer8_); return RawStringComparator::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_) { @@ -9358,7 +9363,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(); @@ -9369,7 +9373,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(len), this, other); + return comparator.Equals(this, other); } @@ -9504,49 +9508,31 @@ bool String::IsTwoByteEqualTo(Vector str) { class IteratingStringHasher: public StringHasher { public: static inline uint32_t Hash(String* string, uint32_t seed) { - const unsigned len = static_cast(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(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(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); }; diff --git a/src/objects.h b/src/objects.h index 0ce8f97..86042ac 100644 --- a/src/objects.h +++ b/src/objects.h @@ -9209,29 +9209,10 @@ class String: public Name { return NonOneByteStart(chars, length) >= length; } - // TODO(dcarney): Replace all instances of this with VisitFlat. - template - static inline void Visit(String* string, - unsigned offset, - Visitor& visitor, - ConsOp& cons_op, - int32_t type, - unsigned length); - - template - static inline ConsString* VisitFlat(Visitor* visitor, - String* string, - int offset, - int length, - int32_t type); - template static inline ConsString* VisitFlat(Visitor* visitor, String* string, - int offset = 0) { - int32_t type = string->map()->instance_type(); - return VisitFlat(visitor, string, offset, string->length(), type); - } + int offset = 0); static Handle CalculateLineEnds(Handle string, bool include_ending_line); @@ -9617,57 +9598,63 @@ class ConsStringNullOp { // This maintains an off-stack representation of the stack frames required // to traverse a ConsString, allowing an entirely iterative and restartable // traversal of the entire string -// Note: this class is not GC-safe. class ConsStringIteratorOp { public: inline ConsStringIteratorOp() {} - String* Operate(String* string, - unsigned* offset_out, - int32_t* type_out, - unsigned* length_out); - inline String* ContinueOperation(int32_t* type_out, unsigned* length_out); - inline void Reset(); - inline bool HasMore(); + inline ConsStringIteratorOp(ConsString* cons_string, int offset = 0) { + Reset(cons_string, offset); + } + inline void Reset(ConsString* cons_string, int offset = 0) { + depth_ = 0; + // Next will always return NULL. + if (cons_string == NULL) return; + Initialize(cons_string, offset); + } + // Returns NULL when complete. + inline String* Next(int* offset_out) { + *offset_out = 0; + if (depth_ == 0) return NULL; + return Continue(offset_out); + } private: - // TODO(dcarney): Templatize this out for different stack sizes. - static const unsigned kStackSize = 32; + static const int kStackSize = 32; // Use a mask instead of doing modulo operations for stack wrapping. - static const unsigned kDepthMask = kStackSize-1; + static const int kDepthMask = kStackSize-1; STATIC_ASSERT(IS_POWER_OF_TWO(kStackSize)); - static inline unsigned OffsetForDepth(unsigned depth); + static inline int OffsetForDepth(int depth); inline void PushLeft(ConsString* string); inline void PushRight(ConsString* string); inline void AdjustMaximumDepth(); inline void Pop(); - String* NextLeaf(bool* blew_stack, int32_t* type_out, unsigned* length_out); - String* Search(unsigned* offset_out, - int32_t* type_out, - unsigned* length_out); + inline bool StackBlown() { return maximum_depth_ - depth_ == kStackSize; } + void Initialize(ConsString* cons_string, int offset); + String* Continue(int* offset_out); + String* NextLeaf(bool* blew_stack); + String* Search(int* offset_out); - unsigned depth_; - unsigned maximum_depth_; // Stack must always contain only frames for which right traversal // has not yet been performed. ConsString* frames_[kStackSize]; - unsigned consumed_; ConsString* root_; + int depth_; + int maximum_depth_; + int consumed_; DISALLOW_COPY_AND_ASSIGN(ConsStringIteratorOp); }; -// Note: this class is not GC-safe. class StringCharacterStream { public: inline StringCharacterStream(String* string, ConsStringIteratorOp* op, - unsigned offset = 0); + int offset = 0); inline uint16_t GetNext(); inline bool HasMore(); - inline void Reset(String* string, unsigned offset = 0); - inline void VisitOneByteString(const uint8_t* chars, unsigned length); - inline void VisitTwoByteString(const uint16_t* chars, unsigned length); + inline void Reset(String* string, int offset = 0); + inline void VisitOneByteString(const uint8_t* chars, int length); + inline void VisitTwoByteString(const uint16_t* chars, int length); private: bool is_one_byte_; diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc index cf7bb6f..f95000e 100644 --- a/test/cctest/test-strings.cc +++ b/test/cctest/test-strings.cc @@ -230,11 +230,11 @@ class ConsStringStats { } void Reset(); void VerifyEqual(const ConsStringStats& that) const; - unsigned leaves_; - unsigned empty_leaves_; - unsigned chars_; - unsigned left_traversals_; - unsigned right_traversals_; + int leaves_; + int empty_leaves_; + int chars_; + int left_traversals_; + int right_traversals_; private: DISALLOW_COPY_AND_ASSIGN(ConsStringStats); }; @@ -250,11 +250,11 @@ void ConsStringStats::Reset() { void ConsStringStats::VerifyEqual(const ConsStringStats& that) const { - CHECK(this->leaves_ == that.leaves_); - CHECK(this->empty_leaves_ == that.empty_leaves_); - CHECK(this->chars_ == that.chars_); - CHECK(this->left_traversals_ == that.left_traversals_); - CHECK(this->right_traversals_ == that.right_traversals_); + CHECK_EQ(this->leaves_, that.leaves_); + CHECK_EQ(this->empty_leaves_, that.empty_leaves_); + CHECK_EQ(this->chars_, that.chars_); + CHECK_EQ(this->left_traversals_, that.left_traversals_); + CHECK_EQ(this->right_traversals_, that.right_traversals_); } @@ -270,14 +270,14 @@ class ConsStringGenerationData { double leftness_; double rightness_; double empty_leaf_threshold_; - unsigned max_leaves_; + int max_leaves_; // Cached data. Handle building_blocks_[kNumberOfBuildingBlocks]; String* empty_string_; MyRandomNumberGenerator rng_; // Stats. ConsStringStats stats_; - unsigned early_terminations_; + int early_terminations_; private: DISALLOW_COPY_AND_ASSIGN(ConsStringGenerationData); }; @@ -356,23 +356,14 @@ void AccumulateStats(Handle cons_string, ConsStringStats* stats) { void AccumulateStatsWithOperator( ConsString* cons_string, ConsStringStats* stats) { - unsigned offset = 0; - int32_t type = cons_string->map()->instance_type(); - unsigned length = static_cast(cons_string->length()); - ConsStringIteratorOp op; - String* string = op.Operate(cons_string, &offset, &type, &length); - CHECK(string != NULL); - while (true) { - ASSERT(!string->IsConsString()); + ConsStringIteratorOp op(cons_string); + String* string; + int offset; + while (NULL != (string = op.Next(&offset))) { // Accumulate stats. + CHECK_EQ(0, offset); stats->leaves_++; stats->chars_ += string->length(); - // Check for completion. - bool keep_going_fast_check = op.HasMore(); - string = op.ContinueOperation(&type, &length); - if (string == NULL) return; - // Verify no false positives for fast check. - CHECK(keep_going_fast_check); } } @@ -380,7 +371,7 @@ void AccumulateStatsWithOperator( void VerifyConsString(Handle root, ConsStringGenerationData* data) { // Verify basic data. CHECK(root->IsConsString()); - CHECK(static_cast(root->length()) == data->stats_.chars_); + CHECK_EQ(root->length(), data->stats_.chars_); // Recursive verify. ConsStringStats stats; AccumulateStats(ConsString::cast(*root), &stats); @@ -625,9 +616,9 @@ static void VerifyCharacterStream( // Want to test the offset == length case. if (offset > length) offset = length; StringCharacterStream flat_stream( - flat_string, &cons_string_iterator_op_1, static_cast(offset)); + flat_string, &cons_string_iterator_op_1, offset); StringCharacterStream cons_stream( - cons_string, &cons_string_iterator_op_2, static_cast(offset)); + cons_string, &cons_string_iterator_op_2, offset); for (int i = offset; i < length; i++) { uint16_t c = flat_string->Get(i); CHECK(flat_stream.HasMore()); -- 2.7.4