mirror of
https://github.com/usatiuk/psil.git
synced 2025-10-28 10:47:49 +01:00
gc seems to work!
This commit is contained in:
147
.clang-tidy
Normal file
147
.clang-tidy
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
# Generated from CLion Inspection settings
|
||||||
|
---
|
||||||
|
Checks: '-*,
|
||||||
|
bugprone-argument-comment,
|
||||||
|
bugprone-assert-side-effect,
|
||||||
|
bugprone-bad-signal-to-kill-thread,
|
||||||
|
bugprone-branch-clone,
|
||||||
|
bugprone-copy-constructor-init,
|
||||||
|
bugprone-dangling-handle,
|
||||||
|
bugprone-dynamic-static-initializers,
|
||||||
|
bugprone-fold-init-type,
|
||||||
|
bugprone-forward-declaration-namespace,
|
||||||
|
bugprone-forwarding-reference-overload,
|
||||||
|
bugprone-inaccurate-erase,
|
||||||
|
bugprone-incorrect-roundings,
|
||||||
|
bugprone-integer-division,
|
||||||
|
bugprone-lambda-function-name,
|
||||||
|
bugprone-macro-parentheses,
|
||||||
|
bugprone-macro-repeated-side-effects,
|
||||||
|
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||||
|
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||||
|
bugprone-misplaced-widening-cast,
|
||||||
|
bugprone-move-forwarding-reference,
|
||||||
|
bugprone-multiple-statement-macro,
|
||||||
|
bugprone-no-escape,
|
||||||
|
bugprone-parent-virtual-call,
|
||||||
|
bugprone-posix-return,
|
||||||
|
bugprone-reserved-identifier,
|
||||||
|
bugprone-sizeof-container,
|
||||||
|
bugprone-sizeof-expression,
|
||||||
|
bugprone-spuriously-wake-up-functions,
|
||||||
|
bugprone-string-constructor,
|
||||||
|
bugprone-string-integer-assignment,
|
||||||
|
bugprone-string-literal-with-embedded-nul,
|
||||||
|
bugprone-suspicious-enum-usage,
|
||||||
|
bugprone-suspicious-include,
|
||||||
|
bugprone-suspicious-memset-usage,
|
||||||
|
bugprone-suspicious-missing-comma,
|
||||||
|
bugprone-suspicious-semicolon,
|
||||||
|
bugprone-suspicious-string-compare,
|
||||||
|
bugprone-suspicious-memory-comparison,
|
||||||
|
bugprone-suspicious-realloc-usage,
|
||||||
|
bugprone-swapped-arguments,
|
||||||
|
bugprone-terminating-continue,
|
||||||
|
bugprone-throw-keyword-missing,
|
||||||
|
bugprone-too-small-loop-variable,
|
||||||
|
bugprone-undefined-memory-manipulation,
|
||||||
|
bugprone-undelegated-constructor,
|
||||||
|
bugprone-unhandled-self-assignment,
|
||||||
|
bugprone-unused-raii,
|
||||||
|
bugprone-unused-return-value,
|
||||||
|
bugprone-use-after-move,
|
||||||
|
bugprone-virtual-near-miss,
|
||||||
|
cert-dcl21-cpp,
|
||||||
|
cert-dcl58-cpp,
|
||||||
|
cert-err34-c,
|
||||||
|
cert-err52-cpp,
|
||||||
|
cert-err60-cpp,
|
||||||
|
cert-flp30-c,
|
||||||
|
cert-msc50-cpp,
|
||||||
|
cert-msc51-cpp,
|
||||||
|
cert-str34-c,
|
||||||
|
cppcoreguidelines-interfaces-global-init,
|
||||||
|
cppcoreguidelines-narrowing-conversions,
|
||||||
|
cppcoreguidelines-pro-type-member-init,
|
||||||
|
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
|
cppcoreguidelines-slicing,
|
||||||
|
google-default-arguments,
|
||||||
|
google-explicit-constructor,
|
||||||
|
google-runtime-operator,
|
||||||
|
hicpp-exception-baseclass,
|
||||||
|
hicpp-multiway-paths-covered,
|
||||||
|
misc-misplaced-const,
|
||||||
|
misc-new-delete-overloads,
|
||||||
|
misc-no-recursion,
|
||||||
|
misc-non-copyable-objects,
|
||||||
|
misc-throw-by-value-catch-by-reference,
|
||||||
|
misc-unconventional-assign-operator,
|
||||||
|
misc-uniqueptr-reset-release,
|
||||||
|
modernize-avoid-bind,
|
||||||
|
modernize-concat-nested-namespaces,
|
||||||
|
modernize-deprecated-headers,
|
||||||
|
modernize-deprecated-ios-base-aliases,
|
||||||
|
modernize-loop-convert,
|
||||||
|
modernize-make-shared,
|
||||||
|
modernize-make-unique,
|
||||||
|
modernize-pass-by-value,
|
||||||
|
modernize-raw-string-literal,
|
||||||
|
modernize-redundant-void-arg,
|
||||||
|
modernize-replace-auto-ptr,
|
||||||
|
modernize-replace-disallow-copy-and-assign-macro,
|
||||||
|
modernize-replace-random-shuffle,
|
||||||
|
modernize-return-braced-init-list,
|
||||||
|
modernize-shrink-to-fit,
|
||||||
|
modernize-unary-static-assert,
|
||||||
|
modernize-use-auto,
|
||||||
|
modernize-use-bool-literals,
|
||||||
|
modernize-use-emplace,
|
||||||
|
modernize-use-equals-default,
|
||||||
|
modernize-use-equals-delete,
|
||||||
|
modernize-use-nodiscard,
|
||||||
|
modernize-use-noexcept,
|
||||||
|
modernize-use-nullptr,
|
||||||
|
modernize-use-override,
|
||||||
|
modernize-use-transparent-functors,
|
||||||
|
modernize-use-uncaught-exceptions,
|
||||||
|
mpi-buffer-deref,
|
||||||
|
mpi-type-mismatch,
|
||||||
|
openmp-use-default-none,
|
||||||
|
performance-faster-string-find,
|
||||||
|
performance-for-range-copy,
|
||||||
|
performance-implicit-conversion-in-loop,
|
||||||
|
performance-inefficient-algorithm,
|
||||||
|
performance-inefficient-string-concatenation,
|
||||||
|
performance-inefficient-vector-operation,
|
||||||
|
performance-move-const-arg,
|
||||||
|
performance-move-constructor-init,
|
||||||
|
performance-no-automatic-move,
|
||||||
|
performance-noexcept-move-constructor,
|
||||||
|
performance-trivially-destructible,
|
||||||
|
performance-type-promotion-in-math-fn,
|
||||||
|
performance-unnecessary-copy-initialization,
|
||||||
|
performance-unnecessary-value-param,
|
||||||
|
portability-simd-intrinsics,
|
||||||
|
readability-avoid-const-params-in-decls,
|
||||||
|
readability-const-return-type,
|
||||||
|
readability-container-size-empty,
|
||||||
|
readability-convert-member-functions-to-static,
|
||||||
|
readability-delete-null-pointer,
|
||||||
|
readability-deleted-default,
|
||||||
|
readability-inconsistent-declaration-parameter-name,
|
||||||
|
readability-make-member-function-const,
|
||||||
|
readability-misleading-indentation,
|
||||||
|
readability-misplaced-array-index,
|
||||||
|
readability-non-const-parameter,
|
||||||
|
readability-redundant-control-flow,
|
||||||
|
readability-redundant-declaration,
|
||||||
|
readability-redundant-function-ptr-dereference,
|
||||||
|
readability-redundant-smartptr-get,
|
||||||
|
readability-redundant-string-cstr,
|
||||||
|
readability-redundant-string-init,
|
||||||
|
readability-simplify-subscript-expr,
|
||||||
|
readability-static-accessed-through-instance,
|
||||||
|
readability-static-definition-in-anonymous-namespace,
|
||||||
|
readability-string-compare,
|
||||||
|
readability-uniqueptr-delete-release,
|
||||||
|
readability-use-anyofallof'
|
||||||
1
.idea/cmake.xml
generated
1
.idea/cmake.xml
generated
@@ -3,6 +3,7 @@
|
|||||||
<component name="CMakeSharedSettings">
|
<component name="CMakeSharedSettings">
|
||||||
<configurations>
|
<configurations>
|
||||||
<configuration PROFILE_NAME="Debug" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DSANITIZE=YES" />
|
<configuration PROFILE_NAME="Debug" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DSANITIZE=YES" />
|
||||||
|
<configuration PROFILE_NAME="RelWithDebInfo" ENABLED="true" CONFIG_NAME="RelWithDebInfo" />
|
||||||
</configurations>
|
</configurations>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
40
.idea/codeStyles/Project.xml
generated
40
.idea/codeStyles/Project.xml
generated
@@ -1,5 +1,45 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
|
<Objective-C-extensions>
|
||||||
|
<rules>
|
||||||
|
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="CLASS_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="_" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="_" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
</rules>
|
||||||
|
</Objective-C-extensions>
|
||||||
|
<Objective-C-extensions>
|
||||||
|
<rules>
|
||||||
|
<rule entity="NAMESPACE" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="MACRO" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="CLASS" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="STRUCT" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="ENUM" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="ENUMERATOR" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="TYPEDEF" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="UNION" visibility="ANY" specifier="ANY" prefix="" style="PASCAL_CASE" suffix="" />
|
||||||
|
<rule entity="CLASS_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="STRUCT_MEMBER_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="CLASS_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="_" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="STRUCT_MEMBER_FIELD" visibility="ANY" specifier="ANY" prefix="_" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="GLOBAL_FUNCTION" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="GLOBAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SCREAMING_SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="PARAMETER" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
<rule entity="LOCAL_VARIABLE" visibility="ANY" specifier="ANY" prefix="" style="SNAKE_CASE" suffix="" />
|
||||||
|
</rules>
|
||||||
|
</Objective-C-extensions>
|
||||||
<clangFormatSettings>
|
<clangFormatSettings>
|
||||||
<option name="ENABLED" value="true" />
|
<option name="ENABLED" value="true" />
|
||||||
</clangFormatSettings>
|
</clangFormatSettings>
|
||||||
|
|||||||
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="OCInconsistentNaming" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@@ -4,6 +4,7 @@
|
|||||||
<component name="CidrRootsConfiguration">
|
<component name="CidrRootsConfiguration">
|
||||||
<excludeRoots>
|
<excludeRoots>
|
||||||
<file path="$PROJECT_DIR$/cmake-build-debug" />
|
<file path="$PROJECT_DIR$/cmake-build-debug" />
|
||||||
|
<file path="$PROJECT_DIR$/cmake-build-relwithdebinfo" />
|
||||||
</excludeRoots>
|
</excludeRoots>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -23,7 +23,7 @@ struct Cell {
|
|||||||
virtual ~Cell() = 0;
|
virtual ~Cell() = 0;
|
||||||
|
|
||||||
CellType _type;
|
CellType _type;
|
||||||
bool live = false;
|
std::atomic<bool> live = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NumAtomCell : public Cell {
|
struct NumAtomCell : public Cell {
|
||||||
@@ -45,8 +45,8 @@ struct ConsCell : public Cell {
|
|||||||
explicit ConsCell(Cell *car) : Cell(CellType::CONS), _car(car) {}
|
explicit ConsCell(Cell *car) : Cell(CellType::CONS), _car(car) {}
|
||||||
ConsCell(Cell *car, Cell *cdr) : Cell(CellType::CONS), _car(car), _cdr(cdr) {}
|
ConsCell(Cell *car, Cell *cdr) : Cell(CellType::CONS), _car(car), _cdr(cdr) {}
|
||||||
|
|
||||||
Cell *_car = nullptr;
|
std::atomic<Cell *> _car = nullptr;
|
||||||
Cell *_cdr = nullptr;
|
std::atomic<Cell *> _cdr = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//PSIL_CELL_H
|
#endif//PSIL_CELL_H
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
#include "MemoryContext.h"
|
#include "MemoryContext.h"
|
||||||
|
|
||||||
namespace ConsUtils {
|
namespace ConsUtils {
|
||||||
static inline MCHandle car(const MCHandle &cell) { return dynamic_cast<ConsCell &>(*cell)._car; }
|
static inline MCHandle car(const MCHandle &cell) { return dynamic_cast<ConsCell &>(*cell)._car.load(); }
|
||||||
static inline MCHandle cdr(const MCHandle &cell) { return dynamic_cast<ConsCell &>(*cell)._cdr; }
|
static inline MCHandle cdr(const MCHandle &cell) { return dynamic_cast<ConsCell &>(*cell)._cdr.load(); }
|
||||||
static inline CellValType val(const MCHandle &cell) { return dynamic_cast<NumAtomCell &>(*cell)._val; }
|
static inline CellValType val(const MCHandle &cell) { return dynamic_cast<NumAtomCell &>(*cell)._val; }
|
||||||
static inline std::string_view strval(const MCHandle &cell) { return dynamic_cast<StrAtomCell &>(*cell)._val; }
|
static inline std::string_view strval(const MCHandle &cell) { return dynamic_cast<StrAtomCell &>(*cell)._val; }
|
||||||
MCHandle cons(const MCHandle &car, const MCHandle &cdr);
|
MCHandle cons(const MCHandle &car, const MCHandle &cdr);
|
||||||
MCHandle pop(MCHandle &from);
|
MCHandle pop(MCHandle &from);
|
||||||
MCHandle push(MCHandle &to, const MCHandle &what);
|
void push(MCHandle &to, const MCHandle &what);
|
||||||
void append(MCHandle to, const MCHandle &what);
|
void append(MCHandle to, const MCHandle &what);
|
||||||
MCHandle makeNumCell(int64_t val);
|
MCHandle makeNumCell(int64_t val);
|
||||||
MCHandle makeStrCell(std::string val);
|
MCHandle makeStrCell(std::string val);
|
||||||
|
|||||||
@@ -6,7 +6,14 @@
|
|||||||
#define PSIL_MEMORYCONTEXT_H
|
#define PSIL_MEMORYCONTEXT_H
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "Cell.h"
|
#include "Cell.h"
|
||||||
|
|
||||||
@@ -19,53 +26,164 @@ public:
|
|||||||
|
|
||||||
template<typename CT, typename... Args>
|
template<typename CT, typename... Args>
|
||||||
Handle create_cell(Args... args) {
|
Handle create_cell(Args... args) {
|
||||||
CT *cell = new CT(std::forward<Args>(args)...);
|
return alloc_cell<CT>(std::forward<Args>(args)...);
|
||||||
_cells.emplace_back(cell);
|
|
||||||
return cell;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
// template<>
|
||||||
Handle create_cell<NumAtomCell>(CellValType val) {
|
// Handle create_cell<NumAtomCell>(CellValType val) {
|
||||||
if (numatom_index.contains(val))
|
// {
|
||||||
return numatom_index.at(val);
|
// std::lock_guard l(_cells_lock);
|
||||||
|
// if (_numatom_index.contains(val)) {
|
||||||
NumAtomCell *cell = new NumAtomCell(val);
|
// _numatom_index.at(val)->live = true;
|
||||||
_cells.emplace_back(cell);
|
// return _numatom_index.at(val);
|
||||||
numatom_index.emplace(val, cell);
|
// }
|
||||||
return cell;
|
// }
|
||||||
}
|
// Handle newc = alloc_cell<NumAtomCell>(val);
|
||||||
|
// {
|
||||||
template<>
|
// std::lock_guard l(_cells_lock);
|
||||||
Handle create_cell<StrAtomCell>(std::string val) {
|
// _numatom_index.emplace(val, newc.get());
|
||||||
if (stratom_index.contains(val))
|
// }
|
||||||
return stratom_index.at(val);
|
// return newc;
|
||||||
|
// }
|
||||||
StrAtomCell *cell = new StrAtomCell(std::move(val));
|
//
|
||||||
_cells.emplace_back(cell);
|
// template<>
|
||||||
stratom_index.emplace(cell->_val, cell);
|
// Handle create_cell<StrAtomCell>(std::string val) {
|
||||||
return cell;
|
// {
|
||||||
}
|
// std::lock_guard l(_cells_lock);
|
||||||
|
// if (_stratom_index.contains(val)) {
|
||||||
|
// _stratom_index.at(val)->live = true;
|
||||||
|
// return _stratom_index.at(val);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Handle newc = alloc_cell<StrAtomCell>(val);
|
||||||
|
// {
|
||||||
|
// std::lock_guard l(_cells_lock);
|
||||||
|
// _stratom_index.emplace(std::move(val), newc.get());
|
||||||
|
// }
|
||||||
|
// return newc;
|
||||||
|
// }
|
||||||
|
|
||||||
class Handle {
|
class Handle {
|
||||||
public:
|
public:
|
||||||
Handle(Cell *target) : _target(target) {}
|
Handle(Cell *target);
|
||||||
|
~Handle();
|
||||||
|
|
||||||
|
Handle(Handle const &other);
|
||||||
|
Handle &operator=(Handle other);
|
||||||
|
|
||||||
Cell *operator->() const { return _target; }
|
Cell *operator->() const { return _target; }
|
||||||
Cell &operator*() const { return *_target; }
|
Cell &operator*() const { return *_target; }
|
||||||
Cell *get() const noexcept { return _target; }
|
Cell *get() const noexcept { return _target; }
|
||||||
|
|
||||||
bool operator==(const Handle &rhs) const {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Cell *_target = nullptr;
|
Cell *_target = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void request_gc_and_wait() {
|
||||||
|
std::unique_lock l(_gc_done_m);
|
||||||
|
_gc_done = false;
|
||||||
|
{
|
||||||
|
request_gc();
|
||||||
|
}
|
||||||
|
if (!_gc_done)
|
||||||
|
_gc_done_cv.wait(l, [&] { return _gc_done.load(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void request_gc() {
|
||||||
|
std::lock_guard l(_gc_request_m);
|
||||||
|
_gc_request = true;
|
||||||
|
_gc_request_cv.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cell_count() {
|
||||||
|
return _cells_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_dirty(const Handle &h, std::function<void()> f);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<Cell *> _cells;
|
template<typename CT, typename... Args>
|
||||||
std::unordered_map<CellValType, Cell *> numatom_index;
|
Handle alloc_cell(Args... args) {
|
||||||
std::unordered_map<std::string, Cell *> stratom_index;
|
|
||||||
|
size_t tcellnum;
|
||||||
|
{
|
||||||
|
std::lock_guard tmplg(_new_roots_lock);
|
||||||
|
tcellnum = _temp_cells.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_cells_num + tcellnum) >= (_cell_limit)) {
|
||||||
|
// We might need to run GC twice as it has to process the messages;
|
||||||
|
std::cerr << "Running forced GC" << std::endl;
|
||||||
|
for (int i = 0; i < 3 && (_cells_num + tcellnum) >= (_cell_limit); i++) {
|
||||||
|
request_gc_and_wait();
|
||||||
|
{
|
||||||
|
std::lock_guard tmplg(_new_roots_lock);
|
||||||
|
tcellnum = _temp_cells.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((_cells_num + tcellnum) >= (_cell_limit)) {
|
||||||
|
throw std::runtime_error("Out of cells");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CT *cell = new CT(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard tmplg(_new_roots_lock);
|
||||||
|
Handle ret(cell);
|
||||||
|
_temp_cells.emplace(cell);
|
||||||
|
if ((_cells_num + _temp_cells.size() + 1) >= (size_t) (_cell_limit / 2)) {
|
||||||
|
request_gc();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void add_root(Cell *c);
|
||||||
|
void remove_root(Cell *c);
|
||||||
|
|
||||||
|
std::mutex _cells_lock;
|
||||||
|
std::set<Cell *> _cells;
|
||||||
|
std::atomic<size_t> _cells_num = 0;
|
||||||
|
std::set<Cell *> _temp_cells;
|
||||||
|
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();
|
||||||
|
|
||||||
|
std::map<Cell *, int64_t> _roots;
|
||||||
|
std::map<Cell *, int64_t> _new_roots;
|
||||||
|
std::recursive_mutex _new_roots_lock;
|
||||||
|
|
||||||
|
std::set<Cell *> _gc_dirty_notif_queue;
|
||||||
|
std::mutex _gc_dirty_notif_queue_lock;
|
||||||
|
|
||||||
|
std::atomic<bool> _gc_request = false;
|
||||||
|
std::mutex _gc_request_m;
|
||||||
|
std::condition_variable _gc_request_cv;
|
||||||
|
|
||||||
|
std::atomic<bool> _gc_done = false;
|
||||||
|
std::mutex _gc_done_m;
|
||||||
|
std::condition_variable _gc_done_cv;
|
||||||
|
|
||||||
|
std::thread _gc_thread;
|
||||||
|
std::atomic<bool> _gc_thread_stop = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using MCHandle = MemoryContext::Handle;
|
using MCHandle = MemoryContext::Handle;
|
||||||
|
|||||||
@@ -54,8 +54,6 @@ private:
|
|||||||
MCHandle PUTNUM = ConsUtils::makeStrCell("PUTNUM");
|
MCHandle PUTNUM = ConsUtils::makeStrCell("PUTNUM");
|
||||||
|
|
||||||
MCHandle CONS = ConsUtils::makeStrCell("CONS");
|
MCHandle CONS = ConsUtils::makeStrCell("CONS");
|
||||||
|
|
||||||
// void gc();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//PSIL_VM_H
|
#endif//PSIL_VM_H
|
||||||
|
|||||||
@@ -17,19 +17,18 @@ MCHandle ConsUtils::pop(MCHandle &from) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MCHandle ConsUtils::push(MCHandle &to, const MCHandle &what) {
|
void ConsUtils::push(MCHandle &to, const MCHandle &what) {
|
||||||
to = cons(what, to);
|
to = cons(what, to);
|
||||||
return to;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsUtils::append(MCHandle to, const MCHandle &what) {
|
void ConsUtils::append(MCHandle to, const MCHandle &what) {
|
||||||
assert(to.get() != nullptr);
|
assert(to.get() != nullptr);
|
||||||
if (car(to).get() == nullptr) {
|
if (car(to).get() == nullptr) {
|
||||||
dynamic_cast<ConsCell &>(*to)._car = what.get();
|
setcar(to, what);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (dynamic_cast<ConsCell &>(*to)._cdr != nullptr) to = cdr(to);
|
while (cdr(to).get() != nullptr) to = cdr(to);
|
||||||
dynamic_cast<ConsCell &>(*to)._cdr = cons(what, nullptr).get();
|
setcdr(to, cons(what, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
MCHandle ConsUtils::makeNumCell(int64_t val) {
|
MCHandle ConsUtils::makeNumCell(int64_t val) {
|
||||||
@@ -41,9 +40,13 @@ MCHandle ConsUtils::makeStrCell(std::string val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConsUtils::setcar(const MCHandle &to, const MCHandle &car) {
|
void ConsUtils::setcar(const MCHandle &to, const MCHandle &car) {
|
||||||
|
CURRENT_MC.load()->run_dirty(to, [&] {
|
||||||
dynamic_cast<ConsCell &>(*to)._car = car.get();
|
dynamic_cast<ConsCell &>(*to)._car = car.get();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsUtils::setcdr(const MCHandle &to, const MCHandle &cdr) {
|
void ConsUtils::setcdr(const MCHandle &to, const MCHandle &cdr) {
|
||||||
|
CURRENT_MC.load()->run_dirty(to, [&] {
|
||||||
dynamic_cast<ConsCell &>(*to)._cdr = cdr.get();
|
dynamic_cast<ConsCell &>(*to)._cdr = cdr.get();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,18 @@
|
|||||||
|
|
||||||
#include "MemoryContext.h"
|
#include "MemoryContext.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
std::atomic<MemoryContext *> CURRENT_MC = nullptr;
|
std::atomic<MemoryContext *> CURRENT_MC = nullptr;
|
||||||
|
|
||||||
MemoryContext::MemoryContext() {
|
MemoryContext::MemoryContext() {
|
||||||
MemoryContext *expected = nullptr;
|
MemoryContext *expected = nullptr;
|
||||||
if (!CURRENT_MC.compare_exchange_strong(expected, this)) throw std::runtime_error("MC already exists!");
|
if (!CURRENT_MC.compare_exchange_strong(expected, this)) throw std::runtime_error("MC already exists!");
|
||||||
|
|
||||||
|
_gc_thread = std::thread(std::bind(&MemoryContext::gc_thread_entry, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryContext::~MemoryContext() {
|
MemoryContext::~MemoryContext() {
|
||||||
@@ -20,4 +24,204 @@ MemoryContext::~MemoryContext() {
|
|||||||
std::cerr << "Global MC pointer was overwritten!" << std::endl;
|
std::cerr << "Global MC pointer was overwritten!" << std::endl;
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
_gc_thread_stop = true;
|
||||||
|
_gc_request_cv.notify_all();
|
||||||
|
_gc_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryContext::Handle::Handle(Cell *target) : _target(target) {
|
||||||
|
if (target != nullptr)
|
||||||
|
CURRENT_MC.load()->add_root(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryContext::Handle::~Handle() {
|
||||||
|
if (_target != nullptr)
|
||||||
|
CURRENT_MC.load()->remove_root(_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryContext::Handle::Handle(MemoryContext::Handle const &other) : _target(other._target) {
|
||||||
|
if (_target != nullptr)
|
||||||
|
CURRENT_MC.load()->add_root(_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryContext::Handle &MemoryContext::Handle::operator=(MemoryContext::Handle other) {
|
||||||
|
std::swap(_target, other._target);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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";
|
||||||
|
if (_new_roots[c] == 0) _new_roots.erase(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryContext::run_dirty(const MemoryContext::Handle &h, std::function<void()> f) {
|
||||||
|
{
|
||||||
|
std::lock_guard l(_gc_dirty_notif_queue_lock);
|
||||||
|
// std::cerr << "dirtied: " << h.get() << "\n";
|
||||||
|
_gc_dirty_notif_queue.emplace(h.get());
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryContext::gc_thread_entry() {
|
||||||
|
while (true) {
|
||||||
|
{
|
||||||
|
std::unique_lock l(_gc_request_m);
|
||||||
|
_gc_request_cv.wait(l, [&] { return _gc_request || _gc_thread_stop; });
|
||||||
|
}
|
||||||
|
if (_gc_thread_stop) return;
|
||||||
|
|
||||||
|
std::cerr << "gc start " << '\n';
|
||||||
|
|
||||||
|
std::unordered_set<Cell *> seenroots;
|
||||||
|
std::queue<Cell *> toVisit;
|
||||||
|
|
||||||
|
auto visitAll = [&]() {
|
||||||
|
while (!toVisit.empty()) {
|
||||||
|
Cell *c = toVisit.front();
|
||||||
|
toVisit.pop();
|
||||||
|
|
||||||
|
if (c == nullptr) continue;
|
||||||
|
|
||||||
|
if (!_cells.contains(c)) _cells.emplace(c);
|
||||||
|
|
||||||
|
if (c->live) continue;
|
||||||
|
|
||||||
|
c->live = true;
|
||||||
|
// std::cerr << "processing c " << c << " " << static_cast<int>(c->_type) << "\n";
|
||||||
|
|
||||||
|
if (c->_type == CellType::CONS) {
|
||||||
|
ConsCell &cc = dynamic_cast<ConsCell &>(*c);
|
||||||
|
// std::cerr << "processing car " << cc._car << "\n";
|
||||||
|
toVisit.emplace(cc._car);
|
||||||
|
// std::cerr << "real car " << toVisit.back() << "\n";
|
||||||
|
// std::cerr << "processing cdr " << cc._cdr << "\n";
|
||||||
|
toVisit.emplace(cc._cdr);
|
||||||
|
// std::cerr << "real cdr " << toVisit.back() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard cl(_cells_lock);
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
{
|
||||||
|
decltype(_new_roots) new_roots;
|
||||||
|
{
|
||||||
|
decltype(_temp_cells) temp_cells;
|
||||||
|
{
|
||||||
|
std::lock_guard l(_new_roots_lock);
|
||||||
|
std::swap(new_roots, _new_roots);
|
||||||
|
std::swap(temp_cells, _temp_cells);
|
||||||
|
}
|
||||||
|
_cells.insert(temp_cells.begin(), temp_cells.end());
|
||||||
|
}
|
||||||
|
_cells_num = _cells.size();
|
||||||
|
|
||||||
|
|
||||||
|
for (auto const &r: new_roots) {
|
||||||
|
// std::cerr << "processing new " << r.first << " diff " << r.second << "\n";
|
||||||
|
if (r.second == 0) continue;
|
||||||
|
_roots[r.first] += r.second;
|
||||||
|
if (_roots[r.first] <= 0)
|
||||||
|
_roots.erase(r.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto stop = std::chrono::high_resolution_clock::now();
|
||||||
|
std::cerr << "New roots time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||||
|
|
||||||
|
assert(std::none_of(_cells.begin(), _cells.end(), [](const auto &p) { return p->live.load(); }));
|
||||||
|
|
||||||
|
start = std::chrono::high_resolution_clock::now();
|
||||||
|
for (const auto &r: _roots) {
|
||||||
|
// std::cerr << "processing r " << r.first << " diff " << r.second << "\n";
|
||||||
|
seenroots.emplace(r.first);
|
||||||
|
toVisit.emplace(r.first);
|
||||||
|
}
|
||||||
|
visitAll();
|
||||||
|
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";
|
||||||
|
|
||||||
|
{
|
||||||
|
decltype(_gc_dirty_notif_queue) dirtied;
|
||||||
|
std::unique_lock dql(_gc_dirty_notif_queue_lock);
|
||||||
|
std::swap(dirtied, _gc_dirty_notif_queue);
|
||||||
|
|
||||||
|
start = std::chrono::high_resolution_clock::now();
|
||||||
|
while (!dirtied.empty()) {
|
||||||
|
dql.unlock();
|
||||||
|
for (const auto &r: dirtied) {
|
||||||
|
// std::cerr << "processing dirty " << r << "\n";
|
||||||
|
if (seenroots.contains(r)) continue;
|
||||||
|
seenroots.emplace(r);
|
||||||
|
toVisit.emplace(r);
|
||||||
|
}
|
||||||
|
visitAll();
|
||||||
|
|
||||||
|
dirtied = {};
|
||||||
|
dql.lock();
|
||||||
|
std::swap(dirtied, _gc_dirty_notif_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop = std::chrono::high_resolution_clock::now();
|
||||||
|
std::cerr << "Dirty mark time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||||
|
|
||||||
|
assert(dql.owns_lock());
|
||||||
|
|
||||||
|
uint64_t freed = 0;
|
||||||
|
start = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
std::vector<Cell *> toremove;
|
||||||
|
for (const auto &l: _cells) {
|
||||||
|
if (!l->live) {
|
||||||
|
freed += 1;
|
||||||
|
|
||||||
|
// if (l->_type == CellType::NUMATOM) {
|
||||||
|
// std::cerr << "deleting num: " << l << "\n";
|
||||||
|
// _numatom_index.erase(dynamic_cast<NumAtomCell &>(*l)._val);
|
||||||
|
// } else if (l->_type == CellType::STRATOM) {
|
||||||
|
// std::cerr << "deleting str: " << l << "\n";
|
||||||
|
// _stratom_index.erase(dynamic_cast<StrAtomCell &>(*l)._val);
|
||||||
|
// }
|
||||||
|
|
||||||
|
assert(!_roots.contains(l));
|
||||||
|
// std::cerr << "deleting: " << l << "\n";
|
||||||
|
toremove.emplace_back(l);
|
||||||
|
delete l;
|
||||||
|
} else {
|
||||||
|
// std::cerr << "resetting num: " << l << "\n";
|
||||||
|
l->live = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &l: toremove) {
|
||||||
|
_cells.erase(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop = std::chrono::high_resolution_clock::now();
|
||||||
|
std::cerr << "Sweep time: " << std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count() << "\n";
|
||||||
|
std::cerr << "GC Freed " << freed << " cells left: " << _cells_num << " \n";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock l(_gc_done_m);
|
||||||
|
std::unique_lock l2(_gc_request_m);
|
||||||
|
_gc_done = true;
|
||||||
|
_gc_request = false;
|
||||||
|
_gc_done_cv.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,6 @@ void VM::step() {
|
|||||||
_s = s;
|
_s = s;
|
||||||
|
|
||||||
push(_s, ret);
|
push(_s, ret);
|
||||||
// gc();
|
|
||||||
} else if (poppedH == DUM) {
|
} else if (poppedH == DUM) {
|
||||||
push(_e, nullptr);
|
push(_e, nullptr);
|
||||||
} else if (poppedH == RAP) {
|
} else if (poppedH == RAP) {
|
||||||
@@ -135,41 +134,3 @@ void VM::step() {
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//void VM::gc() {
|
|
||||||
// std::function<void(ConsCell *)> visit = [&](ConsCell *c) {
|
|
||||||
// if (c == nullptr) return;
|
|
||||||
// if (c->live) return;
|
|
||||||
//
|
|
||||||
// c->live = true;
|
|
||||||
//
|
|
||||||
// if (c->_car) {
|
|
||||||
// if (c->_car->_type == CellType::CONS) visit(dynamic_cast<ConsCell *>(c->_car));
|
|
||||||
// c->_car->live = true;
|
|
||||||
// }
|
|
||||||
// if (c->_cdr) {
|
|
||||||
// if (c->_cdr->_type == CellType::CONS) visit(dynamic_cast<ConsCell *>(c->_cdr));
|
|
||||||
// c->_cdr->live = true;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// visit(_s);
|
|
||||||
// visit(_e);
|
|
||||||
// visit(_c);
|
|
||||||
// visit(_d);
|
|
||||||
//
|
|
||||||
// uint64_t freed = 0;
|
|
||||||
//
|
|
||||||
// _cells.remove_if([&](Cell *l) {
|
|
||||||
// bool ret = !l->live;
|
|
||||||
// if (ret) {
|
|
||||||
// freed += 1;
|
|
||||||
// delete l;
|
|
||||||
// } else {
|
|
||||||
// l->live = false;
|
|
||||||
// }
|
|
||||||
// return ret;
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// std::cout << "GC Freed " << freed << std::endl;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
@@ -18,6 +18,17 @@ target_link_libraries(
|
|||||||
GTest::gtest_main
|
GTest::gtest_main
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
GCTest
|
||||||
|
GCTest.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(
|
||||||
|
GCTest
|
||||||
|
vm
|
||||||
|
GTest::gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
gtest_discover_tests(VMTest)
|
gtest_discover_tests(VMTest)
|
||||||
gtest_discover_tests(VMWithParserTest)
|
gtest_discover_tests(VMWithParserTest)
|
||||||
|
gtest_discover_tests(GCTest)
|
||||||
|
|||||||
92
test/vm/GCTest.cpp
Normal file
92
test/vm/GCTest.cpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
//
|
||||||
|
// Created by Stepan Usatiuk on 26.12.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "ConsUtils.h"
|
||||||
|
#include "MemoryContext.h"
|
||||||
|
|
||||||
|
using namespace ConsUtils;
|
||||||
|
|
||||||
|
TEST(GCTest, GCTest) {
|
||||||
|
MemoryContext mc;
|
||||||
|
{
|
||||||
|
MCHandle c = cons(nullptr, nullptr);
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
append(c, makeNumCell(1));
|
||||||
|
append(c, makeNumCell(2));
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
EXPECT_EQ(val(car(c)), 1);
|
||||||
|
EXPECT_EQ(val(car(cdr(c))), 2);
|
||||||
|
}
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
EXPECT_EQ(mc.cell_count(), 0);
|
||||||
|
{
|
||||||
|
MCHandle c = cons(nullptr, nullptr);
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
push(c, makeNumCell(1));
|
||||||
|
push(c, makeNumCell(2));
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
EXPECT_EQ(val(car(c)), 2);
|
||||||
|
EXPECT_EQ(val(car(cdr(c))), 1);
|
||||||
|
}
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
EXPECT_EQ(mc.cell_count(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(GCTest, GCTestAppend) {
|
||||||
|
MemoryContext mc;
|
||||||
|
for (int i = 0; i < 25000; i++) {
|
||||||
|
MCHandle c = cons(nullptr, nullptr);
|
||||||
|
mc.request_gc();
|
||||||
|
append(c, makeNumCell(1));
|
||||||
|
mc.request_gc();
|
||||||
|
EXPECT_EQ(val(car(c)), 1);
|
||||||
|
}
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
EXPECT_EQ(mc.cell_count(), 0);
|
||||||
|
}
|
||||||
|
TEST(GCTest, GCTestPop) {
|
||||||
|
MemoryContext mc;
|
||||||
|
{
|
||||||
|
MCHandle c = cons(nullptr, nullptr);
|
||||||
|
static constexpr int test_size = 20000;
|
||||||
|
for (int i = 0; i < test_size; i++) {
|
||||||
|
mc.request_gc();
|
||||||
|
push(c, makeNumCell(i));
|
||||||
|
}
|
||||||
|
for (int i = test_size - 1; i >= 0; i--) {
|
||||||
|
mc.request_gc();
|
||||||
|
EXPECT_EQ(i, val(pop(c)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
EXPECT_EQ(mc.cell_count(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(GCTest, GCTestAppend2) {
|
||||||
|
MemoryContext mc;
|
||||||
|
MCHandle c = cons(nullptr, nullptr);
|
||||||
|
static constexpr int test_size = 2000;
|
||||||
|
for (int i = 0; i < test_size; i++) {
|
||||||
|
mc.request_gc();
|
||||||
|
append(c, makeNumCell(i));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < test_size; i++) {
|
||||||
|
mc.request_gc();
|
||||||
|
EXPECT_EQ(i, val(pop(c)));
|
||||||
|
}
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
EXPECT_EQ(mc.cell_count(), 0);
|
||||||
|
}
|
||||||
@@ -52,15 +52,19 @@ TEST(VMWithParserTest, BasicFunction) {
|
|||||||
TEST(VMWithParserTest, RecFunction) {
|
TEST(VMWithParserTest, RecFunction) {
|
||||||
std::stringstream ssin;
|
std::stringstream ssin;
|
||||||
std::stringstream ssout;
|
std::stringstream ssout;
|
||||||
{
|
|
||||||
MemoryContext mc;
|
MemoryContext mc;
|
||||||
|
{
|
||||||
VM vm(ssin, ssout);
|
VM vm(ssin, ssout);
|
||||||
Parser parser;
|
Parser parser;
|
||||||
parser.loadStr(
|
parser.loadStr(
|
||||||
"( DUM NIL LDF ( LD ( 1 . 1 ) SEL ( LD ( 1 . 1 ) LDC -1 ADD SEL ( NIL LD ( 1 . 1 ) LDC -1 ADD CONS LD ( 2 . 1 ) AP NIL LD ( 1 . 1 ) LDC -2 ADD CONS LD ( 2 . 1 ) AP ADD JOIN ) ( LDC 1 JOIN ) JOIN ) ( LDC 0 JOIN ) RET ) CONS LDF ( NIL LDC 10 CONS LD ( 1 . 1 ) AP RET ) RAP PUTNUM STOP )");
|
"( DUM NIL LDF ( LD ( 1 . 1 ) SEL ( LD ( 1 . 1 ) LDC -1 ADD SEL ( NIL LD ( 1 . 1 ) LDC -1 ADD CONS LD ( 2 . 1 ) AP NIL LD ( 1 . 1 ) LDC -2 ADD CONS LD ( 2 . 1 ) AP ADD JOIN ) ( LDC 1 JOIN ) JOIN ) ( LDC 0 JOIN ) RET ) CONS LDF ( NIL LDC 20 CONS LD ( 1 . 1 ) AP RET ) RAP PUTNUM STOP )");
|
||||||
vm.loadControl(parser.parseExpr());
|
vm.loadControl(parser.parseExpr());
|
||||||
vm.run();
|
vm.run();
|
||||||
}
|
}
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
mc.request_gc_and_wait();
|
||||||
|
EXPECT_EQ(mc.cell_count(), 0);
|
||||||
ssout.flush();
|
ssout.flush();
|
||||||
EXPECT_EQ(ssout.str(), "55");
|
EXPECT_EQ(ssout.str(), "6765");
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user