diff --git a/src/stdlib/garbage.cpp b/src/stdlib/garbage.cpp index 3e9c05a3..9ff35a1c 100644 --- a/src/stdlib/garbage.cpp +++ b/src/stdlib/garbage.cpp @@ -43,6 +43,7 @@ void BoehmGarbageCollector::free(void* ptr) { if (ptr == nullptr) { return; } + // TODO: remove the ptr from the allocation GCObjectHeader* hdr = header(ptr); if (hdr->finalizer) { hdr->finalizer(ptr); @@ -84,14 +85,22 @@ void BoehmGarbageCollector::mark_obj(void* obj, GCGen gen) { void BoehmGarbageCollector::sweep(GCGen gen) { Array allocs; for (GCObjectHeader* obj: allocations(gen)) { + if (obj == nullptr) { + continue; + } if (!obj->marked) { kwdebug(outlog(), "free {}", (void*)(obj)); + if (obj->finalizer) { + obj->finalizer(obj->data()); + } std::free(obj); } else { obj->marked = 0; allocs.push_back(obj); } } + + // TODO: promotion logic here allocations(gen) = allocs; } diff --git a/src/stdlib/garbage.h b/src/stdlib/garbage.h index b22aed98..a225c12b 100644 --- a/src/stdlib/garbage.h +++ b/src/stdlib/garbage.h @@ -55,6 +55,9 @@ enum class GCGen * * The header could also be dynamically allocated separately for common * type/size + * + * Currently the GC never runs, some heuristic needs to be put in place + * to make it run periodically */ struct BoehmGarbageCollector { diff --git a/tests/garbage_test.cpp b/tests/garbage_test.cpp index 3f034aee..4c360d50 100644 --- a/tests/garbage_test.cpp +++ b/tests/garbage_test.cpp @@ -4,6 +4,10 @@ #include "stdlib/garbage.h" #include + +#define KIWI_NOINLINE __attribute__ ((noinline)) + + namespace lython { class GargabeCollector; @@ -485,6 +489,16 @@ ListBool* make_list(BoehmGarbageCollector& gc, bool val, ListBool* prev) { return lst; } +void KIWI_NOINLINE print(ListBool* list) { + int i = 0; + while(list != nullptr) { + std::cout << i << " "; + list = list->next; + i += 1; + } +} + + TEST_CASE("BoehmGarbageCollector_Marks recursively find pointers") { BoehmGarbageCollector gc; @@ -515,7 +529,7 @@ TEST_CASE("BoehmGarbageCollector_Globals") { } -void* test_all_there() { +ListBool* KIWI_NOINLINE test_all_there() { BoehmGarbageCollector gc; ListBool* n1 = make_list(gc, true, nullptr); @@ -532,10 +546,10 @@ void* test_all_there() { REQUIRE(gc.allocations(GCGen::Temporary).size() == 5); // need to return it else it might not be in the stack anymore - return (void*)n5; + return n5; } -void* test_only_two() { +ListBool* KIWI_NOINLINE test_only_two() { BoehmGarbageCollector gc; ListBool* n1 = make_list(gc, true, nullptr); @@ -549,19 +563,23 @@ void* test_only_two() { gc.collect(); gc.dump(std::cout); + printf("%lu \n", gc.allocations(GCGen::Temporary).size()); + printf("%lu \n", gc.allocations(GCGen::Medium).size()); + printf("%lu \n", gc.allocations(GCGen::Long).size()); + REQUIRE(gc.allocations(GCGen::Temporary).size() == 2); // need to return it else it might not be in the stack anymore - return (void*)n2; + return n2; } TEST_CASE("BoehmGarbageCollector_AllReachable") { - test_all_there(); + print(test_all_there()); } -void* test_nested() { +ListBool* KIWI_NOINLINE test_nested() { BoehmGarbageCollector gc; ListBool* n5 = make_list( @@ -582,24 +600,16 @@ void* test_nested() { } TEST_CASE("BoehmGarbageCollector_AllReachable_Nested") { - test_nested(); + print(test_nested()); } TEST_CASE("BoehmGarbageCollector_Collect_Garbage") { - test_only_two(); + print(test_only_two()); } -void print(ListBool* list) { - int i = 0; - while(list != nullptr) { - std::cout << i << " "; - list = list->next; - i += 1; - } -} -ListBool* test_relocated(BoehmGarbageCollector& gc) { +ListBool* KIWI_NOINLINE test_relocated(BoehmGarbageCollector& gc) { ListBool* n5 = make_list(gc, true, @@ -638,14 +648,31 @@ ListBool* test_relocated(BoehmGarbageCollector& gc) { return n5; } + +char KIWI_NOINLINE reset_frame() { + volatile char data[1024 * 1024 * 1024]; + char c = 0; + for(int i; i < sizeof(data); i++) { + c += data[i]; + } + return c; +} + + TEST_CASE("BoehmGarbageCollector_Relocate") { BoehmGarbageCollector gc; ListBool* l = test_relocated(gc); + reset_frame(); - gc.dump(std::cout); + //gc.dump(std::cout); gc.collect(); - gc.dump(std::cout); + //gc.dump(std::cout); + + print(l); + + gc.collect(); + // 6 allocations // only 2 should remain reachable