Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <memory>
- #include <new>
- #include <cstdlib>
- #include <cstdio>
- #include <utility>
- #include <array>
- #include <string>
- #include <vector>
- using std::printf;
- using std::size_t;
- using std::string;
- using std::vector;
- // MALLOCATOR
- template <typename T>
- struct mallocator {
- using value_type = T;
- mallocator() = default;
- template <typename U>
- constexpr mallocator(const mallocator<U>&) noexcept {}
- [[nodiscard]] T *allocate(size_t count) {
- return static_cast<T *>(std::malloc(count * sizeof(T)));
- }
- void deallocate(T *ptr, size_t) noexcept {
- return free(ptr);
- }
- };
- template <typename T, typename U>
- bool operator== (const mallocator<T>&, const mallocator<U>&) { return true; }
- template <typename T, typename U>
- bool operator!= (const mallocator<T>&, const mallocator<U>&) { return false; }
- // GARBAGE COLLECTOR
- bool alloc_debug = false;
- struct allocation {
- size_t *base;
- size_t *top;
- bool active; // enum class?
- bool marked; // enum class?
- };
- vector<
- allocation,
- mallocator<allocation>
- > allocations = {};
- bool heuristic = true;
- void *GC_allocate(size_t);
- void GC_free(void *);
- void GC_ondelete(void *);
- void GC_collect();
- void *GC_allocate(size_t len) {
- printf("GC_allocate\n");
- if (heuristic) {
- GC_collect();
- }
- auto ptr = std::malloc(len);
- printf(" allocated %p : %lu\n", ptr, len);
- size_t *base = static_cast<size_t *>(ptr);
- size_t *top = base + (len / sizeof(size_t));
- allocations.push_back({base, top, true, false});
- return ptr;
- }
- void GC_free(void *ptr) {
- printf("GC_free\n");
- std::free(ptr);
- }
- void GC_ondelete(void *) {
- printf("GC_ondelete\n");
- // pass
- }
- size_t *top_of_stack;
- void scan_mark_recurse(size_t *, size_t *);
- void mark_from_registers() {
- std::array<size_t *, 9> registers;
- asm ("mov %%rax, %0" : "=r"(registers[0]));
- asm ("mov %%rcx, %0" : "=r"(registers[1]));
- asm ("mov %%rbx, %0" : "=r"(registers[2]));
- asm ("mov %%rdx, %0" : "=r"(registers[3]));
- asm ("mov %%rsi, %0" : "=r"(registers[4]));
- asm ("mov %%rdi, %0" : "=r"(registers[5]));
- asm ("mov %%rsp, %0" : "=r"(registers[6]));
- asm ("mov %%rbp, %0" : "=r"(registers[7]));
- // asm ("mov %%rip, %0" : "=r"(registers[8]));
- for (auto const& r : registers) {
- // copypaste from below
- for (auto& alloc : allocations) {
- // printf(" looking for allocation: %p\n", (void *)alloc.base);
- if (alloc.marked || !alloc.active) {
- continue;
- }
- if (r >= alloc.base && r < alloc.top) { // CLEANUP TYPE MESS
- alloc.marked = true;
- printf(" found %p\n", (void *)alloc.base);
- scan_mark_recurse(alloc.base, alloc.top);
- continue;
- }
- }
- }
- }
- void scan_mark_recurse(size_t *from, size_t *to) {
- printf("scan_mark_recurse(%p, %p);\n", (void *)from, (void *)to);
- int delta = from > to ? -1 : 1;
- for (size_t *v = from; v != to; v += delta) {
- printf(" v: %p -> %016lx\n", (void *)v, *v);
- for (auto& alloc : allocations) {
- // printf(" looking for allocation: %p\n", (void *)alloc.base);
- if (alloc.marked || !alloc.active) {
- continue;
- }
- if ((size_t*)*v >= alloc.base && (size_t*)*v < alloc.top) { // CLEANUP TYPE MESS
- alloc.marked = true;
- printf(" found %p\n", (void *)alloc.base);
- scan_mark_recurse(alloc.base, alloc.top);
- continue;
- }
- }
- }
- }
- size_t *stack_ptr() {
- size_t *ptr;
- asm ("mov %%rsp, %0" : "=r"(ptr));
- return ptr;
- }
- void GC_collect() {
- printf("GC_collect\n");
- mark_from_registers();
- scan_mark_recurse(top_of_stack, stack_ptr());
- size_t allocs = 0, freed = 0;
- for (auto& alloc : allocations) {
- if (!alloc.active) continue;
- if (!alloc.marked) {
- // printf(" %p not found - freeing\n", (void *)alloc.base);
- freed += 1;
- GC_free(alloc.base);
- alloc.active = false; // not final solution - delete from array?
- } else {
- // printf(" %p found - keeping\n", (void *)alloc.base);
- allocs += 1;
- alloc.marked = false;
- }
- }
- printf("Did a collection: allocs: %lu, freed %lu\n", allocs, freed);
- }
- // OPERATORS
- void * operator new(size_t size) {
- return GC_allocate(size);
- }
- void operator delete(void *ptr) noexcept {
- GC_ondelete(ptr);
- }
- void operator delete(void *ptr, size_t) noexcept {
- GC_ondelete(ptr);
- }
- // MAIN / TEST
- struct destruct {
- string name;
- destruct(string name) : name(name) {
- printf("destruct (%s) constructed\n", name.c_str());
- }
- ~destruct() {
- printf("destruct (%s) destroyed!\n", name.c_str());
- }
- };
- int *inner() {
- vector<int> v1 = {1, 2, 3};
- vector<int> v2 = {3, 4, 5};
- destruct d{"local"};
- auto e = new destruct{"heap"};
- return &v2[1];
- }
- int main(int argc, char **argv) {
- (void)argc;
- top_of_stack = reinterpret_cast<size_t *>(&argv);
- int *f = inner();
- GC_collect();
- printf("%i\n", *f);
- f = nullptr;
- GC_collect();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement