From 5f6a18a2ab0d0ccfd55c42bfb19f6672daf128c6 Mon Sep 17 00:00:00 2001 From: Victor Olin Date: Fri, 17 Feb 2023 12:14:11 +0100 Subject: [PATCH] Debugged mark() Co-authored-by: ValterMiari --- src/GC/Makefile | 10 ++++++--- src/GC/include/heap.hpp | 1 + src/GC/lib/heap.cpp | 47 +++++++++++++++++++++++++++++------------ src/GC/tests/h_test.cpp | 18 +++++++--------- src/GC/todo.md | 23 ++++++++++++++------ 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/src/GC/Makefile b/src/GC/Makefile index f42d28c..6ca9320 100644 --- a/src/GC/Makefile +++ b/src/GC/Makefile @@ -7,19 +7,23 @@ CFLAGS = -Wall -Wextra -v -g -std=gnu++20 -stdlib=libc++ -I VGFLAGS = --leak-check=full --show-leak-kinds=all heap: - $(CC) $(CFLAGS)$(PWD_V) lib/heap.cpp + $(CC) $(CFLAGS)$(PWD) lib/heap.cpp h_test: rm -f tests/h_test.out - $(CC) $(CFLAGS)$(PWD_V) tests/h_test.cpp lib/heap.cpp -o tests/h_test.out + $(CC) $(CFLAGS)$(PWD) tests/h_test.cpp lib/heap.cpp -o tests/h_test.out h_test_vg: make h_test valgrind $(VGFLAGS) tests/h_test.out +h_test_dbg: + make h_test + lldb tests/h_test.out launch + linker: rm -f tests/linker.out - $(CC) $(CFLAGS)$(PWD_V) tests/linker.cpp lib/heap.cpp -o tests/linker.out + $(CC) $(CFLAGS)$(PWD) tests/linker.cpp lib/heap.cpp -o tests/linker.out linker_vg: make linker diff --git a/src/GC/include/heap.hpp b/src/GC/include/heap.hpp index e659598..be1b12e 100644 --- a/src/GC/include/heap.hpp +++ b/src/GC/include/heap.hpp @@ -32,6 +32,7 @@ namespace GC { // void compact(); void mark(uintptr_t *start, const uintptr_t *end, std::vector worklist); void print_line(Chunk *chunk); + void print_worklist(std::vector list); inline static Heap *m_instance = nullptr; const char *m_heap; diff --git a/src/GC/lib/heap.cpp b/src/GC/lib/heap.cpp index 3016159..f01233b 100644 --- a/src/GC/lib/heap.cpp +++ b/src/GC/lib/heap.cpp @@ -23,6 +23,7 @@ namespace GC { } // kolla freed chunks innan + // denna är helt onödig just nu, freed chunks kommer alltid va tom for (size_t i = 0; i < m_freed_chunks.size(); i++) { auto cp = m_freed_chunks.at(i); if (cp->size > size) @@ -80,7 +81,7 @@ namespace GC { // We shouldn't do this, since then m_freed_chunks doesnt' have any real purpose, // it should be used in alloc, it isn't if we delete *all* of its contentes - //release free chunks + // release free chunks while (m_freed_chunks.size()) { auto chunk_pointer = m_freed_chunks.back(); m_freed_chunks.pop_back(); @@ -90,7 +91,14 @@ namespace GC { void Heap::collect(uint flags) { - cout << "DEBUG COLLECT\nFLAGS: " << flags << endl; + cout << "DEBUG COLLECT\nFLAGS: "; + if (flags & MARK) + cout << "\n - MARK"; + if (flags & SWEEP) + cout << "\n - SWEEP"; + if (flags & FREE) + cout << "\n - FREE"; + cout << endl; // get the frame adress, whwere local variables and saved registers are located auto stack_start = reinterpret_cast(__builtin_frame_address(0)); cout << "Stack start:\t" << stack_start << endl; @@ -101,6 +109,7 @@ namespace GC { // reinterpret_cast(__builtin_frame_address(10)); auto work_list = m_allocated_chunks; + // print_worklist(work_list); if (flags & MARK) { mark(stack_start, stack_end, work_list); @@ -136,19 +145,23 @@ namespace GC { } // TODO: return the worklist filtered on mark = true - void Heap::mark(uintptr_t *start, const uintptr_t *end, vector work_list) { + // This assumes that there are no chains of pointers, will be fixed later on + void Heap::mark(uintptr_t *start, const uintptr_t *end, vector worklist) { for (; start > end; start--) { // to find adresses thats in the worklist - cout << "Value of start pointer:\t" << start << endl; - for (size_t i = 0; i < work_list.size(); i++) { // fix this - auto chunk = work_list.at(i); - cout << "Chunk value:\t" << chunk->start << endl; - cout << "Chunk pointer value:\t" << &chunk << endl; - if (chunk->start <= start && start < chunk->start + chunk->size) { - if (!chunk->marked) { - chunk->marked = true; - work_list.erase(work_list.begin() + i); - mark(reinterpret_cast(chunk->start + chunk->size), end, work_list); // - return; + if (*start % 8 == 0) { // all pointers must be aligned as double words + for (size_t i = 0; i < worklist.size(); i++) { // fix this + auto chunk = worklist.at(i); + uintptr_t c_start = reinterpret_cast(chunk->start); + uintptr_t c_end = reinterpret_cast(chunk->start + chunk->size); + if (c_start <= *start && *start < c_end) { + uintptr_t c_start = reinterpret_cast(chunk->start); + if (!chunk->marked) { + chunk->marked = true; + worklist.erase(worklist.begin() + i); + auto new_stack_start = reinterpret_cast(start); + mark(new_stack_start, end, worklist); // + return; + } } } } @@ -204,6 +217,12 @@ namespace GC { cout << "Marked: " << chunk->marked << "\nStart adr: " << chunk->start << "\nSize: " << chunk->size << " B\n" << endl; } + void Heap::print_worklist(std::vector list) { + for (auto cp : list) { + cout << "Chunk at:\t" << cp->start << "\nSize:\t\t" << cp->size << endl; + } + } + void Heap::print_contents() { if (m_allocated_chunks.size()) { cout << "\nALLOCATED CHUNKS #" << m_allocated_chunks.size() << endl; diff --git a/src/GC/tests/h_test.cpp b/src/GC/tests/h_test.cpp index 2f605ca..76e2434 100644 --- a/src/GC/tests/h_test.cpp +++ b/src/GC/tests/h_test.cpp @@ -5,28 +5,26 @@ GC::Heap *gc = GC::Heap::the2(); void init() { auto stack_start = reinterpret_cast(__builtin_frame_address(0)); - auto stack_end = stack_start - 160; + auto stack_end = stack_start - 40; std::cout << "Stack start from init:\t" << stack_start << std::endl; std::cout << "Imaginary stack end:\t" << stack_end << std::endl; - int *arr = static_cast(gc->alloc(sizeof(int) * 300)); - for (int i = 0; i < (sizeof(int) * 300); i++) { + int *arr = static_cast(gc->alloc(sizeof(int) * 100)); + std::cout << "Arr_ptr" << std::hex << arr << "\n\n\n" << std::endl; + for (int i = 0; i < (sizeof(int) * 100); i++) { arr[i] = i; } std::cout << "First stack pointer:\t" << &arr << std::endl; + long a = 20; long *l = static_cast(gc->alloc(sizeof(long))); - *l = 20; - // This doesn't get allocated on our heap, but how is it viewed on valgr? - int *arr2 = new int[1000]; - for (int i = 0; i < 1000; i++) { - arr2[i] = i; - } + l = &a; + //*l = 20; } int main() { auto stack_start = reinterpret_cast(__builtin_frame_address(0)); std::cout << "Stack start from main:\t" << stack_start << std::endl; init(); - gc->collect(MARK | SWEEP); + gc->collect(MARK | SWEEP | FREE); gc->print_contents(); //delete gc; return 0; diff --git a/src/GC/todo.md b/src/GC/todo.md index 939c6a0..a327d71 100644 --- a/src/GC/todo.md +++ b/src/GC/todo.md @@ -6,16 +6,13 @@ Goal for next week (17/2): - Functioning garbage collector - Test it with valgrind -TODO: +## GC TODO: - Merge to main branch - -## Algorithm - -Potential algorithms: -- mark & sweep +- Don't empty m_free_chunks, reuse in a better way **Victor fixes this** ## Tests TODO ### Library linking +**Victor fixes this** Compile the GC lib and a test separately, link them together and evalutate the following: @@ -24,3 +21,17 @@ and evalutate the following: __builtin_return_address(0) __builtin_return_address(1) +### GC Init and __b_f_a +1. Save the first stack fram globally as the stack start +2. For each call to collect, save the prev stack frame as the stack end +3. Scan through the span + + gc_init() + global stack_end = __builtin_frame_address(1) + + collect() + global stack_start = __builtin_frame_address(1) + + sweep() + for all addr in range(stack_end, stack_start) + mark if chunk