Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (97370 => 97371)
--- trunk/Source/_javascript_Core/ChangeLog 2011-10-13 16:55:13 UTC (rev 97370)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-10-13 17:00:59 UTC (rev 97371)
@@ -1,3 +1,20 @@
+2011-10-13 Xianzhu Wang <wangxian...@chromium.org>
+
+ Use realloc() to expand/shrink StringBuilder buffer
+ https://bugs.webkit.org/show_bug.cgi?id=69913
+
+ Reviewed by Darin Adler.
+
+ * wtf/text/StringBuilder.cpp:
+ (WTF::StringBuilder::reserveCapacity):
+ (WTF::StringBuilder::reallocateBuffer):
+ (WTF::StringBuilder::appendUninitialized):
+ (WTF::StringBuilder::shrinkToFit):
+ * wtf/text/StringBuilder.h:
+ * wtf/text/StringImpl.cpp:
+ (WTF::StringImpl::reallocate): Added to allow StringBuilder to reallocate the buffer.
+ * wtf/text/StringImpl.h:
+
2011-10-12 Filip Pizlo <fpi...@apple.com>
If an Arguments object is being used to copy the arguments, then
Modified: trunk/Source/_javascript_Core/wtf/text/StringBuilder.cpp (97370 => 97371)
--- trunk/Source/_javascript_Core/wtf/text/StringBuilder.cpp 2011-10-13 16:55:13 UTC (rev 97370)
+++ trunk/Source/_javascript_Core/wtf/text/StringBuilder.cpp 2011-10-13 17:00:59 UTC (rev 97371)
@@ -83,7 +83,7 @@
if (m_buffer) {
// If there is already a buffer, then grow if necessary.
if (newCapacity > m_buffer->length())
- allocateBuffer(m_buffer->characters(), newCapacity);
+ reallocateBuffer(newCapacity);
} else {
// Grow the string, if necessary.
if (newCapacity > m_length)
@@ -104,13 +104,24 @@
m_string = String();
}
+void StringBuilder::reallocateBuffer(unsigned requiredLength)
+{
+ // If the buffer has only one ref (by this StringBuilder), reallocate it,
+ // otherwise fall back to "allocate and copy" method.
+ m_string = String();
+ if (m_buffer->hasOneRef())
+ m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_bufferCharacters);
+ else
+ allocateBuffer(m_buffer->characters(), requiredLength);
+}
+
// Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
// return a pointer to the newly allocated storage.
UChar* StringBuilder::appendUninitialized(unsigned length)
{
ASSERT(length);
- // Calcuate the new size of the builder after appending.
+ // Calculate the new size of the builder after appending.
unsigned requiredLength = length + m_length;
if (requiredLength < length)
CRASH();
@@ -127,8 +138,7 @@
return m_bufferCharacters + currentLength;
}
- // We need to realloc the buffer.
- allocateBuffer(m_buffer->characters(), std::max(requiredLength, std::max(minimumCapacity, m_buffer->length() * 2)));
+ reallocateBuffer(std::max(requiredLength, std::max(minimumCapacity, m_buffer->length() * 2)));
} else {
ASSERT(m_string.length() == m_length);
allocateBuffer(m_string.characters(), std::max(requiredLength, std::max(minimumCapacity, m_length * 2)));
@@ -164,9 +174,8 @@
{
// If the buffer is at least 80% full, don't bother copying. Need to tune this heuristic!
if (m_buffer && m_buffer->length() > (m_length + (m_length >> 2))) {
- UChar* result;
- m_string = StringImpl::createUninitialized(m_length, result);
- memcpy(result, m_buffer->characters(), static_cast<size_t>(m_length) * 2); // This can't overflow.
+ reallocateBuffer(m_length);
+ m_string = m_buffer;
m_buffer = 0;
}
}
Modified: trunk/Source/_javascript_Core/wtf/text/StringBuilder.h (97370 => 97371)
--- trunk/Source/_javascript_Core/wtf/text/StringBuilder.h 2011-10-13 16:55:13 UTC (rev 97370)
+++ trunk/Source/_javascript_Core/wtf/text/StringBuilder.h 2011-10-13 17:00:59 UTC (rev 97371)
@@ -130,6 +130,7 @@
private:
void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
+ void reallocateBuffer(unsigned requiredLength);
UChar* appendUninitialized(unsigned length);
void reifyString();
Modified: trunk/Source/_javascript_Core/wtf/text/StringImpl.cpp (97370 => 97371)
--- trunk/Source/_javascript_Core/wtf/text/StringImpl.cpp 2011-10-13 16:55:13 UTC (rev 97370)
+++ trunk/Source/_javascript_Core/wtf/text/StringImpl.cpp 2011-10-13 17:00:59 UTC (rev 97371)
@@ -90,6 +90,26 @@
return adoptRef(new (string) StringImpl(length));
}
+PassRefPtr<StringImpl> StringImpl::reallocate(PassRefPtr<StringImpl> originalString, unsigned length, UChar*& data)
+{
+ ASSERT(originalString->hasOneRef() && originalString->bufferOwnership() == BufferInternal);
+
+ if (!length) {
+ data = ""
+ return empty();
+ }
+
+ // Same as createUninitialized() except here we use fastRealloc.
+ if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(UChar)))
+ CRASH();
+ size_t size = sizeof(StringImpl) + length * sizeof(UChar);
+ originalString->~StringImpl();
+ StringImpl* string = static_cast<StringImpl*>(fastRealloc(originalString.leakRef(), size));
+
+ data = "" + 1);
+ return adoptRef(new (string) StringImpl(length));
+}
+
PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length)
{
if (!characters || !length)
Modified: trunk/Source/_javascript_Core/wtf/text/StringImpl.h (97370 => 97371)
--- trunk/Source/_javascript_Core/wtf/text/StringImpl.h 2011-10-13 16:55:13 UTC (rev 97370)
+++ trunk/Source/_javascript_Core/wtf/text/StringImpl.h 2011-10-13 17:00:59 UTC (rev 97371)
@@ -181,6 +181,11 @@
return adoptRef(new(resultImpl) StringImpl(length));
}
+ // Reallocate the StringImpl. The originalString must be only owned by the PassRefPtr,
+ // and the buffer ownership must be BufferInternal. Just like the input pointer of realloc(),
+ // the originalString can't be used after this function.
+ static PassRefPtr<StringImpl> reallocate(PassRefPtr<StringImpl> originalString, unsigned length, UChar*& data);
+
static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data); }
static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&);
static PassRefPtr<StringImpl> createStrippingNullCharacters(const UChar*, unsigned length);