Continued debugging
Co-authored-by: ValterMiari <ValterMiari@users.noreply.github.com>
This commit is contained in:
parent
5ac9b665a1
commit
42c22bc1eb
6 changed files with 95 additions and 57 deletions
|
|
@ -1,6 +1,9 @@
|
||||||
|
mkfile_path = $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
|
current_dir = $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
|
||||||
CC = clang++
|
CC = clang++
|
||||||
PWD = /home/virre/dev/systemF/org/language/src/GC/include
|
PWD = /home/virre/dev/systemF/org/language/src/GC/include
|
||||||
CFLAGS = -Wall -Wextra -v -g -std=gnu++20 -stdlib=libc++ -I
|
CFLAGS = -Wall -Wextra -v -g -std=gnu++20 -stdlib=libc++ -I
|
||||||
|
VGFLAGS = --leak-check=full --show-leak-kinds=all
|
||||||
|
|
||||||
heap:
|
heap:
|
||||||
$(CC) $(CFLAGS)$(PWD) lib/heap.cpp
|
$(CC) $(CFLAGS)$(PWD) lib/heap.cpp
|
||||||
|
|
@ -9,6 +12,14 @@ h_test:
|
||||||
rm -f tests/h_test.out
|
rm -f tests/h_test.out
|
||||||
$(CC) $(CFLAGS)$(PWD) 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
|
||||||
|
|
||||||
linker:
|
linker:
|
||||||
rm -f tests/linker.out
|
rm -f tests/linker.out
|
||||||
$(CC) $(CFLAGS)$(PWD) 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
|
||||||
|
valgrind $(VGFLAGS) tests/linker.out
|
||||||
|
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
#define HEAP_SIZE 65536
|
#define HEAP_SIZE 65536
|
||||||
|
|
||||||
|
#define MARK (uint) 0x1
|
||||||
|
#define SWEEP (uint) 0x2
|
||||||
|
#define FREE (uint) 0x4
|
||||||
|
#define COLLECT_ALL (uint) 0x7
|
||||||
|
|
||||||
namespace GC {
|
namespace GC {
|
||||||
|
|
||||||
class Heap {
|
class Heap {
|
||||||
|
|
@ -60,6 +65,6 @@ namespace GC {
|
||||||
|
|
||||||
void *alloc(size_t size);
|
void *alloc(size_t size);
|
||||||
void print_contents();
|
void print_contents();
|
||||||
void force_collect();
|
void collect(uint flags); // DEBUG ONLY
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -79,17 +79,47 @@ namespace GC {
|
||||||
// BELOW SHOULD BE INCLUDED (commented only for tests, to see which objects freed)
|
// BELOW SHOULD BE INCLUDED (commented only for tests, to see which objects freed)
|
||||||
|
|
||||||
//release free chunks
|
//release free chunks
|
||||||
/* while (m_freed_chunks.size()) {
|
while (m_freed_chunks.size()) {
|
||||||
auto chunk_pointer = m_freed_chunks.back();
|
auto chunk_pointer = m_freed_chunks.back();
|
||||||
m_freed_chunks.pop_back();
|
m_freed_chunks.pop_back();
|
||||||
delete chunk_pointer; // deletes chunk object, doesn't free memory to the OS
|
delete chunk_pointer; // deletes chunk object, doesn't free memory to the OS
|
||||||
} */
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Heap::collect(uint flags) {
|
||||||
|
|
||||||
|
std::cout << "DEBUG COLLECT\nFLAGS: " << flags << std::endl;
|
||||||
|
// get the frame adress, whwere local variables and saved registers are located
|
||||||
|
auto stack_start = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
||||||
|
|
||||||
|
const uintptr_t *stack_end = (uintptr_t *)0; // dummy value
|
||||||
|
|
||||||
|
// denna segfaultar om arg för __b_f_a är > 2
|
||||||
|
// reinterpret_cast<const uintptr_t *>(__builtin_frame_address(10));
|
||||||
|
|
||||||
|
auto work_list = m_allocated_chunks;
|
||||||
|
|
||||||
|
if (flags & MARK) {
|
||||||
|
mark(stack_start, stack_end, work_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & SWEEP) {
|
||||||
|
sweep();
|
||||||
|
}
|
||||||
|
|
||||||
|
//release free chunks
|
||||||
|
if (flags & FREE) {
|
||||||
|
while (m_freed_chunks.size()) {
|
||||||
|
auto chunk_pointer = m_freed_chunks.back();
|
||||||
|
m_freed_chunks.pop_back();
|
||||||
|
delete chunk_pointer; // deletes chunk object, doesn't free heap memory to the OS
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not optimal for now, it doesn't have to loop over all objects
|
// Not optimal for now, it doesn't have to loop over all objects
|
||||||
// but mark needs some refinements before this can be optimised
|
// but mark needs some refinements before this can be optimised
|
||||||
void Heap::sweep() {
|
void Heap::sweep() {
|
||||||
// assert(false && "NOT IMPLEMENTED");
|
|
||||||
for (size_t i = 0; i < m_allocated_chunks.size(); i++) {
|
for (size_t i = 0; i < m_allocated_chunks.size(); i++) {
|
||||||
auto chunk = m_allocated_chunks.at(i);
|
auto chunk = m_allocated_chunks.at(i);
|
||||||
if (chunk->marked == false) {
|
if (chunk->marked == false) {
|
||||||
|
|
@ -99,32 +129,7 @@ namespace GC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Heap::force_collect() {
|
// TODO: return the worklist filtered on mark = true
|
||||||
Heap::collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// dead code
|
|
||||||
// void Heap::compact() {
|
|
||||||
|
|
||||||
// // sort alloced_chunks by their start-addresses
|
|
||||||
// std::sort(m_allocated_chunks.begin(), m_allocated_chunks.end(), [](Chunk *c1, Chunk *c2){
|
|
||||||
// return c1->start < c2->start;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // move all chunks to the start of the heap
|
|
||||||
// auto heap_curr = (uintptr_t *)m_heap; // (char *)m_heap
|
|
||||||
// for (auto space : m_allocated_chunks) {
|
|
||||||
// if (space->start != heap_curr) {
|
|
||||||
// memmove(heap_curr, space->start, space->size);
|
|
||||||
// space->start = heap_curr;
|
|
||||||
// heap_curr += space->size;
|
|
||||||
// } else {
|
|
||||||
// heap_curr += space->size;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return the worklist filtered on mark = true
|
|
||||||
void Heap::mark(uintptr_t *start, const uintptr_t *end, std::vector<Chunk*> work_list) {
|
void Heap::mark(uintptr_t *start, const uintptr_t *end, std::vector<Chunk*> work_list) {
|
||||||
for (; start < end; start++) { // to find adresses thats in the worklist
|
for (; start < end; start++) { // to find adresses thats in the worklist
|
||||||
for (size_t i = 0; i < work_list.size(); i++) { // fix this
|
for (size_t i = 0; i < work_list.size(); i++) { // fix this
|
||||||
|
|
@ -141,6 +146,26 @@ namespace GC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Alternative marking, pseudocode
|
||||||
|
mark_from_roots():
|
||||||
|
worklist <- empty
|
||||||
|
for fld in Roots
|
||||||
|
ref <- *fld
|
||||||
|
if ref ≠ null && !marked(ref)
|
||||||
|
set_marked(ref)
|
||||||
|
worklist.add(ref)
|
||||||
|
mark()
|
||||||
|
|
||||||
|
mark():
|
||||||
|
while size(worklist) > 0
|
||||||
|
ref <- remove_first(worklist)
|
||||||
|
for fld in Pointers(ref)
|
||||||
|
child <- *fld
|
||||||
|
if child ≠ null && !marked(child)
|
||||||
|
set_marked(child)
|
||||||
|
worklist.add(child)
|
||||||
|
*/
|
||||||
// For testing purposes
|
// For testing purposes
|
||||||
void Heap::print_line(Chunk *chunk) {
|
void Heap::print_line(Chunk *chunk) {
|
||||||
std::cout << "Marked: " << chunk->marked << "\nStart adr: " << chunk->start << "\nSize: " << chunk->size << " B" << std::endl;
|
std::cout << "Marked: " << chunk->marked << "\nStart adr: " << chunk->start << "\nSize: " << chunk->size << " B" << std::endl;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ GC::Heap *gc = GC::Heap::the2();
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
std::vector<int> live_int_vec{1, 2, 3, 4, 5};
|
std::vector<int> live_int_vec{1, 2, 3, 4, 5};
|
||||||
std::vector<int> dead_int_vec(10, 1);
|
std::vector<int> dead_int_vec(1000000, 1);
|
||||||
|
int *arr = static_cast<int *>(gc->alloc(sizeof(int) * 300));
|
||||||
int *a_ptr;
|
int *a_ptr;
|
||||||
int a = 10;
|
int a = 10;
|
||||||
a_ptr = &a;
|
a_ptr = &a;
|
||||||
|
|
@ -16,7 +17,7 @@ void init() {
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
init();
|
init();
|
||||||
gc->force_collect();
|
gc->collect(MARK | SWEEP);
|
||||||
gc->print_contents();
|
gc->print_contents();
|
||||||
//delete gc;
|
//delete gc;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,18 @@ int main() {
|
||||||
std::cout << "Start:\t\t" << prev1 << std::endl;
|
std::cout << "Start:\t\t" << prev1 << std::endl;
|
||||||
#pragma clang diagnostic ignored "-Wframe-address"
|
#pragma clang diagnostic ignored "-Wframe-address"
|
||||||
uintptr_t *tmp = reinterpret_cast<uintptr_t *>(__builtin_frame_address(1));
|
uintptr_t *tmp = reinterpret_cast<uintptr_t *>(__builtin_frame_address(1));
|
||||||
std::cout << "Frame 1:\t" << tmp << "\t\tDiff:\t" << std::hex << "0x"<< prev1 - tmp << std::endl;
|
std::cout << "Frame 1:\t" << tmp << "\t\tDiff:\t" << std::hex << "0x"<< tmp - prev1 << std::endl;
|
||||||
prev1 = tmp;
|
prev1 = tmp;
|
||||||
|
|
||||||
#pragma clang diagnostic ignored "-Wframe-address"
|
#pragma clang diagnostic ignored "-Wframe-address"
|
||||||
tmp = reinterpret_cast<uintptr_t *>(__builtin_frame_address(2));
|
tmp = reinterpret_cast<uintptr_t *>(__builtin_frame_address(2));
|
||||||
std::cout << "Frame 2:\t" << tmp << "\tDiff:\t" << std::hex << "0x" << prev1 - tmp << std::endl;
|
std::cout << "Frame 2:\t" << tmp << "\tDiff:\t" << std::hex << "0x" << tmp - prev1 << std::endl;
|
||||||
|
prev1 = tmp;
|
||||||
|
|
||||||
|
// arg > 2 for __builtin_frame_address() results in segfault
|
||||||
|
// #pragma clang diagnostic ignored "-Wframe-address"
|
||||||
|
// tmp = reinterpret_cast<uintptr_t *>(__builtin_frame_address(3));
|
||||||
|
// std::cout << "Frame 3:\t" << tmp << "\tDiff:\t" << std::hex << "0x" << prev1 - tmp << std::endl;
|
||||||
|
|
||||||
dummy1();
|
dummy1();
|
||||||
|
|
||||||
|
|
@ -27,11 +33,11 @@ int main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void dummy1() {
|
void dummy1() {
|
||||||
std::cout << "Frame:\t\t" << __builtin_frame_address(0);
|
std::cout << "D1 SFrame:\t" << __builtin_frame_address(0);
|
||||||
#pragma clang diagnostic ignored "-Wframe-address"
|
#pragma clang diagnostic ignored "-Wframe-address"
|
||||||
std::cout << "\t\tPrev:\t" << __builtin_frame_address(1) << std::endl;
|
std::cout << "\t\tPrev:\t" << __builtin_frame_address(1) << std::endl;
|
||||||
dummy2();
|
|
||||||
std::cout << "D1 RA:\t\t" << std::hex << __builtin_return_address(0) << std::endl;
|
std::cout << "D1 RA:\t\t" << std::hex << __builtin_return_address(0) << std::endl;
|
||||||
|
dummy2();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dummy2() {
|
void dummy2() {
|
||||||
|
|
@ -40,5 +46,6 @@ void dummy2() {
|
||||||
std::cout << "\t\tPrev:\t" << __builtin_frame_address(1) << std::endl;
|
std::cout << "\t\tPrev:\t" << __builtin_frame_address(1) << std::endl;
|
||||||
void *ra = __builtin_return_address(0);
|
void *ra = __builtin_return_address(0);
|
||||||
std::cout << "D2 RA:\t\t" << std::hex << ra << std::endl;
|
std::cout << "D2 RA:\t\t" << std::hex << ra << std::endl;
|
||||||
std::cout << "D2 ERA:\t\t" << std::hex << __builtin_extract_return_addr(ra) << std::endl;
|
// gives same value as pure 'ra'
|
||||||
|
// std::cout << "D2 ERA:\t\t" << std::hex << __builtin_extract_return_addr(ra) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
@ -13,25 +13,14 @@ TODO:
|
||||||
|
|
||||||
Potential algorithms:
|
Potential algorithms:
|
||||||
- mark & sweep
|
- mark & sweep
|
||||||
- easy to implement
|
|
||||||
- slow
|
|
||||||
- mark & compact
|
|
||||||
- no memory fragmentation
|
|
||||||
- slow
|
|
||||||
- stop-copy algorithms (?)
|
|
||||||
- no memory fragmentation
|
|
||||||
- slow
|
|
||||||
- maybe good for FP langs?
|
|
||||||
|
|
||||||
## Type hierarchy
|
## Tests TODO
|
||||||
|
### Library linking
|
||||||
|
Compile the GC lib and a test separately, link them together
|
||||||
|
and evalutate the following:
|
||||||
|
|
||||||
- Heap class
|
__builtin_frame_address(0)
|
||||||
- Holds all memory
|
__builtin_frame_address(1)
|
||||||
- Resizeable array?
|
__builtin_return_address(0)
|
||||||
- Singleton instance
|
__builtin_return_address(1)
|
||||||
- exposes alloc
|
|
||||||
|
|
||||||
- Heap chunks
|
|
||||||
- size
|
|
||||||
- addr
|
|
||||||
- marked bit
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue