Index: src/objects-inl.h |
diff --git a/src/objects-inl.h b/src/objects-inl.h |
index b99ba44723122cbd4b38fa9e1cdd1b070c7710d9..da82082c79992823144815bf9493eaadb5fabc72 100644 |
--- a/src/objects-inl.h |
+++ b/src/objects-inl.h |
@@ -2512,6 +2512,77 @@ String* String::GetUnderlying() { |
} |
+template<class Visitor, class ConsOp> |
+void String::Visit( |
+ String* string, |
+ unsigned offset, |
+ Visitor& visitor, |
+ ConsOp& consOp, |
+ int32_t type, |
+ unsigned length) { |
+ |
+ ASSERT(length == static_cast<unsigned>(string->length())); |
+ ASSERT(offset <= length); |
+ |
+ unsigned sliceOffset = offset; |
+ while (true) { |
+ ASSERT(type == string->map()->instance_type()); |
+ |
+ switch (type & (kStringRepresentationMask | kStringEncodingMask)) { |
+ case kSeqStringTag | kOneByteStringTag: |
+ visitor.VisitOneByteString( |
+ reinterpret_cast<const uint8_t*>( |
+ SeqOneByteString::cast(string)->GetChars()) + sliceOffset, |
+ length - offset); |
+ return; |
+ |
+ case kSeqStringTag | kTwoByteStringTag: |
+ visitor.VisitTwoByteString( |
+ reinterpret_cast<const uint16_t*>( |
+ SeqTwoByteString::cast(string)->GetChars()) + sliceOffset, |
+ length - offset); |
+ return; |
+ |
+ case kExternalStringTag | kOneByteStringTag: |
+ visitor.VisitOneByteString( |
+ reinterpret_cast<const uint8_t*>( |
+ ExternalAsciiString::cast(string)->GetChars()) + sliceOffset, |
+ length - offset); |
+ return; |
+ |
+ case kExternalStringTag | kTwoByteStringTag: |
+ visitor.VisitTwoByteString( |
+ reinterpret_cast<const uint16_t*>( |
+ ExternalTwoByteString::cast(string)->GetChars()) + sliceOffset, |
+ length - offset); |
+ return; |
+ |
+ case kSlicedStringTag | kOneByteStringTag: |
+ case kSlicedStringTag | kTwoByteStringTag: { |
+ SlicedString* slicedString = SlicedString::cast(string); |
+ sliceOffset += slicedString->offset(); |
+ string = slicedString->parent(); |
+ type = string->map()->instance_type(); |
+ continue; |
+ } |
+ |
+ case kConsStringTag | kOneByteStringTag: |
+ case kConsStringTag | kTwoByteStringTag: |
+ string = consOp.Operate(ConsString::cast(string), &offset, &type, |
+ &length); |
+ if (string == NULL) return; |
+ sliceOffset = offset; |
+ ASSERT(length == static_cast<unsigned>(string->length())); |
+ continue; |
+ |
+ default: |
+ UNREACHABLE(); |
+ return; |
+ } |
+ } |
+} |
+ |
+ |
uint16_t SeqOneByteString::SeqOneByteStringGet(int index) { |
ASSERT(index >= 0 && index < length()); |
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); |
@@ -2690,6 +2761,144 @@ const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData( |
} |
+unsigned ConsStringIteratorOp::OffsetForDepth(unsigned depth) { |
+ return depth & kDepthMask; |
+} |
+ |
+ |
+uint32_t ConsStringIteratorOp::MaskForDepth(unsigned depth) { |
+ return 1 << OffsetForDepth(depth); |
+} |
+ |
+ |
+void ConsStringIteratorOp::SetRightDescent() { |
+ trace_ |= MaskForDepth(depth_ - 1); |
+} |
+ |
+ |
+void ConsStringIteratorOp::ClearRightDescent() { |
+ trace_ &= ~MaskForDepth(depth_ - 1); |
+} |
+ |
+ |
+void ConsStringIteratorOp::PushLeft(ConsString* string) { |
+ frames_[depth_++ & kDepthMask] = string; |
+} |
+ |
+ |
+void ConsStringIteratorOp::PushRight(ConsString* string, int32_t type) { |
+ // Inplace update |
+ frames_[depth_-1 & kDepthMask] = string; |
+ if (depth_ != 1) return; |
+ // Optimization: can replace root in this case. |
+ root_ = string; |
+ root_type_ = type; |
+ root_length_ = string->length(); |
+} |
+ |
+ |
+void ConsStringIteratorOp::AdjustMaximumDepth() { |
+ if (depth_ > maximum_depth_) maximum_depth_ = depth_; |
+} |
+ |
+ |
+void ConsStringIteratorOp::Pop() { |
+ ASSERT(depth_ > 0); |
+ ASSERT(depth_ <= maximum_depth_); |
+ depth_--; |
+} |
+ |
+ |
+void ConsStringIteratorOp::Reset() { |
+ consumed_ = 0; |
+ ResetStack(); |
+} |
+ |
+ |
+bool ConsStringIteratorOp::HasMore() { |
+ return depth_ != 0; |
+} |
+ |
+ |
+void ConsStringIteratorOp::ResetStack() { |
+ depth_ = 0; |
+ maximum_depth_ = 0; |
+} |
+ |
+ |
+bool ConsStringIteratorOp::ContinueOperation(ContinueResponse* response) { |
+ bool blewStack; |
+ int32_t type; |
+ String* string = NextLeaf(&blewStack, &type); |
+ // String found. |
+ if (string != NULL) { |
+ unsigned length = string->length(); |
+ consumed_ += length; |
+ response->string_ = string; |
+ response->offset_ = 0; |
+ response->length_ = length; |
+ response->type_ = type; |
+ return true; |
+ } |
+ // Traversal complete. |
+ if (!blewStack) return false; |
+ // Restart search. |
+ ResetStack(); |
+ response->string_ = root_; |
+ response->offset_ = consumed_; |
+ response->length_ = root_length_; |
+ response->type_ = root_type_; |
+ return true; |
+} |
+ |
+ |
+uint16_t StringCharacterStream::GetNext() { |
+ return is_one_byte_ ? *buffer8_++ : *buffer16_++; |
+} |
+ |
+ |
+StringCharacterStream::StringCharacterStream( |
+ String* string, unsigned offset, ConsStringIteratorOp* op) |
+ : buffer8_(NULL), |
+ end_(NULL), |
+ op_(op) { |
+ op->Reset(); |
+ String::Visit(string, |
+ offset, *this, *op, string->map()->instance_type(), string->length()); |
+} |
+ |
+ |
+bool StringCharacterStream::HasMore() { |
+ if (buffer8_ != end_) return true; |
+ if (!op_->HasMore()) return false; |
+ ConsStringIteratorOp::ContinueResponse response; |
+ // This has been checked above |
+ if (!op_->ContinueOperation(&response)) { |
+ UNREACHABLE(); |
+ return false; |
+ } |
+ String::Visit(response.string_, |
+ response.offset_, *this, *op_, response.type_, response.length_); |
+ return true; |
+} |
+ |
+ |
+void StringCharacterStream::VisitOneByteString( |
+ const uint8_t* chars, unsigned length) { |
+ is_one_byte_ = true; |
+ buffer8_ = chars; |
+ end_ = chars + length; |
+} |
+ |
+ |
+void StringCharacterStream::VisitTwoByteString( |
+ const uint16_t* chars, unsigned length) { |
+ is_one_byte_ = false; |
+ buffer16_ = chars; |
+ end_ = reinterpret_cast<const uint8_t*>(chars + length); |
+} |
+ |
+ |
void JSFunctionResultCache::MakeZeroSize() { |
set_finger_index(kEntriesIndex); |
set_size(kEntriesIndex); |