xo-interpreter: setting up for gc in interactive interpreter
This commit is contained in:
parent
37b132821f
commit
8c11c108ca
12 changed files with 154 additions and 42 deletions
|
|
@ -37,14 +37,14 @@ namespace xo {
|
|||
* pages are committed on demand.
|
||||
* Initial committment will be up to @ref incr_gc_threshold_
|
||||
**/
|
||||
std::size_t initial_nursery_z_ = 0;
|
||||
std::size_t initial_nursery_z_ = 64*1024*1024;
|
||||
/** initial size in bytes for oldest (Tenured) generation.
|
||||
* GC allocates two tenured spaces of this size.
|
||||
* This number represents reserved address space.
|
||||
* pages are committed on demand.
|
||||
* Initial committment will be up to @ref full_gc_threshold_
|
||||
**/
|
||||
std::size_t initial_tenured_z_ = 0;
|
||||
std::size_t initial_tenured_z_ = 128*1024*1024;
|
||||
/** trigger incremental GC after this many bytes allocated in nursery **/
|
||||
std::size_t incr_gc_threshold_ = 64*1024;
|
||||
/** trigger full GC after this many bytes promoted to tenured **/
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ namespace xo {
|
|||
}
|
||||
|
||||
if (nursery_size + config_.full_gc_threshold_ > tenured_size) {
|
||||
throw std::runtime_error(tostr("GC::ctor: expected nursery size + tennured gc threshold < tenured size",
|
||||
throw std::runtime_error(tostr("GC::ctor: expected nursery size + tenured gc threshold < tenured size",
|
||||
xtag("nursery-size", nursery_size),
|
||||
xtag("tenured-size", tenured_size),
|
||||
xtag("full-gc-threshold", config_.full_gc_threshold_)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "xo/alloc/IAlloc.hpp"
|
||||
#include "xo/alloc/GC.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
|
|
@ -27,8 +27,13 @@ namespace xo {
|
|||
std::string history_file = "scm_history.txt";
|
||||
/** when true enable console logging for repl internals **/
|
||||
bool debug_flag = false;
|
||||
|
||||
/** garbage collector configuration **/
|
||||
gc::Config gc_config_;
|
||||
};
|
||||
|
||||
using IAlloc = xo::gc::IAlloc;
|
||||
|
||||
public:
|
||||
~Schematika();
|
||||
|
||||
|
|
@ -51,7 +56,7 @@ namespace xo {
|
|||
void interactive_repl();
|
||||
|
||||
private:
|
||||
Schematika(const Config & cfg);
|
||||
explicit Schematika(const Config & cfg);
|
||||
|
||||
private:
|
||||
up<Impl> p_impl_;
|
||||
|
|
|
|||
|
|
@ -5,14 +5,19 @@
|
|||
#include "VsmInstr.hpp"
|
||||
#include "SchematikaError.hpp"
|
||||
#include "xo/expression/Expression.hpp"
|
||||
#include "xo/object/ObjectConverter.hpp"
|
||||
#include "xo/alloc/Object.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
/** @brief state that may be shared across VirtualSchematikaMachine instances **/
|
||||
struct VirtualSchematikaMachineFlyweight {
|
||||
explicit VirtualSchematikaMachineFlyweight(gc::IAlloc * mm);
|
||||
|
||||
/** memory allocator for interpreter operation. **/
|
||||
gc::IAlloc * object_mm_ = nullptr;
|
||||
/** convert TaggedPtr->Object **/
|
||||
ObjectConverter object_converter_;
|
||||
xo::obj::ObjectConverter object_converter_;
|
||||
};
|
||||
|
||||
/** @class VirtualSchematikaMachine
|
||||
|
|
@ -21,7 +26,10 @@ namespace xo {
|
|||
**/
|
||||
class VirtualSchematikaMachine {
|
||||
public:
|
||||
VirtualSchematikaMachine();
|
||||
using IAlloc = xo::gc::IAlloc;
|
||||
|
||||
public:
|
||||
VirtualSchematikaMachine(IAlloc * mm);
|
||||
|
||||
/** evaluate expression @p expr.
|
||||
* borrows calling thread until completion
|
||||
|
|
@ -37,10 +45,16 @@ namespace xo {
|
|||
**/
|
||||
void run();
|
||||
|
||||
/** execute vsm instruction @p pc
|
||||
/** execute vsm instruction in program counter.
|
||||
* Note: may possibly be able to replace with just opcode
|
||||
**/
|
||||
void execute_one(const VsmInstr * pc);
|
||||
void execute_one();
|
||||
|
||||
/** interpret literal constant expression **/
|
||||
void constant_op();
|
||||
|
||||
/** goto error state with message @p err **/
|
||||
void report_error(const std::string & err);
|
||||
|
||||
/** implementation class; contains instruction implementations **/
|
||||
friend class VsmOps;
|
||||
|
|
@ -66,7 +80,7 @@ namespace xo {
|
|||
const VsmInstr * cont_ = nullptr;
|
||||
|
||||
/** possibly-shared data **/
|
||||
VirtualSchemtikaMachineFlyweight flyweight_;
|
||||
VirtualSchematikaMachineFlyweight flyweight_;
|
||||
};
|
||||
|
||||
} /*namespace scm*/
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ set(SELF_SRCS
|
|||
find_package(Threads REQUIRED)
|
||||
|
||||
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||
xo_dependency(${SELF_LIB} xo_alloc)
|
||||
xo_dependency(${SELF_LIB} xo_object)
|
||||
xo_dependency(${SELF_LIB} xo_expression)
|
||||
xo_dependency(${SELF_LIB} xo_reader)
|
||||
xo_external_target_dependency(${SELF_LIB} replxx replxx::replxx)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#include <ostream>
|
||||
|
||||
namespace xo {
|
||||
using xo::gc::IAlloc;
|
||||
using xo::gc::GC;
|
||||
using xo::print::ppconfig;
|
||||
using xo::print::ppstate_standalone;
|
||||
using replxx::Replxx;
|
||||
|
|
@ -19,7 +21,14 @@ namespace xo {
|
|||
|
||||
class Schematika::Impl {
|
||||
public:
|
||||
Impl(const Config & config) : config_{config} {}
|
||||
/** note: choosing to have Schemtika::Impl
|
||||
* rather than VirtualSchematikaMachine to own allocator
|
||||
* to preserve option to share it
|
||||
**/
|
||||
Impl(const Config & config, up<IAlloc> mm) : config_{config}, vsm_{mm.get()}, mm_{std::move(mm)} {}
|
||||
|
||||
/** create instance + allocator **/
|
||||
static up<Impl> make(const Config & cfg);
|
||||
|
||||
/** borrow calling thread to run interactive read-eval-print loop;
|
||||
* input from stdin, output to stdout.
|
||||
|
|
@ -38,8 +47,21 @@ namespace xo {
|
|||
Config config_;
|
||||
/** schematika interpreter **/
|
||||
VirtualSchematikaMachine vsm_;
|
||||
/** ownership for memory allocator / garbage collector;
|
||||
* @ref vsm_ holds naked pointer, so this could in principle be nullptr
|
||||
* in case want to maintain allocator ownership from outside.
|
||||
**/
|
||||
up<IAlloc> mm_;
|
||||
};
|
||||
|
||||
up<Schematika::Impl>
|
||||
Schematika::Impl::make(const Config & cfg)
|
||||
{
|
||||
up<IAlloc> mm = GC::make(cfg.gc_config_);
|
||||
|
||||
return std::make_unique<Impl>(cfg, std::move(mm));
|
||||
}
|
||||
|
||||
void
|
||||
Schematika::Impl::welcome(std::ostream & os)
|
||||
{
|
||||
|
|
@ -106,7 +128,8 @@ namespace xo {
|
|||
// rx.bind_key_internal(Replxx::KEY::control('p'), "history_previous");
|
||||
// rx.bind_key_internal(Replxx::KEY::control('n'), "history_next");
|
||||
|
||||
reader rdr(config_.debug_flag);
|
||||
//reader rdr(config_.debug_flag);
|
||||
reader rdr(true);
|
||||
rdr.begin_interactive_session();
|
||||
|
||||
string input_str;
|
||||
|
|
@ -168,7 +191,8 @@ namespace xo {
|
|||
/* print value */
|
||||
|
||||
cout << "scm result:" << endl;
|
||||
pps.pretty(value);
|
||||
cout << value << endl;
|
||||
//pps.pretty(value);
|
||||
}
|
||||
|
||||
} else if (error.is_error()) {
|
||||
|
|
@ -207,8 +231,7 @@ namespace xo {
|
|||
|
||||
// ----- Schematika -----
|
||||
|
||||
Schematika::Schematika(const Config & cfg) :
|
||||
p_impl_{new Impl(cfg)}
|
||||
Schematika::Schematika(const Config & cfg) : p_impl_{std::move(Impl::make(cfg))}
|
||||
{}
|
||||
|
||||
Schematika::~Schematika()
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
/** @file VirtualSchematikaMachine.cpp **/
|
||||
|
||||
#include "VirtualSchematikaMachine.hpp"
|
||||
|
||||
#include "VsmInstr.hpp"
|
||||
#include "xo/expression/ConstantInterface.hpp"
|
||||
|
||||
/** continue after completing a VSM instruction;
|
||||
* achieve by jumping to continuation.
|
||||
**/
|
||||
#define VSM_CONTINUE() this->pc_ = this->cont_; return;
|
||||
|
||||
/** report error and terminate VSM execution
|
||||
**/
|
||||
#define VSM_ERROR(msg) report_error(msg); return;
|
||||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
|
|
@ -31,7 +34,15 @@ namespace xo {
|
|||
VsmInstr
|
||||
VsmOps::eval_op{VsmInstr::Opcode::eval, "eval"};
|
||||
|
||||
VirtualSchematikaMachine::VirtualSchematikaMachine()
|
||||
// ----- VirtualSchematikaMachineFlyweight -----
|
||||
|
||||
VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm) :
|
||||
object_mm_{mm}
|
||||
{}
|
||||
|
||||
// ----- VirtualSchematikaMachine -----
|
||||
|
||||
VirtualSchematikaMachine::VirtualSchematikaMachine(gc::IAlloc * mm) : flyweight_{mm}
|
||||
{}
|
||||
|
||||
std::pair<gp<Object>,
|
||||
|
|
@ -50,16 +61,16 @@ namespace xo {
|
|||
void
|
||||
VirtualSchematikaMachine::run()
|
||||
{
|
||||
for (const VsmInstr * pc = pc_; pc; pc = pc_)
|
||||
this->execute_one(pc);
|
||||
while(pc_)
|
||||
this->execute_one();
|
||||
}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::execute_one(const VsmInstr * instr)
|
||||
VirtualSchematikaMachine::execute_one()
|
||||
{
|
||||
using Opcode = VsmInstr::Opcode;
|
||||
|
||||
switch (instr->opcode()) {
|
||||
switch (pc_->opcode()) {
|
||||
|
||||
case Opcode::halt:
|
||||
{
|
||||
|
|
@ -104,10 +115,40 @@ namespace xo {
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::report_error(const std::string & err)
|
||||
{
|
||||
/* error short-circuits vsm operation */
|
||||
|
||||
this->pc_ = nullptr;
|
||||
this->value_ = nullptr;
|
||||
this->error_ = SchematikaError(err);
|
||||
this->cont_ = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
VirtualSchematikaMachine::constant_op()
|
||||
{
|
||||
this->value_ = expr_->value_tp();
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
using xo::scm::ConstantInterface;
|
||||
|
||||
bp<ConstantInterface> expr = ConstantInterface::from(expr_);
|
||||
|
||||
assert(expr);
|
||||
|
||||
this->value_ = flyweight_.object_converter_.tp_to_object(flyweight_.object_mm_,
|
||||
expr->value_tp(),
|
||||
false);
|
||||
if (this->value_.ptr()) {
|
||||
log && log("got object: ", xtag("value", value_));
|
||||
|
||||
VSM_CONTINUE();
|
||||
} else {
|
||||
VSM_ERROR(tostr("constant_op: unable to convert native value to object",
|
||||
xtag("id", expr->value_tp().td()->id()),
|
||||
xtag("short_name", expr->value_tp().td()->short_name())));
|
||||
}
|
||||
}
|
||||
|
||||
} /*namespace scm*/
|
||||
|
|
|
|||
|
|
@ -12,11 +12,15 @@
|
|||
|
||||
namespace xo {
|
||||
namespace obj {
|
||||
/* Convert between xo::reflect::TaggedPtr and xo::Object for
|
||||
* a particular wrapped c++ type
|
||||
*/
|
||||
struct Converter {
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using ConvertToObjectFn = gp<Object> (*)(gc::IAlloc *, const TaggedPtr &);
|
||||
|
||||
public:
|
||||
Converter() = default;
|
||||
explicit Converter(ConvertToObjectFn f) : cvt_to_object_{f} {}
|
||||
|
||||
/** convert tagged pointer @p tp to new object,
|
||||
|
|
@ -25,7 +29,7 @@ namespace xo {
|
|||
* Conversion will typically be for some specific type;
|
||||
* see @ref ObjectConverter
|
||||
**/
|
||||
ConvertToObjectFn cvt_to_object_;
|
||||
ConvertToObjectFn cvt_to_object_ = nullptr;
|
||||
};
|
||||
|
||||
/** @class ObjectConverter
|
||||
|
|
@ -48,6 +52,7 @@ namespace xo {
|
|||
**/
|
||||
class ObjectConverter {
|
||||
public:
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using IAlloc = xo::gc::IAlloc;
|
||||
|
||||
/** sets up standard conversions **/
|
||||
|
|
@ -57,6 +62,12 @@ namespace xo {
|
|||
template <typename T>
|
||||
void establish_conversion(Converter::ConvertToObjectFn fn);
|
||||
|
||||
/** convert tagged poitner @p tp to object. allocates memory only from @p mm.
|
||||
* return nullptr if no converter available and @p throw_flag not set.
|
||||
* throw exception if no converter available and @p throw_flag set.
|
||||
**/
|
||||
gp<Object> tp_to_object(IAlloc * mm, const TaggedPtr & tp, bool throw_flag);
|
||||
|
||||
/** convert @p x to object.
|
||||
* return converted object; if allocated, using only memory from @p mm.
|
||||
* return nullptr if no converter available, and @p throw_flag not set.
|
||||
|
|
@ -92,19 +103,8 @@ namespace xo {
|
|||
using xo::reflect::TaggedPtr;
|
||||
|
||||
TaggedPtr x_tp = Reflect::make_tp(&x);
|
||||
Converter * cvt = cvt_.lookup(x_tp.td());
|
||||
|
||||
if (cvt) {
|
||||
return (cvt->cvt_to_object_)(mm, x_tp);
|
||||
} else {
|
||||
if (throw_flag) {
|
||||
throw std::runtime_error(tostr("no object-converter available for instance of type",
|
||||
xtag("id", x_tp.td()->id()),
|
||||
xtag("name", x_tp.td()->short_name())));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
return tp_to_object(mm, x_tp, throw_flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,28 @@ namespace xo {
|
|||
ObjectConverter::ObjectConverter()
|
||||
{
|
||||
this->establish_conversion<std::int32_t>(&int_to_object<std::int32_t>);
|
||||
this->establish_conversion<std::int64_t>(&int_to_object<std::int32_t>);
|
||||
}
|
||||
|
||||
gp<Object>
|
||||
ObjectConverter::tp_to_object(IAlloc * mm, const TaggedPtr & x_tp, bool throw_flag)
|
||||
{
|
||||
using xo::reflect::Reflect;
|
||||
using xo::reflect::TaggedPtr;
|
||||
|
||||
const Converter * cvt = cvt_.lookup(x_tp.td());
|
||||
|
||||
if (cvt) {
|
||||
return (cvt->cvt_to_object_)(mm, x_tp);
|
||||
} else {
|
||||
if (throw_flag) {
|
||||
throw std::runtime_error(tostr("no object-converter available for instance of type",
|
||||
xtag("id", x_tp.td()->id()),
|
||||
xtag("name", x_tp.td()->short_name())));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
namespace xo {
|
||||
namespace scm {
|
||||
reader::reader(bool debug_flag)
|
||||
: parser_{debug_flag}
|
||||
reader::reader(bool debug_flag) :
|
||||
tokenizer_{debug_flag}, parser_{debug_flag}
|
||||
{}
|
||||
|
||||
void
|
||||
|
|
@ -118,7 +118,7 @@ namespace xo {
|
|||
}
|
||||
}
|
||||
|
||||
/* control here: eithero
|
||||
/* control here: either
|
||||
* 1. input.empty (perhaps ate some whitespace, ok)
|
||||
* 2. missing or incomplete token (ok unless eof)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -177,14 +177,18 @@ namespace xo {
|
|||
++eol;
|
||||
|
||||
this->current_line_ = span_type(sol, eol);
|
||||
this->current_pos_ = 0;
|
||||
|
||||
log && log(xtag("current_line", print::printspan(current_line_)));
|
||||
log && log(xtag("current_line", print::printspan(current_line_)),
|
||||
xtag("current_pos", current_pos_));
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
const CharT *
|
||||
input_state<CharT>::skip_leading_whitespace(const span_type & input)
|
||||
{
|
||||
scope log(XO_DEBUG(debug_flag_));
|
||||
|
||||
const CharT * ix = input.lo();
|
||||
|
||||
if (this->current_line().is_null()) {
|
||||
|
|
|
|||
|
|
@ -166,7 +166,10 @@ namespace xo {
|
|||
/** @defgroup tokenizer-instance-vars tokenizer instance variables **/
|
||||
///@{
|
||||
|
||||
/** track input state (line#,pos,..) for error messages **/
|
||||
/** track input state (line#,pos,..) for error messages.
|
||||
* There's an ordering problem here:
|
||||
* 1. input_state_.skip_leading_whitespace() advances current line when it sees newline.
|
||||
**/
|
||||
input_state_type input_state_;
|
||||
/** Accumulate partial token here.
|
||||
* This will happen if input sent to @ref tokenizer::scan
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue