From fb5c43dc856e11e30ef752aa96935b864b2fb471 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 24 Nov 2025 18:01:24 -0500 Subject: [PATCH] xo-interpreter: handle define-expressions. --- xo-alloc/include/xo/alloc/Object.hpp | 2 + xo-interpreter/example/replxx/replxx.cpp | 2 + .../include/xo/interpreter/CVector.hpp | 50 ++++++ .../xo/interpreter/ExpressionBoxed.hpp | 43 +++++ .../include/xo/interpreter/GlobalEnv.hpp | 2 +- .../include/xo/interpreter/LocalEnv.hpp | 31 +--- .../include/xo/interpreter/Schematika.hpp | 3 + .../interpreter/VirtualSchematikaMachine.hpp | 48 +++++- .../include/xo/interpreter/VsmInstr.hpp | 9 ++ .../include/xo/interpreter/VsmStackFrame.hpp | 75 +++++++++ xo-interpreter/src/interpreter/CMakeLists.txt | 2 + .../src/interpreter/ExpressionBoxed.cpp | 59 +++++++ xo-interpreter/src/interpreter/LocalEnv.cpp | 2 +- xo-interpreter/src/interpreter/Schematika.cpp | 4 +- .../interpreter/VirtualSchematikaMachine.cpp | 96 ++++++++++-- .../src/interpreter/VsmStackFrame.cpp | 148 ++++++++++++++++++ 16 files changed, 523 insertions(+), 53 deletions(-) create mode 100644 xo-interpreter/include/xo/interpreter/CVector.hpp create mode 100644 xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp create mode 100644 xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp create mode 100644 xo-interpreter/src/interpreter/ExpressionBoxed.cpp create mode 100644 xo-interpreter/src/interpreter/VsmStackFrame.cpp diff --git a/xo-alloc/include/xo/alloc/Object.hpp b/xo-alloc/include/xo/alloc/Object.hpp index f16dd6ac..73a60edd 100644 --- a/xo-alloc/include/xo/alloc/Object.hpp +++ b/xo-alloc/include/xo/alloc/Object.hpp @@ -97,6 +97,8 @@ namespace xo { /** memory allocator for objects. Likely this will be a GC instance, * but simple arena also supported. + * + * Load-bearing for .assign_member() **/ static gc::IAlloc * mm; diff --git a/xo-interpreter/example/replxx/replxx.cpp b/xo-interpreter/example/replxx/replxx.cpp index d1d134c0..5d9eb9ab 100644 --- a/xo-interpreter/example/replxx/replxx.cpp +++ b/xo-interpreter/example/replxx/replxx.cpp @@ -5,9 +5,11 @@ int main(int argc, char ** argv) { + using xo::log_level; using xo::scm::Schematika; Schematika::Config cfg; + cfg.vsm_log_level_ = log_level::verbose; Schematika scm = Schematika::make(cfg); scm.interactive_repl(); diff --git a/xo-interpreter/include/xo/interpreter/CVector.hpp b/xo-interpreter/include/xo/interpreter/CVector.hpp new file mode 100644 index 00000000..9dc74810 --- /dev/null +++ b/xo-interpreter/include/xo/interpreter/CVector.hpp @@ -0,0 +1,50 @@ +/** @file CVector.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include "xo/alloc/IAlloc.hpp" +#include + +namespace xo { + namespace scm { + /** gc-only vector. + * Used in both LocalEnv and VsmStackFrame + **/ + template + class CVector { + public: + using value_type = ElementType; + + public: + CVector(gc::IAlloc * mm, std::size_t n) + : n_{n}, v_{nullptr} + { + if (n_ > 0) { + std::byte * mem = mm->alloc(n_ * sizeof(ElementType)); + this->v_ = new (mem) ElementType[n]; + } + } + + std::size_t size() const { return n_; } + + ElementType operator[](std::size_t i) const { return v_[i]; } + ElementType & operator[](std::size_t i) { return v_[i]; } + + friend class LocalEnv; + friend class VsmStackFrame; + + private: + /** number of elements in @ref v_ **/ + std::size_t n_ = 0; + /** contiguous array of pointers **/ + ElementType * v_ = nullptr; + }; + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end CVector.hpp */ diff --git a/xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp b/xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp new file mode 100644 index 00000000..ebc8b1ec --- /dev/null +++ b/xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp @@ -0,0 +1,43 @@ +/** @file ExpressionBoxed.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include "xo/alloc/Object.hpp" +#include "xo/expression/Expression.hpp" + +namespace xo { + namespace scm { + /** @class ExpressionBoxed + * @brief xo::scm::Expression, adapted to xo::Object interface + **/ + class ExpressionBoxed : public Object { + public: + explicit ExpressionBoxed(bp c); + + /** create boxed version of @p c, using allocator @p mm **/ + static gp make(gc::IAlloc * mm, + bp c); + + const rp & contents() const { return contents_; } + + // inherited from Object + virtual TaggedPtr self_tp() const final override; + virtual void display(std::ostream & os) const final override; + virtual std::size_t _shallow_size() const final override; + virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; + virtual std::size_t _forward_children(gc::IAlloc * /*gc*/) final override; + + private: + /** reference-counted Expression pointer + * + * NOTE correctness requires finalization support in xo::gc::GC + **/ + rp contents_; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ExpressionBoxed.hpp */ diff --git a/xo-interpreter/include/xo/interpreter/GlobalEnv.hpp b/xo-interpreter/include/xo/interpreter/GlobalEnv.hpp index e8998fea..39c7e66e 100644 --- a/xo-interpreter/include/xo/interpreter/GlobalEnv.hpp +++ b/xo-interpreter/include/xo/interpreter/GlobalEnv.hpp @@ -35,7 +35,7 @@ namespace xo { virtual void display(std::ostream & os) const final override; virtual std::size_t _shallow_size() const final override; virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; - virtual std::size_t _forward_children(gc::IAlloc * /*gc*/) final override; + virtual std::size_t _forward_children(gc::IAlloc * mm) final override; private: GlobalEnv(const GlobalEnv & x); diff --git a/xo-interpreter/include/xo/interpreter/LocalEnv.hpp b/xo-interpreter/include/xo/interpreter/LocalEnv.hpp index 8cd81b57..41ea2310 100644 --- a/xo-interpreter/include/xo/interpreter/LocalEnv.hpp +++ b/xo-interpreter/include/xo/interpreter/LocalEnv.hpp @@ -1,6 +1,7 @@ /** @file LocalEnv.hpp **/ #include "Env.hpp" +#include "CVector.hpp" #include "xo/alloc/IAlloc.hpp" #include "xo/expression/LocalSymtab.hpp" #include @@ -8,36 +9,6 @@ namespace xo { namespace scm { - /** gc-only vector - **/ - template - class CVector { - public: - using value_type = ElementType; - - public: - CVector(gc::IAlloc * mm, std::size_t n) - : n_{n}, v_{nullptr} - { - if (n_ > 0) { - std::byte * mem = mm->alloc(n_ * sizeof(ElementType)); - this->v_ = new (mem) ElementType[n]; - } - } - - std::size_t size() const { return n_; } - - ElementType operator[](std::size_t i) const { return v_[i]; } - ElementType & operator[](std::size_t i) { return v_[i]; } - - friend class LocalEnv; - private: - /** number of elements in @ref v_ **/ - std::size_t n_ = 0; - /** contiguous array of pointers **/ - ElementType * v_ = nullptr; - }; - /** @class LocalEnv * @brief Represent a single runtime stack frame for a Schematika function * diff --git a/xo-interpreter/include/xo/interpreter/Schematika.hpp b/xo-interpreter/include/xo/interpreter/Schematika.hpp index e53c4459..0c02d974 100644 --- a/xo-interpreter/include/xo/interpreter/Schematika.hpp +++ b/xo-interpreter/include/xo/interpreter/Schematika.hpp @@ -30,6 +30,9 @@ namespace xo { /** garbage collector configuration **/ gc::Config gc_config_; + + /** control schematika vsm logging **/ + log_level vsm_log_level_; }; using IAlloc = xo::gc::IAlloc; diff --git a/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp b/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp index 9df2755f..9518fd47 100644 --- a/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp +++ b/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp @@ -3,6 +3,7 @@ #pragma once #include "VsmInstr.hpp" +#include "VsmStackFrame.hpp" #include "SchematikaError.hpp" #include "Env.hpp" #include "xo/expression/Expression.hpp" @@ -14,7 +15,8 @@ namespace xo { /** @brief state that may be shared across VirtualSchematikaMachine instances **/ struct VirtualSchematikaMachineFlyweight { explicit VirtualSchematikaMachineFlyweight(gc::IAlloc * mm, - gp env); + gp env, + log_level log_level); /** memory allocator for interpreter operation. **/ gc::IAlloc * object_mm_ = nullptr; @@ -22,6 +24,8 @@ namespace xo { gp toplevel_env_; /** convert TaggedPtr->Object **/ xo::obj::ObjectConverter object_converter_; + /** control logging level. higher values -> more logging **/ + log_level log_level_; }; /** @class VirtualSchematikaMachine @@ -33,7 +37,7 @@ namespace xo { using IAlloc = xo::gc::IAlloc; public: - VirtualSchematikaMachine(IAlloc * mm, gp toplevel_env); + VirtualSchematikaMachine(IAlloc * mm, gp toplevel_env, log_level log_level); ~VirtualSchematikaMachine(); /** evaluate expression @p expr. @@ -64,12 +68,25 @@ namespace xo { /** execute vsm instruction in program counter. * Note: may possibly be able to replace with just opcode + * + * Registers: + * - expr_ input, caller saves + * - env_ input, caller saves + * - cont_ input, caller saves + * - value_ output + * - error_ output **/ void execute_one(); /** interpret literal constant expression **/ void eval_constant_op(); + /** interpret define expression **/ + void eval_define_op(); + + /** continue after establishing value fo rhs of define exprsssion **/ + void do_defexpr_assign_op(); + /** goto error state with message @p err **/ void report_error(const std::string & err); @@ -82,19 +99,38 @@ namespace xo { **/ const VsmInstr * pc_ = nullptr; - /** expression **/ + /** register to hold Schematika expression to drive @ref execute_one. + * + * caller saves! + **/ rp expr_; - /** holds bindings for all schematika variables **/ + /** holds bindings for all schematika variables, to drive @ref execute_one. + * execute_one will not save this + * + * caller saves! + **/ gp env_; - /** non-error result value from eval() / apply() **/ + /** vsm stack. callee saves! + **/ + gp stack_; + + /** non-error result value from eval() / apply() + * + * output register: caller must save + **/ gp value_; - /** error result value from eval() / apply() **/ + /** error result value from eval() / apply() + * + * output regisetr: caller must save + **/ SchematikaError error_; /** continuation * (Perhaps replace with VsmInstr::Opcode ?) + * + * input register: callee saves! **/ const VsmInstr * cont_ = nullptr; diff --git a/xo-interpreter/include/xo/interpreter/VsmInstr.hpp b/xo-interpreter/include/xo/interpreter/VsmInstr.hpp index 6bf350af..2eab625b 100644 --- a/xo-interpreter/include/xo/interpreter/VsmInstr.hpp +++ b/xo-interpreter/include/xo/interpreter/VsmInstr.hpp @@ -25,6 +25,15 @@ namespace xo { **/ eval, + /** assign to variable + continue + * + * stack: frame with: + * [0] lhs : variable to assign + * [1] cont : continuation after assignment + * ... maybe other vsm state that must be saved + **/ + defexpr_assign, + N_Opcode }; diff --git a/xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp b/xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp new file mode 100644 index 00000000..cd166e0b --- /dev/null +++ b/xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp @@ -0,0 +1,75 @@ +/** @file VsmStackFrame.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include "VsmInstr.hpp" +#include "CVector.hpp" +#include "xo/alloc/Object.hpp" + +namespace xo { + namespace scm { + /** @class VsmStackFrame + * @brief Virtual Schematika Machine stack frame + * + * Intending to use the "cheney on the MTA" strategy, + * i.e. allocate frames using GC's bump allocator. + * + * Parallels LocalEnv, but VSM implementation isn't reflected + **/ + class VsmStackFrame : public Object { + public: + VsmStackFrame(gc::IAlloc * mm, gp p, std::size_t n, const VsmInstr * cont); + +#ifdef NOT_YET + /** create frame using allocator @p mm, + * with parent @p p and exactly @p n_slot object pointers. + **/ + static gp make(gc::IAlloc * mm, + gp p, + const VsmInstr * cont, + std::size_t n_slot); +#endif + + /** create new stack frame using allocator @p mm, + * with parent frame @p p; new frame contains values @p s0, @p s1 + **/ + static gp push1(gc::IAlloc * mm, + gp p, + gp s0, + const VsmInstr * cont); + + + /** reflect VsmStackFrame object representation **/ + static void reflect_self(); + + gp parent() const { return parent_; } + std::size_t size() const { return slot_v_.size(); } + const VsmInstr * continuation() const { return cont_; } + + gp operator[](std::size_t i) const { return slot_v_[i]; } + gp & operator[](std::size_t i) { return slot_v_[i]; } + + // inherited from Object.. + virtual TaggedPtr self_tp() const final override; + virtual void display(std::ostream & os) const final override; + virtual std::size_t _shallow_size() const final override; + virtual Object * _shallow_copy(gc::IAlloc *) const final override; + virtual std::size_t _forward_children(gc::IAlloc *) final override; + + private: + /** parent stack frame **/ + gp parent_; + + /** stored state **/ + CVector> slot_v_; + + /** proceed to this continuation when popping this frame **/ + const VsmInstr * cont_ = nullptr; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end VsmStackFrame.hpp */ diff --git a/xo-interpreter/src/interpreter/CMakeLists.txt b/xo-interpreter/src/interpreter/CMakeLists.txt index ca2dc98d..a483676c 100644 --- a/xo-interpreter/src/interpreter/CMakeLists.txt +++ b/xo-interpreter/src/interpreter/CMakeLists.txt @@ -8,6 +8,8 @@ set(SELF_SRCS GlobalEnv.cpp VirtualSchematikaMachine.cpp VsmInstr.cpp + VsmStackFrame.cpp + ExpressionBoxed.cpp ) find_package(Threads REQUIRED) diff --git a/xo-interpreter/src/interpreter/ExpressionBoxed.cpp b/xo-interpreter/src/interpreter/ExpressionBoxed.cpp new file mode 100644 index 00000000..2d72ef33 --- /dev/null +++ b/xo-interpreter/src/interpreter/ExpressionBoxed.cpp @@ -0,0 +1,59 @@ +/** @file ExpressionBoxed.cpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#include "ExpressionBoxed.hpp" +#include "xo/reflect/Reflect.hpp" + +namespace xo { + using xo::reflect::Reflect; + using xo::reflect::TaggedPtr; + + namespace scm { + ExpressionBoxed::ExpressionBoxed(bp c) : contents_{c.promote()} + {} + + gp + ExpressionBoxed::make(gc::IAlloc * mm, + bp c) + { + return new (MMPtr(mm)) ExpressionBoxed(c); + } + + + TaggedPtr + ExpressionBoxed::self_tp() const + { + return Reflect::make_tp(const_cast(this)); + } + + void + ExpressionBoxed::display(std::ostream & os) const + { + os << contents_; + } + + std::size_t + ExpressionBoxed::_shallow_size() const + { + return sizeof(ExpressionBoxed); + } + + Object * + ExpressionBoxed::_shallow_copy(gc::IAlloc * mm) const + { + Cpof cpof(mm, this); + + return new (cpof) ExpressionBoxed(*this); + } + + std::size_t + ExpressionBoxed::_forward_children(gc::IAlloc *) + { + return _shallow_size(); + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end ExpressionBoxed.cpp */ diff --git a/xo-interpreter/src/interpreter/LocalEnv.cpp b/xo-interpreter/src/interpreter/LocalEnv.cpp index c208c22b..ab43ffb4 100644 --- a/xo-interpreter/src/interpreter/LocalEnv.cpp +++ b/xo-interpreter/src/interpreter/LocalEnv.cpp @@ -101,7 +101,7 @@ namespace xo { { Cpof cpof(mm, this); - size_t z = size(); + size_t z = this->size(); LocalEnv * copy = new (cpof) LocalEnv(cpof.mm_, parent_, symtab_, z); diff --git a/xo-interpreter/src/interpreter/Schematika.cpp b/xo-interpreter/src/interpreter/Schematika.cpp index 073064da..13c717f2 100644 --- a/xo-interpreter/src/interpreter/Schematika.cpp +++ b/xo-interpreter/src/interpreter/Schematika.cpp @@ -28,7 +28,9 @@ namespace xo { * to preserve option to share it **/ Impl(const Config & config, up mm, gp toplevel_env) : - config_{config}, vsm_{mm.get(), toplevel_env}, mm_{std::move(mm)} {} + config_{config}, + vsm_{mm.get(), toplevel_env, config.vsm_log_level_}, + mm_{std::move(mm)} {} /** create instance + allocator **/ static up make(const Config & cfg); diff --git a/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp b/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp index 64b29b5a..59d202e1 100644 --- a/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp +++ b/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp @@ -2,7 +2,10 @@ #include "VirtualSchematikaMachine.hpp" #include "VsmInstr.hpp" +#include "ExpressionBoxed.hpp" #include "xo/expression/ConstantInterface.hpp" +#include "xo/expression/DefineExpr.hpp" +#include "xo/expression/Variable.hpp" #include "xo/alloc/GC.hpp" /** continue after completing a VSM instruction; @@ -14,6 +17,8 @@ **/ #define VSM_ERROR(msg) report_error(msg); return; + + namespace xo { using xo::gc::GC; @@ -29,6 +34,12 @@ namespace xo { * - expression in register @ref expr_ **/ static VsmInstr eval_op; + + /** assign variable after evaluating rhs of a define-expression + * - opcode is Opcode::defexpr_assign + * - top stack frame contains {lhs, cont} + */ + static VsmInstr defexpr_assign_op; }; VsmInstr @@ -37,18 +48,27 @@ namespace xo { VsmInstr VsmOps::eval_op{VsmInstr::Opcode::eval, "eval"}; + VsmInstr + VsmOps::defexpr_assign_op{VsmInstr::Opcode::defexpr_assign, "defexpr-assign"}; + // ----- VirtualSchematikaMachineFlyweight ----- VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm, - gp env) : + gp env, + log_level ll) : object_mm_{mm}, - toplevel_env_{env} + toplevel_env_{env}, + log_level_{ll} {} // ----- VirtualSchematikaMachine ----- - VirtualSchematikaMachine::VirtualSchematikaMachine(gc::IAlloc * mm, gp env) : flyweight_{mm, env} + VirtualSchematikaMachine::VirtualSchematikaMachine(gc::IAlloc * mm, + gp env, + log_level ll) : flyweight_{mm, env, ll} { + this->env_ = env; + // gc roots gc::GC * gc = GC::from(mm); @@ -90,10 +110,13 @@ namespace xo { SchematikaError> VirtualSchematikaMachine::eval(bp expr, gp env) { - this->pc_ = &VsmOps::eval_op; - this->expr_ = expr.promote(); - this->env_ = env; - this->cont_ = &VsmOps::halt_op; + this->pc_ = &VsmOps::eval_op; + this->expr_ = expr.promote(); + this->env_ = env; + this->stack_ = nullptr; + this->value_ = nullptr; + this->error_ = SchematikaError(); + this->cont_ = &VsmOps::halt_op; this->run(); @@ -110,6 +133,9 @@ namespace xo { void VirtualSchematikaMachine::execute_one() { + scope log(XO_DEBUG(true)); + log && log("stack", stack_); + using Opcode = VsmInstr::Opcode; switch (pc_->opcode()) { @@ -123,6 +149,8 @@ namespace xo { case Opcode::eval: { + log && log("eval"); + /* generally speaking: opcode will be 1:1 with extypes */ switch (expr_->extype()) { @@ -130,9 +158,14 @@ namespace xo { this->eval_constant_op(); break; + + case exprtype::define: + this->eval_define_op(); + break; + case exprtype::invalid: case exprtype::primitive: - case exprtype::define: + case exprtype::assign: case exprtype::apply: case exprtype::lambda: @@ -151,6 +184,10 @@ namespace xo { } break; + case Opcode::defexpr_assign: + this->do_defexpr_assign_op(); + break; + case Opcode::N_Opcode: assert(false); break; @@ -197,29 +234,60 @@ namespace xo { // placeholder: primitive_op -#ifdef NOT_YET void - VirtualSchematikaMachine::define_op() + VirtualSchematikaMachine::eval_define_op() { using xo::scm::DefineExpr; + scope log(XO_DEBUG(true)); + + auto mm = flyweight_.object_mm_; + bp expr = DefineExpr::from(expr_); assert(expr); + assert(env_.get()); + + // note: expecting nested define to have expanded iteself into + // applying a lambda // note: establish lhs_var first, to allow for recursion, for example: // def fact(n: i64) { if (n == 0) then 1; else n * fact(n-1); } /** remembers promised variable type **/ - env_->establish_var(expr->lhs_variable()); + this->env_->establish_var(expr->lhs_variable()); + /** must promote rp -> gp **/ + gp lhs_0 = ExpressionBoxed::make(mm, expr->lhs_variable()); + this->pc_ = &VsmOps::eval_op; + this->expr_ = expr->rhs(); - /* lhs_var - * rhs + /* when control arrives at .cont_, will have: + * .value_ -> result of evaluating expr->rhs() */ + + this->stack_ = VsmStackFrame::push1(mm, this->stack_, lhs_0, cont_); + this->cont_ = &VsmOps::defexpr_assign_op; + } + + void + VirtualSchematikaMachine::do_defexpr_assign_op() + { + /* + * - value: contains result of evaluating rhs of define + * - stack: top frame has 1 slot, holds variable to receive assignment + */ + assert(value_.get()); + assert(stack_.get()); + + gp sp0 = this->stack_; + + //this->value_ = this->value_; // preserve value from rhs of defexpr + + this->stack_ = sp0->parent(); + this->pc_ = this->cont_ = sp0->continuation(); } -#endif } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-interpreter/src/interpreter/VsmStackFrame.cpp b/xo-interpreter/src/interpreter/VsmStackFrame.cpp new file mode 100644 index 00000000..e12bf6b9 --- /dev/null +++ b/xo-interpreter/src/interpreter/VsmStackFrame.cpp @@ -0,0 +1,148 @@ +/** @file VsmStackFrame.cpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#include "VsmStackFrame.hpp" +#include "xo/reflect/Reflect.hpp" +#include "xo/reflect/StructReflector.hpp" + +namespace xo { + using xo::reflect::Reflect; + using xo::reflect::StructReflector; + using xo::reflect::TypeDescrW; + using xo::reflect::TaggedPtr; + using xo::reflect::TypeDescrExtra; + using xo::reflect::EstablishTypeDescr; + using xo::reflect::StlVectorTdx; + + namespace scm { + namespace { + // TOOD: move into CVector + + std::size_t + slot_array_size(std::size_t n) { + return n * sizeof(gp); + } + } + + VsmStackFrame::VsmStackFrame(gc::IAlloc * mm, + gp p, + std::size_t n, + const VsmInstr * cont) : parent_{p}, + slot_v_{mm, n}, + cont_{cont} + {} + + gp + VsmStackFrame::push1(gc::IAlloc * mm, + gp p, + gp s0, + const VsmInstr * cont) + { + gp retval = new (MMPtr(mm)) VsmStackFrame(mm, p, 1, cont); + + (*retval)[0] = s0; + + return retval; + } + + TaggedPtr + VsmStackFrame::self_tp() const + { + return Reflect::make_tp(const_cast(this)); + } + + void + VsmStackFrame::display(std::ostream & os) const + { + os << ""; + } + + std::size_t + VsmStackFrame::_shallow_size() const + { + std::size_t retval = sizeof(VsmStackFrame); + + retval += gc::IAlloc::with_padding(slot_array_size(slot_v_.size())); + + return retval; + } + + Object * + VsmStackFrame::_shallow_copy(gc::IAlloc * mm) const + { + Cpof cpof(mm, this); + + size_t n = this->size(); + + VsmStackFrame * copy = new (cpof) VsmStackFrame(cpof.mm_, parent_, n, cont_); + + void * v_dest = copy->slot_v_.v_; + + if (slot_v_.v_) { + ::memcpy(v_dest, slot_v_.v_, slot_array_size(n)); + } + +#ifdef OBSOLETE + for (size_t i = 0, n = n_slot_; i < n; ++i) { + copy->v_[i] = v_[i]; + } +#endif + return copy; + } + + std::size_t + VsmStackFrame::_forward_children(gc::IAlloc * gc) + { + Object::_forward_inplace(parent_, gc); + + for (std::size_t i = 0, n = slot_v_.size(); i < n; ++i) { + Object::_forward_inplace((*this)[i], gc); + } + + return _shallow_size(); + } + + void + VsmStackFrame::reflect_self() + { + StructReflector sr; + + if (sr.is_incomplete() ) { + /* reflect CVector>. + * duplicates similar code in LocalEnv::reflect_self() + */ + using VectorType = CVector>; + + /* custom reflection for array of Object pointers. + * Can use StlVectorTdx here, treating CVector as a vector + * via .size() and .operator[] members + */ + std::unique_ptr tdx1 + = std::make_unique>(); + TypeDescrW td1 + = EstablishTypeDescr::establish(); + td1->assign_tdextra(Reflect::get_final_invoker(), + std::move(tdx1)); + + REFLECT_MEMBER(sr, parent); + REFLECT_MEMBER(sr, slot_v); + } + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end VsmStackFrame.cpp */