Commit 1d998bd0 authored by mlippautz's avatar mlippautz Committed by Commit bot

[heap] Refactor and clean up FreeListCategory.

BUG=

Review URL: https://codereview.chromium.org/1377723003

Cr-Commit-Position: refs/heads/master@{#31048}
parent 2128d6c0
......@@ -2074,7 +2074,6 @@ intptr_t FreeListCategory::Concatenate(FreeListCategory* category) {
category->end()->set_next(top());
}
set_top(category->top());
base::NoBarrier_Store(&top_, category->top_);
available_ += category->available();
category->Reset();
}
......@@ -2083,9 +2082,9 @@ intptr_t FreeListCategory::Concatenate(FreeListCategory* category) {
void FreeListCategory::Reset() {
set_top(NULL);
set_end(NULL);
set_available(0);
set_top(nullptr);
set_end(nullptr);
available_ = 0;
}
......@@ -2160,6 +2159,55 @@ FreeSpace* FreeListCategory::PickNodeFromList(int size_in_bytes,
}
FreeSpace* FreeListCategory::SearchForNodeInList(int size_in_bytes,
int* node_size) {
FreeSpace* return_node = nullptr;
FreeSpace* top_node = top();
for (FreeSpace** node_it = &top_node; *node_it != NULL;
node_it = (*node_it)->next_address()) {
FreeSpace* cur_node = *node_it;
while (cur_node != NULL &&
Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) {
int size = cur_node->Size();
available_ -= size;
Page::FromAddress(cur_node->address())
->add_available_in_free_list(type_, -size);
cur_node = cur_node->next();
}
// Update iterator.
*node_it = cur_node;
if (cur_node == nullptr) {
set_end(nullptr);
break;
}
int size = cur_node->Size();
if (size >= size_in_bytes) {
// Large enough node found. Unlink it from the list.
return_node = cur_node;
*node_it = cur_node->next();
*node_size = size;
available_ -= size;
Page::FromAddress(return_node->address())
->add_available_in_free_list(type_, -size);
break;
}
}
// Top could've changed if we took the first node. Update top and end
// accordingly.
set_top(top_node);
if (top() == nullptr) {
set_end(nullptr);
}
return return_node;
}
void FreeListCategory::Free(FreeSpace* free_space, int size_in_bytes) {
free_space->set_next(top());
set_top(free_space);
......@@ -2188,10 +2236,10 @@ FreeList::FreeList(PagedSpace* owner)
: owner_(owner),
heap_(owner->heap()),
wasted_bytes_(0),
small_list_(this),
medium_list_(this),
large_list_(this),
huge_list_(this) {
small_list_(this, kSmall),
medium_list_(this, kMedium),
large_list_(this, kLarge),
huge_list_(this, kHuge) {
Reset();
}
......@@ -2302,44 +2350,7 @@ FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
}
}
int huge_list_available = huge_list_.available();
FreeSpace* top_node = huge_list_.top();
for (FreeSpace** cur = &top_node; *cur != NULL;
cur = (*cur)->next_address()) {
FreeSpace* cur_node = *cur;
while (cur_node != NULL &&
Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) {
int size = cur_node->Size();
huge_list_available -= size;
page = Page::FromAddress(cur_node->address());
page->add_available_in_huge_free_list(-size);
cur_node = cur_node->next();
}
*cur = cur_node;
if (cur_node == NULL) {
huge_list_.set_end(NULL);
break;
}
int size = cur_node->Size();
if (size >= size_in_bytes) {
// Large enough node found. Unlink it from the list.
node = *cur;
*cur = node->next();
*node_size = size;
huge_list_available -= size;
page = Page::FromAddress(node->address());
page->add_available_in_huge_free_list(-size);
break;
}
}
huge_list_.set_top(top_node);
if (huge_list_.top() == NULL) {
huge_list_.set_end(NULL);
}
huge_list_.set_available(huge_list_available);
node = huge_list_.SearchForNodeInList(size_in_bytes, node_size);
if (node != NULL) {
DCHECK(IsVeryLong() || available() == SumFreeLists());
......
......@@ -752,6 +752,9 @@ class MemoryChunk {
};
enum FreeListCategoryType { kSmall, kMedium, kLarge, kHuge };
// -----------------------------------------------------------------------------
// A page is a memory chunk of a size 1MB. Large object pages may be larger.
//
......@@ -853,6 +856,25 @@ class Page : public MemoryChunk {
#undef FRAGMENTATION_STATS_ACCESSORS
void add_available_in_free_list(FreeListCategoryType type, intptr_t bytes) {
switch (type) {
case kSmall:
add_available_in_small_free_list(bytes);
break;
case kMedium:
add_available_in_medium_free_list(bytes);
break;
case kLarge:
add_available_in_large_free_list(bytes);
break;
case kHuge:
add_available_in_huge_free_list(bytes);
break;
default:
UNREACHABLE();
}
}
#ifdef DEBUG
void Print();
#endif // DEBUG
......@@ -1518,8 +1540,12 @@ class AllocationStats BASE_EMBEDDED {
// the end element of the linked list of free memory blocks.
class FreeListCategory {
public:
explicit FreeListCategory(FreeList* owner)
: top_(0), end_(NULL), available_(0), owner_(owner) {}
explicit FreeListCategory(FreeList* owner, FreeListCategoryType type)
: type_(type),
top_(nullptr),
end_(nullptr),
available_(0),
owner_(owner) {}
intptr_t Concatenate(FreeListCategory* category);
......@@ -1527,45 +1553,52 @@ class FreeListCategory {
void Free(FreeSpace* node, int size_in_bytes);
// Pick a node from the list.
FreeSpace* PickNodeFromList(int* node_size);
// Pick a node from the list and compare it against {size_in_bytes}. If the
// node's size is greater or equal return the node and null otherwise.
FreeSpace* PickNodeFromList(int size_in_bytes, int* node_size);
// Search for a node of size {size_in_bytes}.
FreeSpace* SearchForNodeInList(int size_in_bytes, int* node_size);
intptr_t EvictFreeListItemsInList(Page* p);
bool ContainsPageFreeListItemsInList(Page* p);
void RepairFreeList(Heap* heap);
FreeSpace* top() const {
return reinterpret_cast<FreeSpace*>(base::NoBarrier_Load(&top_));
}
void set_top(FreeSpace* top) {
base::NoBarrier_Store(&top_, reinterpret_cast<base::AtomicWord>(top));
}
FreeSpace* end() const { return end_; }
void set_end(FreeSpace* end) { end_ = end; }
bool IsEmpty() { return top() == nullptr; }
int* GetAvailableAddress() { return &available_; }
FreeList* owner() { return owner_; }
int available() const { return available_; }
void set_available(int available) { available_ = available; }
bool IsEmpty() { return top() == 0; }
#ifdef DEBUG
intptr_t SumFreeList();
int FreeListLength();
#endif
FreeList* owner() { return owner_; }
private:
// top_ points to the top FreeSpace* in the free list category.
base::AtomicWord top_;
FreeSpace* top() { return top_.Value(); }
void set_top(FreeSpace* top) { top_.SetValue(top); }
FreeSpace* end() const { return end_; }
void set_end(FreeSpace* end) { end_ = end; }
// |type_|: The type of this free list category.
FreeListCategoryType type_;
// |top_|: Points to the top FreeSpace* in the free list category.
AtomicValue<FreeSpace*> top_;
// |end_|: Points to the end FreeSpace* in the free list category.
FreeSpace* end_;
// Total available bytes in all blocks of this free list category.
// |available_|: Total available bytes in all blocks of this free list
// category.
int available_;
// |owner_|: The owning free list of this category.
FreeList* owner_;
};
......
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