Wrote a test for shared library linking

This commit is contained in:
Victor Olin 2023-02-19 21:02:08 +01:00
parent 518940ab15
commit 3473c953b5
7 changed files with 139 additions and 69 deletions

View file

@ -1,17 +1,23 @@
mkfile_path = $(abspath $(lastword $(MAKEFILE_LIST))) mkfile_path = $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir = $(notdir $(patsubst %/,%,$(dir $(mkfile_path)))) current_dir = $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
PWD_V = /Users/valtermiari/Desktop/DV/Bachelors/code/language/src/GC/include
CC = clang++ CC = clang++
PWD = /home/virre/dev/systemF/org/language/src/GC/include
PWD_V = /Users/valtermiari/Desktop/DV/Bachelors/code/language/src/GC/include
LIB_INCL = -I/home/virre/dev/systemF/org/language/src/GC/include
LIB_SO = -L/home/virre/dev/systemF/org/language/src/GC/lib/libheap.so
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 VGFLAGS = --leak-check=full --show-leak-kinds=all
STDFLAGS = -std=gnu++20 -stdlib=libc++
WFLAGS = -Wall -Wextra
DBGFLAGS = -g
heap: heap:
$(CC) $(CFLAGS)$(PWD) lib/heap.cpp $(CC) $(WFLAGS) $(STDFLAGS) $(LIB_INCL) lib/heap.cpp
h_test: 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) $(WFLAGS) $(STDFLAGS) $(LIB_INCL) tests/h_test.cpp lib/heap.cpp -o tests/h_test.out
h_test_vg: h_test_vg:
make h_test make h_test
@ -23,8 +29,15 @@ h_test_dbg:
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) $(WFLAGS) $(STDFLAGS) $(LIB_INCL) tests/linker.cpp lib/heap.cpp -o tests/linker.out
linker_vg: linker_vg:
make linker make linker
valgrind $(VGFLAGS) tests/linker.out valgrind $(VGFLAGS) tests/linker.out
extern_lib:
rm -f lib/heap.o
rm -f lib/libheap.so
$(CC) $(STDFLAGS) -c -fPIC -o lib/heap.o lib/heap.cpp
$(CC) $(STDFLAGS) -shared -o lib/libheap.so lib/heap.o
$(CC) $(LIB_INCL) $(LIB_SO) -v -Wall -o tests/extern_lib.out tests/extern_lib.cpp

View file

@ -29,11 +29,11 @@ namespace GC {
m_allocated_size = 0; m_allocated_size = 0;
} }
void collect(); void collect(Heap *heap);
void sweep(); void sweep(Heap *heap);
uintptr_t *try_recycle_chunks(size_t size); uintptr_t *try_recycle_chunks(Heap *heap, size_t size);
void free(); void free(Heap *heap);
void free_overlap(); void free_overlap(Heap *heap);
void mark(uintptr_t *start, const uintptr_t *end, std::vector<Chunk *> worklist); void mark(uintptr_t *start, const uintptr_t *end, std::vector<Chunk *> worklist);
void print_line(Chunk *chunk); void print_line(Chunk *chunk);
void print_worklist(std::vector<Chunk *> list); void print_worklist(std::vector<Chunk *> list);
@ -61,9 +61,12 @@ namespace GC {
std::free((char *)m_heap); std::free((char *)m_heap);
} }
void init();
void *alloc(size_t size); void *alloc(size_t size);
void init();
// DEBUG ONLY
void check_init();
void collect(uint flags);
void print_contents(); void print_contents();
void collect(uint flags); // DEBUG ONLY
}; };
} }

View file

@ -7,7 +7,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <vector> #include <vector>
#include "heap.hpp" #include "../include/heap.hpp"
using namespace std; using namespace std;
namespace GC { namespace GC {
@ -18,6 +18,13 @@ namespace GC {
* this address points to the stack frame of the compiled * this address points to the stack frame of the compiled
* LLVM executable after linking. (NOT CONFIRMED) * LLVM executable after linking. (NOT CONFIRMED)
*/ */
void Heap::check_init() {
auto heap = Heap::the();
cout << "GC m_stack_end:\t" << heap->m_stack_end << endl;
auto stack_start = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
cout << "GC stack_start:\t" << stack_start << endl;
}
void Heap::init() { void Heap::init() {
Heap *heap = Heap::the(); Heap *heap = Heap::the();
heap->m_stack_end = reinterpret_cast<uintptr_t *>(__builtin_frame_address(1)); heap->m_stack_end = reinterpret_cast<uintptr_t *>(__builtin_frame_address(1));
@ -43,13 +50,13 @@ namespace GC {
} }
if (heap->m_size + size > HEAP_SIZE) { if (heap->m_size + size > HEAP_SIZE) {
collect(); collect(heap);
// If collect failed, crash with OOM error // If collect failed, crash with OOM error
assert(heap->m_size + size <= HEAP_SIZE && "Heap: Out Of Memory"); assert(heap->m_size + size <= HEAP_SIZE && "Heap: Out Of Memory");
} }
// If a chunk was recycled, return the old chunk address // If a chunk was recycled, return the old chunk address
uintptr_t *reused_chunk = try_recycle_chunks(size); uintptr_t *reused_chunk = try_recycle_chunks(heap, size);
if (reused_chunk != nullptr) { if (reused_chunk != nullptr) {
return (void *)reused_chunk; return (void *)reused_chunk;
} }
@ -58,18 +65,17 @@ namespace GC {
// then create a new chunk // then create a new chunk
auto new_chunk = new Chunk; auto new_chunk = new Chunk;
new_chunk->size = size; new_chunk->size = size;
new_chunk->start = (uintptr_t *)m_heap + m_size; new_chunk->start = (uintptr_t *)(heap->m_heap + m_size);
m_size += size; heap->m_size += size;
m_allocated_chunks.push_back(new_chunk); heap->m_allocated_chunks.push_back(new_chunk);
// new_chunk should probably be a unique pointer, if that isn't implicit already // new_chunk should probably be a unique pointer, if that isn't implicit already
return new_chunk->start; return new_chunk->start;
} }
uintptr_t *Heap::try_recycle_chunks(size_t size) { uintptr_t *Heap::try_recycle_chunks(Heap *heap, size_t size) {
auto heap = Heap::the();
// Check if there are any freed chunks large enough for current request // Check if there are any freed chunks large enough for current request
for (size_t i = 0; i < heap->m_freed_chunks.size(); i++) { for (size_t i = 0; i < heap->m_freed_chunks.size(); i++) {
auto cp = heap->m_freed_chunks.at(i); auto cp = heap->m_freed_chunks.at(i);
@ -92,16 +98,16 @@ namespace GC {
else if (cp->size == size) else if (cp->size == size)
{ {
// Reuse the whole chunk // Reuse the whole chunk
m_freed_chunks.erase(m_freed_chunks.begin() + i); heap->m_freed_chunks.erase(m_freed_chunks.begin() + i);
m_allocated_chunks.push_back(cp); heap->m_allocated_chunks.push_back(cp);
return cp->start; return cp->start;
} }
} }
return nullptr;
} }
void Heap::collect() { void Heap::collect(Heap *heap) {
// Get the adress of the current stack frame // Get the adress of the current stack frame
auto heap = Heap::the();
uintptr_t *stack_end; uintptr_t *stack_end;
@ -111,38 +117,38 @@ namespace GC {
else else
stack_end = (uintptr_t *)0; // temporary stack_end = (uintptr_t *)0; // temporary
auto work_list = m_allocated_chunks; auto work_list = heap->m_allocated_chunks;
mark(stack_start, stack_end, work_list); mark(stack_start, stack_end, work_list);
sweep(); sweep(heap);
free(); free(heap);
} }
void Heap::free() { void Heap::free(Heap *heap) {
if (m_freed_chunks.size() > FREE_THRESH) { if (heap->m_freed_chunks.size() > FREE_THRESH) {
while (m_freed_chunks.size()) { while (heap->m_freed_chunks.size()) {
auto chunk = m_freed_chunks.back(); auto chunk = heap->m_freed_chunks.back();
m_freed_chunks.pop_back(); heap->m_freed_chunks.pop_back();
delete chunk; delete chunk;
} }
} else { } else {
free_overlap(); free_overlap(heap);
} }
} }
void Heap::free_overlap() { void Heap::free_overlap(Heap *heap) {
std::vector<Chunk *> filtered; std::vector<Chunk *> filtered;
size_t i = 0; size_t i = 0;
filtered.push_back(m_freed_chunks.at(i++)); filtered.push_back(heap->m_freed_chunks.at(i++));
for (; i < m_freed_chunks.size(); i++) { for (; i < heap->m_freed_chunks.size(); i++) {
auto prev = filtered.back(); auto prev = filtered.back();
auto next = m_freed_chunks.at(i); auto next = heap->m_freed_chunks.at(i);
if (next->start > (prev->start + prev->size)) { if (next->start > (prev->start + prev->size)) {
filtered.push_back(next); filtered.push_back(next);
} }
} }
m_freed_chunks.swap(filtered); heap->m_freed_chunks.swap(filtered);
} }
void Heap::collect(uint flags) { void Heap::collect(uint flags) {
@ -155,16 +161,20 @@ namespace GC {
if (flags & FREE) if (flags & FREE)
cout << "\n - FREE"; cout << "\n - FREE";
cout << endl; cout << endl;
auto heap = Heap::the();
// get the frame adress, whwere local variables and saved registers are located // get the frame adress, whwere local variables and saved registers are located
auto stack_start = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0)); auto stack_start = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
cout << "Stack start:\t" << stack_start << endl; cout << "Stack start:\t" << stack_start << endl;
uintptr_t *stack_end;
const uintptr_t *stack_end = (uintptr_t *) stack_start - 40; // dummy value if (heap->m_stack_end != nullptr)
stack_end = heap->m_stack_end;
else
stack_end = (uintptr_t *) stack_start - 40; // dummy value
// denna segfaultar om arg för __b_f_a är > 2 auto work_list = heap->m_allocated_chunks;
// reinterpret_cast<const uintptr_t *>(__builtin_frame_address(10));
auto work_list = m_allocated_chunks;
// print_worklist(work_list); // print_worklist(work_list);
if (flags & MARK) { if (flags & MARK) {
@ -172,31 +182,22 @@ namespace GC {
} }
if (flags & SWEEP) { if (flags & SWEEP) {
sweep(); sweep(heap);
} }
if (flags & FREE) { if (flags & FREE) {
free(); free(heap);
} }
//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(Heap *heap) {
for (auto it = m_allocated_chunks.begin(); it != m_allocated_chunks.end();) { for (auto it = heap->m_allocated_chunks.begin(); it != heap->m_allocated_chunks.end();) {
auto chunk = *it; auto chunk = *it;
if (!chunk->marked) { if (!chunk->marked) {
m_freed_chunks.push_back(chunk); heap->m_freed_chunks.push_back(chunk);
it = m_allocated_chunks.erase(it); it = heap->m_allocated_chunks.erase(it);
} }
else { else {
++it; ++it;
@ -240,17 +241,18 @@ namespace GC {
} }
void Heap::print_contents() { void Heap::print_contents() {
if (m_allocated_chunks.size()) { auto heap = Heap::the();
cout << "\nALLOCATED CHUNKS #" << m_allocated_chunks.size() << endl; if (heap->m_allocated_chunks.size()) {
for (auto chunk : m_allocated_chunks) { cout << "\nALLOCATED CHUNKS #" << heap->m_allocated_chunks.size() << endl;
for (auto chunk : heap->m_allocated_chunks) {
print_line(chunk); print_line(chunk);
} }
} else { } else {
cout << "NO ALLOCATIONS\n" << endl; cout << "NO ALLOCATIONS\n" << endl;
} }
if (m_freed_chunks.size()) { if (heap->m_freed_chunks.size()) {
cout << "\nFREED CHUNKS #" << m_freed_chunks.size() << endl; cout << "\nFREED CHUNKS #" << heap->m_freed_chunks.size() << endl;
for (auto fchunk : m_freed_chunks) { for (auto fchunk : heap->m_freed_chunks) {
print_line(fchunk); print_line(fchunk);
} }
} else { } else {

BIN
src/GC/lib/heap.o Normal file

Binary file not shown.

BIN
src/GC/lib/libheap.so Executable file

Binary file not shown.

View file

@ -0,0 +1,52 @@
#include <cstring>
#include <iostream>
#include "heap.hpp"
// using namespace std;
// GC::Heap *singleton_test();
// void init_gc(GC::Heap *heap);
// void frame_test(GC::Heap *heap);
GC::Heap *singleton_test() {
std::cout << "TESTING SINGLETON INSTANCES" << std::endl;
std::cout << "===========================" << std::endl;
std::cout << "Call 1:\t" << GC::Heap::the() << std::endl;
GC::Heap *heap = GC::Heap::the();
std::cout << "Call 2:\t" << heap << std::endl;
std::cout << "===========================" << std::endl;
return heap;
}
void init_gc(GC::Heap *heap){
std::cout << "\n\n INITIALIZING THE HEAP" << std::endl;
std::cout << "===========================" << std::endl;
heap->init();
std::cout << "===========================" << std::endl;
}
void frame_test(GC::Heap *heap) {
std::cout << "\n\n TESTING FRAME ADDRESSES" << std::endl;
std::cout << "===========================" << std::endl;
#pragma clang diagnostic ignored "-Wframe-address"
auto curr_frame = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
std::cout << "Current stack frame:\t" << curr_frame << std::endl;
#pragma clang diagnostic ignored "-Wframe-address"
auto prev_frame = reinterpret_cast<uintptr_t *>(__builtin_frame_address(1));
std::cout << "Previous stack frame:\t" << prev_frame << std::endl;
heap->check_init();
std::cout << "===========================" << std::endl;
}
int main() {
auto heap = singleton_test();
init_gc(heap);
frame_test(heap);
return 0;
}

View file

@ -1,6 +1,6 @@
#include "../include/heap.hpp" #include "../include/heap.hpp"
GC::Heap *gc = GC::Heap::the2(); GC::Heap *gc = GC::Heap::the();
void init() { void init() {