Index: base/memory/discardable_memory_allocator_android.cc |
diff --git a/base/memory/discardable_memory_allocator_android.cc b/base/memory/discardable_memory_allocator_android.cc |
index 2054e30ff21c379663cb9fcdbd29c72a0cedb41b..662ce658500ecbeaf00e0ae7431337ae2193ec12 100644 |
--- a/base/memory/discardable_memory_allocator_android.cc |
+++ b/base/memory/discardable_memory_allocator_android.cc |
@@ -127,6 +127,7 @@ class DiscardableMemoryAllocator::AshmemRegion { |
~AshmemRegion() { |
const bool result = internal::CloseAshmemRegion(fd_, size_, base_); |
DCHECK(result); |
+ DCHECK(!highest_allocated_chunk_); |
} |
// Returns a new instance of DiscardableMemory whose size is greater or equal |
@@ -144,17 +145,29 @@ class DiscardableMemoryAllocator::AshmemRegion { |
size_t actual_size) { |
DCHECK_LE(client_requested_size, actual_size); |
allocator_->lock_.AssertAcquired(); |
+ |
+ // Check that the |highest_allocated_chunk_| field doesn't contain a stale |
+ // pointer. It should point to either a free chunk or a used chunk. |
+ DCHECK(!highest_allocated_chunk_ || |
+ address_to_free_chunk_map_.find(highest_allocated_chunk_) != |
+ address_to_free_chunk_map_.end() || |
+ used_to_previous_chunk_map_.find(highest_allocated_chunk_) != |
+ used_to_previous_chunk_map_.end()); |
+ |
scoped_ptr<DiscardableMemory> memory = ReuseFreeChunk_Locked( |
client_requested_size, actual_size); |
if (memory) |
return memory.Pass(); |
+ |
Philippe
2014/03/05 12:42:46
FYI, I'm adding those blank lines to improve reada
pasko
2014/03/05 13:36:48
:)
do you mean that when I asked for these extra e
Philippe
2014/03/05 13:39:11
Ahaha :)
|
if (size_ - offset_ < actual_size) { |
// This region does not have enough space left to hold the requested size. |
return scoped_ptr<DiscardableMemory>(); |
} |
+ |
void* const address = static_cast<char*>(base_) + offset_; |
memory.reset( |
new DiscardableAshmemChunk(this, fd_, address, offset_, actual_size)); |
+ |
used_to_previous_chunk_map_.insert( |
std::make_pair(address, highest_allocated_chunk_)); |
highest_allocated_chunk_ = address; |
@@ -183,7 +196,7 @@ class DiscardableMemoryAllocator::AshmemRegion { |
: previous_chunk(previous_chunk), |
start(start), |
size(size) { |
- DCHECK_NE(previous_chunk, start); |
+ DCHECK_LT(previous_chunk, start); |
} |
void* const previous_chunk; |
@@ -288,25 +301,34 @@ class DiscardableMemoryAllocator::AshmemRegion { |
DCHECK(previous_chunk_it != used_to_previous_chunk_map_.end()); |
void* previous_chunk = previous_chunk_it->second; |
used_to_previous_chunk_map_.erase(previous_chunk_it); |
+ |
if (previous_chunk) { |
const FreeChunk free_chunk = RemoveFreeChunk_Locked(previous_chunk); |
if (!free_chunk.is_null()) { |
new_free_chunk_size += free_chunk.size; |
first_free_chunk = previous_chunk; |
+ if (chunk == highest_allocated_chunk_) |
+ highest_allocated_chunk_ = previous_chunk; |
+ |
// There should not be more contiguous previous free chunks. |
previous_chunk = free_chunk.previous_chunk; |
DCHECK(!address_to_free_chunk_map_.count(previous_chunk)); |
} |
} |
+ |
// Merge with the next chunk if free and present. |
void* next_chunk = static_cast<char*>(chunk) + size; |
const FreeChunk next_free_chunk = RemoveFreeChunk_Locked(next_chunk); |
if (!next_free_chunk.is_null()) { |
new_free_chunk_size += next_free_chunk.size; |
+ if (next_free_chunk.start == highest_allocated_chunk_) |
+ highest_allocated_chunk_ = first_free_chunk; |
+ |
// Same as above. |
DCHECK(!address_to_free_chunk_map_.count(static_cast<char*>(next_chunk) + |
next_free_chunk.size)); |
} |
+ |
const bool whole_ashmem_region_is_free = |
used_to_previous_chunk_map_.empty(); |
if (!whole_ashmem_region_is_free) { |
@@ -314,11 +336,14 @@ class DiscardableMemoryAllocator::AshmemRegion { |
FreeChunk(previous_chunk, first_free_chunk, new_free_chunk_size)); |
return; |
} |
+ |
// The whole ashmem region is free thus it can be deleted. |
DCHECK_EQ(base_, first_free_chunk); |
+ DCHECK_EQ(base_, highest_allocated_chunk_); |
DCHECK(free_chunks_.empty()); |
DCHECK(address_to_free_chunk_map_.empty()); |
DCHECK(used_to_previous_chunk_map_.empty()); |
+ highest_allocated_chunk_ = NULL; |
allocator_->DeleteAshmemRegion_Locked(this); // Deletes |this|. |
} |
@@ -367,6 +392,8 @@ class DiscardableMemoryAllocator::AshmemRegion { |
const size_t size_; |
void* const base_; |
DiscardableMemoryAllocator* const allocator_; |
+ // Points to the chunk with the highest address in the region. This pointer |
+ // needs to be carefully updated when chunks are merged/split. |
void* highest_allocated_chunk_; |
// Points to the end of |highest_allocated_chunk_|. |
size_t offset_; |