Quick reference guide and runtime errors.

This commit is contained in:
Victor Olin 2023-03-22 11:18:30 +01:00
parent 87dc0fef2d
commit ad29cc5ee5
5 changed files with 89 additions and 52 deletions

View file

@ -1,47 +0,0 @@
## 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)

83
src/GC/docs/ref-guide.md Normal file
View file

@ -0,0 +1,83 @@
# GC library - reference guide
The Heap class is the core of the library and contains all necessary
functions for using the library. This class exposes four public functions
which are `init`, `dispose`, `alloc`, and `set_profiler`.
To use the library, simply include it as `#include "heap.hpp"` and link
it during compilation. Or you can compile it to a static library using
the target `make static_lib` which compiles everything to an .a file.
It can also be compiled to a shared library if necessary with the target
`make shared_lib` which produces an .so file.
## Quick guide
1. If you want a profiler, call `Heap::set_profiler(true)`. Otherwise this can be skipped.
2. Call `Heap::init()` to initialize the heap before using `alloc` (**crucial**).
3. Use `Heap::alloc()` as you want.
4. At program exit, call `Heap::dispose()` to free up all the memory used.
## Functions
### Heap::init()
When using the library, the user has to, at the start of the program,
call the `void init()` function, which initiates the Heap singleton
and the class member `m_stack_top`. **It is crucial** that this
functions is called from the `main` function of the end program,
as `init` uses the intrinsic function `__builtin_frame_address`
to find the address of the **first** stack frame of the end program.
If the function **is not** called from the `main` function
of the end program, it is not guaranteed that the garbage collector
will collect all objects.
The intrinsic function used is technically unsafe for this use,
but during testing it has only shown to segfault for values greater
than the one used in `init`. If you run into a segfault, please
contact the developers.
### Heap::set_profiler(bool mode)
This function is used to enable or disable the profiler connected
to the Heap. The profiler is primarily used for testing, but can
also be used in general to keep track of the programs history.
This function takes a single boolean as an argument to represent
the state of the profiler. `true` means that the profiler is enabled
and `false` means that the profiler is disabled. This function
can theoretically be called at any time during program execution,
but it's probably a bad idea. It is recommended to call this function
before the call to `init` or at least at before the first call to
`alloc`.
### Heap::alloc(size_t size)
The probably most important function in this library. This function
is called to request memory from the "heap". `alloc` takes a single
argument which is a `size_t` (unsigned long) to represent the amount
of bytes to allocate on the heap. The allocation is C-style, meaning
that alloc returns a `void` pointer similar to `malloc`, which
is then supposed to be cast by the user to a proper pointer. When
`alloc` is called and there is already not enough memory left on
the heap to accommodate the request, a collection is triggered
to free up memory for the allocation. Hence the user does not
need to make their own calls to `free` or manually free up memory.
`alloc` can also return a null pointer, if the user requests to
allocate 0 bytes. This is not recommended.
`alloc` can also throw runtime errors in two cases. The first one
is of there is not enough memory on the heap available after
a collection, which in case the allocation cannot complete.
The second case is during a collection, where the function
`collect` throws a runtime error if the heap is not already
initialized by a call to `init`. Calls to `alloc` can technically
take place without properly initializing the heap, but this is
not recommended.
### Heap::dispose()
This function is used to dispose the heap at the program exit.
If the profiler is enabled, it is also disposed from a call
to `dispose`. When the profiler is disposed, a log file is
dumped containing the events on the heap. If the profiler
is disabled, nothing happens to the profiler during `dispose`.
After the profiler is disposed, the heap is deleted which
frees up all the memory used and deletes (hopefully) all
the remaining objects in memory.

View file

@ -123,6 +123,7 @@ namespace GC
static void init();
static void dispose();
static void *alloc(size_t size);
void set_profiler(bool mode);
#ifdef DEBUG
static Heap *debug_the()
@ -136,7 +137,6 @@ namespace GC
void check_init(); // print dummy things
void print_contents(); // print dummy things
void print_allocated_chunks(Heap *heap); // print the contents in m_allocated_chunks
void set_profiler(bool mode);
#endif
};
}

View file

@ -4,6 +4,7 @@
#include <execinfo.h>
#include <iostream>
#include <setjmp.h>
#include <stdexcept>
#include <stdlib.h>
#include <vector>
@ -70,7 +71,7 @@ namespace GC
{
heap->collect();
// If memory is not enough after collect, crash with OOM error
assert(heap->m_size + size <= HEAP_SIZE && "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
@ -164,7 +165,7 @@ namespace GC
auto stack_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
if (heap->m_stack_top == nullptr)
assert(false && "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;

View file

@ -4,11 +4,11 @@
Deliver to samuel
## GC TODO:
- Code cleanup
- Dokumentera
- Dokumentera alla filer och funktioner
- Skriva reference guide för Samuel
- PR till master
## Tests TODO
- Write complex datastructures for tests with larger programs
- Write complex datastructures for tests with larger programs
- Testa `__builtin_frame_address` mer specifikt för att se om första stack framen skannas