2024-07-19 01:29:30 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <concepts>
|
|
|
|
|
2024-07-20 21:42:49 +00:00
|
|
|
#include "error.hpp"
|
2024-07-19 01:29:30 +00:00
|
|
|
#include "pod.hpp"
|
2024-07-20 21:42:49 +00:00
|
|
|
#include "result.hpp"
|
|
|
|
|
|
|
|
class Arena;
|
|
|
|
class GcRootList;
|
|
|
|
|
|
|
|
class GcRootBase {
|
|
|
|
public:
|
2024-07-20 21:56:45 +00:00
|
|
|
GcRootBase() : _ptr(0), _node(0){};
|
2024-07-20 21:42:49 +00:00
|
|
|
GcRootBase(PodObject* ptr, GcRootList* node);
|
|
|
|
|
|
|
|
~GcRootBase();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
PodObject* _ptr;
|
|
|
|
GcRootList* _node;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
requires std::derived_from<T, PodObject>
|
|
|
|
class GcRoot : public GcRootBase {
|
|
|
|
public:
|
|
|
|
GcRoot() : GcRootBase(0, 0) {}
|
|
|
|
GcRoot(T* ptr, GcRootList* node) : GcRootBase(ptr, node) {}
|
|
|
|
GcRoot(GcRoot&& rhs);
|
|
|
|
|
|
|
|
static Result<GcRoot<T>> create(T* ptr, Arena& arena);
|
2024-07-26 18:32:27 +00:00
|
|
|
Result<GcRoot<T>> copy(Arena& arena) {
|
|
|
|
return GcRoot<T>::create((T*)_ptr, arena);
|
|
|
|
}
|
2024-07-20 21:42:49 +00:00
|
|
|
|
|
|
|
T& operator*() { return *(T*)_ptr; }
|
2024-07-26 18:32:27 +00:00
|
|
|
T* operator->() { return (T*)_ptr; }
|
2024-07-20 21:42:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
requires std::derived_from<T, PodObject>
|
|
|
|
Result<GcRoot<T>> MkGcRoot(T* ptr, Arena& arena) {
|
|
|
|
return GcRoot<T>::create(ptr, arena);
|
|
|
|
}
|
|
|
|
|
|
|
|
class GcRootList {
|
|
|
|
public:
|
|
|
|
GcRootList() : _prev(0), _next(0), _root(0) {}
|
|
|
|
|
|
|
|
GcRootList(GcRootBase* root) : _prev(0), _next(0), _root(root) {}
|
|
|
|
void insert(GcRootList* node) {
|
|
|
|
GcRootList* next = _next;
|
|
|
|
|
|
|
|
_next = node;
|
|
|
|
node->_next = next;
|
|
|
|
node->_prev = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove() {
|
|
|
|
_prev = 0;
|
|
|
|
_next = 0;
|
2024-07-20 21:56:45 +00:00
|
|
|
if (_prev) _prev->_next = _next;
|
|
|
|
if (_next) _next->_prev = _prev;
|
2024-07-20 21:42:49 +00:00
|
|
|
}
|
|
|
|
|
2024-07-26 18:32:27 +00:00
|
|
|
GcRootList* next() { return _next; }
|
|
|
|
|
2024-07-20 21:42:49 +00:00
|
|
|
void update(GcRootBase* root) { _root = root; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
GcRootList* _prev;
|
|
|
|
GcRootList* _next;
|
|
|
|
GcRootBase* _root;
|
|
|
|
};
|
2024-07-19 01:29:30 +00:00
|
|
|
|
|
|
|
class ArenaHeap {
|
|
|
|
public:
|
|
|
|
ArenaHeap(uint8_t* buf, uint64_t bufsize)
|
|
|
|
: buf(buf), bufsize(bufsize), boundary(0) {}
|
|
|
|
|
2024-07-20 21:42:49 +00:00
|
|
|
Result<void*> alloc(uint64_t size) {
|
|
|
|
// Always align to 64 bits
|
|
|
|
if (size % 8 != 0) size += 8 - size % 8;
|
|
|
|
|
|
|
|
if (boundary + size >= bufsize) return ErrorCode::OutOfMemory;
|
|
|
|
void* res = buf + boundary;
|
|
|
|
boundary += size;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2024-07-19 01:29:30 +00:00
|
|
|
private:
|
|
|
|
uint8_t* buf;
|
|
|
|
uint64_t bufsize;
|
|
|
|
uint64_t boundary;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Arena {
|
|
|
|
public:
|
|
|
|
Arena(ArenaHeap* first, ArenaHeap* second)
|
2024-07-20 21:42:49 +00:00
|
|
|
: _heaps{first, second}, _gcroot(), _current(0) {}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
Result<T*> alloc(uint64_t extra = 0) {
|
|
|
|
uint64_t objsize = sizeof(T) + extra;
|
|
|
|
auto ptr = _heaps[_current]->alloc(objsize);
|
|
|
|
|
|
|
|
if (ptr.has_value()) return (T*)ptr.value();
|
|
|
|
|
|
|
|
// TODO: trigger GC
|
|
|
|
|
|
|
|
return (T*)TRY(_heaps[_current]->alloc(objsize));
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_root(GcRootList* node) { _gcroot.insert(node); }
|
2024-07-19 01:29:30 +00:00
|
|
|
|
2024-07-26 18:32:27 +00:00
|
|
|
uint64_t root_count() {
|
|
|
|
uint64_t res = 0;
|
|
|
|
for (GcRootList* cur = &_gcroot; cur->next() != 0; cur = cur->next()) {
|
|
|
|
++res;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
};
|
|
|
|
|
2024-07-19 01:29:30 +00:00
|
|
|
private:
|
|
|
|
ArenaHeap* _heaps[2];
|
2024-07-20 21:42:49 +00:00
|
|
|
GcRootList _gcroot;
|
2024-07-19 01:29:30 +00:00
|
|
|
int _current;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <uint64_t size>
|
2024-07-20 21:56:45 +00:00
|
|
|
class StaticArenaHeap : public ArenaHeap {
|
2024-07-19 01:29:30 +00:00
|
|
|
public:
|
2024-07-20 21:56:45 +00:00
|
|
|
StaticArenaHeap() : ArenaHeap(_buf, heapsize) {}
|
2024-07-19 01:29:30 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
static const uint64_t heapsize = size - sizeof(ArenaHeap);
|
|
|
|
uint8_t _buf[heapsize]{0};
|
|
|
|
};
|
|
|
|
|
|
|
|
template <uint64_t size>
|
2024-07-20 21:56:45 +00:00
|
|
|
class StaticArena : public Arena {
|
2024-07-19 01:29:30 +00:00
|
|
|
public:
|
2024-07-20 21:56:45 +00:00
|
|
|
StaticArena() : Arena(&_heaps[0], &_heaps[1]) {}
|
2024-07-19 01:29:30 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
StaticArenaHeap<(size - sizeof(Arena)) / 2> _heaps[2];
|
|
|
|
};
|
2024-07-20 21:42:49 +00:00
|
|
|
|
|
|
|
template <class T>
|
|
|
|
requires std::derived_from<T, PodObject>
|
|
|
|
Result<GcRoot<T>> GcRoot<T>::create(T* ptr, Arena& arena) {
|
|
|
|
auto lst = TRY(arena.alloc<GcRootList>());
|
|
|
|
arena.add_root(lst);
|
2024-07-20 21:56:45 +00:00
|
|
|
return std::move(GcRoot<T>(ptr, lst));
|
2024-07-20 21:42:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
requires std::derived_from<T, PodObject>
|
|
|
|
GcRoot<T>::GcRoot(GcRoot<T>&& rhs) {
|
|
|
|
rhs._node->update(this);
|
2024-07-20 21:56:45 +00:00
|
|
|
_ptr = rhs._ptr;
|
|
|
|
_node = rhs._node;
|
2024-07-20 21:42:49 +00:00
|
|
|
}
|