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
|
PRIVATE
|
||||||
src/vm.cpp
|
src/vm.cpp
|
||||||
src/common.cpp
|
src/common.cpp
|
||||||
|
src/arena.cpp
|
||||||
|
|
||||||
PUBLIC
|
PUBLIC
|
||||||
FILE_SET HEADERS
|
FILE_SET HEADERS
|
||||||
BASE_DIRS src
|
BASE_DIRS src
|
||||||
FILES
|
FILES
|
||||||
src/vm.hpp
|
src/arena.hpp
|
||||||
src/common.hpp
|
src/common.hpp
|
||||||
|
src/error.hpp
|
||||||
|
src/pod.hpp
|
||||||
|
src/result.hpp
|
||||||
|
src/vm.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(vli src/vli.cpp)
|
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 <concepts>
|
||||||
|
|
||||||
|
#include "error.hpp"
|
||||||
#include "pod.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 {
|
class ArenaHeap {
|
||||||
public:
|
public:
|
||||||
ArenaHeap(uint8_t* buf, uint64_t bufsize)
|
ArenaHeap(uint8_t* buf, uint64_t bufsize)
|
||||||
: buf(buf), bufsize(bufsize), boundary(0) {}
|
: 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:
|
private:
|
||||||
uint8_t* buf;
|
uint8_t* buf;
|
||||||
uint64_t bufsize;
|
uint64_t bufsize;
|
||||||
|
@ -18,10 +91,25 @@ class ArenaHeap {
|
||||||
class Arena {
|
class Arena {
|
||||||
public:
|
public:
|
||||||
Arena(ArenaHeap* first, ArenaHeap* second)
|
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:
|
private:
|
||||||
ArenaHeap* _heaps[2];
|
ArenaHeap* _heaps[2];
|
||||||
|
GcRootList _gcroot;
|
||||||
int _current;
|
int _current;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,13 +120,6 @@ class StaticArenaHeap {
|
||||||
|
|
||||||
ArenaHeap* get() { return &_heap; }
|
ArenaHeap* get() { return &_heap; }
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T* alloc(uint64_t extra = 0)
|
|
||||||
requires std::derived_from<T, PodObject>
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const uint64_t heapsize = size - sizeof(ArenaHeap);
|
static const uint64_t heapsize = size - sizeof(ArenaHeap);
|
||||||
ArenaHeap _heap;
|
ArenaHeap _heap;
|
||||||
|
@ -54,3 +135,17 @@ class StaticArena {
|
||||||
StaticArenaHeap<(size - sizeof(Arena)) / 2> _heaps[2];
|
StaticArenaHeap<(size - sizeof(Arena)) / 2> _heaps[2];
|
||||||
Arena _arena;
|
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 <concepts>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "arena.hpp"
|
#include "arena.hpp"
|
||||||
|
@ -82,18 +83,36 @@ class Nil : public Object {
|
||||||
|
|
||||||
class String : public Object {
|
class String : public Object {
|
||||||
public:
|
public:
|
||||||
|
String() : _value(0) {}
|
||||||
String(PodString* val) : _value(val) {}
|
String(PodString* val) : _value(val) {}
|
||||||
virtual Tag tag() final { return Tag::String; }
|
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:
|
private:
|
||||||
PodString* _value;
|
PodString* _value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Symbol : public Object {
|
class Symbol : public Object {
|
||||||
public:
|
public:
|
||||||
|
Symbol() : _value(0) {}
|
||||||
Symbol(PodSymbol* val) : _value(val) {}
|
Symbol(PodSymbol* val) : _value(val) {}
|
||||||
virtual Tag tag() final { return Tag::Symbol; }
|
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:
|
private:
|
||||||
PodSymbol* _value;
|
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