Skip to content

Commit

Permalink
Implement suballocators for GC
Browse files Browse the repository at this point in the history
  • Loading branch information
john-z-yang committed Dec 8, 2023
1 parent d89460f commit 4bf613f
Show file tree
Hide file tree
Showing 12 changed files with 197 additions and 128 deletions.
2 changes: 1 addition & 1 deletion src/compile/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ Compiler::Compiler(
VM &vm
)
: vm(vm),
gcGuard(vm.heap.pauseGC()),
enclosing(enclosing),
source(source),
srcMap(sourceLoc),
Expand Down Expand Up @@ -619,6 +618,7 @@ void Compiler::handleTypeError(

Compiler::Compiler(std::vector<std::string> source, VM &vm)
: vm(vm),
gcGuard(vm.heap.pauseGC()),
source(source),
curSrcLoc({1, 0}),
param(vm.heap.alloc<Nil>()),
Expand Down
5 changes: 4 additions & 1 deletion src/runtime/Env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,7 @@ bool Env::isNatFn(const sexpr::Sym *sym) {
return natFns.find(sym) != natFns.end();
}

const SymTable &Env::getSymTable() const { return symTable; }
const std::unordered_map<const sexpr::Sym *, const sexpr::SExpr *> &
Env::getSymTable() const {
return symTable;
}
18 changes: 5 additions & 13 deletions src/runtime/Env.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "../sexpr/NatFn.hpp"
#include "../sexpr/SExpr.hpp"
#include "../sexpr/Sym.hpp"
#include "Symtable.hpp"
#include <functional>
#include <initializer_list>
#include <memory>
Expand All @@ -15,17 +14,9 @@ namespace runtime {

class Env {
private:
SymTable symTable;
std::unordered_set<
const sexpr::Sym *,
sexpr::Sym::HashFunction,
sexpr::Sym::EqualFunction>
macros;
std::unordered_set<
const sexpr::Sym *,
sexpr::Sym::HashFunction,
sexpr::Sym::EqualFunction>
natFns;
std::unordered_map<const sexpr::Sym *, const sexpr::SExpr *> symTable;
std::unordered_set<const sexpr::Sym *> macros;
std::unordered_set<const sexpr::Sym *> natFns;

void regMacro(const sexpr::Sym *sym);
void regNative(const sexpr::Sym *sym);
Expand All @@ -45,7 +36,8 @@ class Env {
bool isMacro(const sexpr::Sym *sym);
bool isNatFn(const sexpr::Sym *sym);

const SymTable &getSymTable() const;
const std::unordered_map<const sexpr::Sym *, const sexpr::SExpr *> &
getSymTable() const;
};

} // namespace runtime
Expand Down
55 changes: 28 additions & 27 deletions src/runtime/Heap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void Heap::gc() {
return;
}
#ifndef GC_STRESS_TEST
if (heap.size() < gcHeapSize) {
if (getBytesAlloced() < maxHeapSize) {
return;
}
#endif
Expand All @@ -28,11 +28,26 @@ void Heap::gc() {
trace(sexpr);
}

std::erase_if(heap, [&](const auto &unique) {
return !black.contains(unique.get());
});
std::apply([&](auto &&...args) { (args.free(black), ...); }, allocators);

gcHeapSize = heap.size() * FREESTORE_HEAP_GROWTH_FACTOR;
maxHeapSize = getBytesAlloced() * HEAP_GROWTH_FACTOR;
}

void Heap::markRoots() {
if (vm.getClosure().has_value()) {
grey.push_back(vm.getClosure().value());
}

for (const auto &[sym, sExpr] : vm.getSymTable()) {
grey.push_back(sym);
grey.push_back(sExpr);
}
for (const auto &sExpr : vm.getStack()) {
grey.push_back(sExpr);
}
for (const auto &sExpr : vm.getCallFrames()) {
grey.push_back(sExpr.closure);
}
}

void Heap::mark(const SExpr *sexpr) {
Expand Down Expand Up @@ -66,30 +81,16 @@ void Heap::trace(const SExpr *sExpr) {
return;
}
}
void Heap::markRoots() {
if (vm.getClosure().has_value()) {
grey.push_back(vm.getClosure().value());
}

for (const auto &[sym, sExpr] : vm.getSymTable()) {
grey.push_back(sym);
grey.push_back(sExpr);
}
for (const auto &sExpr : vm.getStack()) {
grey.push_back(sExpr);
}
for (const auto &sExpr : vm.getCallFrames()) {
grey.push_back(sExpr.closure);
}
}
Heap::Heap(VM &vm) : vm(vm), enableGC(true), maxHeapSize(INIT_HEAP_SIZE) {}

Heap::Heap(VM &vm) : vm(vm) {
for (Num::ValueType i{FREESTORE_INT_CACHE_MIN}; i <= FREESTORE_INT_CACHE_MAX;
i++) {
numCache.push_back(std::make_unique<Num>(i));
}
std::size_t Heap::getBytesAlloced() {
std::size_t bytesAlloced = 0;
std::apply(
[&](auto &&...args) { ((bytesAlloced += args.getBytesAlloced()), ...); },
allocators
);
return bytesAlloced;
}

GCGuard Heap::startGC() { return GCGuard(*this); }

GCGuard Heap::pauseGC() { return GCGuard(*this); }
50 changes: 21 additions & 29 deletions src/runtime/Heap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@
#define LISP_SRC_RUNTIME_FREESTORE_HPP_

#include "../sexpr/Bool.hpp"
#include "../sexpr/Closure.hpp"
#include "../sexpr/NatFn.hpp"
#include "../sexpr/Nil.hpp"
#include "../sexpr/Num.hpp"
#include "../sexpr/SExpr.hpp"
#include "../sexpr/SExprs.hpp"
#include "../sexpr/String.hpp"
#include "../sexpr/Undefined.hpp"
#include <cmath>
#include "Suballocator.hpp"
#include <deque>
#include <unordered_set>

#define FREESTORE_HEAP_GROWTH_FACTOR 2
#define FREESTORE_INIT_HEAP_SIZE 512
#define FREESTORE_INT_CACHE_MAX 256.0
#define FREESTORE_INT_CACHE_MIN -16.0

namespace runtime {

class VM;
Expand All @@ -26,11 +25,17 @@ class Heap {
private:
VM &vm;

std::tuple<
Suballocator<sexpr::Closure>,
Suballocator<sexpr::NatFn>,
Suballocator<sexpr::Num>,
Suballocator<sexpr::Prototype>,
Suballocator<sexpr::SExprs>,
Suballocator<sexpr::String>,
Suballocator<sexpr::Sym>>
allocators;
bool enableGC;
size_t gcHeapSize;

std::vector<std::unique_ptr<const sexpr::SExpr>> heap;
std::vector<std::unique_ptr<const sexpr::Num>> numCache;
size_t maxHeapSize;

std::unordered_set<const sexpr::SExpr *> black;
std::deque<const sexpr::SExpr *> grey;
Expand All @@ -41,17 +46,18 @@ class Heap {
void trace(const sexpr::SExpr *sexpr);

public:
static constexpr std::size_t INIT_HEAP_SIZE = 1;
static constexpr std::size_t HEAP_GROWTH_FACTOR = 2;

Heap(VM &vm);

GCGuard startGC();
std::size_t getBytesAlloced();
GCGuard pauseGC();

template <typename T, typename... Args> const T *alloc(Args &&...args) {
gc();
auto unique = std::make_unique<const T>(std::forward<Args>(args)...);
const auto &ref = *unique.get();
heap.emplace_back(std::move(unique));
return &ref;
return std::get<Suballocator<T>>(allocators)
.alloc(std::forward<Args>(args)...);
}
};
template <> inline const sexpr::Undefined *Heap::alloc() {
Expand All @@ -64,20 +70,6 @@ template <>
inline const sexpr::Bool *Heap::alloc(sexpr::Bool::ValueType &&val) {
return sexpr::Bool::getInstance(val);
}
template <> inline const sexpr::Num *Heap::alloc(sexpr::Num::ValueType &val) {
if (val >= FREESTORE_INT_CACHE_MIN && val <= FREESTORE_INT_CACHE_MAX &&
floor(val) == val) {
return numCache.at(val - FREESTORE_INT_CACHE_MIN).get();
}
gc();
auto unique = std::make_unique<const sexpr::Num>(val);
const auto &ref = *unique;
heap.emplace_back(std::move(unique));
return &ref;
}
template <> inline const sexpr::Num *Heap::alloc(double &&val) {
return alloc<sexpr::Num>(val);
}

} // namespace runtime

Expand Down
128 changes: 128 additions & 0 deletions src/runtime/Suballocator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#ifndef LISP_SRC_RUNTIME_ALLOCATOR_HPP_
#define LISP_SRC_RUNTIME_ALLOCATOR_HPP_

#include "../sexpr/NatFn.hpp"
#include "../sexpr/Num.hpp"
#include "../sexpr/SExpr.hpp"
#include "../sexpr/Sym.hpp"
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <list>
#include <math.h>
#include <memory>
#include <numeric>
#include <ostream>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

namespace runtime {

template <class T> class Suballocator {
private:
std::list<std::unique_ptr<const T>> handles;

public:
std::size_t getBytesAlloced() { return sizeof(T) * handles.size(); }

template <typename... Args> const T *alloc(Args &&...args) {
return handles
.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
.get();
}

void free(const std::unordered_set<const sexpr::SExpr *> &reachable) {
std::erase_if(handles, [&](const auto &handle) {
return !reachable.contains(handle.get());
});
}
};

template <> class Suballocator<sexpr::Sym> {
private:
std::list<std::unique_ptr<const sexpr::Sym>> handles;
std::unordered_map<sexpr::Sym::ValueType, const sexpr::Sym *> memo;

public:
std::size_t getBytesAlloced() { return memo.size() * sizeof(sexpr::Sym); }

const sexpr::Sym *alloc(const sexpr::Sym::ValueType v) {
if (memo.contains(v)) {
return memo.at(v);
}

memo.insert(std::make_pair(
v, handles.emplace_back(std::make_unique<sexpr::Sym>(v)).get()
));
return memo.at(v);
}

void free(const std::unordered_set<const sexpr::SExpr *> &reachable) {
std::erase_if(memo, [&](const auto &it) {
return !reachable.contains(it.second);
});
std::erase_if(handles, [&](const auto &handle) {
return !reachable.contains(handle.get());
});
}
};

template <> class Suballocator<sexpr::Num> {
private:
std::list<std::unique_ptr<const sexpr::Num>> handles;
std::vector<std::unique_ptr<const sexpr::Num>> cache;

public:
static constexpr sexpr::Num::ValueType CACHE_MIN_VAL = -512.0;
static constexpr sexpr::Num::ValueType CACHE_MAX_VAL = 512.0;

Suballocator() {
cache.reserve(CACHE_MAX_VAL - CACHE_MIN_VAL + 1);
for (auto i{CACHE_MIN_VAL}; i <= CACHE_MAX_VAL; ++i) {
cache.emplace_back(std::make_unique<sexpr::Num>(i));
}
}

std::size_t getBytesAlloced() {
return sizeof(sexpr::Num) * (handles.size() + cache.size());
}

const sexpr::Num *alloc(const sexpr::Num::ValueType v) {
if (v >= CACHE_MIN_VAL && v <= CACHE_MAX_VAL && floor(v) == v) {
return cache[v - CACHE_MIN_VAL].get();
}

return handles.emplace_back(std::make_unique<sexpr::Num>(v)).get();
}

void free(const std::unordered_set<const sexpr::SExpr *> &reachable) {
std::erase_if(handles, [&](const auto &handle) {
return !reachable.contains(handle.get());
});
}
};

template <> class Suballocator<sexpr::NatFn> {
private:
std::list<std::unique_ptr<const sexpr::NatFn>> handles;

public:
std::size_t getBytesAlloced() {
return sizeof(sexpr::NatFn) * handles.size();
}

template <typename... Args> const sexpr::NatFn *alloc(Args &&...args) {
return handles
.emplace_back(std::make_unique<sexpr::NatFn>(std::forward<Args>(args)...
))
.get();
}

void free(const std::unordered_set<const sexpr::SExpr *> &) {}
};

} // namespace runtime

#endif
16 changes: 0 additions & 16 deletions src/runtime/Symset.hpp

This file was deleted.

17 changes: 0 additions & 17 deletions src/runtime/Symtable.hpp

This file was deleted.

Loading

0 comments on commit 4bf613f

Please sign in to comment.