Initial implementation of arena with gc roots
This commit is contained in:
parent
8ff01726cc
commit
baa10bb56b
7 changed files with 193 additions and 9 deletions
|
@ -13,13 +13,18 @@ target_sources(vm_lib
|
|||
PRIVATE
|
||||
src/vm.cpp
|
||||
src/common.cpp
|
||||
src/arena.cpp
|
||||
|
||||
PUBLIC
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS src
|
||||
FILES
|
||||
src/vm.hpp
|
||||
src/arena.hpp
|
||||
src/common.hpp
|
||||
src/error.hpp
|
||||
src/pod.hpp
|
||||
src/result.hpp
|
||||
src/vm.hpp
|
||||
)
|
||||
|
||||
add_executable(vli src/vli.cpp)
|
||||
|
|
8
src/arena.cpp
Normal file
8
src/arena.cpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include "arena.hpp"
|
||||
|
||||
GcRootBase::GcRootBase(PodObject* ptr, GcRootList* node)
|
||||
: _ptr(ptr), _node(node) {}
|
||||
|
||||
GcRootBase::~GcRootBase() {
|
||||
if (_node != 0) _node->remove();
|
||||
}
|
111
src/arena.hpp
111
src/arena.hpp
|
@ -2,13 +2,86 @@
|
|||
|
||||
#include <concepts>
|
||||
|
||||
#include "error.hpp"
|
||||
#include "pod.hpp"
|
||||
#include "result.hpp"
|
||||
|
||||
class Arena;
|
||||
class GcRootList;
|
||||
|
||||
class GcRootBase {
|
||||
public:
|
||||
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);
|
||||
|
||||
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) {
|
||||
GcRootList* next = _next;
|
||||
|
||||
_next = node;
|
||||
node->_next = next;
|
||||
node->_prev = this;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
_prev = 0;
|
||||
_next = 0;
|
||||
_prev->_next = _next;
|
||||
_next->_prev = _prev;
|
||||
}
|
||||
|
||||
void update(GcRootBase* root) { _root = root; }
|
||||
|
||||
private:
|
||||
GcRootList* _prev;
|
||||
GcRootList* _next;
|
||||
GcRootBase* _root;
|
||||
};
|
||||
|
||||
class ArenaHeap {
|
||||
public:
|
||||
ArenaHeap(uint8_t* buf, uint64_t bufsize)
|
||||
: buf(buf), bufsize(bufsize), boundary(0) {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* buf;
|
||||
uint64_t bufsize;
|
||||
|
@ -18,10 +91,25 @@ class ArenaHeap {
|
|||
class Arena {
|
||||
public:
|
||||
Arena(ArenaHeap* first, ArenaHeap* second)
|
||||
: _heaps{first, second}, _current(0) {}
|
||||
: _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); }
|
||||
|
||||
private:
|
||||
ArenaHeap* _heaps[2];
|
||||
GcRootList _gcroot;
|
||||
int _current;
|
||||
};
|
||||
|
||||
|
@ -32,13 +120,6 @@ class StaticArenaHeap {
|
|||
|
||||
ArenaHeap* get() { return &_heap; }
|
||||
|
||||
template <class T>
|
||||
T* alloc(uint64_t extra = 0)
|
||||
requires std::derived_from<T, PodObject>
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static const uint64_t heapsize = size - sizeof(ArenaHeap);
|
||||
ArenaHeap _heap;
|
||||
|
@ -54,3 +135,17 @@ class StaticArena {
|
|||
StaticArenaHeap<(size - sizeof(Arena)) / 2> _heaps[2];
|
||||
Arena _arena;
|
||||
};
|
||||
|
||||
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);
|
||||
return GcRoot<T>(ptr, lst);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires std::derived_from<T, PodObject>
|
||||
GcRoot<T>::GcRoot(GcRoot<T>&& rhs) {
|
||||
rhs._node->update(this);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "arena.hpp"
|
||||
|
@ -82,18 +83,36 @@ class Nil : public Object {
|
|||
|
||||
class String : public Object {
|
||||
public:
|
||||
String() : _value(0) {}
|
||||
String(PodString* val) : _value(val) {}
|
||||
virtual Tag tag() final { return Tag::String; }
|
||||
|
||||
static Result<String> create(Arena& arena, char32_t* chars, int64_t size) {
|
||||
auto pod_string = TRY(arena.alloc<PodString>(size * sizeof(char32_t)));
|
||||
|
||||
memcpy(pod_string->data, chars, size * sizeof(char32_t));
|
||||
|
||||
return String(pod_string);
|
||||
}
|
||||
|
||||
private:
|
||||
PodString* _value;
|
||||
};
|
||||
|
||||
class Symbol : public Object {
|
||||
public:
|
||||
Symbol() : _value(0) {}
|
||||
Symbol(PodSymbol* val) : _value(val) {}
|
||||
virtual Tag tag() final { return Tag::Symbol; }
|
||||
|
||||
static Result<Symbol> create(Arena& arena, char32_t* chars, int64_t size) {
|
||||
auto pod_symbol = TRY(arena.alloc<PodSymbol>(size * sizeof(char32_t)));
|
||||
|
||||
memcpy(pod_symbol->data, chars, size * sizeof(char32_t));
|
||||
|
||||
return Symbol(pod_symbol);
|
||||
}
|
||||
|
||||
private:
|
||||
PodSymbol* _value;
|
||||
};
|
||||
|
|
8
src/die.hpp
Normal file
8
src/die.hpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#include <cstdio>
|
||||
|
||||
#define die(message) \
|
||||
do { \
|
||||
fprintf(stderr, "ERROR: %s", message); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} while (0)
|
7
src/error.hpp
Normal file
7
src/error.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
enum class ErrorCode {
|
||||
Success,
|
||||
OutOfMemory
|
||||
|
||||
};
|
42
src/result.hpp
Normal file
42
src/result.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "error.hpp"
|
||||
|
||||
template <class T>
|
||||
class Result {
|
||||
public:
|
||||
Result(const T& res) : _value(res) {}
|
||||
Result(T&& res) : _value(std::move(res)) {}
|
||||
Result(ErrorCode err) : _error(err) {}
|
||||
|
||||
bool has_error() { return _error != ErrorCode::Success; }
|
||||
bool has_value() { return !has_error(); }
|
||||
|
||||
T& value() { return _value; }
|
||||
T& operator*() { return _value; }
|
||||
T release_value() { return std::move(_value); }
|
||||
ErrorCode error() { return _error; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
ErrorCode _error;
|
||||
};
|
||||
|
||||
#define TRY(m) \
|
||||
(({ \
|
||||
auto ___res = (m); \
|
||||
if (!___res.has_value()) return ___res.error(); \
|
||||
std::move(___res); \
|
||||
}).release_value())
|
||||
|
||||
#define DIEIF(m) \
|
||||
(({ \
|
||||
auto ___res = (m); \
|
||||
if (!___res.has_value()) { \
|
||||
fprintf(stderr, "%s:%d assertion failed\n", __FILE__, __LINE__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
std::move(___res); \
|
||||
}).release_value())
|
Loading…
Reference in a new issue