Proper singleton implementation
This commit is contained in:
parent
cb0c3717fe
commit
501f319834
5 changed files with 138 additions and 145 deletions
|
|
@ -18,7 +18,7 @@ namespace GC
|
||||||
uintptr_t *const m_start {nullptr};
|
uintptr_t *const m_start {nullptr};
|
||||||
const size_t m_size {0};
|
const size_t m_size {0};
|
||||||
|
|
||||||
Chunk(size_t size, uintptr_t *start) : m_size(size), m_start(start) {}
|
Chunk(size_t size, uintptr_t *start) : m_start(start), m_size(size) {}
|
||||||
Chunk(const Chunk *const c) : m_marked(c->m_marked), m_start(c->m_start), m_size(c->m_size) {}
|
Chunk(const Chunk *const c) : m_marked(c->m_marked), m_start(c->m_start), m_size(c->m_size) {}
|
||||||
Chunk(const Chunk &c) : m_marked(c.m_marked), m_start(c.m_start), m_size(c.m_size) {}
|
Chunk(const Chunk &c) : m_marked(c.m_marked), m_start(c.m_start), m_size(c.m_size) {}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#define HEAP_SIZE 65536
|
#define HEAP_SIZE 65536
|
||||||
#define FREE_THRESH (uint)20
|
#define FREE_THRESH (uint)20
|
||||||
// #define DEBUG
|
#define DEBUG
|
||||||
|
|
||||||
namespace GC
|
namespace GC
|
||||||
{
|
{
|
||||||
|
|
@ -45,67 +45,22 @@ namespace GC
|
||||||
std::free((char *)m_heap);
|
std::free((char *)m_heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If m_instance is a nullptr (the singleton has not
|
|
||||||
* been initialized yet) initialize the singleton
|
|
||||||
* and return the pointer. Otherwise return the
|
|
||||||
* previously initialized pointer.
|
|
||||||
*
|
|
||||||
* @returns The pointer to the heap singleton.
|
|
||||||
*/
|
|
||||||
static Heap *the()
|
|
||||||
{
|
|
||||||
if (m_instance) // if m_instance is not a nullptr
|
|
||||||
return m_instance;
|
|
||||||
m_instance = new Heap();
|
|
||||||
return m_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advances an iterator and returns an element
|
|
||||||
* at position `n`.
|
|
||||||
*
|
|
||||||
* @param list The list to retrieve an element from.
|
|
||||||
*
|
|
||||||
* @param n The position to retrieve an element at.
|
|
||||||
*
|
|
||||||
* @returns The pointer to the chunk at position n in list.
|
|
||||||
*/
|
|
||||||
static Chunk *get_at(std::vector<Chunk *> &list, size_t n)
|
|
||||||
{
|
|
||||||
auto iter = list.begin();
|
|
||||||
if (!n)
|
|
||||||
return *iter;
|
|
||||||
std::advance(iter, n);
|
|
||||||
return *iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a bool whether the profiler is enabled
|
|
||||||
* or not.
|
|
||||||
*
|
|
||||||
* @returns True or false if the profiler is enabled
|
|
||||||
* or disabled respectively.
|
|
||||||
*/
|
|
||||||
inline bool profiler_enabled() {
|
|
||||||
auto heap = Heap::the();
|
|
||||||
return heap->m_profiler_enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *const m_heap;
|
char *const m_heap;
|
||||||
size_t m_size {0};
|
size_t m_size {0};
|
||||||
inline static Heap *m_instance {nullptr};
|
// static Heap *m_instance {nullptr};
|
||||||
uintptr_t *m_stack_top {nullptr};
|
uintptr_t *m_stack_top {nullptr};
|
||||||
bool m_profiler_enable {false};
|
bool m_profiler_enable {false};
|
||||||
|
|
||||||
std::vector<Chunk *> m_allocated_chunks;
|
std::vector<Chunk *> m_allocated_chunks;
|
||||||
std::vector<Chunk *> m_freed_chunks;
|
std::vector<Chunk *> m_freed_chunks;
|
||||||
|
|
||||||
|
static bool profiler_enabled();
|
||||||
|
static Chunk *get_at(std::vector<Chunk *> &list, size_t n);
|
||||||
void collect();
|
void collect();
|
||||||
void sweep(Heap *heap);
|
void sweep(Heap &heap);
|
||||||
Chunk *try_recycle_chunks(size_t size);
|
Chunk *try_recycle_chunks(size_t size);
|
||||||
void free(Heap *heap);
|
void free(Heap &heap);
|
||||||
void free_overlap(Heap *heap);
|
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);
|
||||||
|
|
@ -113,26 +68,36 @@ namespace GC
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* These are the only two functions which are exposed
|
* These are the only five functions which are exposed
|
||||||
* as the API for LLVM. At the absolute start of the
|
* as the API for LLVM. At the absolute start of the
|
||||||
* program the developer has to call init() to ensure
|
* program the developer has to call init() to ensure
|
||||||
* that the address of the topmost stack frame is
|
* that the address of the topmost stack frame is
|
||||||
* saved as the limit for scanning the stack in collect.
|
* saved as the limit for scanning the stack in collect.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation of the() guarantees laziness
|
||||||
|
* on the instance and a correct destruction with
|
||||||
|
* the destructor.
|
||||||
|
*
|
||||||
|
* @returns The singleton object.
|
||||||
|
*/
|
||||||
|
static Heap& the()
|
||||||
|
{
|
||||||
|
static Heap instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
static void init();
|
static void init();
|
||||||
static void dispose();
|
static void dispose();
|
||||||
static void *alloc(size_t size);
|
static void *alloc(size_t size);
|
||||||
void set_profiler(bool mode);
|
void set_profiler(bool mode);
|
||||||
|
|
||||||
|
// Stop the compiler from generating copy-methods
|
||||||
|
Heap(Heap const&) = delete;
|
||||||
|
Heap& operator=(Heap const&) = delete;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static Heap *debug_the()
|
|
||||||
{
|
|
||||||
if (m_instance) // if m_instance is not a nullptr
|
|
||||||
return m_instance;
|
|
||||||
m_instance = new Heap();
|
|
||||||
return m_instance;
|
|
||||||
}
|
|
||||||
void collect(CollectOption flags); // conditional collection
|
void collect(CollectOption flags); // conditional collection
|
||||||
void check_init(); // print dummy things
|
void check_init(); // print dummy things
|
||||||
void print_contents(); // print dummy things
|
void print_contents(); // print dummy things
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ using std::cout, std::endl, std::vector, std::hex, std::dec;
|
||||||
|
|
||||||
namespace GC
|
namespace GC
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the heap singleton and saves the address
|
* Initialises the heap singleton and saves the address
|
||||||
* of the calling function's stack frame as the stack_top.
|
* of the calling function's stack frame as the stack_top.
|
||||||
|
|
@ -22,12 +24,12 @@ namespace GC
|
||||||
*/
|
*/
|
||||||
void Heap::init()
|
void Heap::init()
|
||||||
{
|
{
|
||||||
Heap *heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
if (heap->profiler_enabled())
|
if (heap.profiler_enabled())
|
||||||
Profiler::record(HeapInit);
|
Profiler::record(HeapInit);
|
||||||
// clang complains because arg for __b_f_a is not 0 which is unsafe
|
// clang complains because arg for __b_f_a is not 0 which is "unsafe"
|
||||||
#pragma clang diagnostic ignored "-Wframe-address"
|
#pragma clang diagnostic ignored "-Wframe-address"
|
||||||
heap->m_stack_top = static_cast<uintptr_t *>(__builtin_frame_address(1));
|
heap.m_stack_top = static_cast<uintptr_t *>(__builtin_frame_address(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,10 +39,9 @@ namespace GC
|
||||||
*/
|
*/
|
||||||
void Heap::dispose()
|
void Heap::dispose()
|
||||||
{
|
{
|
||||||
Heap *heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
if (heap->profiler_enabled())
|
if (heap.profiler_enabled())
|
||||||
Profiler::dispose();
|
Profiler::dispose();
|
||||||
delete heap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,8 +56,8 @@ namespace GC
|
||||||
void *Heap::alloc(size_t size)
|
void *Heap::alloc(size_t size)
|
||||||
{
|
{
|
||||||
// Singleton
|
// Singleton
|
||||||
Heap *heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
bool profiler_enabled = heap->profiler_enabled();
|
bool profiler_enabled = heap.profiler_enabled();
|
||||||
|
|
||||||
if (profiler_enabled)
|
if (profiler_enabled)
|
||||||
Profiler::record(AllocStart, size);
|
Profiler::record(AllocStart, size);
|
||||||
|
|
@ -67,15 +68,15 @@ namespace GC
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heap->m_size + size > HEAP_SIZE)
|
if (heap.m_size + size > HEAP_SIZE)
|
||||||
{
|
{
|
||||||
heap->collect();
|
heap.collect();
|
||||||
// If memory is not enough after collect, crash with OOM error
|
// If memory is not enough after collect, crash with OOM error
|
||||||
throw std::runtime_error(std::string("Error: Heap out of memory"));
|
throw std::runtime_error(std::string("Error: Heap out of memory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a chunk was recycled, return the old chunk address
|
// If a chunk was recycled, return the old chunk address
|
||||||
Chunk *reused_chunk = heap->try_recycle_chunks(size);
|
Chunk *reused_chunk = heap.try_recycle_chunks(size);
|
||||||
if (reused_chunk != nullptr)
|
if (reused_chunk != nullptr)
|
||||||
{
|
{
|
||||||
if (profiler_enabled)
|
if (profiler_enabled)
|
||||||
|
|
@ -85,15 +86,14 @@ namespace GC
|
||||||
|
|
||||||
// If no free chunks was found (reused_chunk is a nullptr),
|
// If no free chunks was found (reused_chunk is a nullptr),
|
||||||
// then create a new chunk
|
// then create a new chunk
|
||||||
auto new_chunk = new Chunk(size, (uintptr_t *)(heap->m_heap + heap->m_size));
|
auto new_chunk = new Chunk(size, (uintptr_t *)(heap.m_heap + heap.m_size));
|
||||||
|
|
||||||
heap->m_size += size;
|
heap.m_size += size;
|
||||||
heap->m_allocated_chunks.push_back(new_chunk);
|
heap.m_allocated_chunks.push_back(new_chunk);
|
||||||
|
|
||||||
if (profiler_enabled)
|
if (profiler_enabled)
|
||||||
Profiler::record(NewChunk, new_chunk);
|
Profiler::record(NewChunk, new_chunk);
|
||||||
|
|
||||||
// new_chunk should probably be a unique pointer, if that isn't implicit already
|
|
||||||
return new_chunk->m_start;
|
return new_chunk->m_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,12 +115,12 @@ namespace GC
|
||||||
*/
|
*/
|
||||||
Chunk *Heap::try_recycle_chunks(size_t size)
|
Chunk *Heap::try_recycle_chunks(size_t size)
|
||||||
{
|
{
|
||||||
auto heap = Heap::the();
|
Heap &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 chunk = Heap::get_at(heap->m_freed_chunks, i);
|
auto chunk = Heap::get_at(heap.m_freed_chunks, i);
|
||||||
auto iter = heap->m_freed_chunks.begin();
|
auto iter = heap.m_freed_chunks.begin();
|
||||||
advance(iter, i);
|
advance(iter, i);
|
||||||
if (chunk->m_size > size)
|
if (chunk->m_size > size)
|
||||||
{
|
{
|
||||||
|
|
@ -129,17 +129,17 @@ namespace GC
|
||||||
size_t diff = chunk->m_size - size;
|
size_t diff = chunk->m_size - size;
|
||||||
auto chunk_complement = new Chunk(diff, chunk->m_start + chunk->m_size);
|
auto chunk_complement = new Chunk(diff, chunk->m_start + chunk->m_size);
|
||||||
|
|
||||||
heap->m_freed_chunks.erase(iter);
|
heap.m_freed_chunks.erase(iter);
|
||||||
heap->m_freed_chunks.push_back(chunk_complement);
|
heap.m_freed_chunks.push_back(chunk_complement);
|
||||||
heap->m_allocated_chunks.push_back(chunk);
|
heap.m_allocated_chunks.push_back(chunk);
|
||||||
|
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
else if (chunk->m_size == size)
|
else if (chunk->m_size == size)
|
||||||
{
|
{
|
||||||
// Reuse the whole chunk
|
// Reuse the whole chunk
|
||||||
heap->m_freed_chunks.erase(iter);
|
heap.m_freed_chunks.erase(iter);
|
||||||
heap->m_allocated_chunks.push_back(chunk);
|
heap.m_allocated_chunks.push_back(chunk);
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -147,6 +147,37 @@ namespace GC
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances an iterator and returns an element
|
||||||
|
* at position `n`.
|
||||||
|
*
|
||||||
|
* @param list The list to retrieve an element from.
|
||||||
|
*
|
||||||
|
* @param n The position to retrieve an element at.
|
||||||
|
*
|
||||||
|
* @returns The pointer to the chunk at position n in list.
|
||||||
|
*/
|
||||||
|
Chunk *Heap::get_at(std::vector<Chunk *> &list, size_t n)
|
||||||
|
{
|
||||||
|
auto iter = list.begin();
|
||||||
|
if (!n)
|
||||||
|
return *iter;
|
||||||
|
std::advance(iter, n);
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bool whether the profiler is enabled
|
||||||
|
* or not.
|
||||||
|
*
|
||||||
|
* @returns True or false if the profiler is enabled
|
||||||
|
* or disabled respectively.
|
||||||
|
*/
|
||||||
|
bool Heap::profiler_enabled() {
|
||||||
|
Heap &heap = Heap::the();
|
||||||
|
return heap.m_profiler_enable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection phase of the garbage collector. When
|
* Collection phase of the garbage collector. When
|
||||||
* an allocation is requested and there is no space
|
* an allocation is requested and there is no space
|
||||||
|
|
@ -156,20 +187,20 @@ namespace GC
|
||||||
*/
|
*/
|
||||||
void Heap::collect()
|
void Heap::collect()
|
||||||
{
|
{
|
||||||
auto heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
|
|
||||||
if (heap->profiler_enabled())
|
if (heap.profiler_enabled())
|
||||||
Profiler::record(CollectStart);
|
Profiler::record(CollectStart);
|
||||||
|
|
||||||
// get current stack frame
|
// get current stack frame
|
||||||
auto stack_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
auto stack_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
||||||
|
|
||||||
if (heap->m_stack_top == nullptr)
|
if (heap.m_stack_top == nullptr)
|
||||||
throw std::runtime_error(std::string("Error: Heap is not initialized, read the docs!"));
|
throw std::runtime_error(std::string("Error: Heap is not initialized, read the docs!"));
|
||||||
|
|
||||||
uintptr_t *stack_top = heap->m_stack_top;
|
uintptr_t *stack_top = heap.m_stack_top;
|
||||||
|
|
||||||
auto work_list = heap->m_allocated_chunks;
|
auto work_list = heap.m_allocated_chunks;
|
||||||
mark(stack_bottom, stack_top, work_list);
|
mark(stack_bottom, stack_top, work_list);
|
||||||
|
|
||||||
sweep(heap);
|
sweep(heap);
|
||||||
|
|
@ -195,8 +226,8 @@ namespace GC
|
||||||
*/
|
*/
|
||||||
void Heap::mark(uintptr_t *start, const uintptr_t* const end, vector<Chunk *> &worklist)
|
void Heap::mark(uintptr_t *start, const uintptr_t* const end, vector<Chunk *> &worklist)
|
||||||
{
|
{
|
||||||
Heap *heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
bool profiler_enabled = heap->profiler_enabled();
|
bool profiler_enabled = heap.m_profiler_enable;
|
||||||
if (profiler_enabled)
|
if (profiler_enabled)
|
||||||
Profiler::record(MarkStart);
|
Profiler::record(MarkStart);
|
||||||
|
|
||||||
|
|
@ -249,12 +280,12 @@ namespace GC
|
||||||
*
|
*
|
||||||
* @param heap Pointer to the heap singleton instance.
|
* @param heap Pointer to the heap singleton instance.
|
||||||
*/
|
*/
|
||||||
void Heap::sweep(Heap *heap)
|
void Heap::sweep(Heap &heap)
|
||||||
{
|
{
|
||||||
auto iter = heap->m_allocated_chunks.begin();
|
auto iter = heap.m_allocated_chunks.begin();
|
||||||
bool profiler_enabled = heap->profiler_enabled();
|
bool profiler_enabled = heap.m_profiler_enable;
|
||||||
// This cannot "iter != stop", results in seg fault, since the end gets updated, I think.
|
// This cannot "iter != stop", results in seg fault, since the end gets updated, I think.
|
||||||
while (iter != heap->m_allocated_chunks.end())
|
while (iter != heap.m_allocated_chunks.end())
|
||||||
{
|
{
|
||||||
Chunk *chunk = *iter;
|
Chunk *chunk = *iter;
|
||||||
|
|
||||||
|
|
@ -270,8 +301,8 @@ namespace GC
|
||||||
// the list of allocated chunks
|
// the list of allocated chunks
|
||||||
if (profiler_enabled)
|
if (profiler_enabled)
|
||||||
Profiler::record(ChunkSwept, chunk);
|
Profiler::record(ChunkSwept, chunk);
|
||||||
heap->m_freed_chunks.push_back(chunk);
|
heap.m_freed_chunks.push_back(chunk);
|
||||||
iter = heap->m_allocated_chunks.erase(iter);
|
iter = heap.m_allocated_chunks.erase(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -289,22 +320,22 @@ namespace GC
|
||||||
* @param heap Heap singleton instance, only for avoiding
|
* @param heap Heap singleton instance, only for avoiding
|
||||||
* redundant calls to the singleton get
|
* redundant calls to the singleton get
|
||||||
*/
|
*/
|
||||||
void Heap::free(Heap *heap)
|
void Heap::free(Heap &heap)
|
||||||
{
|
{
|
||||||
if (heap->m_freed_chunks.size() > FREE_THRESH)
|
if (heap.m_freed_chunks.size() > FREE_THRESH)
|
||||||
{
|
{
|
||||||
bool profiler_enabled = heap->profiler_enabled();
|
bool profiler_enabled = heap.profiler_enabled();
|
||||||
while (heap->m_freed_chunks.size())
|
while (heap.m_freed_chunks.size())
|
||||||
{
|
{
|
||||||
auto chunk = heap->m_freed_chunks.back();
|
auto chunk = heap.m_freed_chunks.back();
|
||||||
heap->m_freed_chunks.pop_back();
|
heap.m_freed_chunks.pop_back();
|
||||||
if (profiler_enabled)
|
if (profiler_enabled)
|
||||||
Profiler::record(ChunkFreed, chunk);
|
Profiler::record(ChunkFreed, chunk);
|
||||||
delete chunk;
|
delete chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if there are chunks but not more than FREE_THRESH
|
// if there are chunks but not more than FREE_THRESH
|
||||||
else if (heap->m_freed_chunks.size())
|
else if (heap.m_freed_chunks.size())
|
||||||
{
|
{
|
||||||
// essentially, always check for overlap between
|
// essentially, always check for overlap between
|
||||||
// chunks before finishing the allocation
|
// chunks before finishing the allocation
|
||||||
|
|
@ -327,18 +358,18 @@ namespace GC
|
||||||
* larger chunks. Should remove get_at() to indexing,
|
* larger chunks. Should remove get_at() to indexing,
|
||||||
* since that's constant.
|
* since that's constant.
|
||||||
*/
|
*/
|
||||||
void Heap::free_overlap(Heap *heap) // borde göra en record(ChunkFreed) på onödiga chunks
|
void Heap::free_overlap(Heap &heap) // borde göra en record(ChunkFreed) på onödiga chunks
|
||||||
{
|
{
|
||||||
std::vector<Chunk *> filtered;
|
std::vector<Chunk *> filtered;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
auto prev = Heap::get_at(heap->m_freed_chunks, i++);
|
auto prev = Heap::get_at(heap.m_freed_chunks, i++);
|
||||||
prev->m_marked = true;
|
prev->m_marked = true;
|
||||||
filtered.push_back(prev);
|
filtered.push_back(prev);
|
||||||
cout << filtered.back()->m_start << endl;
|
cout << filtered.back()->m_start << endl;
|
||||||
for (; i < heap->m_freed_chunks.size(); i++)
|
for (; i < heap.m_freed_chunks.size(); i++)
|
||||||
{
|
{
|
||||||
prev = filtered.back();
|
prev = filtered.back();
|
||||||
auto next = Heap::get_at(heap->m_freed_chunks, i);
|
auto next = Heap::get_at(heap.m_freed_chunks, i);
|
||||||
auto p_start = (uintptr_t)(prev->m_start);
|
auto p_start = (uintptr_t)(prev->m_start);
|
||||||
auto p_size = (uintptr_t)(prev->m_size);
|
auto p_size = (uintptr_t)(prev->m_size);
|
||||||
auto n_start = (uintptr_t)(next->m_start);
|
auto n_start = (uintptr_t)(next->m_start);
|
||||||
|
|
@ -348,9 +379,9 @@ namespace GC
|
||||||
filtered.push_back(next);
|
filtered.push_back(next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
heap->m_freed_chunks.swap(filtered);
|
heap.m_freed_chunks.swap(filtered);
|
||||||
|
|
||||||
bool profiler_enabled = heap->profiler_enabled();
|
bool profiler_enabled = heap.m_profiler_enable;
|
||||||
// After swap m_freed_chunks contains still available chunks
|
// After swap m_freed_chunks contains still available chunks
|
||||||
// and filtered contains all the chunks, so delete unused chunks
|
// and filtered contains all the chunks, so delete unused chunks
|
||||||
for (Chunk *chunk : filtered)
|
for (Chunk *chunk : filtered)
|
||||||
|
|
@ -376,9 +407,9 @@ namespace GC
|
||||||
*/
|
*/
|
||||||
void Heap::check_init()
|
void Heap::check_init()
|
||||||
{
|
{
|
||||||
auto heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
cout << "Heap addr:\t" << heap << "\n";
|
cout << "Heap addr:\t" << &heap << "\n";
|
||||||
cout << "GC m_stack_top:\t" << heap->m_stack_top << "\n";
|
cout << "GC m_stack_top:\t" << heap.m_stack_top << "\n";
|
||||||
auto stack_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
auto stack_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
||||||
cout << "GC stack_bottom:\t" << stack_bottom << endl;
|
cout << "GC stack_bottom:\t" << stack_bottom << endl;
|
||||||
}
|
}
|
||||||
|
|
@ -392,9 +423,9 @@ namespace GC
|
||||||
{
|
{
|
||||||
set_profiler(true);
|
set_profiler(true);
|
||||||
|
|
||||||
auto heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
|
|
||||||
if (heap->profiler_enabled())
|
if (heap.m_profiler_enable)
|
||||||
Profiler::record(CollectStart);
|
Profiler::record(CollectStart);
|
||||||
|
|
||||||
cout << "DEBUG COLLECT\nFLAGS: ";
|
cout << "DEBUG COLLECT\nFLAGS: ";
|
||||||
|
|
@ -409,10 +440,10 @@ namespace GC
|
||||||
// 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_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
auto stack_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
||||||
cout << "Stack bottom in collect:\t" << stack_bottom << "\n";
|
cout << "Stack bottom in collect:\t" << stack_bottom << "\n";
|
||||||
uintptr_t *stack_top = heap->m_stack_top;
|
uintptr_t *stack_top = heap.m_stack_top;
|
||||||
|
|
||||||
cout << "Stack end in collect:\t " << stack_top << endl;
|
cout << "Stack end in collect:\t " << stack_top << endl;
|
||||||
auto work_list = heap->m_allocated_chunks;
|
auto work_list = heap.m_allocated_chunks;
|
||||||
|
|
||||||
if (flags & MARK)
|
if (flags & MARK)
|
||||||
mark(stack_bottom, stack_top, work_list);
|
mark(stack_bottom, stack_top, work_list);
|
||||||
|
|
@ -476,21 +507,21 @@ namespace GC
|
||||||
|
|
||||||
void Heap::print_contents()
|
void Heap::print_contents()
|
||||||
{
|
{
|
||||||
auto heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
if (heap->m_allocated_chunks.size())
|
if (heap.m_allocated_chunks.size())
|
||||||
{
|
{
|
||||||
cout << "\nALLOCATED CHUNKS #" << dec << heap->m_allocated_chunks.size() << endl;
|
cout << "\nALLOCATED CHUNKS #" << dec << heap.m_allocated_chunks.size() << endl;
|
||||||
for (auto chunk : heap->m_allocated_chunks)
|
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 (heap->m_freed_chunks.size())
|
if (heap.m_freed_chunks.size())
|
||||||
{
|
{
|
||||||
cout << "\nFREED CHUNKS #" << dec << heap->m_freed_chunks.size() << endl;
|
cout << "\nFREED CHUNKS #" << dec << heap.m_freed_chunks.size() << endl;
|
||||||
for (auto fchunk : heap->m_freed_chunks)
|
for (auto fchunk : heap.m_freed_chunks)
|
||||||
print_line(fchunk);
|
print_line(fchunk);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -501,8 +532,8 @@ namespace GC
|
||||||
|
|
||||||
void Heap::set_profiler(bool mode)
|
void Heap::set_profiler(bool mode)
|
||||||
{
|
{
|
||||||
auto heap = Heap::the();
|
Heap &heap = Heap::the();
|
||||||
heap->m_profiler_enable = mode;
|
heap.m_profiler_enable = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Heap::print_allocated_chunks(Heap *heap) {
|
void Heap::print_allocated_chunks(Heap *heap) {
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,18 @@
|
||||||
|
|
||||||
#include "heap.hpp"
|
#include "heap.hpp"
|
||||||
|
|
||||||
GC::Heap *singleton_test();
|
GC::Heap& singleton_test();
|
||||||
void init_gc(GC::Heap *heap);
|
void init_gc(GC::Heap& heap);
|
||||||
void frame_test(GC::Heap *heap);
|
void frame_test(GC::Heap& heap);
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::cout << "in main" << std::endl;
|
std::cout << "in main" << std::endl;
|
||||||
auto heap = singleton_test();
|
GC::Heap &heap = singleton_test();
|
||||||
|
|
||||||
init_gc(heap);
|
init_gc(heap);
|
||||||
frame_test(heap);
|
frame_test(heap);
|
||||||
|
|
||||||
heap->dispose();
|
heap.dispose();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -28,12 +28,12 @@ int main() {
|
||||||
*
|
*
|
||||||
* @return Pointer to the Heap singleton instance
|
* @return Pointer to the Heap singleton instance
|
||||||
*/
|
*/
|
||||||
GC::Heap *singleton_test() {
|
GC::Heap& singleton_test() {
|
||||||
std::cout << "TESTING SINGLETON INSTANCES" << std::endl;
|
std::cout << "TESTING SINGLETON INSTANCES" << std::endl;
|
||||||
std::cout << "===========================" << std::endl;
|
std::cout << "===========================" << std::endl;
|
||||||
std::cout << "Call 1:\t" << GC::Heap::debug_the() << std::endl; // First call which initializes the singleton instance
|
std::cout << "Call 1:\t" << &GC::Heap::the() << std::endl; // First call which initializes the singleton instance
|
||||||
GC::Heap *heap = GC::Heap::debug_the(); // Second call which should return the initialized instance
|
GC::Heap &heap = GC::Heap::the(); // Second call which should return the initialized instance
|
||||||
std::cout << "Call 2:\t" << heap << std::endl;
|
std::cout << "Call 2:\t" << &heap << std::endl;
|
||||||
std::cout << "===========================" << std::endl;
|
std::cout << "===========================" << std::endl;
|
||||||
return heap;
|
return heap;
|
||||||
}
|
}
|
||||||
|
|
@ -50,11 +50,11 @@ GC::Heap *singleton_test() {
|
||||||
* @param heap The Heap pointer to the singleton instance.
|
* @param heap The Heap pointer to the singleton instance.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void init_gc(GC::Heap *heap){
|
void init_gc(GC::Heap& heap){
|
||||||
std::cout << "\n\n INITIALIZING THE HEAP" << std::endl;
|
std::cout << "\n\n INITIALIZING THE HEAP" << std::endl;
|
||||||
std::cout << "===========================" << std::endl;
|
std::cout << "===========================" << std::endl;
|
||||||
heap->init();
|
heap.init();
|
||||||
heap->set_profiler(true);
|
heap.set_profiler(true);
|
||||||
std::cout << "===========================" << std::endl;
|
std::cout << "===========================" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ void init_gc(GC::Heap *heap){
|
||||||
*
|
*
|
||||||
* @param heap The Heap instance
|
* @param heap The Heap instance
|
||||||
*/
|
*/
|
||||||
void frame_test(GC::Heap *heap) {
|
void frame_test(GC::Heap& heap) {
|
||||||
std::cout << "\n\n TESTING FRAME ADDRESSES" << std::endl;
|
std::cout << "\n\n TESTING FRAME ADDRESSES" << std::endl;
|
||||||
std::cout << "===========================" << std::endl;
|
std::cout << "===========================" << std::endl;
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ void frame_test(GC::Heap *heap) {
|
||||||
auto prev_frame = reinterpret_cast<uintptr_t *>(__builtin_frame_address(1)); // addr of prev stack frame
|
auto prev_frame = reinterpret_cast<uintptr_t *>(__builtin_frame_address(1)); // addr of prev stack frame
|
||||||
std::cout << "Previous stack frame:\t" << prev_frame << std::endl;
|
std::cout << "Previous stack frame:\t" << prev_frame << std::endl;
|
||||||
|
|
||||||
heap->check_init(); // prints the saved absolute top of the stack
|
heap.check_init(); // prints the saved absolute top of the stack
|
||||||
// auto alloced = heap->alloc(sizeof(unsigned long));
|
// auto alloced = heap->alloc(sizeof(unsigned long));
|
||||||
|
|
||||||
std::cout << "===========================" << std::endl;
|
std::cout << "===========================" << std::endl;
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,6 @@
|
||||||
Deliver to samuel
|
Deliver to samuel
|
||||||
|
|
||||||
## GC TODO:
|
## GC TODO:
|
||||||
- Dokumentera
|
|
||||||
- Dokumentera alla filer och funktioner
|
|
||||||
- Skriva reference guide för Samuel
|
|
||||||
- PR till master
|
- PR till master
|
||||||
|
|
||||||
## Tests TODO
|
## Tests TODO
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue