/src/serenity/Userland/Libraries/LibJS/Heap/HeapBlock.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/IntrusiveList.h> |
10 | | #include <AK/Platform.h> |
11 | | #include <AK/StringView.h> |
12 | | #include <AK/Types.h> |
13 | | #include <LibJS/Forward.h> |
14 | | #include <LibJS/Heap/Cell.h> |
15 | | #include <LibJS/Heap/Internals.h> |
16 | | |
17 | | #ifdef HAS_ADDRESS_SANITIZER |
18 | | # include <sanitizer/asan_interface.h> |
19 | | #endif |
20 | | |
21 | | namespace JS { |
22 | | |
23 | | class HeapBlock : public HeapBlockBase { |
24 | | AK_MAKE_NONCOPYABLE(HeapBlock); |
25 | | AK_MAKE_NONMOVABLE(HeapBlock); |
26 | | |
27 | | public: |
28 | | using HeapBlockBase::block_size; |
29 | | static NonnullOwnPtr<HeapBlock> create_with_cell_size(Heap&, CellAllocator&, size_t cell_size, char const* class_name); |
30 | | |
31 | 509k | size_t cell_size() const { return m_cell_size; } |
32 | 514k | size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; } |
33 | 91.2k | bool is_full() const { return !has_lazy_freelist() && !m_freelist; } |
34 | | |
35 | | ALWAYS_INLINE Cell* allocate() |
36 | 85.8k | { |
37 | 85.8k | Cell* allocated_cell = nullptr; |
38 | 85.8k | if (m_freelist) { |
39 | 0 | VERIFY(is_valid_cell_pointer(m_freelist)); |
40 | 0 | allocated_cell = exchange(m_freelist, m_freelist->next); |
41 | 85.8k | } else if (has_lazy_freelist()) { |
42 | 85.8k | allocated_cell = cell(m_next_lazy_freelist_index++); |
43 | 85.8k | } |
44 | | |
45 | 85.8k | if (allocated_cell) { |
46 | 85.8k | ASAN_UNPOISON_MEMORY_REGION(allocated_cell, m_cell_size); |
47 | 85.8k | } |
48 | 85.8k | return allocated_cell; |
49 | 85.8k | } |
50 | | |
51 | | void deallocate(Cell*); |
52 | | |
53 | | template<typename Callback> |
54 | | void for_each_cell(Callback callback) |
55 | 10.8k | { |
56 | 10.8k | auto end = has_lazy_freelist() ? m_next_lazy_freelist_index : cell_count(); |
57 | 182k | for (size_t i = 0; i < end; ++i) |
58 | 171k | callback(cell(i)); |
59 | 10.8k | } Heap.cpp:void JS::HeapBlock::for_each_cell<JS::HeapBlock::for_each_cell_in_state<(JS::Cell::State)0, JS::Heap::finalize_unmarked_cells()::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1}>(JS::Heap::finalize_unmarked_cells()::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1})::{lambda(auto:1*)#1}>(JS::HeapBlock::for_each_cell_in_state<(JS::Cell::State)0, JS::Heap::finalize_unmarked_cells()::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1}>(JS::Heap::finalize_unmarked_cells()::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1})::{lambda(auto:1*)#1}) Line | Count | Source | 55 | 5.43k | { | 56 | 5.43k | auto end = has_lazy_freelist() ? m_next_lazy_freelist_index : cell_count(); | 57 | 91.2k | for (size_t i = 0; i < end; ++i) | 58 | 85.8k | callback(cell(i)); | 59 | 5.43k | } |
Heap.cpp:void JS::HeapBlock::for_each_cell<JS::HeapBlock::for_each_cell_in_state<(JS::Cell::State)0, JS::Heap::sweep_dead_cells(bool, Core::ElapsedTimer const&)::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1}>(JS::Heap::sweep_dead_cells(bool, Core::ElapsedTimer const&)::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1})::{lambda(auto:1*)#1}>(JS::HeapBlock::for_each_cell_in_state<(JS::Cell::State)0, JS::Heap::sweep_dead_cells(bool, Core::ElapsedTimer const&)::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1}>(JS::Heap::sweep_dead_cells(bool, Core::ElapsedTimer const&)::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1})::{lambda(auto:1*)#1}) Line | Count | Source | 55 | 5.43k | { | 56 | 5.43k | auto end = has_lazy_freelist() ? m_next_lazy_freelist_index : cell_count(); | 57 | 91.2k | for (size_t i = 0; i < end; ++i) | 58 | 85.8k | callback(cell(i)); | 59 | 5.43k | } |
|
60 | | |
61 | | template<Cell::State state, typename Callback> |
62 | | void for_each_cell_in_state(Callback callback) |
63 | 10.8k | { |
64 | 171k | for_each_cell([&](auto* cell) { |
65 | 171k | if (cell->state() == state) |
66 | 171k | callback(cell); |
67 | 171k | }); Heap.cpp:_ZZN2JS9HeapBlock22for_each_cell_in_stateILNS_4Cell5StateE0EZZNS_4Heap23finalize_unmarked_cellsEvENK3$_0clIS0_EEDaRT_EUlPS2_E_EEvT0_ENKUlPS7_E_clIS2_EEDaSC_ Line | Count | Source | 64 | 85.8k | for_each_cell([&](auto* cell) { | 65 | 85.8k | if (cell->state() == state) | 66 | 85.8k | callback(cell); | 67 | 85.8k | }); |
Heap.cpp:_ZZN2JS9HeapBlock22for_each_cell_in_stateILNS_4Cell5StateE0EZZNS_4Heap16sweep_dead_cellsEbRKN4Core12ElapsedTimerEENK3$_0clIS0_EEDaRT_EUlPS2_E_EEvT0_ENKUlPSB_E_clIS2_EEDaSG_ Line | Count | Source | 64 | 85.8k | for_each_cell([&](auto* cell) { | 65 | 85.8k | if (cell->state() == state) | 66 | 85.8k | callback(cell); | 67 | 85.8k | }); |
|
68 | 10.8k | } Heap.cpp:void JS::HeapBlock::for_each_cell_in_state<(JS::Cell::State)0, JS::Heap::finalize_unmarked_cells()::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1}>(JS::Heap::finalize_unmarked_cells()::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1}) Line | Count | Source | 63 | 5.43k | { | 64 | 5.43k | for_each_cell([&](auto* cell) { | 65 | 5.43k | if (cell->state() == state) | 66 | 5.43k | callback(cell); | 67 | 5.43k | }); | 68 | 5.43k | } |
Heap.cpp:void JS::HeapBlock::for_each_cell_in_state<(JS::Cell::State)0, JS::Heap::sweep_dead_cells(bool, Core::ElapsedTimer const&)::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1}>(JS::Heap::sweep_dead_cells(bool, Core::ElapsedTimer const&)::$_0::operator()<JS::HeapBlock>(JS::HeapBlock&) const::{lambda(JS::Cell*)#1}) Line | Count | Source | 63 | 5.43k | { | 64 | 5.43k | for_each_cell([&](auto* cell) { | 65 | 5.43k | if (cell->state() == state) | 66 | 5.43k | callback(cell); | 67 | 5.43k | }); | 68 | 5.43k | } |
|
69 | | |
70 | | static HeapBlock* from_cell(Cell const* cell) |
71 | 0 | { |
72 | 0 | return static_cast<HeapBlock*>(HeapBlockBase::from_cell(cell)); |
73 | 0 | } |
74 | | |
75 | | Cell* cell_from_possible_pointer(FlatPtr pointer) |
76 | 166k | { |
77 | 166k | if (pointer < reinterpret_cast<FlatPtr>(m_storage)) |
78 | 0 | return nullptr; |
79 | 166k | size_t cell_index = (pointer - reinterpret_cast<FlatPtr>(m_storage)) / m_cell_size; |
80 | 166k | auto end = has_lazy_freelist() ? m_next_lazy_freelist_index : cell_count(); |
81 | 166k | if (cell_index >= end) |
82 | 0 | return nullptr; |
83 | 166k | return cell(cell_index); |
84 | 166k | } |
85 | | |
86 | | bool is_valid_cell_pointer(Cell const* cell) |
87 | 166k | { |
88 | 166k | return cell_from_possible_pointer((FlatPtr)cell); |
89 | 166k | } |
90 | | |
91 | | IntrusiveListNode<HeapBlock> m_list_node; |
92 | | |
93 | 5.43k | CellAllocator& cell_allocator() { return m_cell_allocator; } |
94 | | |
95 | | private: |
96 | | HeapBlock(Heap&, CellAllocator&, size_t cell_size); |
97 | | |
98 | 354k | bool has_lazy_freelist() const { return m_next_lazy_freelist_index < cell_count(); } |
99 | | |
100 | | struct FreelistEntry final : public Cell { |
101 | | JS_CELL(FreelistEntry, Cell); |
102 | | |
103 | | RawGCPtr<FreelistEntry> next; |
104 | | }; |
105 | | |
106 | | Cell* cell(size_t index) |
107 | 423k | { |
108 | 423k | return reinterpret_cast<Cell*>(&m_storage[index * cell_size()]); |
109 | 423k | } |
110 | | |
111 | | CellAllocator& m_cell_allocator; |
112 | | size_t m_cell_size { 0 }; |
113 | | size_t m_next_lazy_freelist_index { 0 }; |
114 | | GCPtr<FreelistEntry> m_freelist; |
115 | | alignas(__BIGGEST_ALIGNMENT__) u8 m_storage[]; |
116 | | |
117 | | public: |
118 | | static constexpr size_t min_possible_cell_size = sizeof(FreelistEntry); |
119 | | }; |
120 | | |
121 | | } |