valeri/src/arena.hpp

197 lines
4.1 KiB
C++
Raw Normal View History

#pragma once
2024-07-29 19:34:00 +00:00
#include <sanitizer/asan_interface.h>
#include <concepts>
2024-07-29 19:34:00 +00:00
#include <cstring>
2024-07-27 00:01:38 +00:00
#include <iostream>
#include "error.hpp"
#include "pod.hpp"
#include "result.hpp"
class Arena;
class GcRootList;
class GcRootBase {
public:
2024-07-20 21:56:45 +00:00
GcRootBase() : _ptr(0), _node(0){};
GcRootBase(PodObject* ptr, GcRootList* node);
~GcRootBase();
2024-07-27 15:25:44 +00:00
PodObject* get() { return _ptr; }
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);
2024-07-27 22:13:59 +00:00
GcRoot& operator=(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-27 15:25:44 +00:00
T* get() { return (T*)_ptr; }
T& operator*() { return *(T*)_ptr; }
2024-07-26 18:32:27 +00:00
T* operator->() { return (T*)_ptr; }
};
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) {
node->_next = _next;
node->_prev = this;
if (_next) _next->_prev = node;
_next = node;
}
void remove() {
2024-07-20 21:56:45 +00:00
if (_prev) _prev->_next = _next;
if (_next) _next->_prev = _prev;
2024-07-27 00:01:38 +00:00
_prev = 0;
_next = 0;
}
2024-07-26 18:32:27 +00:00
GcRootList* next() { return _next; }
void update(GcRootBase* root) { _root = root; }
private:
GcRootList* _prev;
GcRootList* _next;
GcRootBase* _root;
};
class ArenaHeap {
public:
ArenaHeap(uint8_t* buf, uint64_t bufsize)
2024-07-29 19:34:00 +00:00
: buf(buf), bufsize(bufsize), boundary(0) {
memset(buf, 0, bufsize);
ASAN_POISON_MEMORY_REGION(buf, bufsize);
}
Result<void*> alloc(uint64_t size) {
// Always align to 64 bits
if (size % 8 != 0) size += 8 - size % 8;
2024-07-29 19:34:00 +00:00
// padding for guard value
uint64_t boundary_size = 8;
if (boundary + size + boundary_size >= bufsize)
return ErrorCode::OutOfMemory;
void* res = buf + boundary;
boundary += size;
2024-07-29 19:34:00 +00:00
ASAN_UNPOISON_MEMORY_REGION(res, size);
boundary += boundary_size;
return res;
}
private:
uint8_t* buf;
uint64_t bufsize;
uint64_t boundary;
};
class Arena {
public:
Arena(ArenaHeap* first, ArenaHeap* second)
: _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-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;
};
private:
ArenaHeap* _heaps[2];
GcRootList _gcroot;
int _current;
};
template <uint64_t size>
2024-07-20 21:56:45 +00:00
class StaticArenaHeap : public ArenaHeap {
public:
2024-07-20 21:56:45 +00:00
StaticArenaHeap() : ArenaHeap(_buf, heapsize) {}
private:
static const uint64_t heapsize = size - sizeof(ArenaHeap);
2024-07-29 19:34:00 +00:00
uint8_t _buf[heapsize];
};
template <uint64_t size>
2024-07-20 21:56:45 +00:00
class StaticArena : public Arena {
public:
2024-07-20 21:56:45 +00:00
StaticArena() : Arena(&_heaps[0], &_heaps[1]) {}
private:
StaticArenaHeap<(size - sizeof(Arena)) / 2> _heaps[2];
};
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));
}
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-27 22:13:59 +00:00
rhs._ptr = 0;
2024-07-27 00:01:38 +00:00
rhs._node = 0;
}
2024-07-27 22:13:59 +00:00
template <class T>
requires std::derived_from<T, PodObject>
GcRoot<T>& GcRoot<T>::operator=(GcRoot<T>&& rhs) {
if (_node != 0) _node->remove();
rhs._node->update(this);
_ptr = rhs._ptr;
_node = rhs._node;
rhs._ptr = 0;
rhs._node = 0;
return *this;
}