diff --git a/xo-alloc2/include/xo/alloc2/arena/ArenaConfig.hpp b/xo-alloc2/include/xo/alloc2/arena/ArenaConfig.hpp index 9da3e211..950f9d36 100644 --- a/xo-alloc2/include/xo/alloc2/arena/ArenaConfig.hpp +++ b/xo-alloc2/include/xo/alloc2/arena/ArenaConfig.hpp @@ -47,7 +47,9 @@ namespace xo { * present in arena **/ bool store_header_flag_ = false; - std::uint64_t header_size_mask_ = 0xffffffff; + /** number of bits to represent allocation size **/ + std::uint64_t header_size_bits_ = 32; + std::uint64_t header_size_mask_ = (1ul << header_size_bits_) - 1; /** true to enable debug logging **/ bool debug_flag_ = false; diff --git a/xo-alloc2/include/xo/alloc2/arena/DArena.hpp b/xo-alloc2/include/xo/alloc2/arena/DArena.hpp index 26bd05cf..2a874927 100644 --- a/xo-alloc2/include/xo/alloc2/arena/DArena.hpp +++ b/xo-alloc2/include/xo/alloc2/arena/DArena.hpp @@ -64,7 +64,15 @@ namespace xo { ///@} + /** @defgroup mm-arena-methods **/ + ///@{ + + size_type reserved() const { return hi_ - lo_; } size_type allocated() const { return free_ - lo_; } + size_type committed() const { return committed_z_; } + size_type available() const { return limit_ - free_; } + + bool contains(void * addr) const { return (lo_ <= addr) && (addr < hi_); } /** obtain uncommitted contiguous memory range comprising * a whole multiple of @p hugepage_z bytes, of at least size @p req_z, @@ -72,12 +80,12 @@ namespace xo { **/ static range_type map_aligned_range(size_type req_z, size_type hugepage_z); - /** @defgroup mm-arena-methods **/ - ///@{ - /** true if arena is mapped i.e. has a reserved address range **/ bool is_mapped() const { return (lo_ != nullptr) && (hi_ != nullptr); } + /** get header from allocated object address **/ + header_type * obj2hdr(void * obj); + ///@} /** @defgroup mm-arena-instance-vars **/ diff --git a/xo-alloc2/include/xo/alloc2/gc/DX1Collector.hpp b/xo-alloc2/include/xo/alloc2/gc/DX1Collector.hpp index c27c114c..b8740ee7 100644 --- a/xo-alloc2/include/xo/alloc2/gc/DX1Collector.hpp +++ b/xo-alloc2/include/xo/alloc2/gc/DX1Collector.hpp @@ -40,16 +40,45 @@ namespace xo { struct CollectorConfig { using size_type = std::size_t; + /* + * alloc header + * TTTTTTTTTTTTGGGGGZZZZZZZZZZZZ + * < tseq >< size > + * + * masking + * + * ..432107654321076543210 bit + * + * > < .gen_bits + * 0..............01111111 gen_mask_unshifted + * 0..011111110..........0 gen_mask_shifted + * > < gen_shift + */ + //constexpr std::uint64_t gen_mult() const; + constexpr std::uint64_t gen_shift() const; + constexpr std::uint64_t gen_mask_unshifted() const; + constexpr std::uint64_t gen_mask_shifted() const; + + //constexpr std::uint64_t tseq_mult() const; + constexpr std::uint64_t tseq_shift() const; + constexpr std::uint64_t tseq_mask_unshifted() const; + constexpr std::uint64_t tseq_mask_shifted() const; + /** Configuration for collector spaces. * Will have at least {nursery,tenured} x {from,to} spaces. * Not using name_ member. * * REQUIRE: * - arena_config_.store_header_flag_ must be true - * - arena_config_.header_size_mask_ must be 0x0000ffff **/ ArenaConfig arena_config_; + /** number of bits to represent generation **/ + std::uint64_t gen_bits_ = 8; + + /** number of bits to represent tseq **/ + std::uint64_t tseq_bits_ = 24; + /** Number of generations. * Must be at least 2. **/ @@ -82,7 +111,32 @@ namespace xo { bool debug_flag_ = false; }; + // ----- GCRunState ----- + + /** @class GCRunState + * @brief encapsulate state needed while GC is running + **/ + struct GCRunState { + GCRunState() : gc_upto_{0} {} + explicit GCRunState(generation gc_upto); + + static GCRunState gc_not_running(); + static GCRunState gc_upto(generation g); + + bool is_running() const { return gc_upto_ > 0; } + + generation gc_upto() const { return gc_upto_; } + + private: + /** running gc collecting all generations gi < gc_upto **/ + generation gc_upto_; + }; + + // ----- DX1Collector ----- + struct DX1Collector { + using header_type = DArena::header_type; + explicit DX1Collector(const CollectorConfig & cfg); const DArena * get_space(role r, generation g) const { return space_[r][g]; } @@ -90,12 +144,31 @@ namespace xo { DArena * from_space(generation g) { return get_space(role::from_space(), g); } DArena * to_space(generation g) { return get_space(role::to_space(), g); } + /** true iff address @p addr allocated from this collector + * in role @p r (according to current GC state) + **/ + bool contains(role r, void * addr) const; + + /** get allocation size from header **/ + std::size_t header2size(header_type hdr) const; + /** get generation counter from alloc header **/ + generation header2gen(header_type hdr) const; + /** get tseq from alloc header **/ + uint32_t header2tseq(header_type hdr) const; + + /** true iff original alloc has been replaced by a forwarding pointer **/ + bool is_forwarding_header(header_type hdr) const; + /** reverse to-space and from-space roles for generation g **/ void reverse_roles(generation g); + public: /** garbage collector configuration **/ CollectorConfig config_; + /** current gc state **/ + GCRunState runstate_; + /** collector-managed memory here. * - space_[1] is from-space * - space_[0] is to-space diff --git a/xo-alloc2/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp b/xo-alloc2/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp new file mode 100644 index 00000000..f769fd56 --- /dev/null +++ b/xo-alloc2/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp @@ -0,0 +1,60 @@ +/** @file IAllocator_DX1Collector.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include "alloc2/alloc/Allocator.hpp" +#include "alloc2/alloc/IAllocator_Xfer.hpp" +#include "DX1Collector.hpp" + +namespace xo { + namespace mm { struct IAllocator_DX1Collector; } + + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::mm::IAllocator_Xfer; + }; + } + + namespace mm { + /* changes here coordinate with + * AAllocator AAllocator.hpp + * IAllocator_Any IAllocator_Any.hpp + * IAllocator_Xfer IAllocator_Xfer.hpp + * RAllocator RCollector.hpp + */ + struct IAllocator_DX1Collector { + using size_type = std::size_t; + using value_type = std::byte *; + + // todo: available() + + static std::string_view name(const DX1Collector &) noexcept; + static size_type reserved(const DX1Collector &) noexcept; + static size_type size(const DX1Collector &) noexcept; + static size_type committed(const DX1Collector &) noexcept; + static size_type available(const DX1Collector &) noexcept; + static size_type allocated(const DX1Collector &) noexcept; + static bool contains(const DX1Collector & d, const void * p) noexcept; + static AllocatorError last_error(const DX1Collector &) noexcept; + + static bool expand(DX1Collector & d, size_type z) noexcept; + + static value_type alloc(DX1Collector & d, size_type z); + static value_type super_alloc(DX1Collector & d, size_type z); + static value_type sub_alloc(DX1Collector & d, size_type z, bool complete); + static void clear(DX1Collector & d); + static void destruct_data(DX1Collector & d); + }; + + } /*namespace mm*/ +} /*namespace xo*/ + + +/* end IAllocator_DX1Collector.hpp */ diff --git a/xo-alloc2/include/xo/alloc2/gc/ICollector_Any.hpp b/xo-alloc2/include/xo/alloc2/gc/ICollector_Any.hpp index 9e5d9980..c9779687 100644 --- a/xo-alloc2/include/xo/alloc2/gc/ICollector_Any.hpp +++ b/xo-alloc2/include/xo/alloc2/gc/ICollector_Any.hpp @@ -29,14 +29,14 @@ namespace xo { int32_t _typeseq() const noexcept override { return s_typeseq; } // const methods - [[noreturn]] size_type allocated(Copaque, generation, role) const noexcept { _fatal(); } - [[noreturn]] size_type reserved(Copaque, generation, role) const noexcept { _fatal(); } - [[noreturn]] size_type committed(Copaque, generation, role) const noexcept { _fatal(); } + [[noreturn]] size_type allocated(Copaque, generation, role) const noexcept override { _fatal(); } + [[noreturn]] size_type reserved(Copaque, generation, role) const noexcept override { _fatal(); } + [[noreturn]] size_type committed(Copaque, generation, role) const noexcept override { _fatal(); } // non-const methods - [[noreturn]] void install_type(Opaque, int32_t, IGCObject_Any &) noexcept { _fatal(); } - [[noreturn]] void add_gc_root(Opaque, int32_t, Opaque *) { _fatal(); } - [[noreturn]] void forward_inplace(Opaque, obj *) { _fatal(); } + [[noreturn]] void install_type(Opaque, int32_t, IGCObject_Any &) noexcept override { _fatal(); } + [[noreturn]] void add_gc_root(Opaque, int32_t, Opaque *) override { _fatal(); } + [[noreturn]] void forward_inplace(Opaque, obj *) override { _fatal(); } private: [[noreturn]] static void _fatal(); diff --git a/xo-alloc2/include/xo/alloc2/gc/ICollector_DX1Collector.hpp b/xo-alloc2/include/xo/alloc2/gc/ICollector_DX1Collector.hpp index 320770b7..9bc6e129 100644 --- a/xo-alloc2/include/xo/alloc2/gc/ICollector_DX1Collector.hpp +++ b/xo-alloc2/include/xo/alloc2/gc/ICollector_DX1Collector.hpp @@ -12,7 +12,9 @@ namespace xo { namespace facet { template <> - struct FacetImplementation { + struct FacetImplementation + { using ImplType = xo::mm::ICollector_Xfer; }; @@ -27,16 +29,22 @@ namespace xo { */ struct ICollector_DX1Collector { using size_type = std::size_t; + using header_type = DArena::header_type; - static size_type allocated(const DX1Collector & d, generation g, role r) { - const DArena * arena = d.get_space(r, g); + static bool check_move_policy(const DX1Collector & d, + header_type alloc_hdr, + void * object_data); - if (arena) [[likely]] { - return arena->allocated(); - } else { - return 0; - } - } + // todo: available() + + static size_type allocated(const DX1Collector & d, generation g, role r); + static size_type reserved(const DX1Collector & d, generation g, role r); + static size_type committed(const DX1Collector & d, generation g, role r); + + static void install_type(DX1Collector & d, + int32_t seq, IGCObject_Any & iface); + static void add_gc_root(DX1Collector & d, int32_t tseq, Opaque * root); + static void forward_inplace(DX1Collector & d, obj * lhs); static int32_t s_typeseq; static bool _valid; diff --git a/xo-alloc2/include/xo/alloc2/gc/ICollector_Xfer.hpp b/xo-alloc2/include/xo/alloc2/gc/ICollector_Xfer.hpp index cdd588af..2177b63a 100644 --- a/xo-alloc2/include/xo/alloc2/gc/ICollector_Xfer.hpp +++ b/xo-alloc2/include/xo/alloc2/gc/ICollector_Xfer.hpp @@ -35,22 +35,22 @@ namespace xo { return I::allocated(_dcast(d), g, r); } size_type reserved(Copaque d, generation g, role r) const noexcept override { - return I::reserved(d,g,r); + return I::reserved(_dcast(d), g, r); } size_type committed(Copaque d, generation g, role r) const noexcept override { - return I::committed(d,g,r); + return I::committed(_dcast(d), g, r); } // non-const methods void install_type(Opaque d, int32_t tseq, IGCObject_Any & iface) override { - I::install_type(d, tseq, iface); + I::install_type(_dcast(d), tseq, iface); } void add_gc_root(Opaque d, int32_t tseq, Opaque * root) override { - I::add_gc_root(d, tseq, root); + I::add_gc_root(_dcast(d), tseq, root); } void forward_inplace(Opaque d, obj * lhs) override { - I::forward_inplace(d, lhs); + I::forward_inplace(_dcast(d), lhs); } private: diff --git a/xo-alloc2/include/xo/alloc2/gc/RCollector.hpp b/xo-alloc2/include/xo/alloc2/gc/RCollector.hpp index 5da5b30c..753af3c7 100644 --- a/xo-alloc2/include/xo/alloc2/gc/RCollector.hpp +++ b/xo-alloc2/include/xo/alloc2/gc/RCollector.hpp @@ -23,12 +23,12 @@ namespace xo { RCollector(DataPtr data) : Object{std::move(data)} {} int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); } - size_type allocated(generation g, role r) const noexcept { return O::iface()->allocated(O::data()); } - size_type reserved(generation g, role r) const noexcept { return O::iface()->reserved(O::data()); } - size_type committed(generation g, role r) const noexcept { return O::iface()->committed(O::data()); } + size_type allocated(generation g, role r) const noexcept { return O::iface()->allocated(O::data(), g, r); } + size_type reserved(generation g, role r) const noexcept { return O::iface()->reserved(O::data(), g, r); } + size_type committed(generation g, role r) const noexcept { return O::iface()->committed(O::data(), g, r); } - void install_type(int32_t tseq, IGCObject_Any & iface) { return O::iface()->install_type(O::data()); } - void add_gc_root(int32_t tseq, Opaque * root) { O::iface()->add_gc_root(O::data()); } + void install_type(int32_t tseq, IGCObject_Any & iface) { return O::iface()->install_type(O::data(), tseq, iface); } + void add_gc_root(int32_t tseq, Opaque * root) { O::iface()->add_gc_root(O::data(), tseq, root); } void forward_inplace(obj * lhs) { O::iface()->forward_inplace(O::data(), lhs); } diff --git a/xo-alloc2/include/xo/alloc2/gc/role.hpp b/xo-alloc2/include/xo/alloc2/gc/role.hpp index 3f2de53d..0c41e39e 100644 --- a/xo-alloc2/include/xo/alloc2/gc/role.hpp +++ b/xo-alloc2/include/xo/alloc2/gc/role.hpp @@ -21,9 +21,9 @@ namespace xo { operator value_type() const { return role_; } - std::uint32_t role_; + value_type role_ = 0; }; } /*namespace mm*/ } /*namespace xo*/ -/* end role,hpp */ +/* end role.hpp */ diff --git a/xo-alloc2/src/alloc2/CMakeLists.txt b/xo-alloc2/src/alloc2/CMakeLists.txt index ad821b14..dd111923 100644 --- a/xo-alloc2/src/alloc2/CMakeLists.txt +++ b/xo-alloc2/src/alloc2/CMakeLists.txt @@ -10,6 +10,7 @@ set(SELF_SRCS ICollector_Any.cpp IGCObject_Any.cpp + IAllocator_DX1Collector.cpp ICollector_DX1Collector.cpp DX1Collector.cpp diff --git a/xo-alloc2/src/alloc2/DArena.cpp b/xo-alloc2/src/alloc2/DArena.cpp index ef4a704f..6aacd0f3 100644 --- a/xo-alloc2/src/alloc2/DArena.cpp +++ b/xo-alloc2/src/alloc2/DArena.cpp @@ -238,6 +238,16 @@ namespace xo { error_count_ = 0; last_error_ = AllocatorError(); } + + DArena::header_type * + DArena::obj2hdr(void * obj) + { + assert(config_.store_header_flag_); + + return (header_type *)((byte *)obj - sizeof(header_type)); + } + + } } /*namespace xo*/ diff --git a/xo-alloc2/src/alloc2/DX1Collector.cpp b/xo-alloc2/src/alloc2/DX1Collector.cpp index 025d5f80..0b165aeb 100644 --- a/xo-alloc2/src/alloc2/DX1Collector.cpp +++ b/xo-alloc2/src/alloc2/DX1Collector.cpp @@ -4,15 +4,84 @@ **/ #include "gc/DX1Collector.hpp" +#include "gc/generation.hpp" +#include <_types/_uint32_t.h> #include +#include namespace xo { namespace mm { +#ifdef NOT_USING + constexpr std::uint64_t + CollectorConfig::gen_mult() const { + return 1ul << arena_config_.header_size_bits_; + } +#endif + + constexpr std::uint64_t + CollectorConfig::gen_shift() const { + return arena_config_.header_size_bits_; + } + + constexpr std::uint64_t + CollectorConfig::gen_mask_unshifted() const { + return (1ul << gen_bits_) - 1; + } + + constexpr std::uint64_t + CollectorConfig::gen_mask_shifted() const { + return gen_mask_unshifted() << arena_config_.header_size_bits_; + } + +#ifdef NOT_USING + constexpr std::uint64_t + CollectorConfig::tseq_mult() const { + return 1ul << (gen_bits_ + arena_config_.header_size_bits_); + } +#endif + + constexpr std::uint64_t + CollectorConfig::tseq_shift() const { + return gen_bits_ + arena_config_.header_size_bits_; + } + + constexpr std::uint64_t + CollectorConfig::tseq_mask_unshifted() const { + return (1ul << tseq_bits_) - 1; + } + + constexpr std::uint64_t + CollectorConfig::tseq_mask_shifted() const { + return tseq_mask_unshifted() << (gen_bits_ + arena_config_.header_size_bits_); + } + + // ----- GCRunState ----- + + GCRunState::GCRunState(generation gc_upto) + : gc_upto_{gc_upto} + {} + + GCRunState + GCRunState::gc_not_running() + { + return GCRunState(generation(0)); + } + + GCRunState + GCRunState::gc_upto(generation g) + { + return GCRunState(generation(g + 1)); + } + + // ----- DX1Collector ----- + DX1Collector::DX1Collector(const CollectorConfig & cfg) : config_{cfg} { + assert(config_.arena_config_.header_size_bits_ + config_.gen_bits_ + config_.tseq_bits_ <= 64); + for (uint32_t igen = 0, ngen = cfg.n_generation_; igen < ngen; ++igen) { - space_storage_[0][igen] = std::move(DArena::map(cfg.arena_config_)); - space_storage_[1][igen] = std::move(DArena::map(cfg.arena_config_)); + space_storage_[0][igen] = DArena::map(cfg.arena_config_); + space_storage_[1][igen] = DArena::map(cfg.arena_config_); space_[role::to_space()][igen] = &space_storage_[0][igen]; space_[role::from_space()][igen] = &space_storage_[1][igen]; @@ -24,6 +93,50 @@ namespace xo { } } + bool + DX1Collector::contains(role r, void * addr) const + { + for (generation gi{0}; gi < config_.n_generation_; ++gi) { + if (get_space(r, gi)->contains(addr)) + return true; + } + + return false; + } + + std::size_t + DX1Collector::header2size(header_type hdr) const + { + uint32_t z = (hdr & config_.arena_config_.header_size_mask_); + + return z; + } + + generation + DX1Collector::header2gen(header_type hdr) const + { + uint32_t g = (hdr & config_.gen_mask_shifted()) >> config_.gen_shift(); + + assert(g < c_max_generation); + + return generation(g); + } + + uint32_t + DX1Collector::header2tseq(header_type hdr) const + { + uint32_t tseq = (hdr & config_.tseq_mask_shifted()) >> config_.tseq_shift(); + + return tseq; + } + + bool + DX1Collector::is_forwarding_header(header_type hdr) const + { + /** all 1 bits to flag forwarding pointer **/ + return header2tseq(hdr) == config_.tseq_mask_shifted(); + } + void DX1Collector::reverse_roles(generation g) { assert(g < config_.n_generation_); diff --git a/xo-alloc2/src/alloc2/IAllocator_DArena.cpp b/xo-alloc2/src/alloc2/IAllocator_DArena.cpp index 4b71763a..f4254b39 100644 --- a/xo-alloc2/src/alloc2/IAllocator_DArena.cpp +++ b/xo-alloc2/src/alloc2/IAllocator_DArena.cpp @@ -24,7 +24,7 @@ namespace xo { size_t IAllocator_DArena::reserved(const DArena & s) noexcept { - return s.hi_ - s.lo_; + return s.reserved(); } size_t @@ -34,12 +34,12 @@ namespace xo { size_t IAllocator_DArena::committed(const DArena & s) noexcept { - return s.committed_z_; + return s.committed(); } size_t IAllocator_DArena::available(const DArena & s) noexcept { - return s.limit_ - s.free_; + return s.available(); } size_t diff --git a/xo-alloc2/src/alloc2/IAllocator_DX1Collector.cpp b/xo-alloc2/src/alloc2/IAllocator_DX1Collector.cpp new file mode 100644 index 00000000..bc84e0a3 --- /dev/null +++ b/xo-alloc2/src/alloc2/IAllocator_DX1Collector.cpp @@ -0,0 +1,11 @@ +/** @file IAllocator_DX1Collector.cpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +namespace xo { + namespace mm { + } /*namespace mm*/ +} /*namespace xo*/ + +/* end IAllocator_DX1Collector.cpp */ diff --git a/xo-alloc2/src/alloc2/ICollector_DX1Collector.cpp b/xo-alloc2/src/alloc2/ICollector_DX1Collector.cpp index f2f16888..81962975 100644 --- a/xo-alloc2/src/alloc2/ICollector_DX1Collector.cpp +++ b/xo-alloc2/src/alloc2/ICollector_DX1Collector.cpp @@ -4,9 +4,182 @@ **/ #include "gc/ICollector_DX1Collector.hpp" +#include "GCObject.hpp" namespace xo { namespace mm { + using size_type = ICollector_DX1Collector::size_type; + using std::byte; + + namespace { + size_type + stat_helper(const DX1Collector & d, + size_type (DArena::* getter)() const, + generation g, + role r) + { + const DArena * arena = d.get_space(r, g); + + if (arena) [[likely]] + return (arena->*getter)(); + + return 0; + } + } + + size_type + ICollector_DX1Collector::reserved(const DX1Collector & d, generation g, role r) + { + return stat_helper(d, &DArena::reserved, g, r); + } + + size_type + ICollector_DX1Collector::allocated(const DX1Collector & d, generation g, role r) + { + return stat_helper(d, &DArena::allocated, g, r); + } + + size_type + ICollector_DX1Collector::committed(const DX1Collector & d, generation g, role r) + { + return stat_helper(d, &DArena::committed, g, r); + } + + void + ICollector_DX1Collector::install_type(DX1Collector & d, + std::int32_t tseq, + IGCObject_Any & iface) + { + (void)d; + (void)tseq; + (void)iface; + + assert(false); + } + + void + ICollector_DX1Collector::add_gc_root(DX1Collector & d, + int32_t tseq, + Opaque * root) + { + (void)d; + (void)tseq; + (void)root; + + assert(false); + } + + void + ICollector_DX1Collector::forward_inplace(DX1Collector & d, + obj * lhs) + { + assert(d.runstate_.is_running()); + + /* + * lhs obj + * | +---------+ +---+-+----+ + * \--->| .iface | | T |G|size| header + * +---------+ object_data +---+-+----+ + * | .data x----------------->| alloc | + * +---------+ | data | + * | for | + * | instance | + * | ... | + * +----------+ + */ + + void * object_data = (byte *)(*lhs).opaque_data(); + + if (!d.contains(role::from_space(), object_data)) { + /* *lhs isn't in GC-allocated space. + * + * This happens for a modest number of global + * constant, for example DBoolean {true, false}. + * + * It's important we recognize these up front. + * Since not allocated from GC, they don't have + * an alloc-header. + */ + return; + } + + /** NOTE: for form's sake: + * better to lookup actual arena that + * allocated object data. + * + **/ + DArena * some_arena = d.to_space(generation(0)); + + DArena::header_type * p_header + = some_arena->obj2hdr(object_data); + + DArena::header_type alloc_hdr = *p_header; + + /* recover allocation size */ + std::size_t alloc_z = some_arena->config_.header_size_mask_ & alloc_hdr; + + /* need to be able to fit forwarding pointer + * in place of forwarded object. + * + * This is guaranteed anyway, by alignment rules + */ + assert(alloc_z > sizeof(uintptr_t)); + + if (d.is_forwarding_header(alloc_hdr)) { + /* *lhs already refers to a forwarding pointer */ + + /* + * lhs obj + * | +---------+ +---+-+----+ + * \--->| .iface | |FWD|G|size| alloc_hdr + * +---------+ object_data +---+-+----+ + * | .data x----------------->| x--------> + * +---------+ | | dest + * | | + * +----------+ + */ + void * dest = *(void**)object_data; + + /* update *lhs in-place */ + (*lhs).reset_opaque(dest); + } else if (check_move_policy(d, alloc_hdr, object_data)) { + /* copy object *lhs + replace with forwarding pointer */ + + /* which arena are we writing to? need allocator interface */ + + assert(false); + +#ifdef NOT_YET + // to do this need IAllocator_DX1Collector fully implemented + + void * copy = (*lhs).shallow_copy(xxx); + + xxx mm xxx; +#endif + } else { + /* object doesn't need to move. + * e.g. incremental collection + object is tenured + */ + } + } + + bool + ICollector_DX1Collector::check_move_policy(const DX1Collector & d, + header_type alloc_hdr, + void * object_data) + { + (void)object_data; + + // when gc is moving objects, to- and from- spaces have been + // reversed: forwarding pointers are located in from-space and + // refer to to-space. + + generation g = d.header2gen(alloc_hdr); + + assert(d.runstate_.is_running()); + + return (g < d.runstate_.gc_upto()); + } } /*namespace mm*/ } /*namespace xo*/ diff --git a/xo-alloc2/utest/Collector.test.cpp b/xo-alloc2/utest/Collector.test.cpp index beaa33ab..c1fbca53 100644 --- a/xo-alloc2/utest/Collector.test.cpp +++ b/xo-alloc2/utest/Collector.test.cpp @@ -98,6 +98,9 @@ namespace xo { /* typed collector */ obj x1(&gc); + REQUIRE(x1.iface()); + REQUIRE(x1.data()); + } } } diff --git a/xo-facet/include/xo/facet/OObject.hpp b/xo-facet/include/xo/facet/OObject.hpp index 1f46fad2..66ca9977 100644 --- a/xo-facet/include/xo/facet/OObject.hpp +++ b/xo-facet/include/xo/facet/OObject.hpp @@ -62,6 +62,7 @@ namespace xo { using ISpecific = FacetImplType; using DataType = DRepr; using DataPtr = DRepr*; + using Opaque = void *; explicit OObject() {} explicit OObject(DataPtr d) : data_{d} {} @@ -127,8 +128,10 @@ namespace xo { } DataPtr data() const { return data_; } + Opaque opaque_data() const { return data_; } void reset() { data_ = nullptr; } + void reset_opaque(Opaque data) { data_ = (DataPtr)data; } /** * We're either: diff --git a/xo-facet/include/xo/facet/facet_implementation.hpp b/xo-facet/include/xo/facet/facet_implementation.hpp index bf245d7d..7e561c05 100644 --- a/xo-facet/include/xo/facet/facet_implementation.hpp +++ b/xo-facet/include/xo/facet/facet_implementation.hpp @@ -89,7 +89,7 @@ namespace xo { **/ template struct FacetImplementation { - static_assert(false && "expect specialization which should provide ImplType trait"); + //static_assert(false && "expect specialization which should provide ImplType trait"); }; /** Retrieve facet implementation for a (facet, datatype) pair **/