| Index: src/objects-inl.h
|
| diff --git a/src/objects-inl.h b/src/objects-inl.h
|
| index 53a3183694cbfdfc87f16524888036e27d434d14..dbfdb6c33f5ce118919aa64dd67d3bacd9b43210 100644
|
| --- a/src/objects-inl.h
|
| +++ b/src/objects-inl.h
|
| @@ -177,10 +177,14 @@ bool Object::IsSymbol() {
|
|
|
|
|
| bool Object::IsConsString() {
|
| - if (!this->IsHeapObject()) return false;
|
| - uint32_t type = HeapObject::cast(this)->map()->instance_type();
|
| - return (type & (kIsNotStringMask | kStringRepresentationMask)) ==
|
| - (kStringTag | kConsStringTag);
|
| + if (!IsString()) return false;
|
| + return StringShape(String::cast(this)).IsCons();
|
| +}
|
| +
|
| +
|
| +bool Object::IsSlicedString() {
|
| + if (!IsString()) return false;
|
| + return StringShape(String::cast(this)).IsSliced();
|
| }
|
|
|
|
|
| @@ -280,6 +284,16 @@ bool StringShape::IsCons() {
|
| }
|
|
|
|
|
| +bool StringShape::IsSliced() {
|
| + return (type_ & kStringRepresentationMask) == kSlicedStringTag;
|
| +}
|
| +
|
| +
|
| +bool StringShape::IsIndirect() {
|
| + return (type_ & kIsIndirectStringMask) == kIsIndirectStringTag;
|
| +}
|
| +
|
| +
|
| bool StringShape::IsExternal() {
|
| return (type_ & kStringRepresentationMask) == kExternalStringTag;
|
| }
|
| @@ -2041,6 +2055,7 @@ CAST_ACCESSOR(String)
|
| CAST_ACCESSOR(SeqString)
|
| CAST_ACCESSOR(SeqAsciiString)
|
| CAST_ACCESSOR(SeqTwoByteString)
|
| +CAST_ACCESSOR(SlicedString)
|
| CAST_ACCESSOR(ConsString)
|
| CAST_ACCESSOR(ExternalString)
|
| CAST_ACCESSOR(ExternalAsciiString)
|
| @@ -2127,7 +2142,7 @@ bool String::Equals(String* other) {
|
| MaybeObject* String::TryFlatten(PretenureFlag pretenure) {
|
| if (!StringShape(this).IsCons()) return this;
|
| ConsString* cons = ConsString::cast(this);
|
| - if (cons->second()->length() == 0) return cons->first();
|
| + if (cons->IsFlat()) return cons->first();
|
| return SlowTryFlatten(pretenure);
|
| }
|
|
|
| @@ -2135,10 +2150,42 @@ MaybeObject* String::TryFlatten(PretenureFlag pretenure) {
|
| String* String::TryFlattenGetString(PretenureFlag pretenure) {
|
| MaybeObject* flat = TryFlatten(pretenure);
|
| Object* successfully_flattened;
|
| - if (flat->ToObject(&successfully_flattened)) {
|
| - return String::cast(successfully_flattened);
|
| + if (!flat->ToObject(&successfully_flattened)) return this;
|
| + return String::cast(successfully_flattened);
|
| +}
|
| +
|
| +
|
| +MaybeObject* String::TryTruncate(PretenureFlag pretenure) {
|
| + if (!StringShape(this).IsSliced()) return this;
|
| + SlicedString* slice = SlicedString::cast(this);
|
| + if (slice->IsTruncated()) return slice->parent();
|
| + return SlowTryTruncate(pretenure);
|
| +}
|
| +
|
| +
|
| +String* String::TryTruncateGetString(PretenureFlag pretenure) {
|
| + MaybeObject* truncate = TryTruncate(pretenure);
|
| + Object* successfully_truncated;
|
| + if (!truncate->ToObject(&successfully_truncated)) return this;
|
| + return String::cast(successfully_truncated);
|
| +}
|
| +
|
| +
|
| +MaybeObject* String::TryFlattenOrTruncate(PretenureFlag pretenure) {
|
| + switch (StringShape(this).representation_tag()) {
|
| + case kSlicedStringTag: {
|
| + SlicedString* slice = SlicedString::cast(this);
|
| + if (slice->IsTruncated()) return slice->parent();
|
| + return SlowTryTruncate(pretenure);
|
| + }
|
| + case kConsStringTag: {
|
| + ConsString* cons = ConsString::cast(this);
|
| + if (cons->IsFlat()) return cons->first();
|
| + return SlowTryFlatten(pretenure);
|
| + }
|
| + default:
|
| + return this;
|
| }
|
| - return this;
|
| }
|
|
|
|
|
| @@ -2156,6 +2203,9 @@ uint16_t String::Get(int index) {
|
| return ExternalAsciiString::cast(this)->ExternalAsciiStringGet(index);
|
| case kExternalStringTag | kTwoByteStringTag:
|
| return ExternalTwoByteString::cast(this)->ExternalTwoByteStringGet(index);
|
| + case kSlicedStringTag | kAsciiStringTag:
|
| + case kSlicedStringTag | kTwoByteStringTag:
|
| + return SlicedString::cast(this)->SlicedStringGet(index);
|
| default:
|
| break;
|
| }
|
| @@ -2176,18 +2226,43 @@ void String::Set(int index, uint16_t value) {
|
|
|
|
|
| bool String::IsFlat() {
|
| + if (!StringShape(this).IsCons()) return true;
|
| + return ConsString::cast(this)->second() == GetHeap()->empty_string();
|
| +}
|
| +
|
| +
|
| +bool String::IsTruncated() {
|
| + if (!StringShape(this).IsSliced()) return true;
|
| + SlicedString* slice = SlicedString::cast(this);
|
| + return slice->parent()->length() == slice->length();
|
| +}
|
| +
|
| +
|
| +bool String::IsFlatAndTruncated() {
|
| switch (StringShape(this).representation_tag()) {
|
| - case kConsStringTag: {
|
| - String* second = ConsString::cast(this)->second();
|
| - // Only flattened strings have second part empty.
|
| - return second->length() == 0;
|
| + case kSlicedStringTag: {
|
| + SlicedString* slice = SlicedString::cast(this);
|
| + return slice->parent()->length() == slice->length();
|
| }
|
| + case kConsStringTag:
|
| + return ConsString::cast(this)->second() == GetHeap()->empty_string();
|
| default:
|
| return true;
|
| }
|
| }
|
|
|
|
|
| +String* String::GetIndirect() {
|
| + STATIC_ASSERT(ConsString::kFirstOffset == SlicedString::kParentOffset);
|
| + // Giving direct access to underlying string only makes sense if the
|
| + // wrapping string is already flattened/truncated.
|
| + ASSERT(this->IsFlat());
|
| + ASSERT(this->IsTruncated());
|
| + ASSERT(StringShape(this).IsIndirect());
|
| + return String::cast(reinterpret_cast<ConsString*>(this)->first());
|
| +}
|
| +
|
| +
|
| uint16_t SeqAsciiString::SeqAsciiStringGet(int index) {
|
| ASSERT(index >= 0 && index < length());
|
| return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
|
| @@ -2243,6 +2318,20 @@ int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
|
| }
|
|
|
|
|
| +String* SlicedString::parent() {
|
| + return String::cast(READ_FIELD(this, kParentOffset));
|
| +}
|
| +
|
| +
|
| +void SlicedString::set_parent(String* parent) {
|
| + ASSERT(parent->IsSeqString());
|
| + WRITE_FIELD(this, kParentOffset, parent);
|
| +}
|
| +
|
| +
|
| +SMI_ACCESSORS(SlicedString, offset, kOffsetOffset)
|
| +
|
| +
|
| String* ConsString::first() {
|
| return String::cast(READ_FIELD(this, kFirstOffset));
|
| }
|
|
|