From c2d9cd8d53975016cdb8c5d6a34c63418b7adac8 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 17 May 2021 19:01:08 +0200 Subject: [PATCH] LibJS: Implement lazy freelist allocation for cells HeapBlock now implements the same lazy freelist as LibC malloc() does, where new blocks start out in a "bump allocator" mode that gets used until we've bump-allocated all the way to the end of the block. Then we fall back to the old freelist style as before. This means we don't have to pre-initialize the freelist on HeapBlock construction. This defers page faults and reduces memory usage for blocks where all cells don't get used. :^) --- Userland/Libraries/LibJS/Heap/HeapBlock.cpp | 9 --------- Userland/Libraries/LibJS/Heap/HeapBlock.h | 10 ++++++++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Userland/Libraries/LibJS/Heap/HeapBlock.cpp b/Userland/Libraries/LibJS/Heap/HeapBlock.cpp index 67489deb3f..97bd82dc58 100644 --- a/Userland/Libraries/LibJS/Heap/HeapBlock.cpp +++ b/Userland/Libraries/LibJS/Heap/HeapBlock.cpp @@ -41,15 +41,6 @@ HeapBlock::HeapBlock(Heap& heap, size_t cell_size) , m_cell_size(cell_size) { VERIFY(cell_size >= sizeof(FreelistEntry)); - - FreelistEntry* next = nullptr; - for (ssize_t i = cell_count() - 1; i >= 0; i--) { - auto* freelist_entry = init_freelist_entry(i); - freelist_entry->set_live(false); - freelist_entry->next = next; - next = freelist_entry; - } - m_freelist = next; } void HeapBlock::deallocate(Cell* cell) diff --git a/Userland/Libraries/LibJS/Heap/HeapBlock.h b/Userland/Libraries/LibJS/Heap/HeapBlock.h index 4feada7e49..45f9fa66cf 100644 --- a/Userland/Libraries/LibJS/Heap/HeapBlock.h +++ b/Userland/Libraries/LibJS/Heap/HeapBlock.h @@ -25,10 +25,12 @@ public: size_t cell_size() const { return m_cell_size; } size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; } - bool is_full() const { return !m_freelist; } + bool is_full() const { return !has_lazy_freelist() && !m_freelist; } ALWAYS_INLINE Cell* allocate() { + if (has_lazy_freelist()) + return cell(m_next_lazy_freelist_index++); if (!m_freelist) return nullptr; VERIFY(is_valid_cell_pointer(m_freelist)); @@ -40,7 +42,8 @@ public: template void for_each_cell(Callback callback) { - for (size_t i = 0; i < cell_count(); ++i) + auto end = has_lazy_freelist() ? m_next_lazy_freelist_index : cell_count(); + for (size_t i = 0; i < end; ++i) callback(cell(i)); } @@ -71,6 +74,8 @@ public: private: HeapBlock(Heap&, size_t cell_size); + bool has_lazy_freelist() const { return m_next_lazy_freelist_index < cell_count(); } + struct FreelistEntry final : public Cell { FreelistEntry* next { nullptr }; @@ -89,6 +94,7 @@ private: Heap& m_heap; size_t m_cell_size { 0 }; + size_t m_next_lazy_freelist_index { 0 }; FreelistEntry* m_freelist { nullptr }; alignas(Cell) u8 m_storage[]; };