Object* String::TryFlatten(PretenureFlag pretenure) {
- // We don't need to flatten strings that are already flat. Since this code
- // is inlined, it can be helpful in the flat case to not call out to Flatten.
- if (IsFlat()) return this;
+ if (!StringShape(this).IsCons()) return this;
+ ConsString* cons = ConsString::cast(this);
+ if (cons->second()->length() == 0) return cons->first();
return SlowTryFlatten(pretenure);
}
+String* String::TryFlattenGetString(PretenureFlag pretenure) {
+ Object* flat = TryFlatten(pretenure);
+ return flat->IsFailure() ? this : String::cast(flat);
+}
+
+
uint16_t String::Get(int index) {
ASSERT(index >= 0 && index < length());
switch (StringShape(this).full_representation_tag()) {
case kConsStringTag: {
ConsString* cs = ConsString::cast(this);
if (cs->second()->length() == 0) {
- return this;
+ return cs->first();
}
// There's little point in putting the flat string in new space if the
// cons string is in old space. It can never get GCed until there is
}
cs->set_first(result);
cs->set_second(Heap::empty_string());
- return this;
+ return result;
}
default:
return this;
if (Hash() != other->Hash()) return false;
}
- if (StringShape(this).IsSequentialAscii() &&
- StringShape(other).IsSequentialAscii()) {
- const char* str1 = SeqAsciiString::cast(this)->GetChars();
- const char* str2 = SeqAsciiString::cast(other)->GetChars();
+ // We know the strings are both non-empty. Compare the first chars
+ // before we try to flatten the strings.
+ if (this->Get(0) != other->Get(0)) return false;
+
+ String* lhs = this->TryFlattenGetString();
+ String* rhs = other->TryFlattenGetString();
+
+ if (StringShape(lhs).IsSequentialAscii() &&
+ StringShape(rhs).IsSequentialAscii()) {
+ const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
+ const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
return CompareRawStringContents(Vector<const char>(str1, len),
Vector<const char>(str2, len));
}
- if (this->IsFlat()) {
+ if (lhs->IsFlat()) {
if (IsAsciiRepresentation()) {
- Vector<const char> vec1 = this->ToAsciiVector();
- if (other->IsFlat()) {
- if (other->IsAsciiRepresentation()) {
- Vector<const char> vec2 = other->ToAsciiVector();
+ Vector<const char> vec1 = lhs->ToAsciiVector();
+ if (rhs->IsFlat()) {
+ if (rhs->IsAsciiRepresentation()) {
+ Vector<const char> vec2 = rhs->ToAsciiVector();
return CompareRawStringContents(vec1, vec2);
} else {
VectorIterator<char> buf1(vec1);
- VectorIterator<uc16> ib(other->ToUC16Vector());
+ VectorIterator<uc16> ib(rhs->ToUC16Vector());
return CompareStringContents(&buf1, &ib);
}
} else {
VectorIterator<char> buf1(vec1);
- string_compare_buffer_b.Reset(0, other);
+ string_compare_buffer_b.Reset(0, rhs);
return CompareStringContents(&buf1, &string_compare_buffer_b);
}
} else {
- Vector<const uc16> vec1 = this->ToUC16Vector();
- if (other->IsFlat()) {
- if (other->IsAsciiRepresentation()) {
+ Vector<const uc16> vec1 = lhs->ToUC16Vector();
+ if (rhs->IsFlat()) {
+ if (rhs->IsAsciiRepresentation()) {
VectorIterator<uc16> buf1(vec1);
- VectorIterator<char> ib(other->ToAsciiVector());
+ VectorIterator<char> ib(rhs->ToAsciiVector());
return CompareStringContents(&buf1, &ib);
} else {
- Vector<const uc16> vec2(other->ToUC16Vector());
+ Vector<const uc16> vec2(rhs->ToUC16Vector());
return CompareRawStringContents(vec1, vec2);
}
} else {
VectorIterator<uc16> buf1(vec1);
- string_compare_buffer_b.Reset(0, other);
+ string_compare_buffer_b.Reset(0, rhs);
return CompareStringContents(&buf1, &string_compare_buffer_b);
}
}
} else {
- string_compare_buffer_a.Reset(0, this);
- return CompareStringContentsPartial(&string_compare_buffer_a, other);
+ string_compare_buffer_a.Reset(0, lhs);
+ return CompareStringContentsPartial(&string_compare_buffer_a, rhs);
}
}
}
Object* AsObject() {
- // If the string is a cons string, attempt to flatten it so that
- // symbols will most often be flat strings.
- if (StringShape(string_).IsCons()) {
- ConsString* cons_string = ConsString::cast(string_);
- cons_string->TryFlatten();
- if (cons_string->second()->length() == 0) {
- string_ = cons_string->first();
- }
- }
+ // Attempt to flatten the string, so that symbols will most often
+ // be flat strings.
+ string_ = string_->TryFlattenGetString();
// Transform string to symbol if possible.
Map* map = Heap::SymbolMapForString(string_);
if (map != NULL) {
// to this method are not efficient unless the string is flat.
inline uint16_t Get(int index);
- // Try to flatten the top level ConsString that is hiding behind this
- // string. This is a no-op unless the string is a ConsString. Flatten
- // mutates the ConsString and might return a failure.
- Object* SlowTryFlatten(PretenureFlag pretenure);
-
- // Try to flatten the string. Checks first inline to see if it is necessary.
- // Do not handle allocation failures. After calling TryFlatten, the
- // string could still be a ConsString, in which case a failure is returned.
- // Use FlattenString from Handles.cc to be sure to flatten.
+ // Try to flatten the string. Checks first inline to see if it is
+ // necessary. Does nothing if the string is not a cons string.
+ // Flattening allocates a sequential string with the same data as
+ // the given string and mutates the cons string to a degenerate
+ // form, where the first component is the new sequential string and
+ // the second component is the empty string. If allocation fails,
+ // this function returns a failure. If flattening succeeds, this
+ // function returns the sequential string that is now the first
+ // component of the cons string.
+ //
+ // Degenerate cons strings are handled specially by the garbage
+ // collector (see IsShortcutCandidate).
+ //
+ // Use FlattenString from Handles.cc to flatten even in case an
+ // allocation failure happens.
inline Object* TryFlatten(PretenureFlag pretenure = NOT_TENURED);
+ // Convenience function. Has exactly the same behavior as
+ // TryFlatten(), except in the case of failure returns the original
+ // string.
+ inline String* TryFlattenGetString(PretenureFlag pretenure = NOT_TENURED);
+
Vector<const char> ToAsciiVector();
Vector<const uc16> ToUC16Vector();
unsigned max_chars);
private:
+ // Try to flatten the top level ConsString that is hiding behind this
+ // string. This is a no-op unless the string is a ConsString. Flatten
+ // mutates the ConsString and might return a failure.
+ Object* SlowTryFlatten(PretenureFlag pretenure);
+
// Slow case of String::Equals. This implementation works on any strings
// but it is most efficient on strings that are almost flat.
bool SlowEquals(String* other);