Commit af1bffd3 authored by Hannes Payer's avatar Hannes Payer Committed by Commit Bot

[heap] Move FreeListCategory memory out of the page header.

Bug: chromium:774108
Change-Id: I5345fed261862b0e20356ec4579b16cdf0ea58a6
Reviewed-on: https://chromium-review.googlesource.com/899148
Commit-Queue: Hannes Payer <hpayer@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51606}
parent 15bf3ae5
...@@ -138,12 +138,6 @@ bool NewSpace::FromSpaceContainsSlow(Address a) { ...@@ -138,12 +138,6 @@ bool NewSpace::FromSpaceContainsSlow(Address a) {
bool NewSpace::ToSpaceContains(Object* o) { return to_space_.Contains(o); } bool NewSpace::ToSpaceContains(Object* o) { return to_space_.Contains(o); }
bool NewSpace::FromSpaceContains(Object* o) { return from_space_.Contains(o); } bool NewSpace::FromSpaceContains(Object* o) { return from_space_.Contains(o); }
void MemoryChunk::InitializeFreeListCategories() {
for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
categories_[i].Initialize(static_cast<FreeListCategoryType>(i));
}
}
bool PagedSpace::Contains(Address addr) { bool PagedSpace::Contains(Address addr) {
if (heap_->lo_space()->FindPage(addr)) return false; if (heap_->lo_space()->FindPage(addr)) return false;
return MemoryChunk::FromAnyPointerAddress(heap(), addr)->owner() == this; return MemoryChunk::FromAnyPointerAddress(heap(), addr)->owner() == this;
...@@ -158,6 +152,7 @@ void PagedSpace::UnlinkFreeListCategories(Page* page) { ...@@ -158,6 +152,7 @@ void PagedSpace::UnlinkFreeListCategories(Page* page) {
DCHECK_EQ(this, page->owner()); DCHECK_EQ(this, page->owner());
page->ForAllFreeListCategories([this](FreeListCategory* category) { page->ForAllFreeListCategories([this](FreeListCategory* category) {
DCHECK_EQ(free_list(), category->owner()); DCHECK_EQ(free_list(), category->owner());
category->set_free_list(nullptr);
free_list()->RemoveCategory(category); free_list()->RemoveCategory(category);
}); });
} }
...@@ -165,7 +160,8 @@ void PagedSpace::UnlinkFreeListCategories(Page* page) { ...@@ -165,7 +160,8 @@ void PagedSpace::UnlinkFreeListCategories(Page* page) {
size_t PagedSpace::RelinkFreeListCategories(Page* page) { size_t PagedSpace::RelinkFreeListCategories(Page* page) {
DCHECK_EQ(this, page->owner()); DCHECK_EQ(this, page->owner());
size_t added = 0; size_t added = 0;
page->ForAllFreeListCategories([&added](FreeListCategory* category) { page->ForAllFreeListCategories([this, &added](FreeListCategory* category) {
category->set_free_list(&free_list_);
added += category->available(); added += category->available();
category->Relink(); category->Relink();
}); });
...@@ -257,23 +253,14 @@ MemoryChunk* MemoryChunkIterator::next() { ...@@ -257,23 +253,14 @@ MemoryChunk* MemoryChunkIterator::next() {
UNREACHABLE(); UNREACHABLE();
} }
Page* FreeListCategory::page() const {
return Page::FromAddress(
reinterpret_cast<Address>(const_cast<FreeListCategory*>(this)));
}
Page* FreeList::GetPageForCategoryType(FreeListCategoryType type) { Page* FreeList::GetPageForCategoryType(FreeListCategoryType type) {
return top(type) ? top(type)->page() : nullptr; return top(type) ? top(type)->page() : nullptr;
} }
FreeList* FreeListCategory::owner() { FreeList* FreeListCategory::owner() { return free_list_; }
return reinterpret_cast<PagedSpace*>(
Page::FromAddress(reinterpret_cast<Address>(this))->owner())
->free_list();
}
bool FreeListCategory::is_linked() { bool FreeListCategory::is_linked() {
return prev_ != nullptr || next_ != nullptr || owner()->top(type_) == this; return prev_ != nullptr || next_ != nullptr;
} }
AllocationResult LocalAllocationBuffer::AllocateRawAligned( AllocationResult LocalAllocationBuffer::AllocateRawAligned(
......
...@@ -626,7 +626,10 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size, ...@@ -626,7 +626,10 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size,
chunk->set_next_chunk(nullptr); chunk->set_next_chunk(nullptr);
chunk->set_prev_chunk(nullptr); chunk->set_prev_chunk(nullptr);
chunk->local_tracker_ = nullptr; chunk->local_tracker_ = nullptr;
chunk->InitializeFreeListCategories();
for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
chunk->categories_[i] = nullptr;
}
heap->incremental_marking()->non_atomic_marking_state()->ClearLiveness(chunk); heap->incremental_marking()->non_atomic_marking_state()->ClearLiveness(chunk);
...@@ -649,6 +652,7 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size, ...@@ -649,6 +652,7 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size,
if (reservation != nullptr) { if (reservation != nullptr) {
chunk->reservation_.TakeControl(reservation); chunk->reservation_.TakeControl(reservation);
} }
return chunk; return chunk;
} }
...@@ -658,6 +662,8 @@ Page* PagedSpace::InitializePage(MemoryChunk* chunk, Executability executable) { ...@@ -658,6 +662,8 @@ Page* PagedSpace::InitializePage(MemoryChunk* chunk, Executability executable) {
// Make sure that categories are initialized before freeing the area. // Make sure that categories are initialized before freeing the area.
page->ResetAllocatedBytes(); page->ResetAllocatedBytes();
heap()->incremental_marking()->SetOldSpacePageFlags(page); heap()->incremental_marking()->SetOldSpacePageFlags(page);
page->AllocateFreeListCategories();
page->InitializeFreeListCategories();
page->InitializationMemoryFence(); page->InitializationMemoryFence();
return page; return page;
} }
...@@ -705,6 +711,28 @@ LargePage* LargePage::Initialize(Heap* heap, MemoryChunk* chunk, ...@@ -705,6 +711,28 @@ LargePage* LargePage::Initialize(Heap* heap, MemoryChunk* chunk,
return page; return page;
} }
void Page::AllocateFreeListCategories() {
for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
categories_[i] = new FreeListCategory(
reinterpret_cast<PagedSpace*>(owner())->free_list(), this);
}
}
void Page::InitializeFreeListCategories() {
for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
categories_[i]->Initialize(static_cast<FreeListCategoryType>(i));
}
}
void Page::ReleaseFreeListCategories() {
for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
if (categories_[i] != nullptr) {
delete categories_[i];
categories_[i] = nullptr;
}
}
}
Page* Page::ConvertNewToOld(Page* old_page) { Page* Page::ConvertNewToOld(Page* old_page) {
DCHECK(!old_page->is_anchor()); DCHECK(!old_page->is_anchor());
DCHECK(old_page->InNewSpace()); DCHECK(old_page->InNewSpace());
...@@ -722,6 +750,10 @@ size_t MemoryChunk::CommittedPhysicalMemory() { ...@@ -722,6 +750,10 @@ size_t MemoryChunk::CommittedPhysicalMemory() {
return high_water_mark_.Value(); return high_water_mark_.Value();
} }
bool MemoryChunk::IsPagedSpace() const {
return owner()->identity() != LO_SPACE;
}
void MemoryChunk::InsertAfter(MemoryChunk* other) { void MemoryChunk::InsertAfter(MemoryChunk* other) {
MemoryChunk* other_next = other->next_chunk(); MemoryChunk* other_next = other->next_chunk();
...@@ -875,7 +907,6 @@ MemoryChunk* MemoryAllocator::AllocateChunk(size_t reserve_area_size, ...@@ -875,7 +907,6 @@ MemoryChunk* MemoryAllocator::AllocateChunk(size_t reserve_area_size,
executable, owner, &reservation); executable, owner, &reservation);
if (chunk->executable()) RegisterExecutableMemoryChunk(chunk); if (chunk->executable()) RegisterExecutableMemoryChunk(chunk);
return chunk; return chunk;
} }
...@@ -1249,6 +1280,11 @@ void MemoryChunk::ReleaseAllocatedMemory() { ...@@ -1249,6 +1280,11 @@ void MemoryChunk::ReleaseAllocatedMemory() {
ReleaseInvalidatedSlots(); ReleaseInvalidatedSlots();
if (local_tracker_ != nullptr) ReleaseLocalTracker(); if (local_tracker_ != nullptr) ReleaseLocalTracker();
if (young_generation_bitmap_ != nullptr) ReleaseYoungGenerationBitmap(); if (young_generation_bitmap_ != nullptr) ReleaseYoungGenerationBitmap();
if (IsPagedSpace()) {
Page* page = static_cast<Page*>(this);
page->ReleaseFreeListCategories();
}
} }
static SlotSet* AllocateAndInitializeSlotSet(size_t size, Address page_start) { static SlotSet* AllocateAndInitializeSlotSet(size_t size, Address page_start) {
...@@ -2680,7 +2716,6 @@ void FreeListCategory::Reset() { ...@@ -2680,7 +2716,6 @@ void FreeListCategory::Reset() {
FreeSpace* FreeListCategory::PickNodeFromList(size_t* node_size) { FreeSpace* FreeListCategory::PickNodeFromList(size_t* node_size) {
DCHECK(page()->CanAllocate()); DCHECK(page()->CanAllocate());
FreeSpace* node = top(); FreeSpace* node = top();
if (node == nullptr) return nullptr; if (node == nullptr) return nullptr;
set_top(node->next()); set_top(node->next());
...@@ -2692,7 +2727,6 @@ FreeSpace* FreeListCategory::PickNodeFromList(size_t* node_size) { ...@@ -2692,7 +2727,6 @@ FreeSpace* FreeListCategory::PickNodeFromList(size_t* node_size) {
FreeSpace* FreeListCategory::TryPickNodeFromList(size_t minimum_size, FreeSpace* FreeListCategory::TryPickNodeFromList(size_t minimum_size,
size_t* node_size) { size_t* node_size) {
DCHECK(page()->CanAllocate()); DCHECK(page()->CanAllocate());
FreeSpace* node = PickNodeFromList(node_size); FreeSpace* node = PickNodeFromList(node_size);
if ((node != nullptr) && (*node_size < minimum_size)) { if ((node != nullptr) && (*node_size < minimum_size)) {
Free(node->address(), *node_size, kLinkCategory); Free(node->address(), *node_size, kLinkCategory);
...@@ -2705,7 +2739,6 @@ FreeSpace* FreeListCategory::TryPickNodeFromList(size_t minimum_size, ...@@ -2705,7 +2739,6 @@ FreeSpace* FreeListCategory::TryPickNodeFromList(size_t minimum_size,
FreeSpace* FreeListCategory::SearchForNodeInList(size_t minimum_size, FreeSpace* FreeListCategory::SearchForNodeInList(size_t minimum_size,
size_t* node_size) { size_t* node_size) {
DCHECK(page()->CanAllocate()); DCHECK(page()->CanAllocate());
FreeSpace* prev_non_evac_node = nullptr; FreeSpace* prev_non_evac_node = nullptr;
for (FreeSpace* cur_node = top(); cur_node != nullptr; for (FreeSpace* cur_node = top(); cur_node != nullptr;
cur_node = cur_node->next()) { cur_node = cur_node->next()) {
...@@ -2730,7 +2763,7 @@ FreeSpace* FreeListCategory::SearchForNodeInList(size_t minimum_size, ...@@ -2730,7 +2763,7 @@ FreeSpace* FreeListCategory::SearchForNodeInList(size_t minimum_size,
void FreeListCategory::Free(Address start, size_t size_in_bytes, void FreeListCategory::Free(Address start, size_t size_in_bytes,
FreeMode mode) { FreeMode mode) {
CHECK(page()->CanAllocate()); DCHECK(page()->CanAllocate());
FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start)); FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start));
free_space->set_next(top()); free_space->set_next(top());
set_top(free_space); set_top(free_space);
......
...@@ -150,15 +150,10 @@ enum RememberedSetType { ...@@ -150,15 +150,10 @@ enum RememberedSetType {
// A free list category maintains a linked list of free memory blocks. // A free list category maintains a linked list of free memory blocks.
class FreeListCategory { class FreeListCategory {
public: public:
static const int kSize = kIntSize + // FreeListCategoryType type_ FreeListCategory(FreeList* free_list, Page* page)
kIntSize + // padding for type_ : free_list_(free_list),
kSizetSize + // size_t available_ page_(page),
kPointerSize + // FreeSpace* top_ type_(kInvalidCategory),
kPointerSize + // FreeListCategory* prev_
kPointerSize; // FreeListCategory* next_
FreeListCategory()
: type_(kInvalidCategory),
available_(0), available_(0),
top_(nullptr), top_(nullptr),
prev_(nullptr), prev_(nullptr),
...@@ -198,11 +193,13 @@ class FreeListCategory { ...@@ -198,11 +193,13 @@ class FreeListCategory {
FreeSpace* SearchForNodeInList(size_t minimum_size, size_t* node_size); FreeSpace* SearchForNodeInList(size_t minimum_size, size_t* node_size);
inline FreeList* owner(); inline FreeList* owner();
inline Page* page() const; inline Page* page() const { return page_; }
inline bool is_linked(); inline bool is_linked();
bool is_empty() { return top() == nullptr; } bool is_empty() { return top() == nullptr; }
size_t available() const { return available_; } size_t available() const { return available_; }
void set_free_list(FreeList* free_list) { free_list_ = free_list; }
#ifdef DEBUG #ifdef DEBUG
size_t SumFreeList(); size_t SumFreeList();
int FreeListLength(); int FreeListLength();
...@@ -220,6 +217,12 @@ class FreeListCategory { ...@@ -220,6 +217,12 @@ class FreeListCategory {
FreeListCategory* next() { return next_; } FreeListCategory* next() { return next_; }
void set_next(FreeListCategory* next) { next_ = next; } void set_next(FreeListCategory* next) { next_ = next; }
// This FreeListCategory is owned by the given free_list_.
FreeList* free_list_;
// This FreeListCategory holds free list entries of the given page_.
Page* const page_;
// |type_|: The type of this free list category. // |type_|: The type of this free list category.
FreeListCategoryType type_; FreeListCategoryType type_;
...@@ -235,6 +238,8 @@ class FreeListCategory { ...@@ -235,6 +238,8 @@ class FreeListCategory {
friend class FreeList; friend class FreeList;
friend class PagedSpace; friend class PagedSpace;
DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListCategory);
}; };
// MemoryChunk represents a memory region owned by a specific space. // MemoryChunk represents a memory region owned by a specific space.
...@@ -372,7 +377,7 @@ class MemoryChunk { ...@@ -372,7 +377,7 @@ class MemoryChunk {
+ kSizetSize // size_t wasted_memory_ + kSizetSize // size_t wasted_memory_
+ kPointerSize // AtomicValue next_chunk_ + kPointerSize // AtomicValue next_chunk_
+ kPointerSize // AtomicValue prev_chunk_ + kPointerSize // AtomicValue prev_chunk_
+ FreeListCategory::kSize * kNumberOfCategories + kPointerSize * kNumberOfCategories
// FreeListCategory categories_[kNumberOfCategories] // FreeListCategory categories_[kNumberOfCategories]
+ kPointerSize // LocalArrayBufferTracker* local_tracker_ + kPointerSize // LocalArrayBufferTracker* local_tracker_
+ kIntptrSize // intptr_t young_generation_live_byte_count_ + kIntptrSize // intptr_t young_generation_live_byte_count_
...@@ -612,6 +617,8 @@ class MemoryChunk { ...@@ -612,6 +617,8 @@ class MemoryChunk {
void set_owner(Space* space) { owner_.SetValue(space); } void set_owner(Space* space) { owner_.SetValue(space); }
bool IsPagedSpace() const;
void InsertAfter(MemoryChunk* other); void InsertAfter(MemoryChunk* other);
void Unlink(); void Unlink();
...@@ -622,8 +629,6 @@ class MemoryChunk { ...@@ -622,8 +629,6 @@ class MemoryChunk {
void SetReadAndExecutable(); void SetReadAndExecutable();
void SetReadAndWritable(); void SetReadAndWritable();
inline void InitializeFreeListCategories();
protected: protected:
static MemoryChunk* Initialize(Heap* heap, Address base, size_t size, static MemoryChunk* Initialize(Heap* heap, Address base, size_t size,
Address area_start, Address area_end, Address area_start, Address area_end,
...@@ -701,7 +706,7 @@ class MemoryChunk { ...@@ -701,7 +706,7 @@ class MemoryChunk {
// prev_chunk_ holds a pointer of type MemoryChunk // prev_chunk_ holds a pointer of type MemoryChunk
base::AtomicValue<MemoryChunk*> prev_chunk_; base::AtomicValue<MemoryChunk*> prev_chunk_;
FreeListCategory categories_[kNumberOfCategories]; FreeListCategory* categories_[kNumberOfCategories];
LocalArrayBufferTracker* local_tracker_; LocalArrayBufferTracker* local_tracker_;
...@@ -790,7 +795,7 @@ class Page : public MemoryChunk { ...@@ -790,7 +795,7 @@ class Page : public MemoryChunk {
template <typename Callback> template <typename Callback>
inline void ForAllFreeListCategories(Callback callback) { inline void ForAllFreeListCategories(Callback callback) {
for (int i = kFirstCategory; i < kNumberOfCategories; i++) { for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
callback(&categories_[i]); callback(categories_[i]);
} }
} }
...@@ -822,7 +827,7 @@ class Page : public MemoryChunk { ...@@ -822,7 +827,7 @@ class Page : public MemoryChunk {
} }
FreeListCategory* free_list_category(FreeListCategoryType type) { FreeListCategory* free_list_category(FreeListCategoryType type) {
return &categories_[type]; return categories_[type];
} }
bool is_anchor() { return IsFlagSet(Page::ANCHOR); } bool is_anchor() { return IsFlagSet(Page::ANCHOR); }
...@@ -847,6 +852,10 @@ class Page : public MemoryChunk { ...@@ -847,6 +852,10 @@ class Page : public MemoryChunk {
V8_EXPORT_PRIVATE void CreateBlackArea(Address start, Address end); V8_EXPORT_PRIVATE void CreateBlackArea(Address start, Address end);
void DestroyBlackArea(Address start, Address end); void DestroyBlackArea(Address start, Address end);
void InitializeFreeListCategories();
void AllocateFreeListCategories();
void ReleaseFreeListCategories();
#ifdef DEBUG #ifdef DEBUG
void Print(); void Print();
#endif // DEBUG #endif // DEBUG
...@@ -1179,8 +1188,7 @@ class V8_EXPORT_PRIVATE MemoryAllocator { ...@@ -1179,8 +1188,7 @@ class V8_EXPORT_PRIVATE MemoryAllocator {
} }
void AddMemoryChunkSafe(MemoryChunk* chunk) { void AddMemoryChunkSafe(MemoryChunk* chunk) {
if ((chunk->size() == Page::kPageSize) && if (chunk->IsPagedSpace() && chunk->executable() != EXECUTABLE) {
(chunk->executable() != EXECUTABLE)) {
AddMemoryChunkSafe<kRegular>(chunk); AddMemoryChunkSafe<kRegular>(chunk);
} else { } else {
AddMemoryChunkSafe<kNonRegular>(chunk); AddMemoryChunkSafe<kNonRegular>(chunk);
......
...@@ -80,12 +80,10 @@ class TestCodeRangeScope { ...@@ -80,12 +80,10 @@ class TestCodeRangeScope {
DISALLOW_COPY_AND_ASSIGN(TestCodeRangeScope); DISALLOW_COPY_AND_ASSIGN(TestCodeRangeScope);
}; };
static void VerifyMemoryChunk(Isolate* isolate, static void VerifyMemoryChunk(Isolate* isolate, Heap* heap,
Heap* heap, CodeRange* code_range, size_t reserve_area_size,
CodeRange* code_range, size_t commit_area_size, Executability executable,
size_t reserve_area_size, Space* space) {
size_t commit_area_size,
Executability executable) {
MemoryAllocator* memory_allocator = new MemoryAllocator(isolate); MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
CHECK(memory_allocator->SetUp(heap->MaxReserved(), 0)); CHECK(memory_allocator->SetUp(heap->MaxReserved(), 0));
{ {
...@@ -99,7 +97,7 @@ static void VerifyMemoryChunk(Isolate* isolate, ...@@ -99,7 +97,7 @@ static void VerifyMemoryChunk(Isolate* isolate,
(executable == EXECUTABLE) ? MemoryAllocator::CodePageGuardSize() : 0; (executable == EXECUTABLE) ? MemoryAllocator::CodePageGuardSize() : 0;
MemoryChunk* memory_chunk = memory_allocator->AllocateChunk( MemoryChunk* memory_chunk = memory_allocator->AllocateChunk(
reserve_area_size, commit_area_size, executable, nullptr); reserve_area_size, commit_area_size, executable, space);
size_t alignment = code_range != nullptr && code_range->valid() size_t alignment = code_range != nullptr && code_range->valid()
? MemoryChunk::kAlignment ? MemoryChunk::kAlignment
: CommitPageSize(); : CommitPageSize();
...@@ -178,36 +176,22 @@ TEST(MemoryChunk) { ...@@ -178,36 +176,22 @@ TEST(MemoryChunk) {
const size_t code_range_size = 32 * MB; const size_t code_range_size = 32 * MB;
if (!code_range->SetUp(code_range_size)) return; if (!code_range->SetUp(code_range_size)) return;
VerifyMemoryChunk(isolate, VerifyMemoryChunk(isolate, heap, code_range, reserve_area_size,
heap, initial_commit_area_size, EXECUTABLE, heap->code_space());
code_range,
reserve_area_size, VerifyMemoryChunk(isolate, heap, code_range, reserve_area_size,
initial_commit_area_size, initial_commit_area_size, NOT_EXECUTABLE,
EXECUTABLE); heap->old_space());
VerifyMemoryChunk(isolate,
heap,
code_range,
reserve_area_size,
initial_commit_area_size,
NOT_EXECUTABLE);
delete code_range; delete code_range;
// Without a valid CodeRange, i.e., omitting SetUp. // Without a valid CodeRange, i.e., omitting SetUp.
code_range = new CodeRange(isolate); code_range = new CodeRange(isolate);
VerifyMemoryChunk(isolate, VerifyMemoryChunk(isolate, heap, code_range, reserve_area_size,
heap, initial_commit_area_size, EXECUTABLE, heap->code_space());
code_range,
reserve_area_size, VerifyMemoryChunk(isolate, heap, code_range, reserve_area_size,
initial_commit_area_size, initial_commit_area_size, NOT_EXECUTABLE,
EXECUTABLE); heap->old_space());
VerifyMemoryChunk(isolate,
heap,
code_range,
reserve_area_size,
initial_commit_area_size,
NOT_EXECUTABLE);
delete code_range; delete code_range;
} }
} }
......
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