| Index: cc/base/contiguous_container.cc
|
| diff --git a/cc/base/contiguous_container.cc b/cc/base/contiguous_container.cc
|
| index d6280b43290b8d4d9547f56a1a62b070caf63e66..6e9a3c1139d23c93d75c69a9224c9e20b3839032 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, size_t alignment) {
|
| + char* aligned = reinterpret_cast<char*>(
|
| + alignment *
|
| + ((reinterpret_cast<size_t>(address) + alignment - 1) / alignment));
|
| + DCHECK(reinterpret_cast<size_t>(aligned) % alignment == 0);
|
| + DCHECK(aligned >= address);
|
| + DCHECK(aligned < address + alignment);
|
| + return aligned;
|
| +}
|
| +
|
| +} // namespace
|
|
|
| class ContiguousContainerBase::Buffer {
|
| public:
|
| @@ -26,25 +40,38 @@ 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, size_t alignment) {
|
| + char* aligned_address = AlignAddress(end_, alignment);
|
| + if (aligned_address - begin() + object_size > Capacity())
|
| + return nullptr;
|
| + if (empty())
|
| + first_object_ = aligned_address;
|
| + 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);
|
| + if (end_ == first_object_) {
|
| + // We have deallocated the first object in this buffer. Reset en_ so that
|
| + // empty() can return correct value.
|
| + end_ = begin();
|
| + }
|
| + // Otherwise 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:
|
| char* begin() { return &data_[0]; }
|
| const char* begin() const { return &data_[0]; }
|
|
|
| - // begin() <= end_ <= begin() + capacity_
|
| + // begin() <= first_object_ <= end_ <= begin() + capacity_
|
| std::unique_ptr<char[]> data_;
|
| + // Because of alignment, the first object may be allocated after begin().
|
| + char* first_object_;
|
| char* end_;
|
| size_t capacity_;
|
| };
|
| @@ -80,26 +107,24 @@ size_t ContiguousContainerBase::MemoryUsageInBytes() const {
|
| elements_.capacity() * sizeof(elements_[0]);
|
| }
|
|
|
| -void* ContiguousContainerBase::Allocate(size_t object_size) {
|
| +void* ContiguousContainerBase::Allocate(size_t object_size, size_t 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, 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, 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;
|
| }
|
|
|