Wrote a test for shared library linking
This commit is contained in:
parent
c20ef8f5dd
commit
ff8c270cb8
7 changed files with 139 additions and 69 deletions
|
|
@ -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
|
||||||
CFLAGS = -Wall -Wextra -v -g -std=gnu++20 -stdlib=libc++ -I
|
LIB_INCL = -I/home/virre/dev/systemF/org/language/src/GC/include
|
||||||
VGFLAGS = --leak-check=full --show-leak-kinds=all
|
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
|
||||||
|
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
|
||||||
|
|
@ -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
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
// denna segfaultar om arg för __b_f_a är > 2
|
else
|
||||||
// reinterpret_cast<const uintptr_t *>(__builtin_frame_address(10));
|
stack_end = (uintptr_t *) stack_start - 40; // dummy value
|
||||||
|
|
||||||
auto work_list = m_allocated_chunks;
|
auto work_list = heap->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
BIN
src/GC/lib/heap.o
Normal file
Binary file not shown.
BIN
src/GC/lib/libheap.so
Executable file
BIN
src/GC/lib/libheap.so
Executable file
Binary file not shown.
52
src/GC/tests/extern_lib.cpp
Normal file
52
src/GC/tests/extern_lib.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -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() {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue