Use realloc() to expand/shrink StringBuilder buffer

https://bugs.webkit.org/show_bug.cgi?id=69913

Patch by Xianzhu Wang <wangxianzhu@chromium.org> on 2011-10-13
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:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@97371 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 1e233187
2011-10-13 Xianzhu Wang <wangxianzhu@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 <fpizlo@apple.com>
If an Arguments object is being used to copy the arguments, then
......@@ -83,7 +83,7 @@ void StringBuilder::reserveCapacity(unsigned newCapacity)
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 @@ void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requ
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 @@ UChar* StringBuilder::appendUninitialized(unsigned length)
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 @@ void StringBuilder::shrinkToFit()
{
// 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;
}
}
......
......@@ -130,6 +130,7 @@ public:
private:
void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
void reallocateBuffer(unsigned requiredLength);
UChar* appendUninitialized(unsigned length);
void reifyString();
......
......@@ -90,6 +90,26 @@ PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*&
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 = 0;
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 = reinterpret_cast<UChar*>(string + 1);
return adoptRef(new (string) StringImpl(length));
}
PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned length)
{
if (!characters || !length)
......
......@@ -181,6 +181,11 @@ public:
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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment