| Index: cc/base/contiguous_container.cc
|
| diff --git a/cc/base/contiguous_container.cc b/cc/base/contiguous_container.cc
|
| index d6280b43290b8d4d9547f56a1a62b070caf63e66..92b61c42e7854b0e3c46f41bdf5242b0a1492319 100644
|
| --- a/cc/base/contiguous_container.cc
|
| +++ b/cc/base/contiguous_container.cc
|
| @@ -10,9 +10,23 @@
|
|
|
| namespace cc {
|
|
|
| +namespace {
|
| +
|
| // Default number of max-sized elements to allocate space for, if there is no
|
| // initial buffer.
|
| -static const unsigned kDefaultInitialBufferSize = 32;
|
| +const unsigned kDefaultInitialBufferSize = 32;
|
| +
|
| +inline char* AlignAddress(char* address, unsigned log2_alignment) {
|
| + char* aligned = reinterpret_cast<char*>(
|
| + (((reinterpret_cast<size_t>(address) - 1) >> log2_alignment) + 1)
|
| + << log2_alignment);
|
| + DCHECK_EQ(0u, reinterpret_cast<size_t>(aligned) % (1 << log2_alignment));
|
| + DCHECK(aligned >= address);
|
| + DCHECK(aligned < address + (1 << log2_alignment));
|
| + return aligned;
|
| +}
|
| +
|
| +} // namespace
|
|
|
| class ContiguousContainerBase::Buffer {
|
| public:
|
| @@ -26,17 +40,28 @@ class ContiguousContainerBase::Buffer {
|
| size_t UnusedCapacity() const { return Capacity() - UsedCapacity(); }
|
| bool empty() const { return UsedCapacity() == 0; }
|
|
|
| - void* Allocate(size_t object_size) {
|
| - DCHECK_GE(UnusedCapacity(), object_size);
|
| - void* result = end_;
|
| - end_ += object_size;
|
| - return result;
|
| + void* Allocate(size_t object_size, unsigned log2_alignment) {
|
| + char* aligned_address;
|
| + if (empty()) {
|
| + // begin()'s alignment must be suitable for all possible types.
|
| + DCHECK_EQ(begin(), AlignAddress(begin(), log2_alignment));
|
| + DCHECK(object_size <= capacity_);
|
| + aligned_address = begin();
|
| + } else {
|
| + aligned_address = AlignAddress(end_, log2_alignment);
|
| + if (aligned_address - begin() + object_size > capacity_)
|
| + return nullptr;
|
| + }
|
| + end_ = aligned_address + object_size;
|
| + return aligned_address;
|
| }
|
|
|
| void DeallocateLastObject(void* object) {
|
| DCHECK_LE(begin(), object);
|
| DCHECK_LT(object, end_);
|
| end_ = static_cast<char*>(object);
|
| + // We may leave a gap between the end of the previous object (which we
|
| + // don't know) and end_ because of alignment of the deallocated object.
|
| }
|
|
|
| private:
|
| @@ -80,26 +105,25 @@ size_t ContiguousContainerBase::MemoryUsageInBytes() const {
|
| elements_.capacity() * sizeof(elements_[0]);
|
| }
|
|
|
| -void* ContiguousContainerBase::Allocate(size_t object_size) {
|
| +void* ContiguousContainerBase::Allocate(size_t object_size,
|
| + unsigned log2_alignment) {
|
| DCHECK_LE(object_size, max_object_size_);
|
|
|
| - Buffer* buffer_for_alloc = nullptr;
|
| - if (!buffers_.empty()) {
|
| - Buffer* end_buffer = buffers_[end_index_].get();
|
| - if (end_buffer->UnusedCapacity() >= object_size)
|
| - buffer_for_alloc = end_buffer;
|
| - else if (end_index_ + 1 < buffers_.size())
|
| + void* element = buffers_.empty() ? nullptr : buffers_[end_index_]->Allocate(
|
| + object_size, log2_alignment);
|
| + if (!element) {
|
| + Buffer* buffer_for_alloc;
|
| + if (end_index_ + 1 < buffers_.size()) {
|
| buffer_for_alloc = buffers_[++end_index_].get();
|
| + } else {
|
| + size_t new_buffer_size =
|
| + buffers_.empty() ? kDefaultInitialBufferSize * max_object_size_
|
| + : 2 * buffers_.back()->Capacity();
|
| + buffer_for_alloc = AllocateNewBufferForNextAllocation(new_buffer_size);
|
| + }
|
| + element = buffer_for_alloc->Allocate(object_size, log2_alignment);
|
| + DCHECK(element);
|
| }
|
| -
|
| - if (!buffer_for_alloc) {
|
| - size_t new_buffer_size = buffers_.empty()
|
| - ? kDefaultInitialBufferSize * max_object_size_
|
| - : 2 * buffers_.back()->Capacity();
|
| - buffer_for_alloc = AllocateNewBufferForNextAllocation(new_buffer_size);
|
| - }
|
| -
|
| - void* element = buffer_for_alloc->Allocate(object_size);
|
| elements_.push_back(element);
|
| return element;
|
| }
|
|
|