| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 21:29:22 +01:00
										 |  |  | #include <AK/Badge.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #include <AK/HashTable.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-08 12:48:16 +00:00
										 |  |  | #include <AK/StackInfo.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-15 20:46:52 +02:00
										 |  |  | #include <AK/TemporaryChange.h>
 | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  | #include <LibCore/ElapsedTimer.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  | #include <LibJS/Heap/Allocator.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-18 20:03:17 +01:00
										 |  |  | #include <LibJS/Heap/Handle.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-16 14:20:30 +01:00
										 |  |  | #include <LibJS/Heap/Heap.h>
 | 
					
						
							|  |  |  | #include <LibJS/Heap/HeapBlock.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #include <LibJS/Interpreter.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-16 14:20:30 +01:00
										 |  |  | #include <LibJS/Runtime/Object.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | #include <setjmp.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace JS { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-20 19:24:44 +02:00
										 |  |  | Heap::Heap(VM& vm) | 
					
						
							|  |  |  |     : m_vm(vm) | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |     m_allocators.append(make<Allocator>(16)); | 
					
						
							|  |  |  |     m_allocators.append(make<Allocator>(32)); | 
					
						
							|  |  |  |     m_allocators.append(make<Allocator>(64)); | 
					
						
							|  |  |  |     m_allocators.append(make<Allocator>(128)); | 
					
						
							|  |  |  |     m_allocators.append(make<Allocator>(256)); | 
					
						
							|  |  |  |     m_allocators.append(make<Allocator>(512)); | 
					
						
							|  |  |  |     m_allocators.append(make<Allocator>(1024)); | 
					
						
							|  |  |  |     m_allocators.append(make<Allocator>(3172)); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Heap::~Heap() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-23 14:11:19 +01:00
										 |  |  |     collect_garbage(CollectionType::CollectEverything); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  | ALWAYS_INLINE Allocator& Heap::allocator_for_size(size_t cell_size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for (auto& allocator : m_allocators) { | 
					
						
							|  |  |  |         if (allocator->cell_size() >= cell_size) | 
					
						
							|  |  |  |             return *allocator; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ASSERT_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | Cell* Heap::allocate_cell(size_t size) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-06 12:36:49 +02:00
										 |  |  |     if (should_collect_on_every_allocation()) { | 
					
						
							| 
									
										
										
										
											2020-03-16 19:18:46 +01:00
										 |  |  |         collect_garbage(); | 
					
						
							| 
									
										
										
										
											2020-04-06 12:36:49 +02:00
										 |  |  |     } else if (m_allocations_since_last_gc > m_max_allocations_between_gc) { | 
					
						
							|  |  |  |         m_allocations_since_last_gc = 0; | 
					
						
							|  |  |  |         collect_garbage(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         ++m_allocations_since_last_gc; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-16 19:18:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |     auto& allocator = allocator_for_size(size); | 
					
						
							|  |  |  |     return allocator.allocate_cell(*this); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  | void Heap::collect_garbage(CollectionType collection_type, bool print_report) | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-21 14:35:19 +02:00
										 |  |  |     ASSERT(!m_collecting_garbage); | 
					
						
							|  |  |  |     TemporaryChange change(m_collecting_garbage, true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  |     Core::ElapsedTimer collection_measurement_timer; | 
					
						
							|  |  |  |     collection_measurement_timer.start(); | 
					
						
							| 
									
										
										
										
											2020-03-23 14:11:19 +01:00
										 |  |  |     if (collection_type == CollectionType::CollectGarbage) { | 
					
						
							| 
									
										
										
										
											2020-04-19 11:30:47 +02:00
										 |  |  |         if (m_gc_deferrals) { | 
					
						
							|  |  |  |             m_should_gc_when_deferral_ends = true; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-23 14:11:19 +01:00
										 |  |  |         HashTable<Cell*> roots; | 
					
						
							|  |  |  |         gather_roots(roots); | 
					
						
							|  |  |  |         mark_live_cells(roots); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  |     sweep_dead_cells(print_report, collection_measurement_timer); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-15 15:12:34 +01:00
										 |  |  | void Heap::gather_roots(HashTable<Cell*>& roots) | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-21 13:47:33 +02:00
										 |  |  |     vm().gather_roots(roots); | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  |     gather_conservative_roots(roots); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-18 20:03:17 +01:00
										 |  |  |     for (auto* handle : m_handles) | 
					
						
							|  |  |  |         roots.set(handle->cell()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-19 17:24:56 +02:00
										 |  |  |     for (auto* list : m_marked_value_lists) { | 
					
						
							|  |  |  |         for (auto& value : list->values()) { | 
					
						
							|  |  |  |             if (value.is_cell()) | 
					
						
							|  |  |  |                 roots.set(value.as_cell()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |     dbgln("gather_roots:"); | 
					
						
							|  |  |  |     for (auto* root : roots) | 
					
						
							|  |  |  |         dbgln("  + {}", root); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-05 12:26:23 +01:00
										 |  |  | __attribute__((no_sanitize("address"))) void Heap::gather_conservative_roots(HashTable<Cell*>& roots) | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     FlatPtr dummy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |     dbgln("gather_conservative_roots:"); | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     jmp_buf buf; | 
					
						
							|  |  |  |     setjmp(buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     HashTable<FlatPtr> possible_pointers; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-23 13:14:57 +01:00
										 |  |  |     const FlatPtr* raw_jmp_buf = reinterpret_cast<const FlatPtr*>(buf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-08 22:31:43 +04:30
										 |  |  |     for (size_t i = 0; i < ((size_t)sizeof(buf)) / sizeof(FlatPtr); i += sizeof(FlatPtr)) | 
					
						
							| 
									
										
										
										
											2020-03-23 13:14:57 +01:00
										 |  |  |         possible_pointers.set(raw_jmp_buf[i]); | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     FlatPtr stack_reference = reinterpret_cast<FlatPtr>(&dummy); | 
					
						
							| 
									
										
										
										
											2020-11-08 12:48:16 +00:00
										 |  |  |     auto& stack_info = m_vm.stack_info(); | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-08 12:48:16 +00:00
										 |  |  |     for (FlatPtr stack_address = stack_reference; stack_address < stack_info.top(); stack_address += sizeof(FlatPtr)) { | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  |         auto data = *reinterpret_cast<FlatPtr*>(stack_address); | 
					
						
							|  |  |  |         possible_pointers.set(data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 20:24:08 +01:00
										 |  |  |     HashTable<HeapBlock*> all_live_heap_blocks; | 
					
						
							|  |  |  |     for_each_block([&](auto& block) { | 
					
						
							|  |  |  |         all_live_heap_blocks.set(&block); | 
					
						
							|  |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  |     for (auto possible_pointer : possible_pointers) { | 
					
						
							|  |  |  |         if (!possible_pointer) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |         dbgln("  ? {}", (const void*)possible_pointer); | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-11-10 20:24:08 +01:00
										 |  |  |         auto* possible_heap_block = HeapBlock::from_cell(reinterpret_cast<const Cell*>(possible_pointer)); | 
					
						
							|  |  |  |         if (all_live_heap_blocks.contains(possible_heap_block)) { | 
					
						
							|  |  |  |             if (auto* cell = possible_heap_block->cell_from_possible_pointer(possible_pointer)) { | 
					
						
							|  |  |  |                 if (cell->is_live()) { | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |                     dbgln("  ?-> {}", (const void*)cell); | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-11-10 20:24:08 +01:00
										 |  |  |                     roots.set(cell); | 
					
						
							|  |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |                     dbgln("  #-> {}", (const void*)cell); | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-11-10 20:24:08 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-03-16 19:08:59 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 22:11:22 +01:00
										 |  |  | class MarkingVisitor final : public Cell::Visitor { | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-05-04 13:30:40 +02:00
										 |  |  |     MarkingVisitor() { } | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-16 16:07:50 +02:00
										 |  |  |     virtual void visit_impl(Cell* cell) | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-03-09 22:11:22 +01:00
										 |  |  |         if (cell->is_marked()) | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |         dbgln("  ! {}", cell); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-03-09 22:11:22 +01:00
										 |  |  |         cell->set_marked(true); | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:36 +01:00
										 |  |  |         cell->visit_edges(*this); | 
					
						
							| 
									
										
										
										
											2020-03-09 22:11:22 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 22:11:22 +01:00
										 |  |  | void Heap::mark_live_cells(const HashTable<Cell*>& roots) | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |     dbgln("mark_live_cells:"); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-03-09 22:11:22 +01:00
										 |  |  |     MarkingVisitor visitor; | 
					
						
							| 
									
										
										
										
											2020-04-16 16:07:50 +02:00
										 |  |  |     for (auto* root : roots) | 
					
						
							| 
									
										
										
										
											2020-03-09 22:11:22 +01:00
										 |  |  |         visitor.visit(root); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  | void Heap::sweep_dead_cells(bool print_report, const Core::ElapsedTimer& measurement_timer) | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |     dbgln("sweep_dead_cells:"); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-03-21 11:45:50 +01:00
										 |  |  |     Vector<HeapBlock*, 32> empty_blocks; | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |     Vector<HeapBlock*, 32> full_blocks_that_became_usable; | 
					
						
							| 
									
										
										
										
											2020-03-21 11:45:50 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  |     size_t collected_cells = 0; | 
					
						
							|  |  |  |     size_t live_cells = 0; | 
					
						
							|  |  |  |     size_t collected_cell_bytes = 0; | 
					
						
							|  |  |  |     size_t live_cell_bytes = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |     for_each_block([&](auto& block) { | 
					
						
							| 
									
										
										
										
											2020-03-21 11:45:50 +01:00
										 |  |  |         bool block_has_live_cells = false; | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |         bool block_was_full = block.is_full(); | 
					
						
							|  |  |  |         block.for_each_cell([&](Cell* cell) { | 
					
						
							| 
									
										
										
										
											2020-03-08 23:17:34 +01:00
										 |  |  |             if (cell->is_live()) { | 
					
						
							|  |  |  |                 if (!cell->is_marked()) { | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |                     dbgln("  ~ {}", cell); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |                     block.deallocate(cell); | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  |                     ++collected_cells; | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |                     collected_cell_bytes += block.cell_size(); | 
					
						
							| 
									
										
										
										
											2020-03-08 23:17:34 +01:00
										 |  |  |                 } else { | 
					
						
							|  |  |  |                     cell->set_marked(false); | 
					
						
							| 
									
										
										
										
											2020-03-21 11:45:50 +01:00
										 |  |  |                     block_has_live_cells = true; | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  |                     ++live_cells; | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |                     live_cell_bytes += block.cell_size(); | 
					
						
							| 
									
										
										
										
											2020-03-08 23:17:34 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-03-21 11:45:50 +01:00
										 |  |  |         if (!block_has_live_cells) | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |             empty_blocks.append(&block); | 
					
						
							|  |  |  |         else if (block_was_full != block.is_full()) | 
					
						
							|  |  |  |             full_blocks_that_became_usable.append(&block); | 
					
						
							|  |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2020-03-21 11:45:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (auto* block : empty_blocks) { | 
					
						
							| 
									
										
										
										
											2020-03-23 13:45:01 +01:00
										 |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |         dbgln(" - HeapBlock empty @ {}: cell_size={}", block, block->cell_size()); | 
					
						
							| 
									
										
										
										
											2020-03-23 13:45:01 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |         allocator_for_size(block->cell_size()).block_did_become_empty({}, *block); | 
					
						
							| 
									
										
										
										
											2020-03-21 11:45:50 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |     for (auto* block : full_blocks_that_became_usable) { | 
					
						
							| 
									
										
										
										
											2020-03-23 13:45:01 +01:00
										 |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |         dbgln(" - HeapBlock usable again @ {}: cell_size={}", block, block->cell_size()); | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |         allocator_for_size(block->cell_size()).block_did_become_usable({}, *block); | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef HEAP_DEBUG
 | 
					
						
							|  |  |  |     for_each_block([&](auto& block) { | 
					
						
							| 
									
										
										
										
											2020-12-06 16:55:19 +00:00
										 |  |  |         dbgln(" > Live HeapBlock @ {}: cell_size={}", &block, block.cell_size()); | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2020-03-23 13:45:01 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     int time_spent = measurement_timer.elapsed(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (print_report) { | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |         size_t live_block_count = 0; | 
					
						
							|  |  |  |         for_each_block([&](auto&) { | 
					
						
							|  |  |  |             ++live_block_count; | 
					
						
							|  |  |  |             return IterationDecision::Continue; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-04 15:44:40 +01:00
										 |  |  |         dbgln("Garbage collection report"); | 
					
						
							|  |  |  |         dbgln("============================================="); | 
					
						
							|  |  |  |         dbgln("     Time spent: {} ms", time_spent); | 
					
						
							|  |  |  |         dbgln("     Live cells: {} ({} bytes)", live_cells, live_cell_bytes); | 
					
						
							|  |  |  |         dbgln("Collected cells: {} ({} bytes)", collected_cells, collected_cell_bytes); | 
					
						
							| 
									
										
										
										
											2020-10-06 18:50:47 +02:00
										 |  |  |         dbgln("    Live blocks: {} ({} bytes)", live_block_count, live_block_count * HeapBlock::block_size); | 
					
						
							| 
									
										
										
										
											2020-10-04 15:44:40 +01:00
										 |  |  |         dbgln("   Freed blocks: {} ({} bytes)", empty_blocks.size(), empty_blocks.size() * HeapBlock::block_size); | 
					
						
							|  |  |  |         dbgln("============================================="); | 
					
						
							| 
									
										
										
										
											2020-08-16 20:33:56 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-18 20:03:17 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | void Heap::did_create_handle(Badge<HandleImpl>, HandleImpl& impl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(!m_handles.contains(&impl)); | 
					
						
							|  |  |  |     m_handles.set(&impl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Heap::did_destroy_handle(Badge<HandleImpl>, HandleImpl& impl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(m_handles.contains(&impl)); | 
					
						
							|  |  |  |     m_handles.remove(&impl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-19 17:24:56 +02:00
										 |  |  | void Heap::did_create_marked_value_list(Badge<MarkedValueList>, MarkedValueList& list) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(!m_marked_value_lists.contains(&list)); | 
					
						
							|  |  |  |     m_marked_value_lists.set(&list); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Heap::did_destroy_marked_value_list(Badge<MarkedValueList>, MarkedValueList& list) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(m_marked_value_lists.contains(&list)); | 
					
						
							|  |  |  |     m_marked_value_lists.remove(&list); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-19 11:30:47 +02:00
										 |  |  | void Heap::defer_gc(Badge<DeferGC>) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ++m_gc_deferrals; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Heap::undefer_gc(Badge<DeferGC>) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(m_gc_deferrals > 0); | 
					
						
							|  |  |  |     --m_gc_deferrals; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!m_gc_deferrals) { | 
					
						
							|  |  |  |         if (m_should_gc_when_deferral_ends) | 
					
						
							|  |  |  |             collect_garbage(); | 
					
						
							|  |  |  |         m_should_gc_when_deferral_ends = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 19:23:58 +01:00
										 |  |  | } |