| 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);
|
|
|