| Index: third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
|
| diff --git a/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp b/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
|
| index cb42fefa480b0aa32f03d22131e9d8205945ed00..317f93e8c564ad3cfdcdebae29f509ec50b79bcb 100644
|
| --- a/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
|
| +++ b/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
|
| @@ -18,6 +18,15 @@ namespace blink {
|
| // initial buffer.
|
| static const unsigned kDefaultInitialBufferSize = 32;
|
|
|
| +static inline char* alignAddress(char* address, size_t alignment)
|
| +{
|
| + char* aligned = reinterpret_cast<char*>(alignment * ((reinterpret_cast<size_t>(address) + alignment - 1) / alignment));
|
| + DCHECK_EQ(0u, reinterpret_cast<size_t>(aligned) % alignment);
|
| + DCHECK(aligned >= address);
|
| + DCHECK(aligned < address + alignment);
|
| + return aligned;
|
| +}
|
| +
|
| class ContiguousContainerBase::Buffer {
|
| WTF_MAKE_NONCOPYABLE(Buffer);
|
| USING_FAST_MALLOC(Buffer);
|
| @@ -38,17 +47,19 @@ public:
|
|
|
| size_t capacity() const { return m_capacity; }
|
| size_t usedCapacity() const { return m_end - m_begin; }
|
| - size_t unusedCapacity() const { return capacity() - usedCapacity(); }
|
| bool isEmpty() const { return usedCapacity() == 0; }
|
|
|
| - void* allocate(size_t objectSize)
|
| + void* allocate(size_t objectSize, size_t alignment)
|
| {
|
| - ASSERT(unusedCapacity() >= objectSize);
|
| + char* alignedAddress = alignAddress(m_end, alignment);
|
| + if (alignedAddress - m_begin + objectSize > m_capacity)
|
| + return nullptr;
|
| ANNOTATE_CHANGE_SIZE(
|
| - m_begin, m_capacity, usedCapacity(), usedCapacity() + objectSize);
|
| - void* result = m_end;
|
| - m_end += objectSize;
|
| - return result;
|
| + m_begin, m_capacity, usedCapacity(), usedCapacity() + (alignedAddress - m_end) + objectSize);
|
| + if (isEmpty())
|
| + m_firstObject = alignedAddress;
|
| + m_end = alignedAddress + objectSize;
|
| + return alignedAddress;
|
| }
|
|
|
| void deallocateLastObject(void* object)
|
| @@ -57,11 +68,20 @@ public:
|
| ANNOTATE_CHANGE_SIZE(
|
| m_begin, m_capacity, usedCapacity(), static_cast<char*>(object) - m_begin);
|
| m_end = static_cast<char*>(object);
|
| + if (m_end == m_firstObject) {
|
| + // We have deallocated the first object in this buffer. Reset m_end so that
|
| + // isEmpty() can return correct value.
|
| + m_end = m_begin;
|
| + }
|
| + // Otherwise we may leave a gap between the end of the previous object (which we
|
| + // don't know) and m_end because of alignment of the deallocated object.
|
| }
|
|
|
| private:
|
| - // m_begin <= m_end <= m_begin + m_capacity
|
| + // m_begin <= m_firstObject <= m_end <= m_begin + m_capacity
|
| char* m_begin;
|
| + // Because of alignment, the first object may be allocated after m_begin.
|
| + char* m_firstObject;
|
| char* m_end;
|
| size_t m_capacity;
|
| };
|
| @@ -115,27 +135,24 @@ void ContiguousContainerBase::reserveInitialCapacity(size_t bufferSize, const ch
|
| allocateNewBufferForNextAllocation(bufferSize, typeName);
|
| }
|
|
|
| -void* ContiguousContainerBase::allocate(size_t objectSize, const char* typeName)
|
| +void* ContiguousContainerBase::allocate(size_t objectSize, size_t alignment, const char* typeName)
|
| {
|
| - ASSERT(objectSize <= m_maxObjectSize);
|
| -
|
| - Buffer* bufferForAlloc = nullptr;
|
| - if (!m_buffers.isEmpty()) {
|
| - Buffer* endBuffer = m_buffers[m_endIndex].get();
|
| - if (endBuffer->unusedCapacity() >= objectSize)
|
| - bufferForAlloc = endBuffer;
|
| - else if (m_endIndex + 1 < m_buffers.size())
|
| - bufferForAlloc = m_buffers[++m_endIndex].get();
|
| - }
|
| + DCHECK(objectSize <= m_maxObjectSize);
|
|
|
| - if (!bufferForAlloc) {
|
| - size_t newBufferSize = m_buffers.isEmpty()
|
| - ? kDefaultInitialBufferSize * m_maxObjectSize
|
| - : 2 * m_buffers.last()->capacity();
|
| - bufferForAlloc = allocateNewBufferForNextAllocation(newBufferSize, typeName);
|
| + void* element = m_buffers.isEmpty() ? nullptr : m_buffers[m_endIndex]->allocate(objectSize, alignment);
|
| + if (!element) {
|
| + Buffer* bufferForAlloc;
|
| + if (m_endIndex + 1 < m_buffers.size()) {
|
| + bufferForAlloc = m_buffers[++m_endIndex].get();
|
| + } else {
|
| + size_t newBufferSize = m_buffers.isEmpty()
|
| + ? kDefaultInitialBufferSize * m_maxObjectSize
|
| + : 2 * m_buffers.last()->capacity();
|
| + bufferForAlloc = allocateNewBufferForNextAllocation(newBufferSize, typeName);
|
| + }
|
| + element = bufferForAlloc->allocate(objectSize, alignment);
|
| + DCHECK(element);
|
| }
|
| -
|
| - void* element = bufferForAlloc->allocate(objectSize);
|
| m_elements.append(element);
|
| return element;
|
| }
|
|
|