#include "arena.hpp" #include "die.hpp" #include "error.hpp" static Arena* current_arena = 0; 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); case Tag::Opcode: return gc_opcode((PodOpcode*)obj); case Tag::Function: return gc_function((PodFunction*)obj); case Tag::Stack: return gc_stack((PodStack*)obj); } return ERROR(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 ERROR(NotImplemented); } Result Arena::gc_pair(PodPair* obj) { auto nobj = TRY(alloc()); nobj->header.tag = Tag::Pair; PodObject* first = obj->first.get(); PodObject* rest = obj->rest.get(); first = TRY(gc_pod(first)); rest = TRY(gc_pod(rest)); nobj->first = first; nobj->rest = rest; return nobj; } Result Arena::gc_array(PodArray* obj) { auto nobj = TRY(alloc(sizeof(OffPtr) * 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(); nobj->data[i] = 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) { auto nobj = TRY(alloc(obj->size * 2 * sizeof(OffPtr))); nobj->header.tag = Tag::Dict; nobj->size = obj->size; for (uint64_t i = 0; i < obj->size * 2; i++) { PodObject* val = obj->data[i].get(); nobj->data[i] = TRY(gc_pod(val)); } return nobj; } Result Arena::gc_opcode(PodOpcode* obj) { auto nobj = TRY(alloc()); nobj->header.tag = Tag::Opcode; nobj->opcode = obj->opcode; nobj->arg1 = obj->arg1; nobj->arg2 = obj->arg2; nobj->arg3 = obj->arg3; nobj->arg4 = obj->arg4; return nobj; } Result Arena::gc_function(PodFunction* obj) { auto nobj = TRY(alloc()); nobj->header.tag = Tag::Function; nobj->arity = obj->arity; nobj->name = TRY(gc_pod(obj->name.get())); nobj->constants = TRY(gc_pod(obj->constants.get())); nobj->code = TRY(gc_pod(obj->code.get())); nobj->closure = TRY(gc_pod(obj->closure.get())); return nobj; } Result Arena::gc_stack(PodStack* obj) { auto nobj = TRY(alloc(sizeof(OffPtr) * obj->size)); nobj->header.tag = Tag::Stack; nobj->size = obj->size; nobj->top = obj->top; for (uint64_t i = 0; i < obj->top; i++) { PodObject* val = obj->data[i].get(); nobj->data[i] = TRY(gc_pod(val)); } for (uint64_t i = obj->top; i < obj->size; i++) { nobj->data[i] = 0; } return nobj; } Arena& get_arena() { if (current_arena == 0) die("Arena not set\n"); return *current_arena; } void set_arena(Arena& arena) { current_arena = &arena; } Result arena_gc() { return get_arena().gc(); }