From f87822933a6b151574c9d9339f715bdebed2ed62 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Tue, 30 Jul 2024 00:14:09 +0100 Subject: [PATCH] Make garbage collection work --- src/arena.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ src/arena.hpp | 35 ++++++++++-- src/common.hpp | 26 ++++++++- src/vli.cpp | 2 + 4 files changed, 198 insertions(+), 7 deletions(-) diff --git a/src/arena.cpp b/src/arena.cpp index 7f8a4b4..765b633 100644 --- a/src/arena.cpp +++ b/src/arena.cpp @@ -1,8 +1,150 @@ #include "arena.hpp" +#include "error.hpp" + GcRootBase::GcRootBase(PodObject* ptr, GcRootList* node) : _ptr(ptr), _node(node) {} GcRootBase::~GcRootBase() { if (_node != 0) _node->remove(); } + +Result Arena::gc() { + std::swap(_first, _second); + _first->reset(); + + TRY(gc_roots()); + + _second->reset(); + return Result(); +} + +Result Arena::gc_roots() { + auto node = _gcroot.next(); + while (node != 0) { + node = TRY(gc_root(node)); + node = node->next(); + } + return Result(); +} + +Result Arena::gc_root(GcRootList* node) { + auto pod = TRY(gc_pod(node->_root->_ptr)); + auto lst = TRY(alloc()); + node->_root->_ptr = pod; + node->_root->_node = lst; + + lst->_root = node->_root; + + GcRootList* prev = node->_prev; + GcRootList* next = node->_next; + + prev->_next = lst; + if (next) next->_prev = lst; + lst->_prev = prev; + lst->_next = next; + + // Not strictly needed, but useful for debugging + node->_prev = 0; + node->_next = 0; + node->_root = 0; + + return lst; +} + +Result Arena::gc_pod(PodObject* obj) { + switch (obj->header.tag) { + case Tag::Nil: + return gc_nil((PodNil*)obj); + case Tag::Bool: + return gc_bool((PodBool*)obj); + case Tag::Int64: + return gc_int64((PodInt64*)obj); + case Tag::Float: + return gc_float((PodFloat*)obj); + case Tag::String: + return gc_string((PodString*)obj); + case Tag::Symbol: + return gc_symbol((PodSymbol*)obj); + case Tag::Syntax: + return gc_syntax((PodSyntax*)obj); + case Tag::Pair: + return gc_pair((PodPair*)obj); + case Tag::ByteArray: + return gc_bytearray((PodByteArray*)obj); + } + + return ErrorCode::TypeMismatch; +} + +Result Arena::gc_nil(PodNil* obj) { + auto nobj = TRY(alloc()); + nobj->header.tag = Tag::Nil; + return nobj; +} + +Result Arena::gc_bool(PodBool* obj) { + auto nobj = TRY(alloc()); + nobj->header.tag = Tag::Bool; + nobj->value = obj->value; + return nobj; +} + +Result Arena::gc_int64(PodInt64* obj) { + auto nobj = TRY(alloc()); + nobj->header.tag = Tag::Int64; + nobj->value = obj->value; + return nobj; +} + +Result Arena::gc_float(PodFloat* obj) { + auto nobj = TRY(alloc()); + nobj->header.tag = Tag::Float; + nobj->value = obj->value; + return nobj; +} + +Result Arena::gc_string(PodString* obj) { + auto nobj = TRY(alloc(obj->size * sizeof(char32_t))); + nobj->header.tag = Tag::String; + nobj->size = obj->size; + memcpy(nobj->data, obj->data, obj->size * sizeof(char32_t)); + return nobj; +} + +Result Arena::gc_symbol(PodSymbol* obj) { + auto nobj = TRY(alloc(obj->size * sizeof(char32_t))); + nobj->header.tag = Tag::Symbol; + nobj->size = obj->size; + memcpy(nobj->data, obj->data, obj->size * sizeof(char32_t)); + return nobj; +} + +Result Arena::gc_syntax(PodSyntax* obj) { + return ErrorCode::NotImplemented; +} + +Result Arena::gc_pair(PodPair* obj) { + auto nobj = TRY(alloc()); + + nobj->header.tag = Tag::Pair; + + PodObject* first = obj->first.get(obj); + PodObject* rest = obj->rest.get(obj); + + first = TRY(gc_pod(first)); + rest = TRY(gc_pod(rest)); + + nobj->first = OffPtr(nobj, first); + nobj->rest = OffPtr(nobj, rest); + + return nobj; +} + +Result Arena::gc_bytearray(PodByteArray* obj) { + auto nobj = TRY(alloc(obj->size)); + nobj->header.tag = Tag::ByteArray; + nobj->size = obj->size; + memcpy(nobj->data, obj->data, obj->size); + return nobj; +} diff --git a/src/arena.hpp b/src/arena.hpp index 27c7976..95df398 100644 --- a/src/arena.hpp +++ b/src/arena.hpp @@ -15,6 +15,8 @@ class GcRootList; class GcRootBase { public: + friend class Arena; + GcRootBase() : _ptr(0), _node(0){}; GcRootBase(PodObject* ptr, GcRootList* node); @@ -54,6 +56,8 @@ Result> MkGcRoot(T* ptr, Arena& arena) { class GcRootList { public: + friend class Arena; + GcRootList() : _prev(0), _next(0), _root(0) {} GcRootList(GcRootBase* root) : _prev(0), _next(0), _root(root) {} @@ -72,6 +76,7 @@ class GcRootList { } GcRootList* next() { return _next; } + GcRootList* prev() { return _prev; } void update(GcRootBase* root) { _root = root; } @@ -105,6 +110,11 @@ class ArenaHeap { return res; } + void reset() { + boundary = 0; + ASAN_POISON_MEMORY_REGION(buf, bufsize); + } + private: uint8_t* buf; uint64_t bufsize; @@ -114,20 +124,35 @@ class ArenaHeap { class Arena { public: Arena(ArenaHeap* first, ArenaHeap* second) - : _heaps{first, second}, _gcroot(), _current(0) {} + : _first(first), _second(second), _gcroot() {} template Result alloc(uint64_t extra = 0) { uint64_t objsize = sizeof(T) + extra; - auto ptr = _heaps[_current]->alloc(objsize); + auto ptr = _first->alloc(objsize); if (ptr.has_value()) return (T*)ptr.value(); // TODO: trigger GC - return (T*)TRY(_heaps[_current]->alloc(objsize)); + return (T*)TRY(_first->alloc(objsize)); } + Result gc(); + Result gc_roots(); + Result gc_root(GcRootList* node); + + Result gc_pod(PodObject* obj); + Result gc_nil(PodNil* obj); + Result gc_bool(PodBool* obj); + Result gc_int64(PodInt64* obj); + Result gc_float(PodFloat* obj); + Result gc_string(PodString* obj); + Result gc_symbol(PodSymbol* obj); + Result gc_syntax(PodSyntax* obj); + Result gc_pair(PodPair* obj); + Result gc_bytearray(PodByteArray* obj); + void add_root(GcRootList* node) { _gcroot.insert(node); } uint64_t root_count() { @@ -139,9 +164,9 @@ class Arena { }; private: - ArenaHeap* _heaps[2]; + ArenaHeap* _first; + ArenaHeap* _second; GcRootList _gcroot; - int _current; }; template diff --git a/src/common.hpp b/src/common.hpp index 0f86dce..f1eb5e4 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -19,6 +19,7 @@ class Object { virtual Tag tag() = 0; virtual Result copy(Arena& arena) = 0; virtual PodObject* pod() = 0; + virtual void move(Object*) = 0; virtual ~Object() = default; Object() = default; Object(const Object&) = delete; @@ -46,6 +47,8 @@ class Nil : public Object { virtual Result copy(Arena& arena) final; + virtual void move(Object* obj) final { new (obj) Nil(std::move(_value)); } + private: GcRoot _value; }; @@ -64,6 +67,10 @@ class ByteArray : public Object { virtual Tag tag() final { return Tag::String; } virtual PodObject* pod() final { return _value.get(); } + virtual void move(Object* obj) final { + new (obj) ByteArray(std::move(_value)); + } + static Result create(Arena& arena, PodByteArray* obj) { return ByteArray(TRY(MkGcRoot(obj, arena))); } @@ -164,6 +171,8 @@ class String : public Object { virtual Tag tag() final { return Tag::String; } virtual PodObject* pod() final { return _value.get(); } + virtual void move(Object* obj) final { new (obj) String(std::move(_value)); } + static Result create(Arena& arena, PodString* obj) { return String(TRY(MkGcRoot(obj, arena))); } @@ -262,6 +271,8 @@ class Symbol : public Object { virtual Tag tag() final { return Tag::Symbol; } virtual PodObject* pod() final { return _value.get(); } + virtual void move(Object* obj) final { new (obj) Symbol(std::move(_value)); } + static Result create(Arena& arena, PodSymbol* obj) { return Symbol(TRY(MkGcRoot(obj, arena))); } @@ -298,6 +309,8 @@ class Syntax : public Object { virtual Tag tag() final { return Tag::Syntax; } virtual PodObject* pod() final { return _value.get(); } + virtual void move(Object* obj) final { new (obj) Syntax(std::move(_value)); } + static Result create(Arena& arena, PodSyntax* obj) { return Syntax(TRY(MkGcRoot(obj, arena))); } @@ -318,6 +331,8 @@ class Pair : public Object { virtual Tag tag() final { return Tag::Pair; } virtual PodObject* pod() final { return _value.get(); } + virtual void move(Object* obj) final { new (obj) Pair(std::move(_value)); } + static Result create(Arena& arena, PodPair* obj) { return Pair(TRY(MkGcRoot(obj, arena))); } @@ -340,6 +355,8 @@ class Int64 : public Object { virtual Tag tag() final { return Tag::Int64; } virtual PodObject* pod() final { return _value.get(); } + virtual void move(Object* obj) final { new (obj) Int64(std::move(_value)); } + static Result create(Arena& arena, PodInt64* obj) { return Int64(TRY(MkGcRoot(obj, arena))); } @@ -368,6 +385,8 @@ class Float : public Object { virtual Tag tag() final { return Tag::Float; } virtual PodObject* pod() final { return _value.get(); } + virtual void move(Object* obj) final { new (obj) Float(std::move(_value)); } + static Result create(Arena& arena, PodFloat* obj) { return Float(TRY(MkGcRoot(obj, arena))); } @@ -397,6 +416,8 @@ class Bool : public Object { virtual Tag tag() final { return Tag::Bool; } virtual PodObject* pod() final { return _value.get(); } + virtual void move(Object* obj) final { new (obj) Bool(std::move(_value)); } + static Result create(Arena& arena, PodBool* obj) { return Bool(TRY(MkGcRoot(obj, arena))); } @@ -423,7 +444,8 @@ class Value { Value() { new (buf) Nil(); } ~Value() { ((Object*)buf)->~Object(); } Value(Value&& val) { - memcpy(buf, val.buf, 24); + // TODO: repoint the gc root properly + ((Object*)val.buf)->move((Object*)buf); new (val.buf) Nil(); } Value(const Value&) = delete; @@ -437,7 +459,7 @@ class Value { Value& operator=(Value&& val) { ((Object*)buf)->~Object(); - memcpy(buf, val.buf, 24); + ((Object*)val.buf)->move((Object*)buf); new (val.buf) Nil(); return *this; } diff --git a/src/vli.cpp b/src/vli.cpp index 8613d8b..cf600ab 100644 --- a/src/vli.cpp +++ b/src/vli.cpp @@ -38,6 +38,8 @@ int main() { auto writer = Writer(arena); auto s2 = DIEIF(writer.write_one(r)); + DIEIF(arena.gc()); + DIEIF(debug_print(arena, s2)); /*