2024-07-20 21:42:49 +00:00
|
|
|
#include "arena.hpp"
|
|
|
|
|
2024-08-09 22:45:06 +00:00
|
|
|
#include "die.hpp"
|
2024-07-29 23:14:09 +00:00
|
|
|
#include "error.hpp"
|
2024-09-23 20:23:25 +00:00
|
|
|
#include "pod.hpp"
|
2024-07-29 23:14:09 +00:00
|
|
|
|
2024-08-09 22:45:06 +00:00
|
|
|
static Arena* current_arena = 0;
|
|
|
|
|
2024-07-20 21:42:49 +00:00
|
|
|
GcRootBase::GcRootBase(PodObject* ptr, GcRootList* node)
|
|
|
|
: _ptr(ptr), _node(node) {}
|
|
|
|
|
|
|
|
GcRootBase::~GcRootBase() {
|
|
|
|
if (_node != 0) _node->remove();
|
|
|
|
}
|
2024-07-29 23:14:09 +00:00
|
|
|
|
|
|
|
Result<void> Arena::gc() {
|
|
|
|
std::swap(_first, _second);
|
|
|
|
_first->reset();
|
|
|
|
|
|
|
|
TRY(gc_roots());
|
|
|
|
|
|
|
|
_second->reset();
|
|
|
|
return Result<void>();
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<void> Arena::gc_roots() {
|
|
|
|
auto node = _gcroot.next();
|
|
|
|
while (node != 0) {
|
|
|
|
node = TRY(gc_root(node));
|
|
|
|
node = node->next();
|
|
|
|
}
|
|
|
|
return Result<void>();
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<GcRootList*> Arena::gc_root(GcRootList* node) {
|
|
|
|
auto pod = TRY(gc_pod(node->_root->_ptr));
|
|
|
|
auto lst = TRY(alloc<GcRootList>());
|
|
|
|
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<PodObject*> Arena::gc_pod(PodObject* obj) {
|
2024-09-12 21:43:38 +00:00
|
|
|
if (obj == 0) return 0;
|
|
|
|
|
2024-07-29 23:14:09 +00:00
|
|
|
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);
|
2024-09-05 22:22:45 +00:00
|
|
|
case Tag::SrcLoc:
|
|
|
|
return gc_srcloc((PodSrcLoc*)obj);
|
2024-07-29 23:14:09 +00:00
|
|
|
case Tag::Syntax:
|
|
|
|
return gc_syntax((PodSyntax*)obj);
|
|
|
|
case Tag::Pair:
|
|
|
|
return gc_pair((PodPair*)obj);
|
2024-07-30 22:52:23 +00:00
|
|
|
case Tag::Array:
|
|
|
|
return gc_array((PodArray*)obj);
|
2024-07-29 23:14:09 +00:00
|
|
|
case Tag::ByteArray:
|
|
|
|
return gc_bytearray((PodByteArray*)obj);
|
2024-08-01 17:56:38 +00:00
|
|
|
case Tag::Dict:
|
|
|
|
return gc_dict((PodDict*)obj);
|
2024-08-10 17:24:16 +00:00
|
|
|
case Tag::Opcode:
|
|
|
|
return gc_opcode((PodOpcode*)obj);
|
2024-08-11 20:37:37 +00:00
|
|
|
case Tag::Function:
|
|
|
|
return gc_function((PodFunction*)obj);
|
2024-08-24 23:55:11 +00:00
|
|
|
case Tag::StdlibFunction:
|
|
|
|
return gc_stdlib_function((PodStdlibFunction*)obj);
|
2024-08-23 23:28:29 +00:00
|
|
|
case Tag::Module:
|
|
|
|
return gc_module((PodModule*)obj);
|
2024-09-12 21:43:38 +00:00
|
|
|
case Tag::StackFrame:
|
|
|
|
return gc_stack((PodStackFrame*)obj);
|
2024-09-07 16:37:12 +00:00
|
|
|
case Tag::Error:
|
|
|
|
return gc_error((PodError*)obj);
|
2024-09-23 20:23:25 +00:00
|
|
|
case Tag::Continuation:
|
|
|
|
return gc_continuation((PodContinuation*)obj);
|
2024-07-29 23:14:09 +00:00
|
|
|
}
|
|
|
|
|
2024-08-10 10:17:20 +00:00
|
|
|
return ERROR(TypeMismatch);
|
2024-07-29 23:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Result<PodObject*> Arena::gc_nil(PodNil* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodNil>());
|
|
|
|
nobj->header.tag = Tag::Nil;
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<PodObject*> Arena::gc_bool(PodBool* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodBool>());
|
|
|
|
nobj->header.tag = Tag::Bool;
|
|
|
|
nobj->value = obj->value;
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<PodObject*> Arena::gc_int64(PodInt64* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodInt64>());
|
|
|
|
nobj->header.tag = Tag::Int64;
|
|
|
|
nobj->value = obj->value;
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<PodObject*> Arena::gc_float(PodFloat* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodFloat>());
|
|
|
|
nobj->header.tag = Tag::Float;
|
|
|
|
nobj->value = obj->value;
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<PodObject*> Arena::gc_string(PodString* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodString>(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<PodObject*> Arena::gc_symbol(PodSymbol* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodSymbol>(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;
|
|
|
|
}
|
|
|
|
|
2024-09-05 22:22:45 +00:00
|
|
|
Result<PodObject*> Arena::gc_srcloc(PodSrcLoc* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodSrcLoc>());
|
|
|
|
|
|
|
|
nobj->header.tag = Tag::SrcLoc;
|
|
|
|
|
|
|
|
nobj->sourcerange = obj->sourcerange;
|
|
|
|
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-07-29 23:14:09 +00:00
|
|
|
Result<PodObject*> Arena::gc_syntax(PodSyntax* obj) {
|
2024-09-02 23:24:44 +00:00
|
|
|
auto nobj = TRY(alloc<PodSyntax>());
|
|
|
|
|
|
|
|
nobj->header.tag = Tag::Syntax;
|
|
|
|
|
|
|
|
nobj->filename = TRY(gc_pod(obj->filename.get()));
|
2024-09-05 22:22:45 +00:00
|
|
|
nobj->srcloc = TRY(gc_pod(obj->srcloc.get()));
|
2024-09-02 23:24:44 +00:00
|
|
|
nobj->expression = TRY(gc_pod(obj->expression.get()));
|
|
|
|
|
|
|
|
return nobj;
|
2024-07-29 23:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Result<PodObject*> Arena::gc_pair(PodPair* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodPair>());
|
|
|
|
|
|
|
|
nobj->header.tag = Tag::Pair;
|
|
|
|
|
2024-08-06 19:32:55 +00:00
|
|
|
PodObject* first = obj->first.get();
|
|
|
|
PodObject* rest = obj->rest.get();
|
2024-07-29 23:14:09 +00:00
|
|
|
|
|
|
|
first = TRY(gc_pod(first));
|
|
|
|
rest = TRY(gc_pod(rest));
|
|
|
|
|
2024-08-06 19:32:55 +00:00
|
|
|
nobj->first = first;
|
|
|
|
nobj->rest = rest;
|
2024-07-29 23:14:09 +00:00
|
|
|
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-07-30 22:52:23 +00:00
|
|
|
Result<PodObject*> Arena::gc_array(PodArray* obj) {
|
2024-08-03 01:54:53 +00:00
|
|
|
auto nobj = TRY(alloc<PodArray>(sizeof(OffPtr<PodObject>) * obj->size));
|
2024-07-30 22:52:23 +00:00
|
|
|
nobj->header.tag = Tag::Array;
|
|
|
|
nobj->size = obj->size;
|
|
|
|
for (uint64_t i = 0; i < obj->size; i++) {
|
2024-08-06 19:32:55 +00:00
|
|
|
PodObject* val = obj->data[i].get();
|
|
|
|
nobj->data[i] = TRY(gc_pod(val));
|
2024-07-30 22:52:23 +00:00
|
|
|
}
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-07-29 23:14:09 +00:00
|
|
|
Result<PodObject*> Arena::gc_bytearray(PodByteArray* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodByteArray>(obj->size));
|
|
|
|
nobj->header.tag = Tag::ByteArray;
|
|
|
|
nobj->size = obj->size;
|
|
|
|
memcpy(nobj->data, obj->data, obj->size);
|
|
|
|
return nobj;
|
|
|
|
}
|
2024-08-01 17:56:38 +00:00
|
|
|
|
|
|
|
Result<PodObject*> Arena::gc_dict(PodDict* obj) {
|
2024-08-03 01:54:53 +00:00
|
|
|
auto nobj = TRY(alloc<PodDict>(obj->size * 2 * sizeof(OffPtr<PodObject>)));
|
|
|
|
nobj->header.tag = Tag::Dict;
|
|
|
|
nobj->size = obj->size;
|
|
|
|
for (uint64_t i = 0; i < obj->size * 2; i++) {
|
2024-08-06 19:32:55 +00:00
|
|
|
PodObject* val = obj->data[i].get();
|
|
|
|
nobj->data[i] = TRY(gc_pod(val));
|
2024-08-03 01:54:53 +00:00
|
|
|
}
|
|
|
|
return nobj;
|
2024-08-01 17:56:38 +00:00
|
|
|
}
|
2024-08-09 22:45:06 +00:00
|
|
|
|
2024-08-10 17:24:16 +00:00
|
|
|
Result<PodObject*> Arena::gc_opcode(PodOpcode* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodOpcode>());
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-08-11 20:37:37 +00:00
|
|
|
Result<PodObject*> Arena::gc_function(PodFunction* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodFunction>());
|
|
|
|
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()));
|
2024-08-21 22:45:19 +00:00
|
|
|
nobj->closure = TRY(gc_pod(obj->closure.get()));
|
2024-08-11 20:37:37 +00:00
|
|
|
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-08-24 23:55:11 +00:00
|
|
|
Result<PodObject*> Arena::gc_stdlib_function(PodStdlibFunction* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodStdlibFunction>());
|
|
|
|
nobj->header.tag = Tag::StdlibFunction;
|
|
|
|
nobj->fun_id = obj->fun_id;
|
|
|
|
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-08-23 23:28:29 +00:00
|
|
|
Result<PodObject*> Arena::gc_module(PodModule* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodModule>());
|
2024-08-24 23:55:11 +00:00
|
|
|
nobj->header.tag = Tag::Module;
|
2024-08-23 23:28:29 +00:00
|
|
|
nobj->name = TRY(gc_pod(obj->name.get()));
|
|
|
|
nobj->fun = TRY(gc_pod(obj->fun.get()));
|
|
|
|
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-09-12 21:43:38 +00:00
|
|
|
Result<PodObject*> Arena::gc_stack(PodStackFrame* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * obj->size));
|
|
|
|
nobj->header.tag = Tag::StackFrame;
|
|
|
|
nobj->parent = TRY(gc_pod(obj->parent.get()));
|
2024-09-12 23:54:32 +00:00
|
|
|
nobj->fun = TRY(gc_pod(obj->fun.get()));
|
2024-09-13 20:15:57 +00:00
|
|
|
nobj->pc = obj->pc;
|
2024-08-12 22:05:40 +00:00
|
|
|
nobj->size = obj->size;
|
2024-09-12 23:54:32 +00:00
|
|
|
for (uint64_t i = 0; i < obj->size; i++) {
|
2024-08-12 22:05:40 +00:00
|
|
|
PodObject* val = obj->data[i].get();
|
|
|
|
nobj->data[i] = TRY(gc_pod(val));
|
|
|
|
}
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-09-07 16:37:12 +00:00
|
|
|
Result<PodObject*> Arena::gc_error(PodError* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodError>());
|
|
|
|
nobj->header.tag = Tag::Error;
|
|
|
|
|
|
|
|
nobj->name = TRY(gc_pod(obj->name.get()));
|
|
|
|
nobj->message = TRY(gc_pod(obj->message.get()));
|
|
|
|
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-09-23 20:23:25 +00:00
|
|
|
Result<PodObject*> Arena::gc_continuation(PodContinuation* obj) {
|
|
|
|
auto nobj = TRY(alloc<PodContinuation>());
|
|
|
|
nobj->header.tag = Tag::Error;
|
|
|
|
|
|
|
|
nobj->props = TRY(gc_pod(obj->props.get()));
|
|
|
|
nobj->frame = TRY(gc_pod(obj->frame.get()));
|
|
|
|
|
|
|
|
return nobj;
|
|
|
|
}
|
|
|
|
|
2024-08-09 22:45:06 +00:00
|
|
|
Arena& get_arena() {
|
|
|
|
if (current_arena == 0) die("Arena not set\n");
|
|
|
|
return *current_arena;
|
|
|
|
}
|
|
|
|
void set_arena(Arena& arena) { current_arena = &arena; }
|
|
|
|
|
|
|
|
Result<void> arena_gc() { return get_arena().gc(); }
|