/home/uke/oil/mycpp/mark_sweep_heap.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef MARKSWEEP_HEAP_H |
2 | | #define MARKSWEEP_HEAP_H |
3 | | |
4 | | #include <stdlib.h> |
5 | | |
6 | | #include <vector> |
7 | | |
8 | | #include "mycpp/common.h" |
9 | | #include "mycpp/gc_obj.h" |
10 | | |
11 | | #if GC_ALWAYS |
12 | | #define VALIDATE_ROOTS 1 |
13 | | #else |
14 | | #define VALIDATE_ROOTS 0 // flip this manually to diagnose bugs |
15 | | #endif |
16 | | |
17 | | #if VALIDATE_ROOTS |
18 | | static void ValidateRoot(const RawObject* obj) { |
19 | | if (obj == nullptr) { |
20 | | return; |
21 | | } |
22 | | |
23 | | // Assuming 64-bit == 8 byte alignment |
24 | | if (reinterpret_cast<uintptr_t>(obj) & 0x3) { |
25 | | log("Misaligned object %p", obj); |
26 | | FAIL(kShouldNotGetHere); |
27 | | return; |
28 | | } |
29 | | |
30 | | ObjHeader* header = ObjHeader::FromObject(obj); |
31 | | // log("obj %p header %p", obj, header); |
32 | | |
33 | | if (reinterpret_cast<uintptr_t>(header) & 0x3) { |
34 | | log("Misaligned header %p", header); |
35 | | FAIL(kShouldNotGetHere); |
36 | | return; |
37 | | } |
38 | | |
39 | | switch (header->heap_tag) { |
40 | | case HeapTag::Global: |
41 | | case HeapTag::Opaque: |
42 | | case HeapTag::Scanned: |
43 | | case HeapTag::FixedSize: |
44 | | break; |
45 | | |
46 | | default: |
47 | | log("root %p heap %d type %d mask %d len %d", obj, header->heap_tag, |
48 | | header->type_tag, header->u_mask_npointers); |
49 | | FAIL(kShouldNotGetHere); |
50 | | break; |
51 | | } |
52 | | } |
53 | | #endif |
54 | | |
55 | | class MarkSet { |
56 | | public: |
57 | 209 | MarkSet() : bits_() { |
58 | 209 | } |
59 | | |
60 | | // ReInit() must be called at the start of MarkObjects(). Allocate() should |
61 | | // keep track of the maximum object ID. |
62 | 394 | void ReInit(int max_obj_id) { |
63 | | // https://stackoverflow.com/questions/8848575/fastest-way-to-reset-every-value-of-stdvectorint-to-0 |
64 | 394 | std::fill(bits_.begin(), bits_.end(), 0); |
65 | 394 | int max_byte_index = (max_obj_id >> 3) + 1; // round up |
66 | | // log("ReInit max_byte_index %d", max_byte_index); |
67 | 394 | bits_.resize(max_byte_index); |
68 | 394 | } |
69 | | |
70 | | // Called by MarkObjects() |
71 | 1.73k | void Mark(int obj_id) { |
72 | 1.73k | DCHECK(obj_id >= 0); |
73 | | // log("obj id %d", obj_id); |
74 | 1.73k | DCHECK(!IsMarked(obj_id)); |
75 | 0 | int byte_index = obj_id >> 3; // 8 bits per byte |
76 | 1.73k | int bit_index = obj_id & 0b111; |
77 | | // log("byte_index %d %d", byte_index, bit_index); |
78 | 1.73k | bits_[byte_index] |= (1 << bit_index); |
79 | 1.73k | } |
80 | | |
81 | | // Called by Sweep() |
82 | 139k | bool IsMarked(int obj_id) { |
83 | 139k | DCHECK(obj_id >= 0); |
84 | 0 | int byte_index = obj_id >> 3; |
85 | 139k | int bit_index = obj_id & 0b111; |
86 | 139k | return bits_[byte_index] & (1 << bit_index); |
87 | 139k | } |
88 | | |
89 | 2 | void Debug() { |
90 | | // TODO: should use feature detection of dprintf |
91 | 2 | #ifndef OILS_WIN32 |
92 | 2 | int n = bits_.size(); |
93 | 2 | dprintf(2, "[ "); |
94 | 8 | for (int i = 0; i < n; ++i) { |
95 | 6 | dprintf(2, "%02x ", bits_[i]); |
96 | 6 | } |
97 | 2 | dprintf(2, "] (%d bytes) \n", n); |
98 | 2 | dprintf(2, "[ "); |
99 | 2 | int num_bits = 0; |
100 | 8 | for (int i = 0; i < n; ++i) { |
101 | 54 | for (int j = 0; j < 8; ++j) { |
102 | 48 | int bit = (bits_[i] & (1 << j)) != 0; |
103 | 48 | dprintf(2, "%d", bit); |
104 | 48 | num_bits += bit; |
105 | 48 | } |
106 | 6 | } |
107 | 2 | dprintf(2, " ] (%d bits set)\n", num_bits); |
108 | 2 | #endif |
109 | 2 | } |
110 | | |
111 | | std::vector<uint8_t> bits_; // bit vector indexed by obj_id |
112 | | }; |
113 | | |
114 | | // A simple Pool allocator for allocating small objects. It maintains an ever |
115 | | // growing number of Blocks each consisting of a number of fixed size Cells. |
116 | | // Memory is handed out one Cell at a time. |
117 | | // Note: within the context of the Pool allocator we refer to object IDs as cell |
118 | | // IDs because in addition to identifying an object they're also used to index |
119 | | // into the Cell storage. |
120 | | template <int CellsPerBlock, size_t CellSize> |
121 | | class Pool { |
122 | | public: |
123 | | static constexpr size_t kMaxObjSize = CellSize; |
124 | | static constexpr int kBlockSize = CellSize * CellsPerBlock; |
125 | | |
126 | 140 | Pool() = default; _ZN4PoolILi682ELm24EEC2Ev Line | Count | Source | 126 | 67 | Pool() = default; |
_ZN4PoolILi341ELm48EEC2Ev Line | Count | Source | 126 | 67 | Pool() = default; |
Line | Count | Source | 126 | 4 | Pool() = default; |
Line | Count | Source | 126 | 2 | Pool() = default; |
|
127 | | |
128 | 16.3k | void* Allocate(int* obj_id) { |
129 | 16.3k | num_allocated_++; |
130 | | |
131 | 16.3k | if (!free_list_) { |
132 | | // Allocate a new Block and add every new Cell to the free list. |
133 | 137 | Block* block = static_cast<Block*>(malloc(sizeof(Block))); |
134 | 137 | blocks_.push_back(block); |
135 | 137 | bytes_allocated_ += kBlockSize; |
136 | 137 | num_free_ += CellsPerBlock; |
137 | | |
138 | | // The starting cell_id for Cells in this block. |
139 | 137 | int cell_id = (blocks_.size() - 1) * CellsPerBlock; |
140 | 64.4k | for (Cell& cell : block->cells) { |
141 | 64.4k | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); |
142 | 64.4k | free_cell->id = cell_id++; |
143 | 64.4k | free_cell->next = free_list_; |
144 | 64.4k | free_list_ = free_cell; |
145 | 64.4k | } |
146 | 137 | } |
147 | | |
148 | 16.3k | FreeCell* cell = free_list_; |
149 | 16.3k | free_list_ = free_list_->next; |
150 | 16.3k | num_free_--; |
151 | 16.3k | *obj_id = cell->id; |
152 | 16.3k | return cell; |
153 | 16.3k | } _ZN4PoolILi682ELm24EE8AllocateEPi Line | Count | Source | 128 | 11.1k | void* Allocate(int* obj_id) { | 129 | 11.1k | num_allocated_++; | 130 | | | 131 | 11.1k | if (!free_list_) { | 132 | | // Allocate a new Block and add every new Cell to the free list. | 133 | 62 | Block* block = static_cast<Block*>(malloc(sizeof(Block))); | 134 | 62 | blocks_.push_back(block); | 135 | 62 | bytes_allocated_ += kBlockSize; | 136 | 62 | num_free_ += CellsPerBlock; | 137 | | | 138 | | // The starting cell_id for Cells in this block. | 139 | 62 | int cell_id = (blocks_.size() - 1) * CellsPerBlock; | 140 | 42.2k | for (Cell& cell : block->cells) { | 141 | 42.2k | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); | 142 | 42.2k | free_cell->id = cell_id++; | 143 | 42.2k | free_cell->next = free_list_; | 144 | 42.2k | free_list_ = free_cell; | 145 | 42.2k | } | 146 | 62 | } | 147 | | | 148 | 11.1k | FreeCell* cell = free_list_; | 149 | 11.1k | free_list_ = free_list_->next; | 150 | 11.1k | num_free_--; | 151 | 11.1k | *obj_id = cell->id; | 152 | 11.1k | return cell; | 153 | 11.1k | } |
_ZN4PoolILi341ELm48EE8AllocateEPi Line | Count | Source | 128 | 5.19k | void* Allocate(int* obj_id) { | 129 | 5.19k | num_allocated_++; | 130 | | | 131 | 5.19k | if (!free_list_) { | 132 | | // Allocate a new Block and add every new Cell to the free list. | 133 | 65 | Block* block = static_cast<Block*>(malloc(sizeof(Block))); | 134 | 65 | blocks_.push_back(block); | 135 | 65 | bytes_allocated_ += kBlockSize; | 136 | 65 | num_free_ += CellsPerBlock; | 137 | | | 138 | | // The starting cell_id for Cells in this block. | 139 | 65 | int cell_id = (blocks_.size() - 1) * CellsPerBlock; | 140 | 22.1k | for (Cell& cell : block->cells) { | 141 | 22.1k | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); | 142 | 22.1k | free_cell->id = cell_id++; | 143 | 22.1k | free_cell->next = free_list_; | 144 | 22.1k | free_list_ = free_cell; | 145 | 22.1k | } | 146 | 65 | } | 147 | | | 148 | 5.19k | FreeCell* cell = free_list_; | 149 | 5.19k | free_list_ = free_list_->next; | 150 | 5.19k | num_free_--; | 151 | 5.19k | *obj_id = cell->id; | 152 | 5.19k | return cell; | 153 | 5.19k | } |
_ZN4PoolILi2ELm32EE8AllocateEPi Line | Count | Source | 128 | 14 | void* Allocate(int* obj_id) { | 129 | 14 | num_allocated_++; | 130 | | | 131 | 14 | if (!free_list_) { | 132 | | // Allocate a new Block and add every new Cell to the free list. | 133 | 6 | Block* block = static_cast<Block*>(malloc(sizeof(Block))); | 134 | 6 | blocks_.push_back(block); | 135 | 6 | bytes_allocated_ += kBlockSize; | 136 | 6 | num_free_ += CellsPerBlock; | 137 | | | 138 | | // The starting cell_id for Cells in this block. | 139 | 6 | int cell_id = (blocks_.size() - 1) * CellsPerBlock; | 140 | 12 | for (Cell& cell : block->cells) { | 141 | 12 | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); | 142 | 12 | free_cell->id = cell_id++; | 143 | 12 | free_cell->next = free_list_; | 144 | 12 | free_list_ = free_cell; | 145 | 12 | } | 146 | 6 | } | 147 | | | 148 | 14 | FreeCell* cell = free_list_; | 149 | 14 | free_list_ = free_list_->next; | 150 | 14 | num_free_--; | 151 | 14 | *obj_id = cell->id; | 152 | 14 | return cell; | 153 | 14 | } |
_ZN4PoolILi1ELm32EE8AllocateEPi Line | Count | Source | 128 | 4 | void* Allocate(int* obj_id) { | 129 | 4 | num_allocated_++; | 130 | | | 131 | 4 | if (!free_list_) { | 132 | | // Allocate a new Block and add every new Cell to the free list. | 133 | 4 | Block* block = static_cast<Block*>(malloc(sizeof(Block))); | 134 | 4 | blocks_.push_back(block); | 135 | 4 | bytes_allocated_ += kBlockSize; | 136 | 4 | num_free_ += CellsPerBlock; | 137 | | | 138 | | // The starting cell_id for Cells in this block. | 139 | 4 | int cell_id = (blocks_.size() - 1) * CellsPerBlock; | 140 | 4 | for (Cell& cell : block->cells) { | 141 | 4 | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); | 142 | 4 | free_cell->id = cell_id++; | 143 | 4 | free_cell->next = free_list_; | 144 | 4 | free_list_ = free_cell; | 145 | 4 | } | 146 | 4 | } | 147 | | | 148 | 4 | FreeCell* cell = free_list_; | 149 | 4 | free_list_ = free_list_->next; | 150 | 4 | num_free_--; | 151 | 4 | *obj_id = cell->id; | 152 | 4 | return cell; | 153 | 4 | } |
|
154 | | |
155 | 262 | void PrepareForGc() { |
156 | 262 | DCHECK(!gc_underway_); |
157 | 0 | gc_underway_ = true; |
158 | 262 | mark_set_.ReInit(blocks_.size() * CellsPerBlock); |
159 | 262 | } _ZN4PoolILi682ELm24EE12PrepareForGcEv Line | Count | Source | 155 | 128 | void PrepareForGc() { | 156 | 128 | DCHECK(!gc_underway_); | 157 | 0 | gc_underway_ = true; | 158 | 128 | mark_set_.ReInit(blocks_.size() * CellsPerBlock); | 159 | 128 | } |
_ZN4PoolILi341ELm48EE12PrepareForGcEv Line | Count | Source | 155 | 128 | void PrepareForGc() { | 156 | 128 | DCHECK(!gc_underway_); | 157 | 0 | gc_underway_ = true; | 158 | 128 | mark_set_.ReInit(blocks_.size() * CellsPerBlock); | 159 | 128 | } |
_ZN4PoolILi2ELm32EE12PrepareForGcEv Line | Count | Source | 155 | 4 | void PrepareForGc() { | 156 | 4 | DCHECK(!gc_underway_); | 157 | 0 | gc_underway_ = true; | 158 | 4 | mark_set_.ReInit(blocks_.size() * CellsPerBlock); | 159 | 4 | } |
_ZN4PoolILi1ELm32EE12PrepareForGcEv Line | Count | Source | 155 | 2 | void PrepareForGc() { | 156 | 2 | DCHECK(!gc_underway_); | 157 | 0 | gc_underway_ = true; | 158 | 2 | mark_set_.ReInit(blocks_.size() * CellsPerBlock); | 159 | 2 | } |
|
160 | | |
161 | 1.89k | bool IsMarked(int cell_id) { |
162 | 1.89k | DCHECK(gc_underway_); |
163 | 0 | return mark_set_.IsMarked(cell_id); |
164 | 1.89k | } _ZN4PoolILi682ELm24EE8IsMarkedEi Line | Count | Source | 161 | 1.61k | bool IsMarked(int cell_id) { | 162 | 1.61k | DCHECK(gc_underway_); | 163 | 0 | return mark_set_.IsMarked(cell_id); | 164 | 1.61k | } |
_ZN4PoolILi341ELm48EE8IsMarkedEi Line | Count | Source | 161 | 276 | bool IsMarked(int cell_id) { | 162 | 276 | DCHECK(gc_underway_); | 163 | 0 | return mark_set_.IsMarked(cell_id); | 164 | 276 | } |
|
165 | | |
166 | 1.69k | void Mark(int cell_id) { |
167 | 1.69k | DCHECK(gc_underway_); |
168 | 0 | mark_set_.Mark(cell_id); |
169 | 1.69k | } _ZN4PoolILi682ELm24EE4MarkEi Line | Count | Source | 166 | 1.47k | void Mark(int cell_id) { | 167 | 1.47k | DCHECK(gc_underway_); | 168 | 0 | mark_set_.Mark(cell_id); | 169 | 1.47k | } |
_ZN4PoolILi341ELm48EE4MarkEi Line | Count | Source | 166 | 220 | void Mark(int cell_id) { | 167 | 220 | DCHECK(gc_underway_); | 168 | 0 | mark_set_.Mark(cell_id); | 169 | 220 | } |
_ZN4PoolILi1ELm32EE4MarkEi Line | Count | Source | 166 | 2 | void Mark(int cell_id) { | 167 | 2 | DCHECK(gc_underway_); | 168 | 0 | mark_set_.Mark(cell_id); | 169 | 2 | } |
|
170 | | |
171 | 262 | void Sweep() { |
172 | 262 | DCHECK(gc_underway_); |
173 | | // Iterate over every Cell linking the free ones into a new free list. |
174 | 0 | num_free_ = 0; |
175 | 262 | free_list_ = nullptr; |
176 | 262 | int cell_id = 0; |
177 | 267 | for (Block* block : blocks_) { |
178 | 134k | for (Cell& cell : block->cells) { |
179 | 134k | if (!mark_set_.IsMarked(cell_id)) { |
180 | 132k | num_free_++; |
181 | 132k | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); |
182 | 132k | free_cell->id = cell_id; |
183 | 132k | free_cell->next = free_list_; |
184 | 132k | free_list_ = free_cell; |
185 | 132k | } |
186 | 134k | cell_id++; |
187 | 134k | } |
188 | 267 | } |
189 | 262 | gc_underway_ = false; |
190 | 262 | } _ZN4PoolILi682ELm24EE5SweepEv Line | Count | Source | 171 | 128 | void Sweep() { | 172 | 128 | DCHECK(gc_underway_); | 173 | | // Iterate over every Cell linking the free ones into a new free list. | 174 | 0 | num_free_ = 0; | 175 | 128 | free_list_ = nullptr; | 176 | 128 | int cell_id = 0; | 177 | 133 | for (Block* block : blocks_) { | 178 | 90.7k | for (Cell& cell : block->cells) { | 179 | 90.7k | if (!mark_set_.IsMarked(cell_id)) { | 180 | 89.2k | num_free_++; | 181 | 89.2k | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); | 182 | 89.2k | free_cell->id = cell_id; | 183 | 89.2k | free_cell->next = free_list_; | 184 | 89.2k | free_list_ = free_cell; | 185 | 89.2k | } | 186 | 90.7k | cell_id++; | 187 | 90.7k | } | 188 | 133 | } | 189 | 128 | gc_underway_ = false; | 190 | 128 | } |
_ZN4PoolILi341ELm48EE5SweepEv Line | Count | Source | 171 | 128 | void Sweep() { | 172 | 128 | DCHECK(gc_underway_); | 173 | | // Iterate over every Cell linking the free ones into a new free list. | 174 | 0 | num_free_ = 0; | 175 | 128 | free_list_ = nullptr; | 176 | 128 | int cell_id = 0; | 177 | 128 | for (Block* block : blocks_) { | 178 | 43.6k | for (Cell& cell : block->cells) { | 179 | 43.6k | if (!mark_set_.IsMarked(cell_id)) { | 180 | 43.4k | num_free_++; | 181 | 43.4k | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); | 182 | 43.4k | free_cell->id = cell_id; | 183 | 43.4k | free_cell->next = free_list_; | 184 | 43.4k | free_list_ = free_cell; | 185 | 43.4k | } | 186 | 43.6k | cell_id++; | 187 | 43.6k | } | 188 | 128 | } | 189 | 128 | gc_underway_ = false; | 190 | 128 | } |
_ZN4PoolILi2ELm32EE5SweepEv Line | Count | Source | 171 | 4 | void Sweep() { | 172 | 4 | DCHECK(gc_underway_); | 173 | | // Iterate over every Cell linking the free ones into a new free list. | 174 | 0 | num_free_ = 0; | 175 | 4 | free_list_ = nullptr; | 176 | 4 | int cell_id = 0; | 177 | 4 | for (Block* block : blocks_) { | 178 | 4 | for (Cell& cell : block->cells) { | 179 | 4 | if (!mark_set_.IsMarked(cell_id)) { | 180 | 4 | num_free_++; | 181 | 4 | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); | 182 | 4 | free_cell->id = cell_id; | 183 | 4 | free_cell->next = free_list_; | 184 | 4 | free_list_ = free_cell; | 185 | 4 | } | 186 | 4 | cell_id++; | 187 | 4 | } | 188 | 2 | } | 189 | 4 | gc_underway_ = false; | 190 | 4 | } |
_ZN4PoolILi1ELm32EE5SweepEv Line | Count | Source | 171 | 2 | void Sweep() { | 172 | 2 | DCHECK(gc_underway_); | 173 | | // Iterate over every Cell linking the free ones into a new free list. | 174 | 0 | num_free_ = 0; | 175 | 2 | free_list_ = nullptr; | 176 | 2 | int cell_id = 0; | 177 | 4 | for (Block* block : blocks_) { | 178 | 4 | for (Cell& cell : block->cells) { | 179 | 4 | if (!mark_set_.IsMarked(cell_id)) { | 180 | 2 | num_free_++; | 181 | 2 | FreeCell* free_cell = reinterpret_cast<FreeCell*>(cell); | 182 | 2 | free_cell->id = cell_id; | 183 | 2 | free_cell->next = free_list_; | 184 | 2 | free_list_ = free_cell; | 185 | 2 | } | 186 | 4 | cell_id++; | 187 | 4 | } | 188 | 4 | } | 189 | 2 | gc_underway_ = false; | 190 | 2 | } |
|
191 | | |
192 | 136 | void Free() { |
193 | 137 | for (Block* block : blocks_) { |
194 | 137 | free(block); |
195 | 137 | } |
196 | 136 | blocks_.clear(); |
197 | 136 | num_free_ = 0; |
198 | 136 | } _ZN4PoolILi682ELm24EE4FreeEv Line | Count | Source | 192 | 65 | void Free() { | 193 | 65 | for (Block* block : blocks_) { | 194 | 62 | free(block); | 195 | 62 | } | 196 | 65 | blocks_.clear(); | 197 | 65 | num_free_ = 0; | 198 | 65 | } |
_ZN4PoolILi341ELm48EE4FreeEv Line | Count | Source | 192 | 65 | void Free() { | 193 | 65 | for (Block* block : blocks_) { | 194 | 65 | free(block); | 195 | 65 | } | 196 | 65 | blocks_.clear(); | 197 | 65 | num_free_ = 0; | 198 | 65 | } |
_ZN4PoolILi2ELm32EE4FreeEv Line | Count | Source | 192 | 4 | void Free() { | 193 | 6 | for (Block* block : blocks_) { | 194 | 6 | free(block); | 195 | 6 | } | 196 | 4 | blocks_.clear(); | 197 | 4 | num_free_ = 0; | 198 | 4 | } |
_ZN4PoolILi1ELm32EE4FreeEv Line | Count | Source | 192 | 2 | void Free() { | 193 | 4 | for (Block* block : blocks_) { | 194 | 4 | free(block); | 195 | 4 | } | 196 | 2 | blocks_.clear(); | 197 | 2 | num_free_ = 0; | 198 | 2 | } |
|
199 | | |
200 | 28 | int num_allocated() { |
201 | 28 | return num_allocated_; |
202 | 28 | } _ZN4PoolILi682ELm24EE13num_allocatedEv Line | Count | Source | 200 | 12 | int num_allocated() { | 201 | 12 | return num_allocated_; | 202 | 12 | } |
_ZN4PoolILi341ELm48EE13num_allocatedEv Line | Count | Source | 200 | 12 | int num_allocated() { | 201 | 12 | return num_allocated_; | 202 | 12 | } |
_ZN4PoolILi2ELm32EE13num_allocatedEv Line | Count | Source | 200 | 4 | int num_allocated() { | 201 | 4 | return num_allocated_; | 202 | 4 | } |
|
203 | | |
204 | 16 | int64_t bytes_allocated() { |
205 | 16 | return bytes_allocated_; |
206 | 16 | } _ZN4PoolILi682ELm24EE15bytes_allocatedEv Line | Count | Source | 204 | 6 | int64_t bytes_allocated() { | 205 | 6 | return bytes_allocated_; | 206 | 6 | } |
_ZN4PoolILi341ELm48EE15bytes_allocatedEv Line | Count | Source | 204 | 6 | int64_t bytes_allocated() { | 205 | 6 | return bytes_allocated_; | 206 | 6 | } |
_ZN4PoolILi2ELm32EE15bytes_allocatedEv Line | Count | Source | 204 | 4 | int64_t bytes_allocated() { | 205 | 4 | return bytes_allocated_; | 206 | 4 | } |
|
207 | | |
208 | 5.04k | int num_live() { |
209 | 5.04k | #ifndef OPTIMIZED |
210 | 5.04k | int capacity = blocks_.size() * CellsPerBlock; |
211 | | // log("Pool capacity = %d", capacity); |
212 | | // log("Pool num_free_ = %d", num_free_); |
213 | 5.04k | DCHECK(num_free_ <= capacity); |
214 | 0 | #endif |
215 | 0 | return blocks_.size() * CellsPerBlock - num_free_; |
216 | 5.04k | } _ZN4PoolILi682ELm24EE8num_liveEv Line | Count | Source | 208 | 2.51k | int num_live() { | 209 | 2.51k | #ifndef OPTIMIZED | 210 | 2.51k | int capacity = blocks_.size() * CellsPerBlock; | 211 | | // log("Pool capacity = %d", capacity); | 212 | | // log("Pool num_free_ = %d", num_free_); | 213 | 2.51k | DCHECK(num_free_ <= capacity); | 214 | 0 | #endif | 215 | 0 | return blocks_.size() * CellsPerBlock - num_free_; | 216 | 2.51k | } |
_ZN4PoolILi341ELm48EE8num_liveEv Line | Count | Source | 208 | 2.51k | int num_live() { | 209 | 2.51k | #ifndef OPTIMIZED | 210 | 2.51k | int capacity = blocks_.size() * CellsPerBlock; | 211 | | // log("Pool capacity = %d", capacity); | 212 | | // log("Pool num_free_ = %d", num_free_); | 213 | 2.51k | DCHECK(num_free_ <= capacity); | 214 | 0 | #endif | 215 | 0 | return blocks_.size() * CellsPerBlock - num_free_; | 216 | 2.51k | } |
_ZN4PoolILi2ELm32EE8num_liveEv Line | Count | Source | 208 | 6 | int num_live() { | 209 | 6 | #ifndef OPTIMIZED | 210 | 6 | int capacity = blocks_.size() * CellsPerBlock; | 211 | | // log("Pool capacity = %d", capacity); | 212 | | // log("Pool num_free_ = %d", num_free_); | 213 | 6 | DCHECK(num_free_ <= capacity); | 214 | 0 | #endif | 215 | 0 | return blocks_.size() * CellsPerBlock - num_free_; | 216 | 6 | } |
_ZN4PoolILi1ELm32EE8num_liveEv Line | Count | Source | 208 | 2 | int num_live() { | 209 | 2 | #ifndef OPTIMIZED | 210 | 2 | int capacity = blocks_.size() * CellsPerBlock; | 211 | | // log("Pool capacity = %d", capacity); | 212 | | // log("Pool num_free_ = %d", num_free_); | 213 | 2 | DCHECK(num_free_ <= capacity); | 214 | 0 | #endif | 215 | 0 | return blocks_.size() * CellsPerBlock - num_free_; | 216 | 2 | } |
|
217 | | |
218 | | private: |
219 | | using Cell = uint8_t[CellSize]; |
220 | | |
221 | | struct Block { |
222 | | Cell cells[CellsPerBlock]; |
223 | | }; |
224 | | |
225 | | // Unused/free cells are tracked via a linked list of FreeCells. The FreeCells |
226 | | // are stored in the unused Cells, so it takes no extra memory to track them. |
227 | | struct FreeCell { |
228 | | int id; |
229 | | FreeCell* next; |
230 | | }; |
231 | | static_assert(CellSize >= sizeof(FreeCell), "CellSize is too small"); |
232 | | |
233 | | // Whether a GC is underway, for asserting that calls are in order. |
234 | | bool gc_underway_ = false; |
235 | | |
236 | | FreeCell* free_list_ = nullptr; |
237 | | int num_free_ = 0; |
238 | | int num_allocated_ = 0; |
239 | | int64_t bytes_allocated_ = 0; |
240 | | std::vector<Block*> blocks_; |
241 | | MarkSet mark_set_; |
242 | | |
243 | | DISALLOW_COPY_AND_ASSIGN(Pool); |
244 | | }; |
245 | | |
246 | | class MarkSweepHeap { |
247 | | public: |
248 | | // reserve 32 frames to start |
249 | 67 | MarkSweepHeap() { |
250 | 67 | } |
251 | | |
252 | | void Init(); // use default threshold |
253 | | void Init(int gc_threshold); |
254 | | |
255 | 16.2k | void PushRoot(RawObject** p) { |
256 | | #if VALIDATE_ROOTS |
257 | | ValidateRoot(*p); |
258 | | #endif |
259 | 16.2k | roots_.push_back(p); |
260 | 16.2k | } |
261 | | |
262 | 16.2k | void PopRoot() { |
263 | 16.2k | roots_.pop_back(); |
264 | 16.2k | } |
265 | | |
266 | 9 | void RootGlobalVar(void* root) { |
267 | 9 | global_roots_.push_back(reinterpret_cast<RawObject*>(root)); |
268 | 9 | } |
269 | | |
270 | | void* Allocate(size_t num_bytes, int* obj_id, int* pool_id); |
271 | | |
272 | | #if 0 |
273 | | void* Reallocate(void* p, size_t num_bytes); |
274 | | #endif |
275 | | int MaybeCollect(); |
276 | | int Collect(); |
277 | | |
278 | | void MaybeMarkAndPush(RawObject* obj); |
279 | | void TraceChildren(); |
280 | | |
281 | | void Sweep(); |
282 | | |
283 | | void PrintStats(int fd); // public for testing |
284 | | void PrintShortStats(); |
285 | | |
286 | | void CleanProcessExit(); // do one last GC, used in unit tests |
287 | | void ProcessExit(); // main() lets OS clean up, except ASAN variant |
288 | | |
289 | 2.51k | int num_live() { |
290 | 2.51k | return num_live_ |
291 | 2.51k | #ifndef NO_POOL_ALLOC |
292 | 2.51k | + pool1_.num_live() + pool2_.num_live() |
293 | 2.51k | #endif |
294 | 2.51k | ; |
295 | 2.51k | } |
296 | | |
297 | | bool is_initialized_ = true; // mark/sweep doesn't need to be initialized |
298 | | |
299 | | // Runtime params |
300 | | |
301 | | // Threshold is a number of live objects, since we aren't keeping track of |
302 | | // total bytes |
303 | | int gc_threshold_; |
304 | | |
305 | | // Show debug logging |
306 | | bool gc_verbose_ = false; |
307 | | |
308 | | // Current stats |
309 | | int num_live_ = 0; |
310 | | // Should we keep track of sizes? |
311 | | // int64_t bytes_live_ = 0; |
312 | | |
313 | | // Cumulative stats |
314 | | int max_survived_ = 0; // max # live after a collection |
315 | | int num_allocated_ = 0; |
316 | | int64_t bytes_allocated_ = 0; // avoid overflow |
317 | | int num_gc_points_ = 0; // manual collection points |
318 | | int num_collections_ = 0; |
319 | | int num_growths_; |
320 | | double max_gc_millis_ = 0.0; |
321 | | double total_gc_millis_ = 0.0; |
322 | | |
323 | | #ifndef NO_POOL_ALLOC |
324 | | // 16,384 / 24 bytes = 682 cells (rounded), 16,368 bytes |
325 | | // 16,384 / 48 bytes = 341 cells (rounded), 16,368 bytes |
326 | | // Conveniently, the glibc malloc header is 16 bytes, giving exactly 16 Ki |
327 | | // differences |
328 | | Pool<682, 24> pool1_; |
329 | | Pool<341, 48> pool2_; |
330 | | #endif |
331 | | |
332 | | std::vector<RawObject**> roots_; |
333 | | std::vector<RawObject*> global_roots_; |
334 | | |
335 | | // Allocate() appends live objects, and Sweep() compacts it |
336 | | std::vector<ObjHeader*> live_objs_; |
337 | | // Allocate lazily frees these, and Sweep() replenishes it |
338 | | std::vector<ObjHeader*> to_free_; |
339 | | |
340 | | std::vector<ObjHeader*> gray_stack_; |
341 | | MarkSet mark_set_; |
342 | | |
343 | | int greatest_obj_id_ = 0; |
344 | | |
345 | | private: |
346 | | void FreeEverything(); |
347 | | void MaybePrintStats(); |
348 | | |
349 | | DISALLOW_COPY_AND_ASSIGN(MarkSweepHeap); |
350 | | }; |
351 | | |
352 | | #endif // MARKSWEEP_HEAP_H |