clean up
This commit is contained in:
parent
c6c0468c8d
commit
c20ef8f5dd
4 changed files with 135 additions and 110 deletions
47
src/GC/docs/heap.md
Normal file
47
src/GC/docs/heap.md
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
## Heap Documentation
|
||||||
|
|
||||||
|
### Algorithm notes
|
||||||
|
|
||||||
|
void mark_test(vector<Chunk *> worklist) {
|
||||||
|
while (worklist.size() > 0) {
|
||||||
|
Chunk *ref = worklist.pop_back();
|
||||||
|
Chunk *child = (Chunk*) *ref;
|
||||||
|
if (child != NULL && !child->marked) {
|
||||||
|
child->marked = true;
|
||||||
|
worklist.push_back(child);
|
||||||
|
mark_test(worklist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mark_from_roots(uintptr_t *start, const uintptr_t *end) {
|
||||||
|
vector<Chunk *> worklist;
|
||||||
|
for (;start > end; start--) {
|
||||||
|
Chunk *ref = *start;
|
||||||
|
if (ref != NULL && !ref->marked) {
|
||||||
|
ref->marked = true;
|
||||||
|
worklist.push_back(ref);
|
||||||
|
mark_test(worklist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
@ -31,9 +31,9 @@ namespace GC {
|
||||||
|
|
||||||
void collect();
|
void collect();
|
||||||
void sweep();
|
void sweep();
|
||||||
|
uintptr_t *try_recycle_chunks(size_t size);
|
||||||
void free();
|
void free();
|
||||||
void free_overlap();
|
void free_overlap();
|
||||||
// void compact();
|
|
||||||
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);
|
||||||
|
|
@ -42,21 +42,14 @@ namespace GC {
|
||||||
const char *m_heap;
|
const char *m_heap;
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
size_t m_allocated_size;
|
size_t m_allocated_size;
|
||||||
|
uintptr_t *m_stack_end = nullptr;
|
||||||
|
|
||||||
std::vector<Chunk *> m_allocated_chunks;
|
std::vector<Chunk *> m_allocated_chunks;
|
||||||
std::vector<Chunk *> m_freed_chunks;
|
std::vector<Chunk *> m_freed_chunks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Singleton
|
static Heap *the() {
|
||||||
static Heap &the() {
|
|
||||||
if (m_instance)
|
|
||||||
return *m_instance;
|
|
||||||
m_instance = new Heap();
|
|
||||||
return *m_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Heap *the2() {
|
|
||||||
if (m_instance)
|
if (m_instance)
|
||||||
return m_instance;
|
return m_instance;
|
||||||
m_instance = new Heap();
|
m_instance = new Heap();
|
||||||
|
|
@ -64,10 +57,11 @@ namespace GC {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BEWARE only for testing, this should be adressed
|
// BEWARE only for testing, this should be adressed
|
||||||
/* ~Heap() {
|
~Heap() {
|
||||||
free((char *)m_heap);
|
std::free((char *)m_heap);
|
||||||
} */
|
}
|
||||||
|
|
||||||
|
void init();
|
||||||
void *alloc(size_t size);
|
void *alloc(size_t size);
|
||||||
void print_contents();
|
void print_contents();
|
||||||
void collect(uint flags); // DEBUG ONLY
|
void collect(uint flags); // DEBUG ONLY
|
||||||
|
|
|
||||||
|
|
@ -12,45 +12,50 @@ using namespace std;
|
||||||
|
|
||||||
namespace GC {
|
namespace GC {
|
||||||
|
|
||||||
// alloc assumes that after the collect phase, the aligned memory in the heap is compacted from the start,
|
/**
|
||||||
|
* Initialises the heap singleton and saves the address
|
||||||
|
* of the calling stack frame as the stack_end. Presumeably
|
||||||
|
* this address points to the stack frame of the compiled
|
||||||
|
* LLVM executable after linking. (NOT CONFIRMED)
|
||||||
|
*/
|
||||||
|
void Heap::init() {
|
||||||
|
Heap *heap = Heap::the();
|
||||||
|
heap->m_stack_end = reinterpret_cast<uintptr_t *>(__builtin_frame_address(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a given amount of bytes on the heap.
|
||||||
|
*
|
||||||
|
* @param size The amount of bytes to be allocated.
|
||||||
|
*
|
||||||
|
* @return A pointer to the address where the memory
|
||||||
|
* has been allocated. This pointer is supposed
|
||||||
|
* to be casted to and object pointer.
|
||||||
|
*/
|
||||||
void *Heap::alloc(size_t size) {
|
void *Heap::alloc(size_t size) {
|
||||||
auto heap = Heap::the();
|
|
||||||
assert(size > 0 && "Heap: Cannot alloc less than 0B");
|
// Singleton
|
||||||
if (heap.m_size + size > HEAP_SIZE) {
|
Heap *heap = Heap::the();
|
||||||
// try collect
|
|
||||||
|
if (size < 0) {
|
||||||
|
cout << "Heap: Cannot alloc less than 0B. No bytes allocated." << endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heap->m_size + size > HEAP_SIZE) {
|
||||||
collect();
|
collect();
|
||||||
assert(heap.m_size + size <= HEAP_SIZE && "Heap: Out Of Memory");
|
// If collect failed, crash with OOM error
|
||||||
|
assert(heap->m_size + size <= HEAP_SIZE && "Heap: Out Of Memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
// kolla freed chunks innan
|
// If a chunk was recycled, return the old chunk address
|
||||||
// denna är helt onödig just nu, freed chunks kommer alltid va tom
|
uintptr_t *reused_chunk = try_recycle_chunks(size);
|
||||||
for (size_t i = 0; i < m_freed_chunks.size(); i++) {
|
if (reused_chunk != nullptr) {
|
||||||
auto cp = m_freed_chunks.at(i);
|
return (void *)reused_chunk;
|
||||||
if (cp->size > size)
|
|
||||||
{
|
|
||||||
// dela upp chunken och sno ena delen
|
|
||||||
size_t diff = cp->size - size;
|
|
||||||
|
|
||||||
auto chunk_complement = new Chunk;
|
|
||||||
chunk_complement->size = diff;
|
|
||||||
chunk_complement->start = cp->start + cp->size;
|
|
||||||
|
|
||||||
m_freed_chunks.erase(m_freed_chunks.begin() + i);
|
|
||||||
m_freed_chunks.push_back(chunk_complement);
|
|
||||||
m_allocated_chunks.push_back(cp);
|
|
||||||
|
|
||||||
return cp->start;
|
|
||||||
}
|
|
||||||
else if (cp->size == size)
|
|
||||||
{
|
|
||||||
// sno hela chunken
|
|
||||||
m_freed_chunks.erase(m_freed_chunks.begin() + i);
|
|
||||||
m_allocated_chunks.push_back(cp);
|
|
||||||
return cp->start;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Om inga free chunks finns, skapa ny chunk
|
// If no free chunks was found (reused_chunk is a nullptr),
|
||||||
|
// 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 *)m_heap + m_size;
|
||||||
|
|
@ -63,32 +68,55 @@ namespace GC {
|
||||||
return new_chunk->start;
|
return new_chunk->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uintptr_t *Heap::try_recycle_chunks(size_t size) {
|
||||||
|
auto heap = Heap::the();
|
||||||
|
// Check if there are any freed chunks large enough for current request
|
||||||
|
for (size_t i = 0; i < heap->m_freed_chunks.size(); i++) {
|
||||||
|
auto cp = heap->m_freed_chunks.at(i);
|
||||||
|
if (cp->size > size)
|
||||||
|
{
|
||||||
|
// Split the chunk, use one part and add the remaining part to
|
||||||
|
// the list of freed chunks
|
||||||
|
size_t diff = cp->size - size;
|
||||||
|
|
||||||
|
auto chunk_complement = new Chunk;
|
||||||
|
chunk_complement->size = diff;
|
||||||
|
chunk_complement->start = cp->start + cp->size;
|
||||||
|
|
||||||
|
heap->m_freed_chunks.erase(m_freed_chunks.begin() + i);
|
||||||
|
heap->m_freed_chunks.push_back(chunk_complement);
|
||||||
|
heap->m_allocated_chunks.push_back(cp);
|
||||||
|
|
||||||
|
return cp->start;
|
||||||
|
}
|
||||||
|
else if (cp->size == size)
|
||||||
|
{
|
||||||
|
// Reuse the whole chunk
|
||||||
|
m_freed_chunks.erase(m_freed_chunks.begin() + i);
|
||||||
|
m_allocated_chunks.push_back(cp);
|
||||||
|
return cp->start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Heap::collect() {
|
void Heap::collect() {
|
||||||
|
// Get the adress of the current stack frame
|
||||||
|
auto heap = Heap::the();
|
||||||
|
|
||||||
|
uintptr_t *stack_end;
|
||||||
|
|
||||||
// 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));
|
||||||
// looking at 10 stack frames back
|
if (heap->m_stack_end != nullptr)
|
||||||
const uintptr_t *stack_end = (uintptr_t *)0; // temporary
|
stack_end = heap->m_stack_end;
|
||||||
|
else
|
||||||
|
stack_end = (uintptr_t *)0; // temporary
|
||||||
|
|
||||||
// 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;
|
auto work_list = m_allocated_chunks;
|
||||||
mark(stack_start, stack_end, work_list);
|
mark(stack_start, stack_end, work_list);
|
||||||
|
|
||||||
sweep();
|
sweep();
|
||||||
|
|
||||||
// compact();
|
|
||||||
|
|
||||||
free();
|
free();
|
||||||
|
|
||||||
// We shouldn't do this, since then m_freed_chunks doesnt' have any real purpose,
|
|
||||||
// it should be used in alloc, it isn't if we delete *all* of its contentes
|
|
||||||
// release free chunks
|
|
||||||
// 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 memory to the OS
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Heap::free() {
|
void Heap::free() {
|
||||||
|
|
@ -200,50 +228,6 @@ namespace GC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* void mark_test(vector<Chunk *> worklist) {
|
|
||||||
while (worklist.size() > 0) {
|
|
||||||
Chunk *ref = worklist.pop_back();
|
|
||||||
Chunk *child = (Chunk*) *ref;
|
|
||||||
if (child != NULL && !child->marked) {
|
|
||||||
child->marked = true;
|
|
||||||
worklist.push_back(child);
|
|
||||||
mark_test(worklist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mark_from_roots(uintptr_t *start, const uintptr_t *end) {
|
|
||||||
vector<Chunk *> worklist;
|
|
||||||
for (;start > end; start--) {
|
|
||||||
Chunk *ref = *start;
|
|
||||||
if (ref != NULL && !ref->marked) {
|
|
||||||
ref->marked = true;
|
|
||||||
worklist.push_back(ref);
|
|
||||||
mark_test(worklist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* 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) {
|
||||||
cout << "Marked: " << chunk->marked << "\nStart adr: " << chunk->start << "\nSize: " << chunk->size << " B\n" << endl;
|
cout << "Marked: " << chunk->marked << "\nStart adr: " << chunk->start << "\nSize: " << chunk->size << " B\n" << endl;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ Goal for next week (24/2):
|
||||||
|
|
||||||
## GC TODO:
|
## GC TODO:
|
||||||
- Merge to main branch
|
- Merge to main branch
|
||||||
- Don't empty m_free_chunks, reuse in a better way **Victor fixes this**
|
- Fix singleton references
|
||||||
|
|
||||||
## Tests TODO
|
## Tests TODO
|
||||||
### Library linking
|
### Library linking
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue