Index: src/objects-inl.h |
diff --git a/src/objects-inl.h b/src/objects-inl.h |
index 0d83c4794666f1ed6e4b72bd1b74e8933e0d839b..33b8f0c1a952c00046ac7f8264e35c7cdbeb4229 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(); |
} |
@@ -268,6 +272,38 @@ bool String::IsTwoByteRepresentation() { |
} |
+bool String::IsAsciiRepresentationUnderneath() { |
+ uint32_t type = map()->instance_type(); |
+ STATIC_ASSERT(kIsIndirectStringTag != 0); |
+ STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0); |
+ ASSERT(IsFlat()); |
+ switch (type & (kIsIndirectStringMask | kStringEncodingMask)) { |
+ case kAsciiStringTag: |
+ return true; |
+ case kTwoByteStringTag: |
+ return false; |
+ default: // Cons or sliced string. Need to go deeper. |
+ return GetUnderlying()->IsAsciiRepresentation(); |
+ } |
+} |
+ |
+ |
+bool String::IsTwoByteRepresentationUnderneath() { |
+ uint32_t type = map()->instance_type(); |
+ STATIC_ASSERT(kIsIndirectStringTag != 0); |
+ STATIC_ASSERT((kIsIndirectStringMask & kStringEncodingMask) == 0); |
+ ASSERT(IsFlat()); |
+ switch (type & (kIsIndirectStringMask | kStringEncodingMask)) { |
+ case kAsciiStringTag: |
+ return false; |
+ case kTwoByteStringTag: |
+ return true; |
+ default: // Cons or sliced string. Need to go deeper. |
+ return GetUnderlying()->IsTwoByteRepresentation(); |
+ } |
+} |
+ |
+ |
bool String::HasOnlyAsciiChars() { |
uint32_t type = map()->instance_type(); |
return (type & kStringEncodingMask) == kAsciiStringTag || |
@@ -280,6 +316,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; |
} |
@@ -2030,6 +2076,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) |
@@ -2116,7 +2163,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); |
} |
@@ -2124,10 +2171,8 @@ 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); |
- } |
- return this; |
+ if (!flat->ToObject(&successfully_flattened)) return this; |
+ return String::cast(successfully_flattened); |
} |
@@ -2145,6 +2190,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; |
} |
@@ -2165,15 +2213,19 @@ void String::Set(int index, uint16_t value) { |
bool String::IsFlat() { |
- switch (StringShape(this).representation_tag()) { |
- case kConsStringTag: { |
- String* second = ConsString::cast(this)->second(); |
- // Only flattened strings have second part empty. |
- return second->length() == 0; |
- } |
- default: |
- return true; |
- } |
+ if (!StringShape(this).IsCons()) return true; |
+ return ConsString::cast(this)->second()->length() == 0; |
+} |
+ |
+ |
+String* String::GetUnderlying() { |
+ // Giving direct access to underlying string only makes sense if the |
+ // wrapping string is already flattened. |
+ ASSERT(this->IsFlat()); |
+ ASSERT(StringShape(this).IsIndirect()); |
+ STATIC_ASSERT(ConsString::kFirstOffset == SlicedString::kParentOffset); |
+ const int kUnderlyingOffset = SlicedString::kParentOffset; |
+ return String::cast(READ_FIELD(this, kUnderlyingOffset)); |
} |
@@ -2232,6 +2284,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)); |
} |