From f79e44a2b931f7a8dd73965cd76a71d859519509 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 28 Apr 2026 23:17:00 -0400 Subject: [PATCH] xo-object2: obj argument to DArray::push_back() --- xo-alloc2/include/xo/alloc2/gc/RCollector.hpp | 12 +- .../include/xo/alloc2/gc/RCollector_aux.hpp | 4 +- .../src/expression2/DGlobalSymtab.cpp | 16 +- .../src/expression2/DLocalSymtab.cpp | 13 +- .../src/expression2/DSequenceExpr.cpp | 17 +- xo-gc/include/xo/gc/X1CollectorConfig.hpp | 12 ++ xo-gc/src/gc/GCObjectStore.cpp | 17 +- xo-gc/src/gc/X1CollectorConfig.cpp | 16 ++ xo-gc/utest/Collector.test.cpp | 173 +++++++++++++++++- xo-gc/utest/init_gc_utest.cpp | 5 +- .../DVirtualSchematikaMachine.cpp | 8 +- xo-object2/include/xo/object2/DArray.hpp | 67 +++++-- xo-object2/include/xo/object2/DDictionary.hpp | 8 +- xo-object2/src/object2/DArray.cpp | 17 +- xo-object2/src/object2/DDictionary.cpp | 38 ++-- xo-object2/utest/DArray.test.cpp | 36 ++-- xo-reader2/src/reader2/DApplySsm.cpp | 10 +- .../src/reader2/DExpectFormalArglistSsm.cpp | 13 +- xo-reader2/src/reader2/DExpectQArraySsm.cpp | 9 +- xo-reader2/src/reader2/DGlobalEnv.cpp | 2 +- 20 files changed, 388 insertions(+), 105 deletions(-) diff --git a/xo-alloc2/include/xo/alloc2/gc/RCollector.hpp b/xo-alloc2/include/xo/alloc2/gc/RCollector.hpp index b7c54d44..3f647159 100644 --- a/xo-alloc2/include/xo/alloc2/gc/RCollector.hpp +++ b/xo-alloc2/include/xo/alloc2/gc/RCollector.hpp @@ -52,7 +52,7 @@ public: void * alloc_copy_for(const T * src) noexcept { return O::iface()->alloc_copy(O::data(), (std::byte *)const_cast(src)); } - + /** convenience template for move-constructible T (this is common) **/ template T * std_move_for(T * src) noexcept { @@ -62,28 +62,28 @@ public: } return nullptr; } - + /** forward faceted object pointer in place. Defined in GCObject.hpp to avoid #include cycle **/ template void forward_inplace(obj * p_obj); - + /** another convenience template for forwarding. * Defined in RGCObject.hpp to avoid #include cycle. **/ template void forward_inplace(DRepr ** pp_repr); - + /** convenience template where pointer requires pivot **/ template requires (!std::is_same_v) void forward_pivot_inplace(obj * p_obj); - + /** add root @p p_root **/ template void add_gc_root(obj * p_root) { O::iface()->add_gc_root_poly(O::data(), (obj *)p_root); } - + /** remove root @p p_root **/ template void remove_gc_root(obj * p_root) { diff --git a/xo-alloc2/include/xo/alloc2/gc/RCollector_aux.hpp b/xo-alloc2/include/xo/alloc2/gc/RCollector_aux.hpp index e964a931..0aa86f0d 100644 --- a/xo-alloc2/include/xo/alloc2/gc/RCollector_aux.hpp +++ b/xo-alloc2/include/xo/alloc2/gc/RCollector_aux.hpp @@ -110,7 +110,7 @@ namespace xo { *p_lhs = rhs; } }; - } -} + } /*namespace mm*/ +} /*namespace xo*/ /* end RCollector_aux.hpp */ diff --git a/xo-expression2/src/expression2/DGlobalSymtab.cpp b/xo-expression2/src/expression2/DGlobalSymtab.cpp index 7b6bd760..d927288a 100644 --- a/xo-expression2/src/expression2/DGlobalSymtab.cpp +++ b/xo-expression2/src/expression2/DGlobalSymtab.cpp @@ -16,6 +16,7 @@ namespace xo { using xo::map::DArenaHashMap; + using xo::mm::ACollector; using xo::mm::AGCObject; namespace scm { @@ -51,13 +52,13 @@ namespace xo { assert(var_map); /* choosing same capacity for hash, vars */ - DArray * vars = DArray::empty(mm, var_map->capacity()); + DArray * vars = DArray::_empty(mm, var_map->capacity()); assert(vars); auto type_map = dp::make(aux_mm, type_cfg); assert(type_map); - DArray * types = DArray::empty(mm, type_map->capacity()); + DArray * types = DArray::_empty(mm, type_map->capacity()); void * mem = mm.alloc_for(); @@ -110,6 +111,8 @@ namespace xo { { scope log(XO_DEBUG(false), std::string_view(*var->name())); + auto gc = mm.try_to_facet(); + // It's possible there's already a global variable // with the same name. // @@ -165,7 +168,7 @@ namespace xo { // need slot# in .map_ for this unique symbol (*var_map_)[var->name()] = binding.j_slot(); - vars_->push_back(obj(var)); + vars_->push_back(gc, obj(var)); } } @@ -191,6 +194,8 @@ namespace xo { scope log(XO_DEBUG(true), std::string_view(*tname->name())); + auto gc = mm.try_to_facet(); + auto ix = type_map_->find(tname->name()); if (ix == type_map_->end()) { @@ -218,12 +223,13 @@ namespace xo { (*type_map_)[tname->name()] = n; log && log("STUB: need write barrier"); - types_->push_back(obj(tname)); + types_->push_back(gc, obj(tname)); } else { Binding::slot_type i_slot = ix->second; log && log("STUB: need write barrier"); - (*types_)[i_slot] = obj(tname); + types_->assign_at(gc, i_slot, + obj(tname)); } } diff --git a/xo-expression2/src/expression2/DLocalSymtab.cpp b/xo-expression2/src/expression2/DLocalSymtab.cpp index 9d85a97c..c5bf6e1e 100644 --- a/xo-expression2/src/expression2/DLocalSymtab.cpp +++ b/xo-expression2/src/expression2/DLocalSymtab.cpp @@ -13,9 +13,9 @@ #include namespace xo { + using xo::mm::ACollector; using xo::mm::AGCObject; using xo::print::APrintable; - //using xo::facet::typeseq; using xo::print::ppstate; namespace scm { @@ -34,8 +34,8 @@ namespace xo { { void * mem = mm.alloc_for(); - DArray * vars = DArray::empty(mm, nv); - DArray * types = DArray::empty(mm, nt); + DArray * vars = DArray::_empty(mm, nv); + DArray * types = DArray::_empty(mm, nt); return new (mem) DLocalSymtab(p, vars, types); } @@ -69,7 +69,9 @@ namespace xo { Binding binding = Binding::local(vars_->size()); DVariable * var = DVariable::make(mm, name, typeref, binding); - vars_->push_back(obj(var)); + + auto gc = mm.try_to_facet(); + vars_->push_back(gc, obj(var)); return binding; } @@ -87,7 +89,8 @@ namespace xo { } else { obj tname = DTypename::make(mm, name, type); - types_->push_back(tname); + auto gc = mm.try_to_facet(); + types_->push_back(gc, tname); } } diff --git a/xo-expression2/src/expression2/DSequenceExpr.cpp b/xo-expression2/src/expression2/DSequenceExpr.cpp index 8fdfcf9b..bfece9e6 100644 --- a/xo-expression2/src/expression2/DSequenceExpr.cpp +++ b/xo-expression2/src/expression2/DSequenceExpr.cpp @@ -15,6 +15,7 @@ #include namespace xo { + using xo::mm::ACollector; using xo::mm::AGCObject; using xo::print::APrintable; using xo::facet::FacetRegistry; @@ -47,8 +48,8 @@ namespace xo { /** allocate 2nd, so it comes after DSequenceExpr in * memory. This may later allow realloc **/ - DArray * expr_v = DArray::empty(mm, - c_hint_capacity); + DArray * expr_v = DArray::_empty(mm, + c_hint_capacity); expr->expr_v_ = expr_v; @@ -73,23 +74,25 @@ namespace xo { DSequenceExpr::push_back(obj mm, obj expr) { + // null gc -> no write barrier + obj gc = mm.try_to_facet(); + if (expr_v_->size() == expr_v_->capacity()) { /* reallocate+expand */ DArray * expr_2x_v - = DArray::empty(mm, 2 * expr_v_->capacity()); + = DArray::_empty(mm, 2 * expr_v_->capacity()); for (size_type i = 0, z = expr_v_->size(); i < z; ++i) { - expr_2x_v->push_back((*expr_2x_v)[i]); + expr_2x_v->push_back(gc, (*expr_2x_v)[i]); } this->expr_v_ = expr_2x_v; } - obj expr_gco - = FacetRegistry::instance().variant(expr); + obj expr_gco = expr.to_facet(); - this->expr_v_->push_back(expr_gco); + this->expr_v_->push_back(gc, expr_gco); } void diff --git a/xo-gc/include/xo/gc/X1CollectorConfig.hpp b/xo-gc/include/xo/gc/X1CollectorConfig.hpp index 4b889efa..a8681c1d 100644 --- a/xo-gc/include/xo/gc/X1CollectorConfig.hpp +++ b/xo-gc/include/xo/gc/X1CollectorConfig.hpp @@ -24,8 +24,20 @@ namespace xo { **/ X1CollectorConfig with_name(std::string name); + /** copy of this config, + * but with @ref n_generation_ set to @p n_gen + **/ + X1CollectorConfig with_n_gen(uint32_t n_gen); + + /** copy of this config, + * but with @ref n_survive_ set to @p n_survive + **/ + X1CollectorConfig with_n_survive(uint32_t n_survive); + /** copy of this config, * but with @c arena_config_.size_ set to @p gen_z + * + * TODO: rename to with_halfspace_size() **/ X1CollectorConfig with_size(std::size_t gen_z); diff --git a/xo-gc/src/gc/GCObjectStore.cpp b/xo-gc/src/gc/GCObjectStore.cpp index 830fdb43..0dc5ed38 100644 --- a/xo-gc/src/gc/GCObjectStore.cpp +++ b/xo-gc/src/gc/GCObjectStore.cpp @@ -305,7 +305,7 @@ namespace xo { // could use c++ vector in scratch space instead of running on // boxed types. // - DArray * stats_v = DArray::empty(mm, object_types_.size()); + DArray * stats_v = DArray::_empty(mm, object_types_.size()); if (!stats_v) return false; @@ -346,7 +346,8 @@ namespace xo { recd->upsert_cstr(mm, "n-live", DInteger::box(mm, 0)); recd->upsert_cstr(mm, "bytes", DInteger::box(mm, 0)); - stats_v->assign_at(tseq.seqno(), obj(recd)); + stats_v->assign_at(mm.try_to_facet(), + tseq.seqno(), obj(recd)); } } @@ -385,13 +386,15 @@ namespace xo { stats_v->resize(max_tseq + 1); - DArray * final_stats_v = DArray::empty(mm, n_tseq_present); + DArray * final_stats_v = DArray::_empty(mm, n_tseq_present); for (std::size_t i = 0, n = stats_v->size(); i < n; ++i) { auto recd = stats_v->at(i); if (recd) { - bool ok = final_stats_v->push_back(recd); + obj gc = mm.try_to_facet(); + + bool ok = final_stats_v->push_back(gc, recd); assert(ok); } } @@ -433,7 +436,7 @@ namespace xo { } // stats, indexed by age - DArray * stats_v = DArray::empty(mm, soft_max_age + 1); + DArray * stats_v = DArray::_empty(mm, soft_max_age + 1); if (!stats_v) return false; @@ -448,7 +451,9 @@ namespace xo { recd->upsert_cstr(mm, "n-live", DInteger::box(mm, 0)); recd->upsert_cstr(mm, "bytes", DInteger::box(mm, 0)); - stats_v->push_back(obj(recd)); + obj gc = mm.try_to_facet(); + + stats_v->push_back(gc, obj(recd)); } log && log(xtag("soft_max_age", soft_max_age), diff --git a/xo-gc/src/gc/X1CollectorConfig.cpp b/xo-gc/src/gc/X1CollectorConfig.cpp index 812e276f..c7781fbb 100644 --- a/xo-gc/src/gc/X1CollectorConfig.cpp +++ b/xo-gc/src/gc/X1CollectorConfig.cpp @@ -16,6 +16,22 @@ namespace xo { return copy; } + X1CollectorConfig + X1CollectorConfig::with_n_gen(std::uint32_t n_gen) + { + X1CollectorConfig copy = *this; + copy.n_generation_ = n_gen; + return copy; + } + + X1CollectorConfig + X1CollectorConfig::with_n_survive(std::uint32_t n_survive) + { + X1CollectorConfig copy = *this; + copy.n_survive_threshold_ = n_survive; + return copy; + } + X1CollectorConfig X1CollectorConfig::with_size(std::size_t gen_z) { diff --git a/xo-gc/utest/Collector.test.cpp b/xo-gc/utest/Collector.test.cpp index 225a5ab6..94baeb58 100644 --- a/xo-gc/utest/Collector.test.cpp +++ b/xo-gc/utest/Collector.test.cpp @@ -7,12 +7,15 @@ * see xo-object2/utest **/ -#include -#include "Collector.hpp" +//#include #include "random_allocs.hpp" -#include "detail/ICollector_DX1Collector.hpp" -#include "detail/IAllocator_DX1Collector.hpp" -//#include "gc/DX1Collector.hpp" +#include +#include +#include +#include +//#include "detail/ICollector_DX1Collector.hpp" +//#include "detail/IAllocator_DX1Collector.hpp" +#include #include #include #include @@ -21,10 +24,15 @@ #include namespace xo { + using xo::scm::DList; + using xo::scm::DArray; + using xo::scm::DInteger; using xo::mm::AAllocator; using xo::mm::ACollector; + using xo::mm::AGCObject; using xo::mm::X1CollectorConfig; using xo::mm::DX1Collector; + using xo::mm::Role; using xo::mm::ArenaConfig; using xo::mm::AllocHeaderConfig; using xo::mm::Generation; @@ -263,8 +271,163 @@ namespace xo { auto rng = rng::xoshiro256ss(seed); + // these are not gc-aware objects. + // just testing ability to work as a low-level allocator REQUIRE(utest::AllocUtil::random_allocs(25, false, &rng, x1alloc)); } + + namespace { + class Testcase { + public: + Testcase(uint32_t ng, uint32_t ns, size_t gcz, uint32_t otz, bool dbg_flag) + : n_gen_{ng}, + n_survive_{ns}, + gc_halfspace_z_{gcz}, + object_type_z_{otz}, + debug_flag_{dbg_flag} + {} + + public: + /** number of generations in gco store **/ + uint32_t n_gen_ = 0; + /** promote to next gen on surviving this number of gc cycles **/ + uint32_t n_survive_ = 0; + /** size of each generations' half-space, in bytes **/ + size_t gc_halfspace_z_ = 0; + /** storage for object type array, in bytes + * one 8-byte facet pointer per type + **/ + uint32_t object_type_z_; +#ifdef NOT_YET + /** size for error output arena **/ + size_t error_size_ = 0; +#endif + /** true to enable debug output for this test case **/ + bool debug_flag_ = false; + }; + + class X1Fixture { + public: + explicit X1Fixture(uint32_t i_tc, const Testcase & tc); + +#ifdef NOT_IN_USE + DArena error_arena_; +#endif + DX1Collector gc_; + }; + + X1Fixture::X1Fixture(uint32_t i_tc, const Testcase & tc) + : gc_(X1CollectorConfig() + .with_name("collector-x1-gc-" + std::to_string(i_tc)) + .with_n_gen(tc.n_gen_) + .with_n_survive(tc.n_survive_) + .with_size(tc.gc_halfspace_z_) + .with_debug_flag(tc.debug_flag_)) + {} + +# define nil nullptr +# define T true +# define F false + + static std::vector s_testcase_v = { + /** + * debug_flag + * object_type_z | + * gc_halfspace_z | | + * n_survive | | | + * n_gen | | | | + * v v v v v + **/ + Testcase(1, 2, 16 * 1024, 128, F), + }; + +# undef T +# undef F +# undef nil + } /*namespace*/ + + // full collector test. + TEST_CASE("collector-x1-gc", "[alloc2][gc]") + { + scope log(XO_DEBUG(true), + "DX1Collector gc test"); + + //std::uint64_t seed = 7988747704879432247ul; + //random_seed(&seed); + + for (size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { + // auto rgen = xoshiro256ss(seed + i_tc); + + const Testcase & tc = s_testcase_v[i_tc]; + + scope log1(XO_DEBUG(tc.debug_flag_), + "testcase loop", + xtag("i_tc", i_tc)); + + INFO(tostr(xtag("i_tc", i_tc), xtag("n_tc", n_tc))); + + X1Fixture fixture(i_tc, tc); + + auto & x1 = fixture.gc_; + + REQUIRE(x1.verify_ok()); + + auto mm = x1.ref(); + auto gc = mm.to_facet(); + Generation g1{1}; + { + auto roots = DArray::_empty(mm, 1)->ref(); + REQUIRE(mm->contains_allocated(Role::to_space(), roots.data())); + + gc.add_gc_root(&roots); + { + auto x1 = DInteger::box(mm, 42); + auto x1_gco = obj(x1); + auto l1 = DList::cons(mm, x1, DList::_nil()); + +#ifdef NOT_YET + REQUIRE(roots->push_back(l1)); + REQUIRE(mm->contains_allocated(Role::to_space(), x1.data())); + REQUIRE(mm->contains_allocated(Role::to_space(), l1.data())); + + gc->add_gc_root_poly(&(*roots.operator->())[0]); + + gc->request_gc(g1); // 1st GC + + // x1 target got moved, og locn now relabeled from-space + REQUIRE(mm->contains(Role::from_space(), x1.data())); + REQUIRE(!mm->contains_allocated(Role::from_space(), x1.data())); + // l1 target got moved, og locn now relabeled from-space + REQUIRE(mm->contains(Role::from_space(), l1.data())); + REQUIRE(!mm->contains_allocated(Role::from_space(), l1.data())); +#endif + } + REQUIRE(mm->contains_allocated(Role::to_space(), roots.data())); + } + } + +#ifdef NOT_YET + /* typed collector i/face */ + auto x1gc = with_facet::mkobj(&x1state); + /* typed allocator i/face */ + auto x1alloc = with_facet::mkobj(&x1state); + + REQUIRE(x1gc.iface()); + REQUIRE(x1gc.data()); + + REQUIRE(x1alloc.iface()); + REQUIRE(x1alloc.data()); + + rng::Seed seed; + log && log("ratio: seed=", seed); + + auto rng = rng::xoshiro256ss(seed); + + // these are not gc-aware objects. + // just testing ability to work as a low-level allocator + REQUIRE(utest::AllocUtil::random_allocs(25, false, &rng, x1alloc)); +#endif + } } } diff --git a/xo-gc/utest/init_gc_utest.cpp b/xo-gc/utest/init_gc_utest.cpp index f92c1f4b..6aa39cc8 100644 --- a/xo-gc/utest/init_gc_utest.cpp +++ b/xo-gc/utest/init_gc_utest.cpp @@ -12,7 +12,7 @@ namespace xo { using xo::mm::SetupGcUtest; using xo::facet::FacetRegistry; - using xo::reflect::typeseq; + //using xo::reflect::typeseq; bool SetupGcUtest::register_facets() @@ -33,7 +33,8 @@ namespace xo { } InitEvidence - InitSubsys::require() { + InitSubsys::require() + { InitEvidence retval; /* recursive subsystem deps for xo-gc/utest */ diff --git a/xo-interpreter2/src/interpreter2/DVirtualSchematikaMachine.cpp b/xo-interpreter2/src/interpreter2/DVirtualSchematikaMachine.cpp index c7e864c6..fc64e2e8 100644 --- a/xo-interpreter2/src/interpreter2/DVirtualSchematikaMachine.cpp +++ b/xo-interpreter2/src/interpreter2/DVirtualSchematikaMachine.cpp @@ -561,8 +561,8 @@ namespace xo { auto apply = obj::from(expr_); // accumulate evaluated arguments here - DArray * args = DArray::empty(mm_.to_op(), - apply->n_args()); + DArray * args = DArray::_empty(mm_.to_op(), + apply->n_args()); // TODO: check function signature @@ -821,7 +821,9 @@ namespace xo { log && log(xtag("i_arg", i_arg), xtag("n_arg", args->size()), xtag("cap", args->capacity())); - args->push_back(value); + auto gc = mm_.to_op().to_facet(); + + args->push_back(gc, value); i_arg = evalargs_frame->increment_arg(); diff --git a/xo-object2/include/xo/object2/DArray.hpp b/xo-object2/include/xo/object2/DArray.hpp index 1d3499aa..de65d1d2 100644 --- a/xo-object2/include/xo/object2/DArray.hpp +++ b/xo-object2/include/xo/object2/DArray.hpp @@ -15,6 +15,24 @@ namespace xo { namespace scm { + class DArray; + + namespace detail { + /** null base case **/ + static inline bool do_array_push_back(DArray *, + obj) + { + return true; + } + + template + requires (std::convertible_to>) + static bool do_array_push_back(DArray * lhs, + obj gc, + A arg1, + Rest... rest); + } + /** @class DArray * @brief Polymorphic array implementation with gc hooks * @@ -30,11 +48,8 @@ namespace xo { /** type for array size **/ using size_type = std::uint32_t; - /** xo allocator facet **/ using AAllocator = xo::mm::AAllocator; - /** garbage collector facet **/ - //using ACollector = xo::mm::ACollector; - /** gc-aware object facet **/ + using ACollector = xo::mm::ACollector; using AGCObject = xo::mm::AGCObject; /** gc-centric object visitor **/ using AGCObjectVisitor = xo::mm::AGCObjectVisitor; @@ -59,8 +74,8 @@ namespace xo { * using memory from allocator @p mm. * Nullptr if space exhausted **/ - static DArray * empty(obj mm, - size_type cap); + static DArray * _empty(obj mm, + size_type cap); /** create copy of @p src using memory from @p mm * with capacity for @p new_cap elements @@ -80,8 +95,13 @@ namespace xo { static DArray * array(obj mm, Args... args); ///@} - /** @defgroup darray-access acecss methods **/ + /** @defgroup darray-access access methods **/ ///@{ + + /** create fop for this instance **/ + template + obj ref() { return obj(this); } + /** true iff array is empty **/ bool is_empty() const noexcept { return size_ == 0; } /** only support finite arrays :-) **/ @@ -108,13 +128,17 @@ namespace xo { /** store @p elt at position @p index. * true on success, false otherwise **/ - bool assign_at(size_type index, obj elt) noexcept; + bool assign_at(obj gc, size_type index, obj elt) noexcept; /** append @p elt at the end of array. * true on success, false otherwise. * on failure array is unaltered **/ - bool push_back(obj elt) noexcept; + bool push_back(obj gc, obj elt) noexcept; + + template + requires (std::convertible_to> && ...) + bool push_back_all(obj gc, Args... args) noexcept; /** store last element in array into @p elt and decrement array size. * true on success; false on failure (implies array was empty) @@ -182,13 +206,34 @@ namespace xo { DArray * DArray::array(obj mm, Args... args) { - DArray * result = empty(mm, sizeof...(args)); + obj gc = mm.try_to_facet(); + DArray * result = _empty(mm, sizeof...(args)); if (result) { - (result->push_back(args), ...); + detail::do_array_push_back(result, gc, args...); } return result; } + namespace detail { + template + requires (std::convertible_to>) + static bool do_array_push_back(DArray * lhs, + obj gc, + A arg1, + Rest... rest) + { + return (lhs->push_back(gc, arg1) + && do_array_push_back(lhs, gc, rest...)); + } + } + + template + requires (std::convertible_to> && ...) + bool + DArray::push_back_all(obj gc, Args... args) noexcept { + return detail::do_array_push_back(this, gc, args...); + } + } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-object2/include/xo/object2/DDictionary.hpp b/xo-object2/include/xo/object2/DDictionary.hpp index 8227721c..972c71b2 100644 --- a/xo-object2/include/xo/object2/DDictionary.hpp +++ b/xo-object2/include/xo/object2/DDictionary.hpp @@ -144,12 +144,12 @@ namespace xo { * * @return true if key-value pair updated; false if key not found **/ - bool try_update(const pair_type & kvpair); + bool try_update(obj gc, const pair_type & kvpair); /** update key-value pair for existing @p key to map to @p value. * false if @p key not already present. **/ - bool try_update_cstr(const char * key, obj value); + bool try_update_cstr(obj gc, const char * key, obj value); /** convenience method: * try_upsert pair (k, @p value), after boxing c-style string @p key with @p mm to get k @@ -167,7 +167,7 @@ namespace xo { * * False if dictionary already at capacity **/ - bool try_upsert(const pair_type & kvpair); + bool try_upsert(obj gc, const pair_type & kvpair); /** upsert key-value pair @p kvpair into dictionary. * If at capacity, expand capacity, getting new memory from @p mm. @@ -217,7 +217,7 @@ namespace xo { /** append {key, value} pair @p kv_pair to this dictionary * Require: @p kv_pair.first not already present in @ref keys_ **/ - bool _append_kv_aux(const pair_type & kv_pair); + bool _append_kv_aux(obj gc, const pair_type & kv_pair); ///@} private: diff --git a/xo-object2/src/object2/DArray.cpp b/xo-object2/src/object2/DArray.cpp index a181f9c3..1910e8e9 100644 --- a/xo-object2/src/object2/DArray.cpp +++ b/xo-object2/src/object2/DArray.cpp @@ -4,6 +4,7 @@ **/ #include "DArray.hpp" +#include "gc/RCollector_aux.hpp" #include #include #include @@ -15,13 +16,14 @@ namespace xo { using xo::print::APrintable; using xo::facet::FacetRegistry; using xo::mm::AGCObject; + using xo::mm::mm_do_assign; using xo::facet::typeseq; namespace scm { // TODO: error reporting? DArray * - DArray::empty(obj mm, - size_type cap) + DArray::_empty(obj mm, + size_type cap) { DArray * result = nullptr; @@ -45,7 +47,7 @@ namespace xo { DArray * src, size_type new_cap) { - DArray * dest = empty(mm, new_cap); + DArray * dest = _empty(mm, new_cap); if (dest) [[likely]] { /** could just memcpy here **/ @@ -73,20 +75,20 @@ namespace xo { } bool - DArray::assign_at(size_type ix, obj x) noexcept + DArray::assign_at(obj gc, size_type ix, obj x) noexcept { if (ix >= size_) return false; scope log(XO_DEBUG(true), "need write barrier"); - this->elts_[ix] = x; + mm_do_assign(gc, this, &elts_[ix], x); return true; } bool - DArray::push_back(obj elt) noexcept + DArray::push_back(obj gc, obj elt) noexcept { if (size_ >= capacity_) { return false; @@ -94,8 +96,9 @@ namespace xo { static_assert(!std::is_trivially_constructible_v>); void * mem = &(elts_[size_]); + new (mem) obj(); - new (mem) obj(elt); + mm_do_assign(gc, this, &(elts_[size_]), elt); ++(this->size_); diff --git a/xo-object2/src/object2/DDictionary.cpp b/xo-object2/src/object2/DDictionary.cpp index 57e71ed4..43a4e1cd 100644 --- a/xo-object2/src/object2/DDictionary.cpp +++ b/xo-object2/src/object2/DDictionary.cpp @@ -30,8 +30,8 @@ namespace xo { if (cap <= 0) cap = 1; - DArray * keys = DArray::empty(mm, cap); - DArray * values = DArray::empty(mm, cap); + DArray * keys = DArray::_empty(mm, cap); + DArray * values = DArray::_empty(mm, cap); if (keys && values) return new (mem) DDictionary(keys, values); @@ -108,7 +108,7 @@ namespace xo { } bool - DDictionary::try_update(const pair_type & kv_pair) + DDictionary::try_update(obj gc, const pair_type & kv_pair) { for (size_type i = 0, n = keys_->size(); i < n; ++i) { auto key_i = obj::from((*keys_)[i]); @@ -116,7 +116,7 @@ namespace xo { assert(key_i); if (*(key_i.data()) == *(kv_pair.first)) { - values_->assign_at(i, kv_pair.second); + values_->assign_at(gc, i, kv_pair.second); return true; } } @@ -125,7 +125,7 @@ namespace xo { } bool - DDictionary::try_update_cstr(const char * key, obj value) + DDictionary::try_update_cstr(obj gc, const char * key, obj value) { for (size_type i = 0, n = keys_->size(); i < n; ++i) { auto key_i = obj::from((*keys_)[i]); @@ -133,7 +133,7 @@ namespace xo { assert(key_i); if (strcmp(key, key_i->data()) == 0) { - values_->assign_at(i, value); + values_->assign_at(gc, i, value); return true; } @@ -147,8 +147,10 @@ namespace xo { { const DString * k1 = DString::from_cstr(mm, key_cstr); - if (k1) - return this->try_upsert(std::make_pair(k1, value)); + if (k1) { + obj gc = mm.try_to_facet(); + return this->try_upsert(gc, std::make_pair(k1, value)); + } return false; } @@ -165,21 +167,23 @@ namespace xo { } bool - DDictionary::try_upsert(const pair_type & kv_pair) + DDictionary::try_upsert(obj gc, const pair_type & kv_pair) { - if (this->try_update(kv_pair)) + if (this->try_update(gc, kv_pair)) return true; if (keys_->size() == keys_->capacity()) return false; - return this->_append_kv_aux(kv_pair); + return this->_append_kv_aux(gc, kv_pair); } bool DDictionary::upsert(obj mm, const pair_type & kv_pair) { - if (this->try_update(kv_pair)) + obj gc = mm.try_to_facet(); + + if (this->try_update(gc, kv_pair)) return true; // key not present -> must expand {key array, value array} @@ -200,17 +204,19 @@ namespace xo { } } - return this->_append_kv_aux(kv_pair); + return this->_append_kv_aux(gc, kv_pair); } bool - DDictionary::_append_kv_aux(const pair_type & kv_pair) + DDictionary::_append_kv_aux(obj gc, const pair_type & kv_pair) { + DString * key = const_cast(kv_pair.first); + bool ok - = keys_->push_back(obj(const_cast(kv_pair.first))); + = keys_->push_back(gc, obj(key)); if (ok) { - ok = values_->push_back(kv_pair.second); + ok = values_->push_back(gc, kv_pair.second); if (!ok) { // since we couldn't insert value, also drop key diff --git a/xo-object2/utest/DArray.test.cpp b/xo-object2/utest/DArray.test.cpp index 84afbe11..af26c719 100644 --- a/xo-object2/utest/DArray.test.cpp +++ b/xo-object2/utest/DArray.test.cpp @@ -14,6 +14,7 @@ namespace xo { using xo::scm::ListOps; using xo::scm::DArray; using xo::scm::DInteger; + using xo::mm::ACollector; using xo::mm::AAllocator; using xo::mm::AGCObject; using xo::mm::DArena; @@ -31,7 +32,10 @@ namespace xo { REQUIRE(arr.is_empty());; - REQUIRE(arr.push_back(ListOps::nil()) == false); + // null_gc: for no memory barrier + obj null_gc; + + REQUIRE(arr.push_back(null_gc, ListOps::nil()) == false); } TEST_CASE("DArray-empty", "[object2][DArray]") @@ -41,7 +45,7 @@ namespace xo { DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); - DArray * arr = DArray::empty(alloc, 16); + DArray * arr = DArray::_empty(alloc, 16); REQUIRE(arr != nullptr); REQUIRE(arr->capacity() == 16); @@ -57,15 +61,16 @@ namespace xo { .size_ = 4*1024 }; DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); + obj null_gc; - DArray * arr = DArray::empty(alloc, 16); + DArray * arr = DArray::_empty(alloc, 16); REQUIRE(arr != nullptr); REQUIRE(arr->capacity() == 16); REQUIRE(arr->size() == 0); obj elt = DInteger::box(alloc, 42); - bool ok = arr->push_back(elt); + bool ok = arr->push_back(null_gc, elt); REQUIRE(ok == true); REQUIRE(arr->is_empty() == false); @@ -79,8 +84,9 @@ namespace xo { .size_ = 4*1024 }; DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); + obj null_gc; - DArray * arr = DArray::empty(alloc, 4); + DArray * arr = DArray::_empty(alloc, 4); REQUIRE(arr != nullptr); REQUIRE(arr->capacity() == 4); REQUIRE(arr->size() == 0); @@ -90,7 +96,7 @@ namespace xo { REQUIRE(arr->size() == i); obj elt = DInteger::box(alloc, 100 + i); - bool ok = arr->push_back(elt); + bool ok = arr->push_back(null_gc, elt); REQUIRE(ok == true); REQUIRE(arr->capacity() == 4); @@ -106,7 +112,8 @@ namespace xo { DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); - DArray * arr = DArray::empty(alloc, 2); + DArray * arr = DArray::_empty(alloc, 2); + obj null_gc; REQUIRE(arr != nullptr); REQUIRE(arr->capacity() == 2); @@ -116,11 +123,11 @@ namespace xo { obj e2 = DInteger::box(alloc, 2); obj e3 = DInteger::box(alloc, 3); - REQUIRE(arr->push_back(e1) == true); + REQUIRE(arr->push_back(null_gc, e1) == true); REQUIRE(arr->size() == 1); - REQUIRE(arr->push_back(e2) == true); + REQUIRE(arr->push_back(null_gc, e2) == true); REQUIRE(arr->size() == 2); - REQUIRE(arr->push_back(e3) == false); + REQUIRE(arr->push_back(null_gc, e3) == false); REQUIRE(arr->size() == 2); REQUIRE(arr->capacity() == 2); } @@ -132,7 +139,8 @@ namespace xo { DArena arena = DArena::map(cfg); auto alloc = with_facet::mkobj(&arena); - DArray * arr = DArray::empty(alloc, 4); + DArray * arr = DArray::_empty(alloc, 4); + obj null_gc; REQUIRE(arr != nullptr); REQUIRE(arr->size() == 0); @@ -142,9 +150,9 @@ namespace xo { obj e1 = DInteger::box(alloc, 200); obj e2 = DInteger::box(alloc, 300); - arr->push_back(e0); - arr->push_back(e1); - arr->push_back(e2); + arr->push_back(null_gc, e0); + arr->push_back(null_gc, e1); + arr->push_back(null_gc, e2); REQUIRE(arr->size() == 3); diff --git a/xo-reader2/src/reader2/DApplySsm.cpp b/xo-reader2/src/reader2/DApplySsm.cpp index ef84187b..5c4802cc 100644 --- a/xo-reader2/src/reader2/DApplySsm.cpp +++ b/xo-reader2/src/reader2/DApplySsm.cpp @@ -15,6 +15,7 @@ //#include "expect_expr_xs.hpp" namespace xo { + using xo::mm::ACollector; using xo::mm::AGCObject; using xo::print::APrintable; using xo::reflect::typeseq; @@ -73,7 +74,7 @@ namespace xo { * * See similar code in DExpectFormalArglistSsm::_make */ - DArray * args = DArray::empty(mm, 8); + DArray * args = DArray::_empty(mm, 8); applyexprstatetype applystate = (fn_expr @@ -232,23 +233,24 @@ namespace xo { assert(expr_gco); obj mm(&(p_psm->parser_alloc())); + auto gc = obj(mm).try_to_facet(); if (args_expr_v_->size() == args_expr_v_->capacity()) { // need to expand .args_expr_v_ capacity. // Could use DArena checkpoint to redo this in place, // since argument array must be on the top of the stack. - DArray * argv_2x = DArray::empty(mm, 2 * args_expr_v_->capacity()); + DArray * argv_2x = DArray::_empty(mm, 2 * args_expr_v_->capacity()); for (DArray::size_type i = 0, n = args_expr_v_->size(); i < n; ++i) { - argv_2x->push_back((*args_expr_v_)[i]); + argv_2x->push_back(gc, (*args_expr_v_)[i]); } this->args_expr_v_ = argv_2x; } if (args_expr_v_->size() < args_expr_v_->capacity()) - args_expr_v_->push_back(expr_gco); + args_expr_v_->push_back(gc, expr_gco); if (tk.tk_type() == tokentype::tk_rightparen) { obj apply_ex = this->assemble_expr(p_psm->expr_alloc()); diff --git a/xo-reader2/src/reader2/DExpectFormalArglistSsm.cpp b/xo-reader2/src/reader2/DExpectFormalArglistSsm.cpp index 6d68a610..18531816 100644 --- a/xo-reader2/src/reader2/DExpectFormalArglistSsm.cpp +++ b/xo-reader2/src/reader2/DExpectFormalArglistSsm.cpp @@ -17,6 +17,7 @@ namespace xo { using xo::print::APrintable; using xo::print::ppstate; using xo::print::ppindentinfo; + using xo::mm::ACollector; using xo::mm::AGCObject; using xo::mm::AAllocator; using xo::facet::FacetRegistry; @@ -61,7 +62,7 @@ namespace xo { /* allocate room for 8 arguments (during parsing) * will re-alloc to expand as needed */ - DArray * argl = DArray::empty(mm, 8); + DArray * argl = DArray::_empty(mm, 8); return new (mem) DExpectFormalArglistSsm(argl); } @@ -198,18 +199,22 @@ namespace xo { // could do this in place since this SSM is at the top of the parser stack. obj mm(&parser_alloc); - DArray * argl_2x = DArray::empty(mm, 2 * argl_->capacity()); + DArray * argl_2x = DArray::_empty(mm, 2 * argl_->capacity()); + + auto gc = obj(mm).try_to_facet(); for (DArray::size_type i = 0, n = argl_->size(); i < n; ++i) { // TODO: prefer non-bounds-checked access here - argl_2x->push_back(argl_->at(i)); + argl_2x->push_back(gc, argl_->at(i)); } // update in place this->argl_ = argl_2x; } - this->argl_->push_back(var_o); + auto gc = expr_alloc.try_to_facet(); + + this->argl_->push_back(gc, var_o); } void diff --git a/xo-reader2/src/reader2/DExpectQArraySsm.cpp b/xo-reader2/src/reader2/DExpectQArraySsm.cpp index 97e68228..1d09b154 100644 --- a/xo-reader2/src/reader2/DExpectQArraySsm.cpp +++ b/xo-reader2/src/reader2/DExpectQArraySsm.cpp @@ -13,6 +13,7 @@ namespace xo { using xo::print::APrintable; using xo::facet::FacetRegistry; + using xo::mm::ACollector; using xo::mm::AGCObject; namespace scm { @@ -142,8 +143,8 @@ namespace xo { if (state_.code() == QArrayXst::code::qarray_0) { this->state_ = QArrayXst(QArrayXst::code::qarray_1a); - this->array_ = DArray::empty(p_psm->expr_alloc(), - 8 /*heuristic starting capacity*/); + this->array_ = DArray::_empty(p_psm->expr_alloc(), + 8 /*heuristic starting capacity*/); DExpectQLiteralSsm::start(p_psm, false /*cxl_on_rightparen*/, @@ -177,6 +178,8 @@ namespace xo { DExpectQArraySsm::on_quoted_literal(obj lit, ParserStateMachine * p_psm) { + auto gc = p_psm->expr_alloc().try_to_facet(); + if(state_.code() == QArrayXst::code::qarray_1a) { // append lit at the end of array_ { @@ -192,7 +195,7 @@ namespace xo { 2 * array_->capacity()); } - bool ok = array_->push_back(lit); + bool ok = array_->push_back(gc, lit); assert(ok); } diff --git a/xo-reader2/src/reader2/DGlobalEnv.cpp b/xo-reader2/src/reader2/DGlobalEnv.cpp index b1eecf37..2fc2e881 100644 --- a/xo-reader2/src/reader2/DGlobalEnv.cpp +++ b/xo-reader2/src/reader2/DGlobalEnv.cpp @@ -21,7 +21,7 @@ namespace xo { DGlobalEnv::_make(obj mm, DGlobalSymtab * symtab) { - DArray * values = DArray::empty(mm, symtab->var_capacity()); + DArray * values = DArray::_empty(mm, symtab->var_capacity()); void * mem = mm.alloc_for();