#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::Array: return gc_array((PodArray*)obj); case Tag::ByteArray: return gc_bytearray((PodByteArray*)obj); case Tag::Dict: return gc_dict((PodDict*)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_array(PodArray* obj) { auto nobj = TRY(alloc(obj->size)); nobj->header.tag = Tag::Array; nobj->size = obj->size; for (uint64_t i = 0; i < obj->size; i++) { PodObject* val = obj->data[i].get(obj); nobj->data[i] = OffPtr(nobj, TRY(gc_pod(val))); } 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; } Result Arena::gc_dict(PodDict* obj) { return ErrorCode::NotImplemented; }