Try flattening strings before comparing for equality.

Review URL: http://codereview.chromium.org/2076010

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4684 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
vitalyr@chromium.org 2010-05-20 09:01:39 +00:00
parent af70ad5fdc
commit 91cbd98dfc
4 changed files with 66 additions and 43 deletions

View File

@ -2080,7 +2080,7 @@ Object* Heap::AllocateSubString(String* buffer,
}
// Make an attempt to flatten the buffer to reduce access time.
buffer->TryFlatten();
buffer = buffer->TryFlattenGetString();
Object* result = buffer->IsAsciiRepresentation()
? AllocateRawAsciiString(length, pretenure )

View File

@ -1691,13 +1691,19 @@ bool String::Equals(String* other) {
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()) {

View File

@ -631,7 +631,7 @@ Object* String::SlowTryFlatten(PretenureFlag pretenure) {
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
@ -669,7 +669,7 @@ Object* String::SlowTryFlatten(PretenureFlag pretenure) {
}
cs->set_first(result);
cs->set_second(Heap::empty_string());
return this;
return result;
}
default:
return this;
@ -4580,51 +4580,58 @@ bool String::SlowEquals(String* other) {
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);
}
}
@ -7038,15 +7045,9 @@ class SymbolKey : public HashTableKey {
}
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) {

View File

@ -4001,17 +4001,28 @@ class String: public HeapObject {
// 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();
@ -4197,6 +4208,11 @@ class String: public HeapObject {
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);