mirror of
https://github.com/usatiuk/psil.git
synced 2025-10-28 18:57:48 +01:00
compiler!
This commit is contained in:
@@ -2,6 +2,6 @@ set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_library(vm src/VM.cpp src/Cell.cpp
|
||||
src/Parser.cpp src/MemoryContext.cpp src/Handle.cpp)
|
||||
src/Parser.cpp src/MemoryContext.cpp src/Handle.cpp src/Compiler.cpp)
|
||||
|
||||
target_include_directories(vm PUBLIC includes)
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
enum class CellType {
|
||||
NUMATOM,
|
||||
STRATOM,
|
||||
@@ -23,7 +24,9 @@ struct Cell {
|
||||
virtual ~Cell() = 0;
|
||||
|
||||
CellType _type;
|
||||
std::atomic<bool> live = false;
|
||||
std::atomic<bool> _live = false;
|
||||
|
||||
virtual void print(std::ostream &out) = 0;
|
||||
};
|
||||
|
||||
struct NumAtomCell : public Cell {
|
||||
@@ -31,6 +34,10 @@ struct NumAtomCell : public Cell {
|
||||
explicit NumAtomCell(CellValType val) : Cell(CellType::NUMATOM), _val(val) {}
|
||||
|
||||
CellValType _val;
|
||||
|
||||
void print(std::ostream &out) override {
|
||||
out << _val;
|
||||
}
|
||||
};
|
||||
|
||||
struct StrAtomCell : public Cell {
|
||||
@@ -38,6 +45,10 @@ struct StrAtomCell : public Cell {
|
||||
explicit StrAtomCell(std::string val) : Cell(CellType::STRATOM), _val(std::move(val)) {}
|
||||
|
||||
std::string _val;
|
||||
|
||||
void print(std::ostream &out) override {
|
||||
out << _val;
|
||||
}
|
||||
};
|
||||
|
||||
struct ConsCell : public Cell {
|
||||
@@ -47,6 +58,29 @@ struct ConsCell : public Cell {
|
||||
|
||||
std::atomic<Cell *> _car = nullptr;
|
||||
std::atomic<Cell *> _cdr = nullptr;
|
||||
|
||||
void print(std::ostream &out) override {
|
||||
std::stringstream res;
|
||||
if (_car) {
|
||||
if (_car.load()->_type == CellType::CONS) {
|
||||
res << "(";
|
||||
_car.load()->print(res);
|
||||
res << ")";
|
||||
} else {
|
||||
_car.load()->print(res);
|
||||
}
|
||||
}
|
||||
if (_cdr) {
|
||||
if (_cdr.load()->_type == CellType::CONS) {
|
||||
res << " ";
|
||||
_cdr.load()->print(res);
|
||||
} else {
|
||||
res << ".";
|
||||
_cdr.load()->print(res);
|
||||
}
|
||||
}
|
||||
out << res.str();
|
||||
}
|
||||
};
|
||||
|
||||
#endif//PSIL_CELL_H
|
||||
|
||||
19
src/vm/includes/Compiler.h
Normal file
19
src/vm/includes/Compiler.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 27.12.2023.
|
||||
//
|
||||
|
||||
#ifndef PSIL_COMPILER_H
|
||||
#define PSIL_COMPILER_H
|
||||
|
||||
|
||||
#include "Handle.h"
|
||||
class Compiler {
|
||||
public:
|
||||
static Handle compile(Handle src, Handle fake_env = nullptr, Handle suffix = nullptr);
|
||||
|
||||
private:
|
||||
static Handle findIndex(Handle symbol, Handle env);
|
||||
};
|
||||
|
||||
|
||||
#endif//PSIL_COMPILER_H
|
||||
@@ -13,7 +13,7 @@ class Handle {
|
||||
public:
|
||||
friend MemoryContext;
|
||||
|
||||
Handle(Cell *target);
|
||||
Handle(Cell *target = nullptr);
|
||||
Handle(int64_t val);
|
||||
Handle(std::string strval);
|
||||
~Handle();
|
||||
@@ -22,7 +22,20 @@ public:
|
||||
Handle &operator=(Handle other);
|
||||
|
||||
bool operator==(const Handle &rhs) const {
|
||||
return _target == rhs._target;
|
||||
if (_target == rhs._target) {
|
||||
return true;
|
||||
} else if ((_target != nullptr && rhs._target != nullptr) && (_target->_type == rhs._target->_type)) {
|
||||
if (_target->_type == CellType::NUMATOM) {
|
||||
return dynamic_cast<NumAtomCell &>(*_target)._val == dynamic_cast<NumAtomCell &>(*rhs._target)._val;
|
||||
} else if (_target->_type == CellType::STRATOM) {
|
||||
return dynamic_cast<StrAtomCell &>(*_target)._val == dynamic_cast<StrAtomCell &>(*rhs._target)._val;
|
||||
} else if (_target->_type == CellType::CONS) {
|
||||
// This is questionable
|
||||
return dynamic_cast<ConsCell &>(*_target)._car == dynamic_cast<ConsCell &>(*rhs._target)._car &&
|
||||
dynamic_cast<ConsCell &>(*_target)._cdr == dynamic_cast<ConsCell &>(*rhs._target)._cdr;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Handle cons(const Handle &car, const Handle &cdr);
|
||||
@@ -32,15 +45,37 @@ public:
|
||||
CellValType val() { return dynamic_cast<NumAtomCell &>(*_target)._val; }
|
||||
std::string_view strval() { return dynamic_cast<StrAtomCell &>(*_target)._val; }
|
||||
|
||||
CellType type() const {
|
||||
if (!_target) return CellType::CONS;
|
||||
return _target->_type;
|
||||
}
|
||||
|
||||
bool atom() const {
|
||||
return type() != CellType::CONS;
|
||||
}
|
||||
|
||||
bool null() {
|
||||
if (!_target) return true;
|
||||
if (type() == CellType::CONS && car() == nullptr && cdr() == nullptr) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Handle pop();
|
||||
void push(const Handle &what);
|
||||
void append(const Handle &what);
|
||||
void splice(const Handle &what);
|
||||
|
||||
static Handle makeNumCell(int64_t val);
|
||||
static Handle makeStrCell(std::string val);
|
||||
void setcar(const Handle &car);
|
||||
void setcdr(const Handle &cdr);
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &stream, const Handle &h) {
|
||||
if (h._target)
|
||||
h._target->print(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
private:
|
||||
Cell *operator->() const { return _target; }
|
||||
Cell &operator*() const { return *_target; }
|
||||
|
||||
@@ -32,50 +32,6 @@ public:
|
||||
return alloc_cell<CT>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<>
|
||||
Handle create_cell<NumAtomCell>(CellValType val) {
|
||||
std::optional<Handle> ret = run_dirty<std::optional<Handle>>([&](std::function<void(Cell *)> dirty) -> std::optional<Handle> {
|
||||
std::lock_guard il(_indexes_lock);
|
||||
if (_numatom_index.contains(val)) {
|
||||
dirty(_numatom_index.at(val));
|
||||
return _numatom_index.at(val);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
});
|
||||
|
||||
if (ret.has_value()) return *ret;
|
||||
|
||||
Handle newc = alloc_cell<NumAtomCell>(val);
|
||||
{
|
||||
std::lock_guard il(_indexes_lock);
|
||||
_numatom_index.emplace(val, newc.get());
|
||||
}
|
||||
return newc;
|
||||
}
|
||||
|
||||
template<>
|
||||
Handle create_cell<StrAtomCell>(std::string val) {
|
||||
std::optional<Handle> ret = run_dirty<std::optional<Handle>>([&](std::function<void(Cell *)> dirty) -> std::optional<Handle> {
|
||||
std::lock_guard il(_indexes_lock);
|
||||
if (_stratom_index.contains(val)) {
|
||||
dirty(_stratom_index.at(val));
|
||||
return _stratom_index.at(val);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
});
|
||||
|
||||
if (ret.has_value()) return *ret;
|
||||
|
||||
Handle newc = alloc_cell<StrAtomCell>(val);
|
||||
{
|
||||
std::lock_guard il(_indexes_lock);
|
||||
_stratom_index.emplace(val, newc.get());
|
||||
}
|
||||
return newc;
|
||||
}
|
||||
|
||||
|
||||
void request_gc_and_wait() {
|
||||
std::unique_lock l(_gc_done_m);
|
||||
@@ -100,7 +56,14 @@ public:
|
||||
template<typename R>
|
||||
R run_dirty(const std::function<R(std::function<void(Cell *)>)> &f) {
|
||||
std::lock_guard l(_gc_dirty_notif_queue_lock);
|
||||
return f([&](Cell *c) { _gc_dirty_notif_queue.emplace(c); });
|
||||
return f([&](Cell *c) {
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "marked dirty: " << c << " \n";
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
|
||||
_gc_dirty_notif_queue.emplace(c); });
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -149,10 +112,6 @@ private:
|
||||
std::atomic<size_t> _cells_num = 0;
|
||||
std::list<Cell *> _temp_cells;
|
||||
|
||||
std::mutex _indexes_lock;
|
||||
std::unordered_map<CellValType, Cell *> _numatom_index;
|
||||
std::unordered_map<std::string, Cell *> _stratom_index;
|
||||
|
||||
static constexpr size_t _cell_limit = {50000};
|
||||
|
||||
void gc_thread_entry();
|
||||
|
||||
@@ -45,6 +45,7 @@ private:
|
||||
Handle RAP = Handle::makeStrCell("RAP");
|
||||
Handle STOP = Handle::makeStrCell("STOP");
|
||||
|
||||
Handle ATOM = Handle::makeStrCell("ATOM");
|
||||
Handle ADD = Handle::makeStrCell("ADD");
|
||||
Handle SUB = Handle::makeStrCell("SUB");
|
||||
|
||||
@@ -52,6 +53,9 @@ private:
|
||||
Handle PUTCHAR = Handle::makeStrCell("PUTCHAR");
|
||||
Handle PUTNUM = Handle::makeStrCell("PUTNUM");
|
||||
|
||||
Handle EVAL = Handle::makeStrCell("EVAL");
|
||||
Handle PRINT = Handle::makeStrCell("PRINT");
|
||||
|
||||
Handle CONS = Handle::makeStrCell("CONS");
|
||||
};
|
||||
|
||||
|
||||
132
src/vm/src/Compiler.cpp
Normal file
132
src/vm/src/Compiler.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 27.12.2023.
|
||||
//
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) {
|
||||
Handle out;
|
||||
|
||||
std::function<Handle(Handle)> compileArgsRaw = [&](Handle args) {
|
||||
Handle out;
|
||||
while (args != nullptr) {
|
||||
out.splice(compile(args.car(), fake_env));
|
||||
args = args.cdr();
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
std::function<Handle(Handle, Handle)> compileArgsList = [&](Handle args, Handle env) {
|
||||
Handle out;
|
||||
out.append(Handle("NIL"));
|
||||
while (args != nullptr) {
|
||||
out.splice(compile(args.car(), env));
|
||||
out.append(Handle("CONS"));
|
||||
args = args.cdr();
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
|
||||
Handle expr = src;
|
||||
if (expr.null()) {
|
||||
out.append(Handle("NIL"));
|
||||
} else if (expr.atom()) {
|
||||
if (expr.type() == CellType::NUMATOM) {
|
||||
out.append(Handle("LDC"));
|
||||
out.append(expr);
|
||||
} else if (expr.type() == CellType::STRATOM) {
|
||||
Handle idx = findIndex(expr, fake_env);
|
||||
if (idx == nullptr) {
|
||||
out.append(Handle("LDC"));
|
||||
out.append(expr);
|
||||
} else {
|
||||
out.append(Handle("LD"));
|
||||
out.append(idx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Handle car = expr.car();
|
||||
Handle cdr = expr.cdr();
|
||||
if (car.atom()) {
|
||||
if (car.strval() == "+") {
|
||||
out.splice(compileArgsRaw(cdr));
|
||||
out.append(Handle("ADD"));
|
||||
} else if (car.strval() == "lambda") {
|
||||
out.append(Handle("LDF"));
|
||||
out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car(), fake_env), Handle("RET")));
|
||||
} else if (car.strval() == "if") {
|
||||
out.splice(compile(cdr.car(), fake_env));
|
||||
out.append(Handle("SEL"));
|
||||
out.append(compile(cdr.cdr().car(), fake_env, Handle("JOIN")));
|
||||
out.append(compile(cdr.cdr().cdr().car(), fake_env, Handle("JOIN")));
|
||||
} else if (car.strval() == "let" || car.strval() == "letrec") {
|
||||
std::vector<std::pair<Handle, Handle>> argBody;
|
||||
|
||||
Handle definitions = cdr.car();
|
||||
|
||||
Handle argNames;
|
||||
Handle argBodies;
|
||||
|
||||
Handle body = cdr.cdr().car();
|
||||
|
||||
while (definitions != nullptr) {
|
||||
argBody.emplace_back(definitions.car().car(), definitions.car().cdr().car());
|
||||
argNames.append(definitions.car().car());
|
||||
argBodies.append(definitions.car().cdr().car());
|
||||
definitions = definitions.cdr();
|
||||
}
|
||||
|
||||
Handle newenv = Handle::cons(argNames, fake_env);
|
||||
if (car.strval() == "let")
|
||||
out.splice(compileArgsList(argBodies, fake_env));
|
||||
else if (car.strval() == "letrec") {
|
||||
out.append(Handle("DUM"));
|
||||
out.splice(compileArgsList(argBodies, newenv));
|
||||
}
|
||||
|
||||
out.append(Handle("LDF"));
|
||||
out.append(compile(body, newenv, Handle("RET")));
|
||||
if (car.strval() == "let")
|
||||
out.append(Handle("AP"));
|
||||
else
|
||||
out.append(Handle("RAP"));
|
||||
} else {
|
||||
out.splice(compileArgsList(cdr, fake_env));
|
||||
|
||||
out.append(Handle("LD"));
|
||||
Handle idx = findIndex(car, fake_env);
|
||||
out.append(idx);
|
||||
out.append(Handle("AP"));
|
||||
}
|
||||
} else {
|
||||
out.splice(compileArgsList(cdr, fake_env));
|
||||
out.splice(compile(car, fake_env, Handle("AP")));
|
||||
}
|
||||
}
|
||||
out.splice(suffix);
|
||||
return out;
|
||||
}
|
||||
Handle Compiler::findIndex(Handle symbol, Handle env) {
|
||||
int64_t frame = 1;
|
||||
|
||||
Handle curFrame = env;
|
||||
|
||||
while (curFrame != nullptr) {
|
||||
int64_t arg = 1;
|
||||
Handle curArg = curFrame.car();
|
||||
|
||||
while (curArg != nullptr) {
|
||||
if (curArg.car() == symbol) return Handle::cons(frame, arg);
|
||||
curArg = curArg.cdr();
|
||||
arg++;
|
||||
}
|
||||
|
||||
curFrame = curFrame.cdr();
|
||||
frame++;
|
||||
}
|
||||
|
||||
return Handle(nullptr);
|
||||
}
|
||||
@@ -42,8 +42,8 @@ void Handle::push(const Handle &what) {
|
||||
}
|
||||
|
||||
void Handle::append(const Handle &what) {
|
||||
if (_target == nullptr) *this = cons(nullptr, nullptr);
|
||||
Handle cur = *this;
|
||||
assert(cur.get() != nullptr);
|
||||
if (cur.car().get() == nullptr) {
|
||||
cur.setcar(what);
|
||||
return;
|
||||
@@ -52,6 +52,23 @@ void Handle::append(const Handle &what) {
|
||||
cur.setcdr(cons(what, nullptr));
|
||||
}
|
||||
|
||||
void Handle::splice(const Handle &what) {
|
||||
if (_target == nullptr) {
|
||||
*this = what;
|
||||
return;
|
||||
}
|
||||
Handle cur = *this;
|
||||
if (cur.car().get() == nullptr) {
|
||||
*this = what;
|
||||
return;
|
||||
}
|
||||
while (cur.cdr().get() != nullptr)
|
||||
cur = cur.cdr();
|
||||
if (what.atom()) cur.setcdr(Handle::cons(what, nullptr));
|
||||
else
|
||||
cur.setcdr(what);
|
||||
}
|
||||
|
||||
Handle Handle::makeNumCell(int64_t val) {
|
||||
return CURRENT_MC.load()->create_cell<NumAtomCell>(val);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
std::atomic<MemoryContext *> CURRENT_MC = nullptr;
|
||||
@@ -34,14 +35,22 @@ void MemoryContext::add_root(Cell *c) {
|
||||
{
|
||||
std::lock_guard l(_new_roots_lock);
|
||||
_new_roots[c]++;
|
||||
// std::cerr << "new root: " << c << " T: " << static_cast<int>(c->_type) << " NUM: " << _new_roots[c] << "\n";
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "new root: " << c << " T: " << static_cast<int>(c->_type) << " NUM: " << _new_roots[c] << "\n";
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
}
|
||||
}
|
||||
void MemoryContext::remove_root(Cell *c) {
|
||||
{
|
||||
std::lock_guard l(_new_roots_lock);
|
||||
_new_roots[c]--;
|
||||
// std::cerr << "del root: " << c << " T: " << static_cast<int>(c->_type) << " NUM: " << _new_roots[c] << "\n";
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "del root: " << c << " T: " << static_cast<int>(c->_type) << " NUM: " << _new_roots[c] << "\n";
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
if (_new_roots[c] == 0) _new_roots.erase(c);
|
||||
}
|
||||
}
|
||||
@@ -54,7 +63,11 @@ void MemoryContext::gc_thread_entry() {
|
||||
}
|
||||
if (_gc_thread_stop) return;
|
||||
|
||||
std::cerr << "gc start " << '\n';
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "gc start " << '\n';
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
auto gcstart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
std::queue<Cell *> toVisit;
|
||||
@@ -65,19 +78,23 @@ void MemoryContext::gc_thread_entry() {
|
||||
toVisit.pop();
|
||||
|
||||
if (c == nullptr) continue;
|
||||
if (c->live) continue;
|
||||
c->live = true;
|
||||
|
||||
// std::cerr << "processing c " << c << " " << static_cast<int>(c->_type) << "\n";
|
||||
if (c->_live) continue;
|
||||
c->_live = true;
|
||||
//
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "processing c " << c << " " << static_cast<int>(c->_type) << "\n";
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
|
||||
if (c->_type == CellType::CONS) {
|
||||
ConsCell &cc = dynamic_cast<ConsCell &>(*c);
|
||||
// std::cerr << "processing car " << cc._car << "\n";
|
||||
// {std::stringstream out; out << "processing car " << cc._car << "\n"; std::cerr<<out.str();}
|
||||
toVisit.emplace(cc._car);
|
||||
// std::cerr << "real car " << toVisit.back() << "\n";
|
||||
// std::cerr << "processing cdr " << cc._cdr << "\n";
|
||||
// {std::stringstream out; out << "real car " << toVisit.back() << "\n"; std::cerr<<out.str();}
|
||||
// {std::stringstream out; out << "processing cdr " << cc._cdr << "\n"; std::cerr<<out.str();}
|
||||
toVisit.emplace(cc._cdr);
|
||||
// std::cerr << "real cdr " << toVisit.back() << "\n";
|
||||
// {std::stringstream out; out << "real cdr " << toVisit.back() << "\n"; std::cerr<<out.str();}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -97,7 +114,11 @@ void MemoryContext::gc_thread_entry() {
|
||||
|
||||
|
||||
for (auto const &r: new_roots) {
|
||||
// std::cerr << "processing new " << r.first << " diff " << r.second << "\n";
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "processing new " << r.first << " diff " << r.second << "\n";
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
if (r.second == 0) continue;
|
||||
_roots[r.first] += r.second;
|
||||
if (_roots[r.first] <= 0)
|
||||
@@ -105,46 +126,72 @@ void MemoryContext::gc_thread_entry() {
|
||||
}
|
||||
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
std::cerr << "New roots time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "New roots time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||
std::cout << out.str();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
std::for_each(_cells.begin(), _cells.end(), [&](Cell *c) {
|
||||
c->live = false;
|
||||
c->_live = false;
|
||||
});
|
||||
|
||||
for (const auto &r: _roots) {
|
||||
// std::cerr << "processing r " << r.first << " diff " << r.second << "\n";
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "processing r " << r.first << " diff " << r.second << "\n";
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
toVisit.emplace(r.first);
|
||||
}
|
||||
visitAll();
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
// std::cerr << "Scanned " << _roots.size() << " roots" << std::endl;
|
||||
std::cerr << "Roots scan time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "Scanned " << _roots.size() << " roots" << std::endl;
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "Roots scan time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||
std::cout << out.str();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
decltype(_gc_dirty_notif_queue) dirtied;
|
||||
std::unique_lock dql(_gc_dirty_notif_queue_lock);
|
||||
std::swap(dirtied, _gc_dirty_notif_queue);
|
||||
|
||||
{
|
||||
std::lock_guard dql(_gc_dirty_notif_queue_lock);
|
||||
std::swap(dirtied, _gc_dirty_notif_queue);
|
||||
}
|
||||
while (!dirtied.empty()) {
|
||||
dql.unlock();
|
||||
for (const auto &r: dirtied) {
|
||||
// std::cerr << "processing dirty " << r << "\n";
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "processing dirty " << r << "\n";
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
toVisit.emplace(r);
|
||||
}
|
||||
visitAll();
|
||||
|
||||
dirtied = {};
|
||||
dql.lock();
|
||||
std::swap(dirtied, _gc_dirty_notif_queue);
|
||||
{
|
||||
std::lock_guard dql(_gc_dirty_notif_queue_lock);
|
||||
std::swap(dirtied, _gc_dirty_notif_queue);
|
||||
}
|
||||
}
|
||||
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
std::cerr << "Dirty mark time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "Dirty mark time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||
std::cout << out.str();
|
||||
}
|
||||
}
|
||||
{
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
@@ -152,18 +199,14 @@ void MemoryContext::gc_thread_entry() {
|
||||
uint64_t freed = 0;
|
||||
|
||||
_cells.remove_if([&](Cell *l) {
|
||||
if (!l->live) {
|
||||
if (!l->_live) {
|
||||
freed += 1;
|
||||
|
||||
if (l->_type == CellType::NUMATOM) {
|
||||
std::lock_guard il(_indexes_lock);
|
||||
// std::cerr << "deleting num: " << l << "\n";
|
||||
_numatom_index.erase(dynamic_cast<NumAtomCell &>(*l)._val);
|
||||
} else if (l->_type == CellType::STRATOM) {
|
||||
std::lock_guard il(_indexes_lock);
|
||||
// std::cerr << "deleting str: " << l << "\n";
|
||||
_stratom_index.erase(dynamic_cast<StrAtomCell &>(*l)._val);
|
||||
}
|
||||
// {
|
||||
// std::stringstream out;
|
||||
// out << "deleting: " << l << "\n";
|
||||
// std::cerr << out.str();
|
||||
// }
|
||||
|
||||
delete l;
|
||||
return true;
|
||||
@@ -172,13 +215,25 @@ void MemoryContext::gc_thread_entry() {
|
||||
});
|
||||
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
std::cerr << "Sweep time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "Sweep time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||
std::cout << out.str();
|
||||
}
|
||||
_cells_num = _cells.size();
|
||||
std::cerr << "GC Freed " << freed << " cells left: " << _cells_num << " \n";
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "GC Freed " << freed << " cells left: " << _cells_num << " \n";
|
||||
std::cout << out.str();
|
||||
}
|
||||
}
|
||||
|
||||
auto gcstop = std::chrono::high_resolution_clock::now();
|
||||
std::cerr << "GC total time: " << std::chrono::duration_cast<std::chrono::microseconds>(gcstop - gcstart).count() << "\n";
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "GC total time: " << std::chrono::duration_cast<std::chrono::microseconds>(gcstop - gcstart).count() << "\n";
|
||||
std::cout << out.str();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
|
||||
@@ -39,10 +39,10 @@ Handle Parser::parseExpr() {
|
||||
return out;
|
||||
} else {
|
||||
token = _tokenizer.getNext();
|
||||
try {
|
||||
if (token.find_first_not_of("-0123456789") == std::string::npos) {
|
||||
CellValType val = std::stoi(token);
|
||||
return Handle::makeNumCell(val);
|
||||
} catch (...) {
|
||||
} else {
|
||||
return Handle::makeStrCell(token);
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ std::string_view Parser::Tokenizer::peek() const {
|
||||
void Parser::Tokenizer::load(std::string_view input) {
|
||||
std::string_view::size_type curpos = input.find_first_not_of(' ');
|
||||
|
||||
static const std::string alnum = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
static const std::string alnum = "-+0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
static const std::string special = "().";
|
||||
|
||||
while (curpos != std::string_view::npos) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
#include "Compiler.h"
|
||||
#include "VM.h"
|
||||
|
||||
|
||||
@@ -21,6 +22,8 @@ void VM::step() {
|
||||
_s.push(nullptr);
|
||||
} else if (poppedH == LDC) {
|
||||
_s.push(_c.pop());
|
||||
} else if (poppedH == ATOM) {
|
||||
_s.push(_c.pop().atom() ? 1 : 0);
|
||||
} else if (poppedH == LD) {
|
||||
Handle poppedH2 = _c.pop();
|
||||
|
||||
@@ -123,6 +126,17 @@ void VM::step() {
|
||||
_outstream << (char) _s.pop().val();
|
||||
} else if (poppedH == PUTNUM) {
|
||||
_outstream << _s.pop().val();
|
||||
} else if (poppedH == EVAL) {
|
||||
Handle code = _s.pop();
|
||||
Handle newc = Compiler::compile(code, nullptr);
|
||||
std::cerr << "compiled:\n";
|
||||
std::cerr << "(" << code << ")\n";
|
||||
std::cerr << "to:\n";
|
||||
std::cerr << "(" << newc << ")\n";
|
||||
newc.splice(_c);
|
||||
_c = newc;
|
||||
} else if (poppedH == PRINT) {
|
||||
_outstream << _s.pop().val();
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,19 @@ target_link_libraries(
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
add_executable(
|
||||
CompilerTest
|
||||
CompilerTest.cpp
|
||||
)
|
||||
target_link_libraries(
|
||||
CompilerTest
|
||||
vm
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(VMTest)
|
||||
gtest_discover_tests(VMWithParserTest)
|
||||
gtest_discover_tests(GCTest)
|
||||
gtest_discover_tests(CompilerTest)
|
||||
|
||||
96
test/vm/CompilerTest.cpp
Normal file
96
test/vm/CompilerTest.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 27.12.2023.
|
||||
//
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "MemoryContext.h"
|
||||
#include "Parser.h"
|
||||
#include "VM.h"
|
||||
|
||||
TEST(CompilerTest, BasicHello) {
|
||||
std::stringstream ssin;
|
||||
std::stringstream ssout;
|
||||
{
|
||||
MemoryContext mc;
|
||||
VM vm(ssin, ssout);
|
||||
Parser parser;
|
||||
parser.loadStr("(LDC 3 EVAL PRINT STOP)");
|
||||
vm.loadControl(parser.parseExpr());
|
||||
vm.run();
|
||||
}
|
||||
ssout.flush();
|
||||
EXPECT_EQ(ssout.str(), "3");
|
||||
}
|
||||
|
||||
TEST(CompilerTest, BasicLet) {
|
||||
std::stringstream ssin;
|
||||
std::stringstream ssout;
|
||||
{
|
||||
MemoryContext mc;
|
||||
VM vm(ssin, ssout);
|
||||
Parser parser;
|
||||
parser.loadStr("(LDC (let ((x 1)) x) EVAL PRINT STOP)");
|
||||
vm.loadControl(parser.parseExpr());
|
||||
vm.run();
|
||||
}
|
||||
ssout.flush();
|
||||
EXPECT_EQ(ssout.str(), "1");
|
||||
}
|
||||
|
||||
TEST(CompilerTest, BasicFn) {
|
||||
std::stringstream ssin;
|
||||
std::stringstream ssout;
|
||||
{
|
||||
MemoryContext mc;
|
||||
VM vm(ssin, ssout);
|
||||
Parser parser;
|
||||
parser.loadStr("(LDC (let ((plfn (lambda (a b) (+ a b)))) (plfn 2 3)) EVAL PRINT STOP)");
|
||||
vm.loadControl(parser.parseExpr());
|
||||
vm.run();
|
||||
}
|
||||
ssout.flush();
|
||||
EXPECT_EQ(ssout.str(), "5");
|
||||
}
|
||||
|
||||
TEST(CompilerTest, BasicFnIfT) {
|
||||
std::stringstream ssin;
|
||||
std::stringstream ssout;
|
||||
{
|
||||
MemoryContext mc;
|
||||
VM vm(ssin, ssout);
|
||||
Parser parser;
|
||||
parser.loadStr("(LDC (let ((plfn (lambda (a) (if a 1 2)))) (plfn 1)) EVAL PRINT STOP)");
|
||||
vm.loadControl(parser.parseExpr());
|
||||
vm.run();
|
||||
}
|
||||
ssout.flush();
|
||||
EXPECT_EQ(ssout.str(), "1");
|
||||
}
|
||||
TEST(CompilerTest, BasicFnIfF) {
|
||||
std::stringstream ssin;
|
||||
std::stringstream ssout;
|
||||
{
|
||||
MemoryContext mc;
|
||||
VM vm(ssin, ssout);
|
||||
Parser parser;
|
||||
parser.loadStr("(LDC (let ((plfn (lambda (a) (if a 1 2)))) (plfn 0)) EVAL PRINT STOP)");
|
||||
vm.loadControl(parser.parseExpr());
|
||||
vm.run();
|
||||
}
|
||||
ssout.flush();
|
||||
EXPECT_EQ(ssout.str(), "2");
|
||||
}
|
||||
TEST(CompilerTest, RecursiveFn) {
|
||||
std::stringstream ssin;
|
||||
std::stringstream ssout;
|
||||
{
|
||||
MemoryContext mc;
|
||||
VM vm(ssin, ssout);
|
||||
Parser parser;
|
||||
parser.loadStr("(LDC (letrec ((fib (lambda (n) (if n (if (+ n -1) (+ (fib (+ n -1)) (fib(+ n -2))) 1) 0) ))) (fib 10)) EVAL PRINT STOP)");
|
||||
vm.loadControl(parser.parseExpr());
|
||||
vm.run();
|
||||
}
|
||||
ssout.flush();
|
||||
EXPECT_EQ(ssout.str(), "55");
|
||||
}
|
||||
@@ -85,8 +85,9 @@ TEST(GCTest, GCTestAppend2) {
|
||||
|
||||
TEST(GCTest, GCTestAppend3) {
|
||||
MemoryContext mc;
|
||||
for (int i = 0; i < 25000; i++) {
|
||||
for (int i = 0; i < 250000; i++) {
|
||||
Handle c = Handle::cons(nullptr, nullptr);
|
||||
mc.request_gc();
|
||||
c.append(Handle::makeNumCell(1));
|
||||
c.append(Handle::makeNumCell(2));
|
||||
mc.request_gc();
|
||||
|
||||
Reference in New Issue
Block a user